⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bluetooth_wm.cpp

📁 蓝牙设备搜索与连接 RDSTerminal
💻 CPP
字号:
#include "StdAfx.h"
#include "BlueTooth_WM.h"

// for PORTEMUPortParams
#include <bt_api.h>

DEFINE_GUID(SerialPortServiceClass_UUID,               0x00001101, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB);

DWORD WINAPI ThreadProc_ScanNearbyBthDev(
  LPVOID lpParameter   // thread data
)
{
	CBlueTooth_WM *pBlueTooth_WM = reinterpret_cast<CBlueTooth_WM*>(lpParameter);
	if ( pBlueTooth_WM )
		pBlueTooth_WM->ThreadProc_ScanNearbyBthDev ();
	return TRUE;
}

CBlueTooth_WM::CBlueTooth_WM(void)
	: m_hThread_ScanNearbyBthDev ( NULL )
	, m_dwThreadID_ScanNearbyBthDev ( 0 )
	, m_hEvtEndModule ( NULL )
	, m_hEvt_Notify_ScanNearbyBthDev ( NULL )
	, m_hWnd_Noify_ScanNearbyBthDev ( NULL )
	, m_socketClient ( INVALID_SOCKET )

{
	m_Ary_RemoteBthDevInfo.SetSize ( 0, 10*sizeof(t_RemoteBthDevInfo) );
}

CBlueTooth_WM::~CBlueTooth_WM(void)
{
	if ( HANDLE_IS_VALID(m_hEvtEndModule) )
		::SetEvent ( m_hEvtEndModule );

	WaitForThreadEnd ( &m_hThread_ScanNearbyBthDev, 10*1000 );
	SAFE_CLOSE_HANDLE ( m_hEvtEndModule );
	if ( m_socketClient != INVALID_SOCKET )
		closesocket ( m_socketClient );

	RemoveAll_RemoteBthDevInfo ();
}

//
// 调用该类中任何函数之前必须先调用该函数来初始化
//
BOOL CBlueTooth_WM::Init ( LPCTSTR lpszCurDir )
{
	m_hEvtEndModule = ::CreateEvent ( NULL, TRUE, FALSE, NULL );
	if ( !HANDLE_IS_VALID(m_hEvtEndModule) )
		return FALSE;
	m_csCurDir = GET_SAFE_STRING(lpszCurDir);
	Read_RemoteBthDevInfo_FromFile ( m_csCurDir );

	return TRUE;
}

void CBlueTooth_WM::ThreadProc_ScanNearbyBthDev ()
{
	int nRetValue = ScanNearbyBthDev_Direct ();
	if ( HANDLE_IS_VALID(m_hEvt_Notify_ScanNearbyBthDev) )
		SetEvent ( m_hEvt_Notify_ScanNearbyBthDev );
	if ( IsWindow(m_hWnd_Noify_ScanNearbyBthDev) )
		PostMessage ( m_hWnd_Noify_ScanNearbyBthDev, WM_SCAN_BLUETOOTH_DEVICE_FINISHED, nRetValue, 0 );

	SAFE_CLOSE_HANDLE ( m_hThread_ScanNearbyBthDev );
	TRACE ( L"ThreadProc_ScanNearbyBthDev END\n" );
}

//
// 搜索附近的蓝牙设备,如果指定 hEvt_Notify 或 hWnd_Noify 参数,表示异步查找,完成后以这两个参数中的一个通知调用者
// 如果这两个参数都未指定,表示同步查找,即完成后才会返回
//
BOOL CBlueTooth_WM::ScanNearbyBthDev ( HANDLE hEvt_Notify/*=NULL*/, HWND hWnd_Noify/*=NULL*/ )
{
	if ( HANDLE_IS_VALID(m_hThread_ScanNearbyBthDev) ) return TRUE;

	// 异步查找蓝牙设备,启动查找函数
	if ( hEvt_Notify || IsWindow(hWnd_Noify) )
	{
		m_hEvt_Notify_ScanNearbyBthDev = hEvt_Notify;
		m_hWnd_Noify_ScanNearbyBthDev = hWnd_Noify;
		m_hThread_ScanNearbyBthDev = ::CreateThread ( NULL, 0, ::ThreadProc_ScanNearbyBthDev, this, 0, &m_dwThreadID_ScanNearbyBthDev );
		return HANDLE_IS_VALID(m_hThread_ScanNearbyBthDev);
	}
	return ( ScanNearbyBthDev_Direct() >= 0 );
}

