如何在 Windows 上将成员函数作为与蓝牙相关的参数回调函数传递



我正在尝试使用 Windows 的蓝牙 API 从心率监测器获取心率,但我遇到了蓝牙 GATTRegisterEvent 函数的问题,即第四个参数,它需要PFNBLUETOOTH_GATT_EVENT_CALLBACK回调函数作为参数。执行以下代码可以正常工作:

// Function definition
void SomeEvent(BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)
{ /* Function code */}
// Calling BluetoothGATTRegisterEvent
hr = BluetoothGATTRegisterEvent(
                hLEDevice,
                EventType,
                &EventParameterIn,
                SomeEvent,
                NULL,
                &EventHandle,
                BLUETOOTH_GATT_FLAG_NONE);

但是,如果我尝试传递成员函数(例如HeartRateMonitor::SomeEvent而不仅仅是SomeEvent(,则会出现以下错误:

argument of type "void (HeartRateMonitor::*)(BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)" is incompatible with parameter of type "PFNBLUETOOTH_GATT_EVENT_CALLBACK"

我的第一直觉是尝试使用函数指针或 std::bind 对象,但两者都不起作用。将回调函数作为此参数传递时是否需要进行一些特殊考虑,或者我是否缺少有关成员函数的明显内容?

这就是

BluetoothGATTRegisterEventCallbackContext参数的用途。

必须传递static成员函数作为回调,this作为CallbackContext传递。非静态成员函数有一个隐式this作为第一个参数(__thiscall(,不能用作回调。

在回调中,您可以将Context强制转换为this并访问类的其他成员。

例:

class HeartRateMonitor {
public:
    //...
    void MemberFun(BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)
    {}
    static void StaticMemberFun(BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)
    {
        HeartRateMonitor* pThis = static_cast<HeartRateMonitor*>(Context);
        /* Function code */
        // and here you could access your class non-static data by pThis->...
        // or call a non-static method, so you don't need to always writhe `pThis`
    }
    HeartRateMonitor()
    {
        HANDLE hLEDevice = 0;
        BTH_LE_GATT_EVENT_TYPE EventType = CharacteristicValueChangedEvent;
        PVOID EventParameterIn = 0;
        BLUETOOTH_GATT_EVENT_HANDLE EventHandle = 0;
        HRESULT hr = 0;
        hr = ::BluetoothGATTRegisterEvent(  // ok
                hLEDevice,
                EventType,
                &EventParameterIn,
                &HeartRateMonitor::StaticMemberFun,
                this,
                &EventHandle,
                BLUETOOTH_GATT_FLAG_NONE);
        hr = ::BluetoothGATTRegisterEvent(  // error C2664: 'unsigned long BluetoothGATTRegisterEvent(HANDLE,BTH_LE_GATT_EVENT_TYPE,void *,PFNBLUETOOTH_GATT_EVENT_CALLBACK,void *,BLUETOOTH_GATT_EVENT_HANDLE *,unsigned long)': cannot convert argument 4 from 'void (__cdecl HeartRateMonitor::* )(BTH_LE_GATT_EVENT_TYPE,void *,void *)' to 'PFNBLUETOOTH_GATT_EVENT_CALLBACK'
                hLEDevice,
                EventType,
                &EventParameterIn,
                &HeartRateMonitor::MemberFun,
                this,
                &EventHandle,
                BLUETOOTH_GATT_FLAG_NONE);
    }
};

在函数名称前加上"CALLBACK":

// Function definition
void CALLBACK SomeEvent(BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)
{ /* Function code */}

它对我有用(VC 2019 和 mingw(。

最新更新