Get Familiar: Microsoft Bluetooth Stack on Windows Mobile
Few General Words
The previous article, "Experiencing This Mysterious Bluetooth Stack Programming," gave you a very brief overview of the Widcomm BT stack and how to manage it from your own applications. Now, you switch to yet another implementation of Bluetooth stack, this time from Microsoft as a part of the Windows Mobile OS SDK. It follows the common Microsoft C-style paradigm and is quite different from, for example, the Widcomm stack. In this article, you will repeat those typical operations you might be needing to use in many cases (as in BT devices enumeration and so forth) as you did for the Widcomm stack. Code snippets here and there throughout the article should provide you a good basis for your own experiments.
Enumerating Bluetooth Devices
If you look at the SDK headers, you will see a few files related to Bluetooth. What you are interested in right now is located in winsock2.h. Here, you may find client-level APIs to the BT stack. For enumeration purposes, you will use the following functions:
WSALookupServiceBegin WSALookupServiceNext WSALookupServiceEnd
Seeing a "WSA" prefix in the API declarations above, you might bet it has to deal with sockets somehow. Yes, that's correct. Here, you'll get a good mix of sockets with virtual RFComm channels. Saying all this, the actual programming may be even simpler than for the Widcomm stack, but it really depends on your requirements.
All right, let me start with device enumeration. A scheme here is quite typical for many enumerating operations you can perform with other media, such as, for example, files:
- Open enumeration
- Loop through with 'Next' function
- Close enumeration
In practice you have to do the following steps, as in this code snippet:
struct BtInfo
{
CString m_sName;
BT_ADDR m_btAddr;
};
typedef CArray<BtInfo,BtInfo&> CBtInfoArray;
int DiscoverBtDevList(CBtInfoArray& arrBtInfo)
{
BOOL bRes = FALSE;
int iResult = 0;
LPWSAQUERYSET pwsaResults;
DWORD dwSize = 0;
WSAQUERYSET wsaq;
HANDLE hLookup = 0;
memset (&wsaq, 0, sizeof(wsaq));
wsaq.dwSize = sizeof(wsaq);
wsaq.dwNameSpace = NS_BTH;
wsaq.lpcsaBuffer = NULL;
// initialize searching procedure
iResult = WSALookupServiceBegin(&wsaq,
LUP_CONTAINERS,
&hLookup);
if (iResult != 0)
{
iResult = WSAGetLastError();
return iResult;
}
union {
// returned struct can be quite large
CHAR buf[5000];
// properly align buffer to BT_ADDR requirements
SOCKADDR_BTH __unused;
};
for (;;)
{
pwsaResults = (LPWSAQUERYSET) buf;
dwSize = sizeof(buf);
memset(pwsaResults,0,sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
// namespace MUST be NS_BTH for bluetooth queries
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
// iterate through all found devices, returning name and address
iResult = WSALookupServiceNext (hLookup,
LUP_RETURN_NAME | LUP_RETURN_ADDR,
&dwSize,
pwsaResults);
if (iResult != 0)
{
iResult = WSAGetLastError();
if (iResult != WSA_E_NO_MORE)
{
TCHAR tszErr[32];
iResult = WSAGetLastError();
_sntprintf(tszErr, 32, _T("Socket Error: %d"), iResult);
AfxMessageBox(tszErr, MB_OK);
}
break;
}
// collect name and address
if (pwsaResults->lpszServiceInstanceName)
{
BtInfo btInfo;
btInfo.m_sName = pwsaResults->lpszServiceInstanceName;
memcpy(&(btInfo.m_btAddr),pwsaResults->
lpcsaBuffer,sizeof(BT_ADDR));
arrBtInfo.Add(btInfo);
}
Sleep(100);
}
WSALookupServiceEnd(hLookup);
return iResult;
}
As you can see, there is nothing complex except few magical words and passes. The latter, I will discuss right here. First, you want to look up all containers in NS_BTH namespace. Second, you don't want to get back any additional information about neither local nor remote addresses. Thus wsaq variable setup and call to WSALookupServiceBegin start the race.
The next stage is a simple iteration through obtained results until you get an error WSA_E_NO_MORE after calling WSALookupServiceNext. You can control which data you want to get via parameters of that function. Our snippet requests a name and BT address. For simplicity, you use MFC's CArray here, but you may return the result as you want to—for example, looking up only for specific device and so forth.
