2
votes

I am currently trying to use the WINSOCK 2 API in order to discover available Bluetooth devices near by. I am using code which is based on a Microsoft example which can be found here.

I am mainly using WSALookupServiceNext to iterate through the available devices. The issue is that I only get a list of previous paired Bluetooth devices, and I am not seeing any other devices. I added some code in order to print device information:

*********************
Winsock search started!
*********************

Device #:1
Device name:MagicBox II
Device connected: 0
Device remembered: 1
Device authenticated: 1
Remote Bluetooth device is 0x00025b3dc371, server channel = 0
Local Bluetooth device is 0x84ef18b8460a, server channel = 0
Device #:2
Device name:Mpow Flame
Device connected: 0
Device remembered: 1
Device authenticated: 1
Remote Bluetooth device is 0x501801101c68, server channel = 0
Local Bluetooth device is 0x84ef18b8460a, server channel = 0
Device #:3
Device name:WH-1000XM2
Device connected: 0
Device remembered: 1
Device authenticated: 1
Remote Bluetooth device is 0x702605aba41d, server channel = 0
Local Bluetooth device is 0x84ef18b8460a, server channel = 0
Device #:4
Device name:Magicbuds
Device connected: 0
Device remembered: 1
Device authenticated: 1
Remote Bluetooth device is 0x5017032a701b, server channel = 0
Local Bluetooth device is 0x84ef18b8460a, server channel = 0

Here is the corresponding code section, ( I did call WSAStartup beforehand):

void WSALookupAvailableDevices(void)
{
    WSAQUERYSET     wsaQuery{};
    LPWSAQUERYSET   pwsaResults{};
    HANDLE          hLookup{};

    CSADDR_INFO     *pAddrInfo{};
    SOCKADDR_BTH    *pBtSockRemote{}, 
                    *pBtSockLocal{};

    char    buffer[4096] = {};
    int     nDevicesFound = 1;
    DWORD   swSize = sizeof(buffer);
    DWORD   flags = LUP_RETURN_ADDR | LUP_RETURN_NAME | LUP_RES_SERVICE | LUP_CONTAINERS | LUP_RETURN_BLOB | LUP_RETURN_TYPE;

    /*Preparing the query set*/
    wsaQuery.dwNameSpace = NS_BTH;
    wsaQuery.dwSize = sizeof(WSAQUERYSET);


    if (WSALookupServiceBegin(&wsaQuery, flags, &hLookup) == SOCKET_ERROR)
    {
        wprintf(L"Shit something went wrong! error: %d!\n", WSAGetLastError());
        return;
    }

    wprintf(L"*********************\n");
    wprintf(L"Winsock search started!\n");
    wprintf(L"*********************\n\n");


    /*Preparing the queryset return buffer*/
    pwsaResults = (LPWSAQUERYSET)buffer;
    pwsaResults->dwNameSpace = NS_BTH;
    pwsaResults->dwSize = sizeof(WSAQUERYSET);

    while (WSALookupServiceNext(hLookup, flags, &swSize, pwsaResults) == NO_ERROR)
    {
        pAddrInfo       = (CSADDR_INFO*)pwsaResults->lpcsaBuffer;
        pBtSockRemote   = (SOCKADDR_BTH*)(pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr);
        pBtSockLocal    = (SOCKADDR_BTH*)(pwsaResults->lpcsaBuffer->LocalAddr.lpSockaddr);

        wprintf(L"Device #:%d\n", nDevicesFound);
        wprintf(L"Device name:%s\n", pwsaResults->lpszServiceInstanceName);
        wprintf(L"Device connected: %d\n", (pwsaResults->dwOutputFlags & BTHNS_RESULT_DEVICE_CONNECTED));
        wprintf(L"Device remembered: %d\n", (pwsaResults->dwOutputFlags & BTHNS_RESULT_DEVICE_REMEMBERED)>0);
        wprintf(L"Device authenticated: %d\n", (pwsaResults->dwOutputFlags & BTHNS_RESULT_DEVICE_AUTHENTICATED)>0);
        wprintf(L"Remote Bluetooth device is 0x%04x%08x, server channel = %d\n",
            GET_NAP(pBtSockRemote->btAddr), GET_SAP(pBtSockRemote->btAddr), pBtSockRemote->port);
        wprintf(L"Local Bluetooth device is 0x%04x%08x, server channel = %d\n",
            GET_NAP(pBtSockLocal->btAddr), GET_SAP(pBtSockLocal->btAddr), pBtSockLocal->port);

        nDevicesFound++;

    }
    WSALookupServiceEnd(hLookup);
    wprintf(L"\n");
}

Thanks for the help in advance!

1
Do you have the same issue if you change your use of flags to pass only LUP_CONTAINERS to WSALookupServiceBegin(), and to omit LUP_CONTAINERS from WSALookupServiceNext()?Remy Lebeau
Yes, issue is still persistent after changing WSALookupServiceBegin()' flags to LUP_CONTAINERS` and omitting it for WSALookupServiceNext().Nawin
It does not matter until you provide LUP_FLUSHCACHE flag which says to driver exewcute discovering. Any other flags only change returned information set. And yes, you do not need LUP_RES_SERVICE (it queries services from remote device). And better to read device's name later because MS stack resolves device's name later, after discovering completed. For name it is better to use WM_DEVICECHANGE message to be sure you get device's name. However it depends on requirements but for new just found devices name will appears as empty in 99%.Mike Petrichenko

1 Answers

1
votes

LUP_FLUSHCACHE is what you need. And yes, it will always return paired device (in addition to discovered). I mean that if device paired WSALookup returns it in the list even it is not available (turned off or out of range).

https://docs.microsoft.com/en-us/windows/desktop/bluetooth/bluetooth-and-wsalookupservicebegin-for-device-inquiry

DWORD   flags = LUP_RETURN_ADDR | LUP_RETURN_NAME | LUP_RES_SERVICE | LUP_CONTAINERS | LUP_RETURN_BLOB | LUP_RETURN_TYPE | LUP_FLUSHCACHE;

But the best way to discover devices is to use this flags set.

DWORD   flags = LUP_RETURN_ADDR | LUP_CONTAINERS | LUP_FLUSHCACHE;

Also it is good idea to provide additional information (BTH_QUERY_DEVICE) so you can set discovering timeout and other params

BTH_QUERY_DEVICE qDev;
qDev.LAP = 0;
qDev.length = bTimeout; // Timeout in seconds
BLOB Blb;
Blb.cbSize = sizeof(BTH_QUERY_DEVICE);
Blb.pBlobData = (PBYTE)&qDev;
QuerySet.lpBlob = &Blb;

https://docs.microsoft.com/th-th/windows/desktop/api/ws2bth/ns-ws2bth-_bth_query_device

After discovering completed (please note that WSALookupServiceBegin takes time (blocks) until discovering finished) you can use BluetoothGetDeviceInfo to get extended information such as device's name and other info.

https://docs.microsoft.com/en-us/windows/desktop/api/bluetoothapis/nf-bluetoothapis-bluetoothgetdeviceinfo

You should know that because of some Bluetooth limitations name resolution can be executed only after discovering completed. And this operation may take time. So if you call to BluetoothGetDeviceInfo right after discovering completed you can still get empty device name for new discovered devices (devices that was not previouslt discovered).

There is not easy way to resolve this issue except switch to WinRT API or wait for some time before reading device name. You also can use WM_DEVICECHANGE message to get notification about device name resolution

https://docs.microsoft.com/en-us/windows/desktop/bluetooth/bluetooth-and-wm-devicechange-messages

And there is one more problem: MS stack always returnsd paired devices during discovering even they are not available.