//
// 用 Socket 函数搜索附近的蓝牙设备,成功时返回设备数,否则返回-1
//
int CBlueTooth_WM::ScanNearbyBthDev_Direct ()
{
	m_Ary_RemoteBthDevInfo.RemoveAll ();

	SetWaitCursor ();

	WSAQUERYSET querySet;
	HANDLE hLookup;
	DWORD flags = LUP_RETURN_NAME | LUP_RETURN_ADDR; 

	union
	{
		CHAR buf[5000];
		double __unused; // ensure proper alignment
	};

	LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
	DWORD dwSize = sizeof(buf);
	BOOL bHaveName;
	ZeroMemory(&querySet, sizeof(querySet));
	querySet.dwSize = sizeof(querySet);
	querySet.dwNameSpace = NS_BTH;
	if ( ::WaitForSingleObject ( m_hEvtEndModule, 0 ) == WAIT_OBJECT_0 )
		return -1;
	if (ERROR_SUCCESS != WSALookupServiceBegin (&querySet, LUP_CONTAINERS, &hLookup))
	{
		ResotreCursor ();
		MsgBoxErr ( _T("WSALookupServiceBegin failed") );
		return (-1);
	}

	ZeroMemory(pwsaResults, sizeof(WSAQUERYSET));
	pwsaResults->dwSize = sizeof(WSAQUERYSET);
	pwsaResults->dwNameSpace = NS_BTH;
	pwsaResults->lpBlob = NULL;
	BOOL bError = FALSE;
	while ( TRUE )
	{
		if ( ::WaitForSingleObject ( m_hEvtEndModule, 0 ) == WAIT_OBJECT_0 )
			break;
		if ( ERROR_SUCCESS == WSALookupServiceNext (hLookup, flags, &dwSize, pwsaResults) )
		{
			ASSERT (pwsaResults->dwNumberOfCsAddrs == 1);
			BT_ADDR b = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
			bHaveName = pwsaResults->lpszServiceInstanceName && *(pwsaResults->lpszServiceInstanceName);
			t_RemoteBthDevInfo RemoteBthDevInfo;
			if ( bHaveName )
			{
				hwSnprintf ( RemoteBthDevInfo.szName, sizeof(RemoteBthDevInfo.szName), _T("%s"), 
					pwsaResults->lpszServiceInstanceName );
			}
			RemoteBthDevInfo.RemoteAddr = b;

			CSADDR_INFO* pCSAddr = (CSADDR_INFO *)pwsaResults->lpcsaBuffer;
			RemoteBthDevInfo.LocalAddr = ((SOCKADDR_BTH *)pCSAddr->LocalAddr.lpSockaddr)->btAddr;

			TRACE (L"%s ( %04x%08x )\n", RemoteBthDevInfo.szName, GET_NAP(b), GET_SAP(b) );
			Add_RemoteBthDevInfo ( RemoteBthDevInfo );
		}
		else
		{
			if ( WSAGetLastError() != WSA_E_NO_MORE )
			{
				bError = TRUE;
				ResotreCursor ();
				MsgBoxErr ( L"Lookup bluetooth device failed" );
			}
			break;
		}
	}
	WSALookupServiceEnd(hLookup);

	ResotreCursor ();
	if ( bError ) return (-1);
	return (int)m_Ary_RemoteBthDevInfo.GetSize();
}

CString CBlueTooth_WM::FormatBthAddress(BT_ADDR BthAddress)
{
	ASSERT ( BthAddress );
	BLUETOOTH_ADDRESS Address;
	BYTE *pAddress = (BYTE*)&BthAddress;
	CString csBthAddress;
	for ( int i=0; i<LENGTH(Address.rgBytes); i++ )
	{
		CString csNode;
		csNode.Format ( _T("%.2x"), pAddress[LENGTH(Address.rgBytes)-i-1] );
		if ( !csBthAddress.IsEmpty() ) csBthAddress += ":";
		csBthAddress += csNode;
	}
	return csBthAddress;
}

int CBlueTooth_WM::Find_RemoteBthDevInfo ( LPCTSTR lpszName_Found, t_RemoteBthDevInfo *pRemoteBthDevInfo/*=NULL*/ )
{
	if ( !lpszName_Found || strlen_s(lpszName_Found) < 1 ) return -1;
	for ( int i=0; i<m_Ary_RemoteBthDevInfo.GetSize(); i++ )
	{
		t_RemoteBthDevInfo &RemoteBthDevInfoRef = m_Ary_RemoteBthDevInfo.GetAt(i);
		if ( stricmp_s ( RemoteBthDevInfoRef.szName, lpszName_Found ) == 0 )
		{
			if ( pRemoteBthDevInfo )
			{
				memcpy ( pRemoteBthDevInfo, &RemoteBthDevInfoRef, sizeof(t_RemoteBthDevInfo) );
			}
			return i;
		}
	}
	return -1;
}

