Windows Bluetooth WSALookupServiceBegin returns WSASERVICE_NOT_FOUND (10108) if there are no devices in range?

StackOverflow https://stackoverflow.com/questions/19762847

Question

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:

  1. There is no adapter on the host machine
  2. There are no bluetooth devices within range to scan (i.e. an empty scan set)

So my questions are:

  1. Is this expected?
  2. How do I further determine which one is happening?

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;
    }
}
Was it helpful?

Solution

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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top