3

there's a question: Is there any way to pair Bluetooth device in Windows programmatically? (c++, c#)

thanks for replies

Taras
  • 2,526
  • 3
  • 33
  • 63
  • You should be using the WinRT Windows.Devices.Enumeration pairing API. Here is a sample: https://learn.microsoft.com/en-us/samples/microsoft/windows-universal-samples/deviceenumerationandpairing/ – sam msft Aug 17 '23 at 18:56

5 Answers5

3

Yes, the reference documentation is available on MSDN.

32feet.NET is a C# wrapper, available here. Information on pairing is here.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Can I use 32feet.NET for commercial project? – Taras Jun 25 '12 at 14:42
  • @Division_Bell: The license is [here](http://32feet.codeplex.com/license) Looks like commercial use is ok as long as you give credit, but contact a lawyer when you need reliable legal advice. – Ben Voigt Jun 25 '12 at 14:44
  • The Windows Bluetooth stack has not been investing in the win32 APIs for at least 10 years. This sample covers how to use the WinRT pairing APIs for C++ (recommened: CppWinrt) and C#, etc. https://learn.microsoft.com/en-us/samples/microsoft/windows-universal-samples/deviceenumerationandpairing/ – sam msft Aug 17 '23 at 18:39
3

Python is a tempting and overall easy solution, but PyBlueZ does not expose the windows Bluetooth authentication APIs here: https://msdn.microsoft.com/en-us/library/windows/desktop/cc766819(v=vs.85).aspx

One way to get around this is to create a command line tool and use this through Python. To create command line tools for Windows, use Visual Studio and add the necessary libraries to your project linker properties: Bthprops.lib and ws2_32.lib

Below is the code for a project to make a command line tool with 1 parameter, the MAC address, that pairs the specified device using "Just Works" pairing. See commented code for using passkey pairing.

#include "stdafx.h"
#include <initguid.h>
#include <winsock2.h>
#include <BluetoothAPIs.h>
#include <ws2bth.h>

BOOL WINAPI BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams);

int _tmain(int argc, _TCHAR* argv[])
{
    SOCKADDR_BTH sa = { 0 };
    int sa_len = sizeof(sa);
    DWORD dwRet;
    BLUETOOTH_DEVICE_INFO  btdi = { 0 };
    HBLUETOOTH_AUTHENTICATION_REGISTRATION hRegHandle = 0;

    // initialize windows sockets
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(2, 0);
    if (WSAStartup(wVersionRequested, &wsaData) != 0) {
        ExitProcess(2);
    }

    // parse the specified Bluetooth address
    if (argc < 2) {
        fprintf(stderr, "usage: csbtpair <addr>\n"
            "\n  addr must be in the form (XX:XX:XX:XX:XX:XX)");
        ExitProcess(2);
    }
    if (SOCKET_ERROR == WSAStringToAddress(argv[1], AF_BTH,
        NULL, (LPSOCKADDR)&sa, &sa_len)) {
        ExitProcess(2);
    }

    // setup device info
    btdi.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
    btdi.Address.ullLong = sa.btAddr;
    btdi.ulClassofDevice = 0;
    btdi.fConnected = false;
    btdi.fRemembered = false;
    btdi.fAuthenticated = false;

    // register authentication callback. this prevents UI from showing up.
    dwRet = BluetoothRegisterForAuthenticationEx(&btdi, &hRegHandle, &BluetoothAuthCallback, NULL);
    if (dwRet != ERROR_SUCCESS)
    {
        fprintf(stderr, "BluetoothRegisterForAuthenticationEx ret %d\n", dwRet);
        ExitProcess(2);
    }

    // authenticate device (will call authentication callback)
    AUTHENTICATION_REQUIREMENTS authreqs = MITMProtectionNotRequired;
    fprintf(stderr, "BluetoothAuthReqs = %d\n", authreqs);
    dwRet = BluetoothAuthenticateDeviceEx(NULL, NULL, &btdi, NULL, authreqs);
    if (dwRet != ERROR_SUCCESS)
    {
        fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
        if (dwRet == ERROR_CANCELLED)
        {
            fprintf(stderr, "Cancelled");
        }
        else if (dwRet == ERROR_INVALID_PARAMETER)
        {
            fprintf(stderr, "Invalid Parameter");
        }
        else if (dwRet == ERROR_NO_MORE_ITEMS)
        {
            fprintf(stderr, "Already paired!");
        }
    }

    fprintf(stderr, "pairing finish\n");
    ExitProcess(0);
    return 0;
}

// Authentication callback
BOOL WINAPI BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams)
{
    DWORD dwRet;

    fprintf(stderr, "BluetoothAuthCallback 0x%x\n", pAuthCallbackParams->deviceInfo.Address.ullLong);
    BLUETOOTH_AUTHENTICATE_RESPONSE AuthRes;
    AuthRes.authMethod = pAuthCallbackParams->authenticationMethod;
    fprintf(stderr, "Authmethod %d\n", AuthRes.authMethod);
    // Check to make sure we are using numeric comparison (Just Works)
    if (AuthRes.authMethod == BLUETOOTH_AUTHENTICATION_METHOD_NUMERIC_COMPARISON) 
    {
        fprintf(stderr, "Numeric Comparison supported\n");
    }
    AuthRes.bthAddressRemote = pAuthCallbackParams->deviceInfo.Address;
    AuthRes.negativeResponse = FALSE;

    // Commented out code is used for pairing using the BLUETOOTH_AUTHENTICATION_METHOD_PASSKEY method
    //memcpy_s(AuthRes.pinInfo.pin, sizeof(AuthRes.pinInfo.pin), L"1234", 0);
    //AuthRes.pinInfo.pinLength = 0;
    // Respond with numerical value for Just Works pairing
    AuthRes.numericCompInfo.NumericValue = 1;

    // Send authentication response to authenticate device
    dwRet = BluetoothSendAuthenticationResponseEx(NULL, &AuthRes);
    if (dwRet != ERROR_SUCCESS)
    {
        fprintf(stderr, "BluetoothSendAuthenticationResponseEx ret %d\n", dwRet);
        if (dwRet == ERROR_CANCELLED)
        {
            fprintf(stderr, "Bluetooth device denied passkey response or communicatino problem.\n");
        }
        else if (dwRet == E_FAIL)
        {
            fprintf(stderr, "Device returned a failure code during authentication.\n");
        }
        else if (dwRet == 1244)
        {
            fprintf(stderr, "Not authenticated\n");
        }
    }
    else
    {
        fprintf(stderr, "BluetoothAuthCallback finish\n");
    }

    return 1; // This value is ignored
}

In lieu of creating this yourself, you may want to try this pre-made solution: http://bluetoothinstaller.com/bluetooth-command-line-tools/ It did not work for my particular solution.

Then, you will need to run your downloaded or custom command line tool from python as an administrator. To do this reliably, I recommend the stackoverflow question: How to run python script with elevated privilege on windows

Community
  • 1
  • 1
jamesw6811
  • 448
  • 3
  • 10
2

Microsoft has introduced the Windows.Devices.Enumeration API, available for UWP and traditional applications. This makes the pairing of Bluetooth devices very easy. For details, refer to the official C# and C++ examples. You can also take a look at my BluetoothDevicePairing utility written using this API.

PolarBear
  • 1,117
  • 15
  • 24
  • This is the most correct answer. The Device Enumeration and Paring sample show how best to do this. The WinRT API and built in system UX pairing do ultimately use the flows and internal APIs, but they are a bit different. To understand why, the WinRT APIs require a broker, Device Association Broker (DAB), to be able to pair devices for a low integrity level app container process. Actually the Windows shell also runs many of their UIs in low IL and use brokers too for things like pairing, but once the code is at the broker layer, the WinRT API and the shell UXes are very similar. – sam msft Aug 17 '23 at 18:52
1

I meet the same problem,and I have resolved the problem, Maybe you can try it:

  1. make a windows tool named pairtool.exe, it help you to pairing with command line. the key api is BluetoothAuthenticateDevice, please refering the functions document

    dwRet = BluetoothAuthenticateDevice(NULL, NULL, &btdi, L"1234", 4);
    if(dwRet != ERROR_SUCCESS)
    {
        fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
        ExitProcess(2);
    }
    
  2. python code:

    def connect2Btdev(devName):
    #found the device addr
    addr = inquiry(devName)
    if addr == None:
       return None
    
    #pairing with pairtool.exe
    cmd=r'%s %s' % ('pairtool.exe',addr)
    ret = os.system(cmd)
    
    if ret <> 0:
        return None
    

