Pairing a bluetooth device in windows with c++

11,260

Solution 1

As far as I know, I can see many problems in your code:

1) you are calling BluetoothRegisterForAuthenticationEx inside your call to 'pairDevice': hCallbackHandle variable will only live during the call so you must Register before 'pairDevice'

2) your are not calling BluetoothUnregister afterwards

3) you are not deleting the hCallbackHandle handle

4) your 'bluetoothAuthCallback' is empty: you must do something like

BLUETOOTH_AUTHENTICATE_RESPONSE response;
::ZeroMemory(&response,sizeof(BLUETOOTH_AUTHENTICATE_RESPONSE));
response.authMethod = cbparams->authenticationMethod;
response.bthAddressRemote = cbparams->deviceInfo.Address;
response.negativeResponse = FALSE;
DWORD error=::BluetoothSendAuthenticationResponseEx(nullptr, &response);

(see above comment ;-)

5) your call to 'BluetoothAuthenticateDeviceEx' will trigger the callback routine asynchronously..., so you have to 'wait' for it... before leaving the main() function...

Solution 2

Maybe you should add response into your authentication callback. Smth like this:

BLUETOOTH_DEVICE_INFO aw = params->deviceInfo;
HANDLE lRadio = NULL;

BLUETOOTH_AUTHENTICATE_RESPONSE bar2Send;
::ZeroMemory(&bar2Send, sizeof(BLUETOOTH_AUTHENTICATE_RESPONSE));
bar2Send.bthAddressRemote = params->deviceInfo.Address;
bar2Send.authMethod = params->authenticationMethod;

DWORD result = BluetoothSendAuthenticationResponseEx(lRadio, &bar2Send);
Share:
11,260
ambershark
Author by

ambershark

Updated on June 24, 2022

