The Microsoft Windows SDK versions 7.0 and 7.1 appear to have broken BluetoothAPIs.h header files.
Update: Microsoft has fixed the errors in the Bluetooth header as of SDK version 8.0 for Windows 8.
So far, I have uncovered two types of errors in this header file:
The use of
- instead of
- , causing compiler warnings.
Several callback function pointer type definitions omit the
- ) calling convention, causing a crash.
The first error simply results in compiler warnings.
warning C4068: unknown pragma
The second type of error results in dereferencing of an invalid memory location when using BluetoothRegisterForAuthenticationEx and BluetoothAuthenticateDeviceEx. This is because the standard calling convention (__cdecl) assumes that the caller will clean up the stack. Since the caller in this case is assuming that the callback function minded its own stack, it immediately pops ESI, placing zero into the register:
5EBCFFE2 mov ecx,dword ptr [ebp-4] 5EBCFFE5 pop esi 5EBCFFE6 xor ecx,ebp 5EBCFFE8 pop ebx 5EBCFFE9 call @__security_check_cookie@4 (5EBDBBBBh)
Later, ntdll.dll dereferences memory at ESI + 4, triggering an access violation:
774A8301 test byte ptr [esi+4],4
“Unhandled exception at 0x774a8301 (ntdll.dll) in [Application]: 0xC0000005: Access violation reading location 0×00000004.
To the compiler warnings, I replaced all instances of
To fix the crash bug, I added the CALLBACK calling convention keyword to PFN_AUTHENTICATION_CALLBACK and PFN_AUTHENTICATION_CALLBACK_EX. They now appear as follows:
typedef BOOL (CALLBACK *PFN_AUTHENTICATION_CALLBACK)(LPVOID pvParam, PBLUETOOTH_DEVICE_INFO pDevice);
typedef BOOL (CALLBACK *PFN_AUTHENTICATION_CALLBACK_EX)(__in_opt LPVOID pvParam, __in PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams);
Interestingly, the function pointer type definitions for the attribute-enumeration and device-selection callbacks (PFN_BLUETOOTH_ENUM_ATTRIBUTES_CALLBACK and PFN_DEVICE_CALLBACK, respectively) are defined correctly, using CALLBACK or WINAPI. I suspect that the inconsistency is because someone at Microsoft was using the /Gz compiler switch, making __stdcall the default calling convention.