Querying Service Capability on Remote Bluetooth Devices (Windows Embedded CE 6.0)
1/6/2010
An application can query for services on a remote Bluetooth device by using the following standard Winsock programming elements:
- WSAQUERYSET (Bluetooth) structure
- WSALookupServiceBegin (Bluetooth) function
- WSALookupServiceNext (Bluetooth) function
- WSALookupServiceEnd (Bluetooth) function
Before you query service capability on remote Bluetooth devices, you must have the following information:
You must have the address of the a remote Bluetooth device to query, as a BT_ADDR type, as defined in Ws2bth.h:
typedef ULONGLONG bt_addr, *pbt_addr, BT_ADDR, *PBT_ADDR;
Note
This procedure does not include error handling for code clarity.
The Ssa sample that ships with Windows Embedded CE, contains source code for querying Bluetooth services by using Winsock.
For more information about this sample, see Windows Embedded CE topic Winsock Interface Sample.
To perform a service query on a remote Bluetooth device
To 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);
Specify the search parameters by configuring the WSAQUERYSET structure.
The following code example shows the values in this structure.
WSAQUERYSET wsaq; memset (&wsaq, 0, sizeof(wsaq)); wsaq.dwSize = sizeof(wsaq); wsaq.dwNameSpace = NS_BTH; wsaq.lpBlob = &blob; wsaq.lpcsaBuffer = &csai;
Restrict the search to Bluetooth queries by setting the dwNameSpace member to NS_BTH. For information about how to set the other members, see Configuring WSAQUERYSET for Service Discovery.
To initiate the search process, call the WSALookupServiceBegin function. Specify the search criteria by passing the WSAQUERYSET variable, created in step 1, in the pQuerySet parameter. The following code example show how to call WSALookupServiceBegin.
int iRet = WSALookupServiceBegin (&wsaq, 0, &hLookup);
Pass zero (0) in the dwFlags parameter to perform a service query on the remote device. WSALookupServiceBegin returns a handle in the hLookup parameter.
Note
Passing LUP_CONTAINERS in the dwFlags parameter, sets up WSALookupServiceBegin to perform a device inquiry. For more information about creating device queries, see Discovering Bluetooth Devices Using Winsock.
To retrieve data about the services found on the remote device, call the WSALookupServiceNext function by using the handle returned by WSALookupServiceBegin as shown in the following code example.
CHAR buf[5000]; LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf; DWORD dwSize = sizeof(buf); memset(pwsaResults,0,sizeof(WSAQUERYSET)); pwsaResults->dwSize = sizeof(WSAQUERYSET); pwsaResults->dwNameSpace = NS_BTH; pwsaResults->lpBlob = NULL; iRet = WSALookupServiceNext (hLookup, 0, &dwSize, pwsaResults);
WSALookupServiceNext returns a pointer to WSAQUERYSET that references the service data in the lpBlob member. This member points to a BLOB (Windows Sockets) structure, which contains the binary data that is returned by WSALookupServiceNext all at once. Windows Embedded CE provides COM interfaces that you can use to parse service data. For more information about how to use these interfaces to parse the binary data, see Parsing an SDP Record Using COM Interfaces.
To terminate the service discovery process, call the WSALookupServiceEnd function. This function releases the lookup handle created by WSALookupServiceBegin.
The following code example 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 shows a function, PerformServiceSearch that queries a remote Bluetooth device for the supported services. The remote device is specified by passing a pointer to the address of the device stored in the in a BT_ADDR type, as defined in Ws2bth.h:
typedef ULONGLONG bt_addr, *pbt_addr, BT_ADDR, *PBT_ADDR;
//------------------------------------------------------------------------
// Function: PerformServiceSearch
// Purpose: Performs a service search and returns the RFCOMM channel for
// the specified Bluetooth remote device.
// Arguments: BT_ADDR *pb
// Returns: int
//------------------------------------------------------------------------
static int PerformServiceSearch (BT_ADDR *pb)
{
CoInitializeEx (0, COINIT_MULTITHREADED);
int iResult = 0;
BTHNS_RESTRICTIONBLOB RBlob;
memset (&RBlob, 0, sizeof(RBlob));
RBlob.type = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
RBlob.numRange = 1;
RBlob.pRange[0].minAttribute = SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST;
RBlob.pRange[0].maxAttribute = SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST;
RBlob.uuids[0].uuidType = SDP_ST_UUID16;
RBlob.uuids[0].u.uuid16 = SerialPortServiceClassID_UUID16;
BLOB blob;
blob.cbSize = sizeof(RBlob);
blob.pBlobData = (BYTE *)&RBlob;
SOCKADDR_BTH sa;
memset (&sa, 0, sizeof(sa));
*(BT_ADDR *)(&sa.btAddr) = *pb;
sa.addressFamily = AF_BT;
CSADDR_INFO csai;
memset (&csai, 0, sizeof(csai));
csai.RemoteAddr.lpSockaddr = (sockaddr *)&sa;
csai.RemoteAddr.iSockaddrLength = sizeof(sa);
WSAQUERYSET wsaq;
memset (&wsaq, 0, sizeof(wsaq));
wsaq.dwSize = sizeof(wsaq);
wsaq.dwNameSpace = NS_BTH;
wsaq.lpBlob = &blob;
wsaq.lpcsaBuffer = &csai;
HANDLE hLookup;
int iRet = WSALookupServiceBegin (&wsaq, 0, &hLookup);
if (ERROR_SUCCESS == iRet)
{
CHAR buf[5000];
LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
DWORD dwSize = sizeof(buf);
memset(pwsaResults,0,sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
iRet = WSALookupServiceNext (hLookup, 0, &dwSize, pwsaResults);
if (iRet == ERROR_SUCCESS) // Success - got the stream
{
//Parse the SDP result set by using the FindRFCOMMChannel function.
if (ERROR_SUCCESS == FindRFCOMMChannel (pwsaResults->lpBlob->pBlobData, pwsaResults->lpBlob->cbSize, &cChannel))
iResult = cChannel;
}
WSALookupServiceEnd(hLookup);
}
CoUninitialize ();
return iResult;
}