Discovering Bluetooth Devices Using Winsock
A version of this page is also available for
4/8/2010
An application can create a query for discovering remote Bluetooth devices within range, by using the following standard Winsock programming elements:
- WSAQUERYSET (Bluetooth) structure
- WSALookupServiceBegin (Bluetooth) function
- WSALookupServiceNext (Bluetooth) function
- WSALookupServiceEnd (Bluetooth) function
Note
For clarity, information about error handling has been omitted from this.
The sample that ships with Windows Mobile contains source code for discovering Bluetooth devices by using Winsock.
Procedures
To perform device discovery and retrieve the address of a remote Bluetooth device
Prepare the caller application by providing Winsock-related data such as version and implementation details. This data can be retrieved by calling the WSAStartup function as the following example shows.
WSADATA wsd; WSAStartup (MAKEWORD(1,0), &wsd);
Create and initialize a WSAQUERYSET variable to specify search parameters. Set the dwNameSpace member to NS_BTH to restrict the query to Bluetooth devices.
The following code example shows the values to set in WSAQUERYSET.
WSAQUERYSET wsaq; ZeroMemory(&wsaq, sizeof(wsaq)); wsaq.dwSize = sizeof(wsaq); wsaq.dwNameSpace = NS_BTH; wsaq.lpcsaBuffer = NULL;
To start an inquiry, call the WSALookupServiceBegin function.
The following code example shows how to call WSALookupServiceBegin to perform a device inquiry by passing the WSAQUERYSET variable, created in step 1.
int iRet = WSALookupServiceBegin (&wsaq, LUP_CONTAINERS, &hLookup);
In the preceding example, LUP_CONTAINERS is passed in the dwFlags parameter. This enables Service Discovery Protocol (SDP) to search for other Bluetooth devices within range.
Note
Passing zero(0) in the dwFlags parameter performs a service search. For more information about SDP search, see Querying Service Capability on Remote Bluetooth Devices.
The WSALookupServiceBegin function returns a handle in the hLookup parameter.
To enumerate devices that were scanned in the previous call to WSALookupServiceBegin, call the WSALookupServiceNext function. This function returns a pointer to a buffer that stores the result set in a WSAQUERYSET structure.
Configure a WSAQUERYSET structure to store device data returned by WSALookupServiceNext. The following code shows how to configure this structure.
CHAR buf[4096]; LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf; ZeroMemory(pwsaResults, sizeof(WSAQUERYSET)); pwsaResults->dwSize = sizeof(WSAQUERYSET); pwsaResults->dwNameSpace = NS_BTH; pwsaResults->lpBlob = NULL;
Call WSALookupServiceNext by passing the handle returned by WSALookupServiceBegin in the hLookUp parameter. To improve performance, the call to WSALookupServiceBegin returns only the addresses of the devices, and these addresses are is stored in memory. To retrieve the name and address of the device, pass LUP_RETURN_NAME | LUP_RETURN_ADDR in the dwFlags parameter. The following code shows how to call WSALookupServiceNext.
DWORD dwSize = sizeof(buf); int iRet = WSALookupServiceNext (hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults)
To enumerate the devices, the caller application can loop through the list of devices, by calling WSALookupServiceNext repetitively.
To terminate the device discovery process, call the WSALookupServiceEnd function. This function releases the lookup handle created by WSALookupServiceBegin.
The following code shows how to call WSALookupServiceEnd.
WSALookupServiceEnd(hLookup);
To terminate the use of Winsock services, call the WSACleanup function. There must be a call to WSACleanup for every successful call to WSAStartup made by an application.
The following code example performs a device inquiry displays the device name in a user interface.
//------------------------------------------------------------------------
// Function: PerformInquiry
// Purpose: Performs a device inquiry displays the device name in a user interface.
// Note: This function does not include a call to WSAStartup as described
// in the procedure.
// This sample has not been tested and is not intended for production use.
//------------------------------------------------------------------------
#define MAX_NAME 248
static BOOL PerformInquiry()
{
WSAQUERYSET wsaq;
HANDLE hLookup;
union {
CHAR buf[5000];
double __unused; // ensure proper alignment
};
LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
DWORD dwSize = sizeof(buf);
BOOL bHaveName;
ZeroMemory(&wsaq, sizeof(wsaq));
wsaq.dwSize = sizeof(wsaq);
wsaq.dwNameSpace = NS_BTH;
wsaq.lpcsaBuffer = NULL;
if (ERROR_SUCCESS != WSALookupServiceBegin (&wsaq, LUP_CONTAINERS, &hLookup))
{
wprintf(L"WSALookupServiceBegin failed %d\r\n", GetLastError());
return FALSE;
}
ZeroMemory(pwsaResults, sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
while (ERROR_SUCCESS == WSALookupServiceNext (hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults))
{
ASSERT (pwsaResults->dwNumberOfCsAddrs == 1);
BT_ADDR b = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
bHaveName = pwsaResults->lpszServiceInstanceName && *(pwsaResults->lpszServiceInstanceName);
wprintf (L"%s%s%04x%08x%s\n", bHaveName ? pwsaResults->lpszServiceInstanceName : L"",
bHaveName ? L"(" : L"", GET_NAP(b), GET_SAP(b), bHaveName ? L")" : L"");
}
WSALookupServiceEnd(hLookup);
return TRUE;
}