Reputation: 384
I have been trying out Bluetooth programming on Windows using the Winsock APIs and have encountered a problem in how to determine whether there is no bluetooth on the host or whether the scan set is empty..
So the program is very simple, Start Winsock, call WSALookupServiceBegin and then call ServiceNext and ServiceEnd as we scan for devices. The development machine has a Bluetooth radio, the driver is Microsoft BT Stack and I can find devices using the Devices wizard through Windows.
The problem is that on the call to WSALookupServiceBegin, WSASERVICE_NOT_FOUND is returned in two cases:
So my questions are:
Thanks in advance!
Code attached:
int main(int argc, char **argv)
{
WSADATA wsd;
BOOL retVal;
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
printf("WSAStartup() failed with error code %ld\n", WSAGetLastError());
else
printf("WSAStartup() is OK!\n");
scan();
if (WSACleanup() == 0)
printf("WSACleanup() is OK!\n");
else
printf("WSACleanup() failed with error code %ld\n", WSAGetLastError());
return 0;
}
And scan();
void scan()
{
WSAQUERYSET queryset;
memset(&queryset, 0, sizeof(WSAQUERYSET));
queryset.dwSize = sizeof(WSAQUERYSET);
queryset.dwNameSpace = NS_BTH;
// begin query
HANDLE hDeviceLookup;
if (WSALookupServiceBegin(&queryset, LUP_FLUSHCACHE | LUP_CONTAINERS, &hDeviceLookup)) {
int last_error = WSAGetLastError();
wcout << getWinErrorMessage(last_error) << endl;
return;
}
int bufSize = 0x2000;
void* buf = malloc(bufSize);
int result = -1;
while (result == -1) {
memset(buf, 0, bufSize);
LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET)buf;
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
DWORD size = bufSize;
if (hDeviceLookup == NULL) {
break;
}
if (WSALookupServiceNext(hDeviceLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR | LUP_RETURN_BLOB, &size, pwsaResults)) {
int last_error = WSAGetLastError();
switch (last_error) {
case WSAENOMORE:
case WSA_E_NO_MORE:
result = 2;
break;
default:
wcout << getWinErrorMessage(last_error) << endl;
result = 3;
}
WSALookupServiceEnd(hDeviceLookup);
hDeviceLookup = NULL;
break;
}
BTH_DEVICE_INFO *p_inqRes = (BTH_DEVICE_INFO *)pwsaResults->lpBlob->pBlobData;
// get device name
WCHAR name[256];
BOOL bHaveName = pwsaResults->lpszServiceInstanceName && *(pwsaResults->lpszServiceInstanceName);
wcout << pwsaResults->lpszServiceInstanceName << endl;
int deviceClass = p_inqRes->classOfDevice;
BTH_ADDR deviceAddr;
deviceAddr = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
}
if (buf != NULL) {
free(buf);
}
if (hDeviceLookup != NULL) {
WSALookupServiceEnd(hDeviceLookup);
hDeviceLookup = NULL;
}
}
Upvotes: 1
Views: 3034
Reputation: 21644
I use the following code to determine if I can use the Windows Bluetooth stack and if the required hardware is present.
CanUseBluetooth() simply checks that there's a winsock provider that understands the bluetooth protocol. If that's the case then the stack is installed.
static bool CanUseBluetooth(
bool throwOnFailure)
{
static const CAddressTypeBluetooth addressType;
SOCKET s = ::socket(addressType.Family(), SOCK_STREAM, addressType.Protocol());
const bool canUseBluetooth = (s != INVALID_SOCKET);
const DWORD lastError = ::GetLastError();
::closesocket(s);
if (!canUseBluetooth && throwOnFailure)
{
throw CWin32Exception(_T("CUsesXPBluetooth::CanUseBluetooth()"), lastError);
}
return canUseBluetooth;
}
HarwareActive() checks that we can bind to the wildcard address, if we can do that then we have some active bluetooth hardware that's using the Windows stack.
static bool HardwareActive(
bool throwOnFailure)
{
static const CAddressTypeBluetooth addressType;
SOCKET s = ::socket(addressType.Family(), SOCK_STREAM, addressType.Protocol());
if (s == INVALID_SOCKET)
{
const DWORD lastError = ::GetLastError();
::closesocket(s);
throw CWin32Exception(_T("CUsesXPBluetooth::HardwareActive() - CanUseBluetooth"), lastError);
}
bool hardwareActive = true;
static const IAddress &address = addressType.WildcardAddress();
if (SOCKET_ERROR == ::bind(s, &address.AsSockAddr(), address.Size()))
{
hardwareActive = false;
}
const DWORD lastError = ::GetLastError();
::closesocket(s);
if (!hardwareActive && throwOnFailure)
{
throw CWin32Exception(_T("CUsesXPBluetooth::HardwareActive()"), lastError);
}
return hardwareActive;
}
Upvotes: 1