int CBlueTooth_WM::Find_RemoteBthDevInfo ( BT_ADDR Addr_Found, t_RemoteBthDevInfo *pRemoteBthDevInfo/*=NULL*/ )
{
	for ( int i=0; i<m_Ary_RemoteBthDevInfo.GetSize(); i++ )
	{
		t_RemoteBthDevInfo &RemoteBthDevInfoRef = m_Ary_RemoteBthDevInfo.GetAt(i);
		if ( RemoteBthDevInfoRef.RemoteAddr == Addr_Found )
		{
			if ( pRemoteBthDevInfo )
			{
				memcpy ( pRemoteBthDevInfo, &RemoteBthDevInfoRef, sizeof(t_RemoteBthDevInfo) );
			}
			return i;
		}
	}
	return -1;
}

int CBlueTooth_WM::Add_RemoteBthDevInfo ( t_RemoteBthDevInfo &RemoteBthDevInfo )
{
	if ( Find_RemoteBthDevInfo ( RemoteBthDevInfo.RemoteAddr ) >= 0 )
		return TRUE;
	m_Ary_RemoteBthDevInfo.Add ( RemoteBthDevInfo );
}

void CBlueTooth_WM::RemoveAll_RemoteBthDevInfo(void)
{
	Save_RemoteBthDevInfo_ToFile ( m_csCurDir );
	for ( int i=0; i<m_Ary_RemoteBthDevInfo.GetSize(); i++ )
	{
		t_RemoteBthDevInfo &RemoteBthDevInfo = m_Ary_RemoteBthDevInfo.GetAt(i);
	}
	m_Ary_RemoteBthDevInfo.RemoveAll ();
}

//
// 将周边蓝牙设备信息保存到文件中,这样就可以不用每次都重新搜索蓝牙设备了,只要当连接蓝牙设备失败的时候再重新搜索
//
BOOL CBlueTooth_WM::Save_RemoteBthDevInfo_ToFile(LPCTSTR lpszPath)
{
	CString csFileName;
	csFileName.Format ( L"%sRemoteBthInfo.info", GET_SAFE_STRING(lpszPath) );
	CFile file;
	BOOL bRet = TRUE;
	TRY
	{
		if ( file.Open ( csFileName, CFile::modeCreate|CFile::modeWrite) )
		{
			for ( int i=0; i<m_Ary_RemoteBthDevInfo.GetSize(); i++ )
			{
				t_RemoteBthDevInfo &RemoteBthDevInfo = m_Ary_RemoteBthDevInfo.GetAt(i);
				file.Write ( &RemoteBthDevInfo, sizeof(RemoteBthDevInfo) );
			}
		}
	}
	CATCH( CFileException, e )
	{
		e->Delete ();
		bRet = FALSE;
	}
	END_CATCH
	if ( HANDLE_IS_VALID ( file.m_hFile ) )
		file.Close ();

	return bRet;
}

//
// 从文件中读取上次保存的周边蓝牙设备信息,结果保存到 m_Ary_RemoteBthDevInfo 数组中
//
BOOL CBlueTooth_WM::Read_RemoteBthDevInfo_FromFile(LPCTSTR lpszPath)
{
	CString csFileName;
	csFileName.Format ( L"%sRemoteBthInfo.info", GET_SAFE_STRING(lpszPath) );
	CFile file;
	BOOL bRet = TRUE;
	TRY
	{
		if ( file.Open ( csFileName, CFile::modeRead) )
		{
			while ( TRUE )
			{
				t_RemoteBthDevInfo RemoteBthDevInfo;
				if ( file.Read ( &RemoteBthDevInfo, sizeof(t_RemoteBthDevInfo) ) != sizeof(t_RemoteBthDevInfo) )
					break;
				else
				{
					Add_RemoteBthDevInfo ( RemoteBthDevInfo );
				}
			}
		}
	}
	CATCH( CFileException, e )
	{
		e->Delete ();
		bRet = FALSE;
	}
	END_CATCH
	if ( HANDLE_IS_VALID ( file.m_hFile ) )
		file.Close ();

	return bRet;
}

