如何将成员函数作为与 Windows 上的蓝牙相关的参数回调函数传递?
Posted
技术标签:
【中文标题】如何将成员函数作为与 Windows 上的蓝牙相关的参数回调函数传递?【英文标题】:How do I pass a member function as a parameter callback function with regards to Bluetooth on Windows? 【发布时间】:2018-07-03 20:05:30 【问题描述】:我正在尝试使用 Windows 的蓝牙 API 从心率监视器获取心率,但我遇到了 BluetoothGATTRegisterEvent 函数的问题,即第四个参数需要一个 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 对象,但这些都不起作用。将回调函数作为此参数传递时是否需要特别注意,或者我是否遗漏了一些关于成员函数的明显内容?
【问题讨论】:
c++: How to obtain context when callback doesn't provide user arg?的可能重复 【参考方案1】:在函数名前加上“CALLBACK”:
// Function definition
void CALLBACK SomeEvent(BTH_LE_GATT_EVENT_TYPE EventType, PVOID EventOutParameter, PVOID Context)
/* Function code */
它对我有用(VC 2019 和 mingw)。
【讨论】:
【参考方案2】:这就是 BluetoothGATTRegisterEvent
's CallbackContext
参数的用途。
必须将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);
;
Example
【讨论】:
我遇到了同样的问题,但是我无法用你的建议解决这个问题,你能否给出具体的例子@Mihayl,因为我无法尝试什么我面临同样的错误,在问题以上是关于如何将成员函数作为与 Windows 上的蓝牙相关的参数回调函数传递?的主要内容,如果未能解决你的问题,请参考以下文章
如何在windows pc和android设备之间建立蓝牙连接
如何将一个类成员函数与param作为rvalue绑定到boost :: function? [关闭]
如何修复与 MacOSX 上的全局命名空间错误中没有成员相关的缺失时间?