蓝牙设备发现与C#封装类

在开发移动社交网络应用时,了解附近可用的蓝牙设备是非常重要的。本文将介绍如何使用Winsock 2 API实现蓝牙设备发现功能,并提供一个C#封装类来简化这一过程。

为了开发一个使用Windows Mobile蓝牙功能的移动社交网络应用,需要一种方法来识别附近的蓝牙设备。正在使用.NET Compact Framework 3.5和C#开发这个应用,这意味着需要用C++编写底层的蓝牙功能,将它们编译成DLL,然后编写一个C#封装类并通过P/Invoke来调用这些蓝牙功能。在开发封装类之前,尝试寻找了C#中提供蓝牙发现功能的第三方库,发现了32feet.NET,但它有一些许可限制。因此,决定自己编写一个更简单、可定制的封装类。

架构

封装类DevicesDiscoveryWrapper是用C#编写的,它使用P/Invoke来访问WMBluetoothWrapper DLL文件中导出的函数。后者是用C++编写的,利用Winsock 2 API提供的蓝牙功能来构建设备发现功能。

使用代码

要在开发应用时使用蓝牙设备发现封装类,只需将C#文件DevicesDiscoveryWrapper.cs添加到项目中,并使用DevicesDiscoveryWrapper类。部署时,不要忘记将DLL文件WMBluetoothWrapper.dll复制到项目移动工作目录中。下面,将详细描述使用蓝牙Winsock 2 API编写的设备发现功能和C#封装类。

以下是C++代码示例,展示了如何实现设备发现功能:

// WMBluetoothWrapper.h extern "C" int DevicesDiscovery(wchar_t* devicesList); // WMBluetoothWrapper.cpp #include extern "C" int DevicesDiscovery(wchar_t* devicesList) { WSADATA wsd; WSAStartup(MAKEWORD(1, 0), &wsd); HANDLE hLookup; union { CHAR buf[5000]; double __unused; // ensure proper alignment }; LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET)buf; DWORD dwSize = sizeof(buf); BOOL bHaveName; WSAQUERYSET wsaq; ZeroMemory(&wsaq, sizeof(wsaq)); wsaq.dwSize = sizeof(wsaq); wsaq.dwNameSpace = NS_BTH; wsaq.lpcsaBuffer = NULL; if (ERROR_SUCCESS != WSALookupServiceBegin(&wsaq, LUP_CONTAINERS, &hLookup)) { wsprintf(devicesList, L"WSALookupServiceBegin failed %d\r\n", GetLastError()); return -1; } ZeroMemory(pwsaResults, sizeof(WSAQUERYSET)); pwsaResults->dwSize = sizeof(WSAQUERYSET); pwsaResults->dwNameSpace = NS_BTH; pwsaResults->lpBlob = NULL; int numberRetrivedDevices = 0; while (ERROR_SUCCESS == WSALookupServiceNext(hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults)) { wchar_t currentDev[1024]; if (pwsaResults->dwNumberOfCsAddrs != 1) { wsprintf(devicesList, L"WSALookupServiceNext failed %d\r\n", GetLastError()); return -1; } if (numberRetrivedDevices > 0) wcscat(devicesList, L","); BT_ADDR b = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr; bHaveName = pwsaResults->lpszServiceInstanceName && *(pwsaResults->lpszServiceInstanceName); wsprintf(currentDev, L"%s%s%04x%08x%s\n", bHaveName ? pwsaResults->lpszServiceInstanceName : L"", bHaveName ? L"(" : L"", GET_NAP(b), GET_SAP(b), bHaveName ? L")" : L""); wcscat(devicesList, currentDev); numberRetrivedDevices++; } WSALookupServiceEnd(hLookup); WSACleanup(); return numberRetrivedDevices; }

以下是C#封装类代码示例:

using System; using System.Text; using System.Runtime.InteropServices; using System.Windows.Forms; class DevicesDiscoveryWrapper { [DllImport("WMBluetoothWrapper.dll")] private static extern System.Int32 DevicesDiscovery([MarshalAs(UnmanagedType.LPWStr)] StringBuilder listDevices); private static string devicesList; private static int numberDevices; private static DevicesDiscoveryWrapper _wrapper = null; private DevicesDiscoveryWrapper() { devicesList = null; numberDevices = 0; } public static DevicesDiscoveryWrapper GetDevicesDiscoveryWrapper() { if (_wrapper == null) { _wrapper = new DevicesDiscoveryWrapper(); } return _wrapper; } public string GetDevices { get { lock (this) { return devicesList; } } } public int GetNumberOfDevices { get { lock (this) { return numberDevices; } } } public void RunDevicesDiscovery() { lock (this) { StringBuilder tmpListDevices = new StringBuilder(); tmpListDevices.Capacity = 1024; int res = DevicesDiscovery(tmpListDevices); if (res == -1) { MessageBox.Show("Error occurred while calling the unmanaged DevicesDiscovery functions: " + tmpListDevices.ToString()); } else { devicesList = tmpListDevices.ToString(); numberDevices = res; } } } }

相关工具

DLL Export Viewer工具对于验证/调试WMBluetoothWrapper DLL文件中导出的函数列表及其虚拟内存地址非常有用。有关此工具的更多详细信息,请访问:。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485