BOOL CBlueTooth_WM::StringToGUID ( LPCTSTR lpszGUID, GUID *pGUID)
{
	if ( !lpszGUID ) return FALSE;
	int data1, data2, data3;
	int data4[8];

	if (11 ==  sscanf_s(lpszGUID, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
					&data1, &data2, &data3,
					&data4[0], &data4[1], &data4[2], &data4[3], 
					&data4[4], &data4[5], &data4[6], &data4[7])) {
		pGUID->Data1 = data1;
		pGUID->Data2 = data2 & 0xffff;
		pGUID->Data3 = data3 & 0xffff;

		for (int i = 0 ; i < 8 ; ++i)
			pGUID->Data4[i] = data4[i] & 0xff;

		return TRUE;
	}
	return FALSE;
}

//
// 连接到蓝牙服务器中的某一个服务,成功返回0,失败返回错误代码
//
int CBlueTooth_WM::ConnectToBlueToothServer ( BT_ADDR ServerAddress, LPCTSTR lpszServiceGUID )
{
	if ( m_socketClient==INVALID_SOCKET )
	{
		GUID ServerGuid;

		if ( !StringToGUID(lpszServiceGUID, &ServerGuid) )
			return -1;
		m_socketClient = socket (AF_BT, SOCK_STREAM, BTHPROTO_RFCOMM);
		if (m_socketClient == INVALID_SOCKET) 
		{
			return WSAGetLastError();
		}

		SOCKADDR_BTH sa;
		memset (&sa, 0, sizeof(sa));
		sa.addressFamily = AF_BT;
		sa.serviceClassId = ServerGuid;
		sa.btAddr = ServerAddress;
		if (connect (m_socketClient, (SOCKADDR *)&sa, sizeof(sa)) == SOCKET_ERROR) 
		{
			m_socketClient = INVALID_SOCKET;
			return WSAGetLastError();
		}
	}

	// Set nonblocking of socket
/*	long cmd = FIONBIO;
	u_long argp = 1;	// 0 表示阻塞, 非0 表示非阻塞
	BOOL err = ioctlsocket ( m_socketClient, cmd, (u_long*)&argp );
	if ( err )
	{
		TRACE ( L"Set main socket to(#1) nonblocking failed!\n" );
	}
*/
	return 0;
}

//
// 断开连接
//
void CBlueTooth_WM::Disconnect ()
{
	if ( m_socketClient==INVALID_SOCKET ) return;
	shutdown ( m_socketClient, SD_BOTH );
	closesocket ( m_socketClient );
	m_socketClient = INVALID_SOCKET;
}

//
// 数据传输(收/发)
// 返回成功传输的字节数。失败时返回 -1;连接已经断开,返回 -2;处理不能立即完成,返回-3
//
int CBlueTooth_WM::Transmite ( LPVOID lpData, int nSize, BOOL bSend )
{
	if ( m_socketClient==INVALID_SOCKET ) return -1;
	if ( !lpData ) return -1;
	if ( nSize < 1 ) return 0;

	int iBytesTransmited = 0;
	if ( bSend )
		iBytesTransmited = send (m_socketClient, (char *)lpData, nSize, 0);
	else
		iBytesTransmited = recv (m_socketClient, (char *)lpData, nSize, 0);
	if ( iBytesTransmited > 0 ) return iBytesTransmited;

	int nLastError = WSAGetLastError ();
	if ( nLastError == WSAENETDOWN || nLastError == WSAENOTCONN || nLastError == WSAENOTSOCK || nLastError == WSAESHUTDOWN ||
		nLastError == WSAETIMEDOUT )
	{
		Disconnect ();
		return -2;
	}
	if ( nLastError == WSAEWOULDBLOCK )
		return -3;

	return -1;
}

//
// 发送数据
// 返回成功发送的字节数。失败时返回 -1;连接已经断开,返回 -2;处理不能立即完成,返回-3
//
int CBlueTooth_WM::Send ( LPVOID lpData, int nSize )
{
	return Transmite ( lpData, nSize, TRUE );
}

//
// 接收数据
// 返回接受到的字节数。失败时返回 -1;连接已经断开,返回 -2;处理不能立即完成,返回-3
//
int CBlueTooth_WM::Recv ( LPVOID lpData, int nSize )
{
	// 得到可读的数据长度
	long cmd = FIONREAD;
	u_long argp = 0;
	BOOL err = ioctlsocket ( m_socketClient, cmd, (u_long*)&argp );
	if ( err || argp < 1 )
	{
		return 0;
	}

	return Transmite ( lpData, nSize, FALSE );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -