This C++ code demonstrates how to automatically and permanently pair a Wiimote/Wii balance board to a Windows computer running the Microsoft Bluetooth stack. This avoids the hassle of pressing the red pairing button each time the Wiimote/Wii balance board is powered on.

A prebuilt version of this code is available here.

#include "stdafx.h"

#include <windows.h>
#include <bthsdpdef.h>
#include <bthdef.h>
#include <BluetoothAPIs.h>
#include <strsafe.h>

#pragma comment(lib, "Bthprops.lib")

DWORD ShowErrorCode(LPTSTR msg, DWORD dw)
{
   // Retrieve the system error message for the last-error code

   LPVOID lpMsgBuf;

   FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
      NULL,
      dw,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR) &lpMsgBuf,
      0,
      NULL
      );

   _tprintf(_T("%s: %s"), msg, lpMsgBuf);

   LocalFree(lpMsgBuf);

   return dw;
}

_TCHAR * FormatBTAddress(BLUETOOTH_ADDRESS address)
{
   static _TCHAR ret[20];
   _stprintf(ret, _T("%02x:%02x:%02x:%02x:%02x:%02x"),
      address.rgBytes[5],
      address.rgBytes[4],
      address.rgBytes[3],
      address.rgBytes[2],
      address.rgBytes[1],
      address.rgBytes[0]
      );
   return ret;
}

int _tmain(int argc, _TCHAR* argv[])
{
   HANDLE hRadios[256];
   int nRadios;
   int nPaired = 0;

   ///////////////////////////////////////////////////////////////////////
   // Enumerate BT radios
   ///////////////////////////////////////////////////////////////////////
   {
      HBLUETOOTH_RADIO_FIND hFindRadio;
      BLUETOOTH_FIND_RADIO_PARAMS radioParam;

      _tprintf(_T("Enumerating radios...\n"));

      radioParam.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS);

      nRadios = 0;
      hFindRadio = BluetoothFindFirstRadio(&radioParam, &hRadios[nRadios++]);
      if (hFindRadio)
      {
         while (BluetoothFindNextRadio(&radioParam, &hRadios[nRadios++]));
         BluetoothFindRadioClose(hFindRadio);
      }
      else
      {
         ShowErrorCode(_T("Error enumerating radios"), GetLastError());
         return (1);
      }
      nRadios--;
      _tprintf(_T("Found %d radios\n"), nRadios);
   }

   ///////////////////////////////////////////////////////////////////////
   // Keep looping until we pair with a Wii device
   ///////////////////////////////////////////////////////////////////////

   while (nPaired == 0)
   {
      int radio;

      for (radio = 0; radio < nRadios; radio++)
      {
         BLUETOOTH_RADIO_INFO radioInfo;
         HBLUETOOTH_DEVICE_FIND hFind;
         BLUETOOTH_DEVICE_INFO btdi;
         BLUETOOTH_DEVICE_SEARCH_PARAMS srch;

         radioInfo.dwSize = sizeof(radioInfo);
         btdi.dwSize = sizeof(btdi);
         srch.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);

         ShowErrorCode(_T("BluetoothGetRadioInfo"), BluetoothGetRadioInfo(hRadios[radio], &radioInfo));

         _tprintf(_T("Radio %d: %ls %s\n"),
               radio,
               radioInfo.szName,
               FormatBTAddress(radioInfo.address)
               );

         srch.fReturnAuthenticated = TRUE;
         srch.fReturnRemembered = TRUE;
         srch.fReturnConnected = TRUE;
         srch.fReturnUnknown = TRUE;
         srch.fIssueInquiry = TRUE;
         srch.cTimeoutMultiplier = 2;
         srch.hRadio = hRadios[radio];

         _tprintf(_T("Scanning...\n"));

         hFind = BluetoothFindFirstDevice(&srch, &btdi);

         if (hFind == NULL)
         {
            if (GetLastError() == ERROR_NO_MORE_ITEMS)
            {
               _tprintf(_T("No bluetooth devices found.\n"));
            }
            else
            {
               ShowErrorCode(_T("Error enumerating devices"), GetLastError());
               return (1);
            }
         }
         else
         {
            do
            {
               _tprintf(_T("Found: %s\n"), btdi.szName);

               if (!wcscmp(btdi.szName, L"Nintendo RVL-WBC-01") || !wcscmp(btdi.szName, L"Nintendo RVL-CNT-01"))
               {
                  WCHAR pass[6];
                  DWORD pcServices = 16;
                  GUID guids[16];
                  BOOL error = FALSE;

                  if (!error)
                  {
                     if (btdi.fRemembered)
                     {
                        // Make Windows forget pairing
                        if (ShowErrorCode(_T("BluetoothRemoveDevice"), BluetoothRemoveDevice(&btdi.Address)) != ERROR_SUCCESS)
                           error = TRUE;
                     }
                  }

                   // MAC address is passphrase
                  pass[0] = radioInfo.address.rgBytes[0];
                  pass[1] = radioInfo.address.rgBytes[1];
                  pass[2] = radioInfo.address.rgBytes[2];
                  pass[3] = radioInfo.address.rgBytes[3];
                  pass[4] = radioInfo.address.rgBytes[4];
                  pass[5] = radioInfo.address.rgBytes[5];

                  if (!error)
                  {
                     // Pair with Wii device
                     if (ShowErrorCode(_T("BluetoothAuthenticateDevice"), BluetoothAuthenticateDevice(NULL, hRadios[radio], &btdi, pass, 6)) != ERROR_SUCCESS)
                        error = TRUE;
                  }

                  if (!error)
                  {
                     // If this is not done, the Wii device will not remember the pairing
                     if (ShowErrorCode(_T("BluetoothEnumerateInstalledServices"), BluetoothEnumerateInstalledServices(hRadios[radio], &btdi, &pcServices, guids)) != ERROR_SUCCESS)
                        error = TRUE;
                  }

                  if (!error)
                  {
                     // Activate service
                     if (ShowErrorCode(_T("BluetoothSetServiceState"), BluetoothSetServiceState (hRadios[radio], &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE )) != ERROR_SUCCESS)
                        error = TRUE;
                  }

                  if (!error)
                  {
                     nPaired++;
                  }
               } // if (!wcscmp(btdi.szName, L"Nintendo RVL-WBC-01") || !wcscmp(btdi.szName, L"Nintendo RVL-CNT-01"))
            }
            while (BluetoothFindNextDevice(hFind, &btdi));
         } // if (hFind == NULL)
      } // for (radio = 0; radio < nRadios; radio++)

      Sleep(1000);
   }

   ///////////////////////////////////////////////////////////////////////
   // Clean up
   ///////////////////////////////////////////////////////////////////////

   {
      int radio;

      for (radio = 0; radio < nRadios; radio++)
      {
         CloseHandle(hRadios[radio]);
      }
   }

   _tprintf(_T("=============================================\n"), nPaired);
   _tprintf(_T("%d Wii devices paired\n"), nPaired);

   return 0;
}
 
  • The prebuilt version is 404 Not Found…

    • The link should be fixed now. Thanks for pointing it out,

      Rich

  • Yannick241

    Under Windwos 7 and 8 I get an error saying “user not authenticated”, when the programm tries to connect the wiimote

  • Marc Wegkamp

    Although I still have to pair everytime, I can now connect using the MS stack. Many thanks!!!

  • Ankur Arora

    This code helped me a lot. Thank you so much 🙂

    I am trying to achieve something similar, pair a Bluetooth audio device with Windows (7).

    What should be the PassKey that I need to provide in BluetoothAuthenticateDevice?

    While pairing manually no Pass Key is required!

    I tried passing “0000” to the function and a notification balloon popped up saying “A bluetooth device is trying to connect. Click to Allow this” On clicking this “Add a Device” dialog popped up in which I had to Click Next.

    I don’t want all this and want the Authentication to be transparent. Any pointers towards achieving this would be much appreciated.

    Thanks

    • scott

      I’m trying to get the correct pass key as well. I have another utility that uses the Wii Yourself API but the permanent sync function doesn’t work due to incorrect pass key. Did you ever figure this out?

  • scott

    The utility works great! Is the source code available? What API’s does this use? Under what license?

    • The source code is on this page. It’s public domain.

      • scott

        Thank you so much for the reply. 🙂 One last question I’d love your help with. I’m on a Win8.1 Pro laptop with built-in Intel Bluetooth and the WiiPair.exe keeps saying “BluetoothAuthenticateDevice: A device attached to the system is not functioning.” and for the life of me I can’t figure out why. I can get it to go through if I time the pressing of the sync button with the initial launch of the WiiPair cmd but if I don’t get it the first time it just errors every time after. Ideas?

  • TS

    Hi, any idea if the microsoft stack provides callbacks when a device connects to it? I googled for reference, but found almost nothing useful to work with. I’m trying to get the system to log automatically upon stepping onto the balance board. Thanks!