Comments

  • ambershark
    ambershark almost 2 years

    I need to be able to pair a device using code in C++ for windows (specifically win7 or newer). I have written the code that should work but it doesn't. I can pair a lot of devices, a Roku, a headset, speakers, etc, but for some reason the device I need to pair will not work.

    It always returns an error code of 0x05 which according to bthdefs.h is defined as BTH_ERROR_AUTHENTICATION_FAILURE.

    So the weird part here. It never tries to authenticate. The callback function that should get called to provide the passkey during pairing doesn't get called. I have verified it does get called with other devices like a headset.

    I have tried using BluetoothAuthenticateDeviceEx() without the callback function which should pop up the GUI in windows to finish the pairing. It pops up for my headset and other devices, it won't pop up for my device.

    As a side note I can pair the device using Window's bluetooth wizard just fine. It just refuses to work programmatically.

    I can't figure out what the difference is between the winapi code I am using and what windows' wizard is doing during pairing.

    Here is the simplest test app I could get. My real app was using Qt and mingw to build. This app uses MSVC 2012 and pure windows code to remove any obfuscation from the problem. All my code has the same problems with that error code 5.

    #include <windows.h>
    #include "bthdef.h"
    #include "BluetoothAPIs.h"
    #include <tchar.h>
    #include <string>
    #include <iostream>
    #include <vector>
    
    #pragma comment(lib, "bthprops.lib")
    
    using namespace std;
    
    vector<BLUETOOTH_DEVICE_INFO> scanDevices()
    {
        vector<BLUETOOTH_DEVICE_INFO> res;
    
        BLUETOOTH_DEVICE_SEARCH_PARAMS bdsp;
        BLUETOOTH_DEVICE_INFO bdi;
        HBLUETOOTH_DEVICE_FIND hbf;
    
        ZeroMemory(&bdsp, sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
    
        // set options for how we want to load our list of BT devices
        bdsp.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
        bdsp.fReturnAuthenticated = TRUE;
        bdsp.fReturnRemembered = TRUE;
        bdsp.fReturnUnknown = TRUE;
        bdsp.fReturnConnected = TRUE;
        bdsp.fIssueInquiry = TRUE;
        bdsp.cTimeoutMultiplier = 4;
        bdsp.hRadio = NULL;
    
        bdi.dwSize = sizeof(bdi);
    
        // enumerate our bluetooth devices
        hbf = BluetoothFindFirstDevice(&bdsp, &bdi);
        if (hbf)
        {
            do
            {
                res.push_back(bdi);
            } while (BluetoothFindNextDevice(hbf, &bdi));
    
            // close our device enumerator
            BluetoothFindDeviceClose(hbf);
        }
    
        return res;
    }
    
    BOOL CALLBACK bluetoothAuthCallback(LPVOID param, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS params)
    {
        cout << "callback happened" << endl;
        return TRUE;
    }
    
    void pairDevice(BLUETOOTH_DEVICE_INFO device)
    {
        wstring ws = device.szName;
        cout << "Pairing device " << string(ws.begin(), ws.end()) << endl;
    
        // register callback
        cout << "Registering callback" << endl;
        HBLUETOOTH_AUTHENTICATION_REGISTRATION hCallbackHandle = 0;
        DWORD result = BluetoothRegisterForAuthenticationEx(&device, &hCallbackHandle, (PFN_AUTHENTICATION_CALLBACK_EX)&bluetoothAuthCallback, NULL);
        if (result != ERROR_SUCCESS)
        {
            cout << "Failed to register callback" << endl;
            return;
        }
    
        // authenticate
        result = BluetoothAuthenticateDeviceEx(NULL, NULL, &device, NULL, MITMProtectionNotRequired);
        //DWORD result = BluetoothAuthenticateDeviceEx(NULL, NULL, &device, NULL, MITMProtectionRequired);
        //DWORD result = BluetoothAuthenticateDeviceEx(NULL, NULL, &device, NULL, MITMProtectionNotRequiredBonding);
        //DWORD result = BluetoothAuthenticateDeviceEx(NULL, NULL, &device, NULL, MITMProtectionRequiredBonding);
        //DWORD result = BluetoothAuthenticateDeviceEx(NULL, NULL, &device, NULL, MITMProtectionNotRequiredGeneralBonding);
        //DWORD result = BluetoothAuthenticateDeviceEx(NULL, NULL, &device, NULL, MITMProtectionRequiredGeneralBonding);
        //DWORD result = BluetoothAuthenticateDeviceEx(NULL, NULL, &device, NULL, MITMProtectionNotDefined);
        switch (result)
        {
        case ERROR_SUCCESS:
            cout << "pair device success" << endl;
            break;
    
        case ERROR_CANCELLED:
            cout << "pair device failed, user cancelled" << endl;
            break;
    
        case ERROR_INVALID_PARAMETER:
            cout << "pair device failed, invalid parameter" << endl;
            break;
    
        case ERROR_NO_MORE_ITEMS:
            cout << "pair device failed, device appears paired already" << endl;
            break;
    
        default:
            cout << "pair device failed, unknown error, code " << (unsigned int)result << endl;
            break;
        }
    }
    
    int _tmain(int argc, _TCHAR *argv[])
    {
        cout << "Scanning bluetooth devices..." << endl;
        cout.flush();
    
        // scan devices
        vector<BLUETOOTH_DEVICE_INFO> devices = scanDevices();
    
        cout << "Got " << devices.size() << " devices" << endl;
    
        // list all devices
        int pdIndex = -1;
        int foundDev = -1;
        vector<BLUETOOTH_DEVICE_INFO>::const_iterator devci;
        for (devci=devices.begin();devci!=devices.end();devci++)
        {
            pdIndex++;
            wstring ws = (*devci).szName;
            cout << "Device: " << string(ws.begin(), ws.end()) << endl;
    
            // see if we find our device (case sensitive)
            if (ws.find(L"smp") != string::npos)
                foundDev = pdIndex;
        }
    
        // pick our ismp device
        if (foundDev == -1)
        {
            cout << "Could not find a device to pair" << endl;
            return 1;
        }
    
        BLUETOOTH_DEVICE_INFO pd = devices[foundDev];
        wstring ws = pd.szName;
        cout << "Found device to pair, " << string(ws.begin(), ws.end()) << endl;
    
        // attempt to pair device
        pairDevice(pd);
    
        return 0;
    }
    
  • ambershark
    ambershark about 9 years
    Thanks for the response. The code shown was a minimal example and so I didn't care about clean up of handles and such. So for #1 it doesn't matter that hCallbackHandle goes out of scope as the allocated handle stays valid until CloseHandle is called. 2. Again don't care about memory or anything so unregister wasn't a concern. 3. Same as 1/2 4. The function is empty but it is never called. Don't forget this code works with all other bluetooth devices except the one I wanted it to work with.
  • ambershark
    ambershark about 9 years
    5. I'm not entirely sure this is asynchronous. It works fine with a bluetooth headet and a ROKU player. The function is called and the main thread is used, i.e. synchronous. So I don't think it works like you think it does.
  • adanteny
    adanteny about 9 years
    Point 4 is the main point imho. You need it for 2.1 compliant devices using SSP instead of 2.0 pincodes... Maybe it's the problem involved...