here is all the code of pairtool.exe:

#include "stdafx.h"
#include <initguid.h>
#include <winsock2.h>
#include <BluetoothAPIs.h>
#include <ws2bth.h>

bool BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams)
{
    DWORD dwRet;

    fprintf(stderr, "BluetoothAuthCallback 0x%x\n", pAuthCallbackParams->deviceInfo.Address.ullLong);

    dwRet = BluetoothSendAuthenticationResponse(NULL, &(pAuthCallbackParams->deviceInfo), L"1234");
    if(dwRet != ERROR_SUCCESS)
    {
        fprintf(stderr, "BluetoothSendAuthenticationResponse ret %d\n", dwRet);
        ExitProcess(2);
        return 1;
    }
    fprintf(stderr, "BluetoothAuthCallback finish\n");
    ExitProcess(0);
    return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
    SOCKADDR_BTH sa = { 0 };
    int sa_len = sizeof(sa);
    DWORD dwRet;
    BLUETOOTH_DEVICE_INFO  btdi = {0};
    HBLUETOOTH_AUTHENTICATION_REGISTRATION hRegHandle = 0;

    // initialize windows sockets
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD( 2, 0 );
    if( WSAStartup( wVersionRequested, &wsaData ) != 0 ) {
        ExitProcess(2);
    }

    // parse the specified Bluetooth address
    if( argc < 2 ) {
        fprintf(stderr, "usage: rfcomm-client <addr>\n"
                "\n  addr must be in the form (XX:XX:XX:XX:XX:XX)");
        ExitProcess(2);
    }
    if( SOCKET_ERROR == WSAStringToAddress( argv[1], AF_BTH,
                NULL, (LPSOCKADDR) &sa, &sa_len ) ) {
        ExitProcess(2);
    }

    //注册回调函数
    btdi.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
    btdi.Address.ullLong = sa.btAddr;
    btdi.ulClassofDevice = 0;
    btdi.fConnected = false;
    btdi.fRemembered = false;
    btdi.fAuthenticated = false;

    dwRet = BluetoothRegisterForAuthenticationEx(&btdi, &hRegHandle, &BluetoothAuthCallback, NULL);
    if(dwRet != ERROR_SUCCESS)
    {
        fprintf(stderr, "BluetoothRegisterForAuthenticationEx ret %d\n", dwRet);
        ExitProcess(2);
    }

    dwRet = BluetoothAuthenticateDevice(NULL, NULL, &btdi, L"1234", 4);
    if(dwRet != ERROR_SUCCESS)
    {
        fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
        ExitProcess(2);
    }

    Sleep(1000);
      fprintf(stderr, "pairing finish\n");
    ExitProcess(0);

    return 0;
}
zhouziwei
  • 27
  • 2
  • In recent versions of Windows, there is an inbox pairtool.exe fyi. It lives in c:\windows\system32\pairtool.exe. Here are the features: C:\>pairtool Microsoft Device Pairing Tool pairtool [/enum-endpoints <...> | /enum-services <...> | /enum-containers <...> | /enum-protocols <...> | /associate <...> | /associate-oob <...> | /disassociate <...> | /challenge <...> | /?] – sam msft Aug 17 '23 at 18:45
-1

You can do so by using the functions documented under MSDN Bluetooth Functions.

These enable searching and pairing of bluetooth devices programmatically.

Turbo J
  • 7,563
  • 1
  • 23
  • 43
  • No, you should be using the WinRT Windows.Devices.Enumeration pairing API. Here is a sample: https://learn.microsoft.com/en-us/samples/microsoft/windows-universal-samples/deviceenumerationandpairing/ – sam msft Aug 17 '23 at 18:55
  • I don't belive this API was available in 2012. The question is quite old. – Turbo J Aug 17 '23 at 19:54
  • Fair point. In the Win8/8.1 timeframe there wasn't a good story for pairing. You might have been stuck using Function Discovery. I wrote the WinRT pairing API somewhere around the TH1 or TH2 timeframe...which was the code name for the original release of Windows 10. At this point, I don't there are any supported versions of Windows that wouldn't have the WinRT version of the pairing API though...assuming the SKU has Bluetooth support. – sam msft Aug 24 '23 at 20:57