如何获取Delphi类对象中成员方法的指针?
解决Delphi类成员方法无法作为JsNativeFunction回调的问题
当将原本可直接作为JsNativeFunction的普通函数改为TTestObject的成员方法后,直接通过@TestObject.Window_Atob获取指针会触发编译器错误E2036,核心原因是Delphi非静态类成员方法隐含一个Self参数,其函数签名与JsNativeFunction不匹配,无法直接转换。
以下是两种可行的解决方案:
方案一:使用静态成员方法
静态类成员方法不包含隐含的Self参数,函数签名可以与JsNativeFunction对齐。如果需要访问实例数据,可以将对象实例存入CallbackState参数中:
type TTestObject = class public // 定义静态成员方法,严格匹配JsNativeFunction的签名和调用约定 class function Window_Atob(callee: JsValueRef; isConstructCall: bool; arguments: PJsValueRef; argumentCount: Word; callbackState: Pointer): JsValueRef; stdcall; end; // 实现静态方法 class function TTestObject.Window_Atob(callee: JsValueRef; isConstructCall: bool; arguments: PJsValueRef; argumentCount: Word; callbackState: Pointer): JsValueRef; stdcall; var Obj: TTestObject; begin // 从CallbackState中取出对象实例 Obj := TTestObject(callbackState); // 调用实例逻辑 Result := Obj.YourInstanceLogic(callee, isConstructCall, arguments, argumentCount); end; // 注册回调时传入静态方法地址和实例 JsSetCallback(Instance, 'atob', @TTestObject.Window_Atob, TestObjectInstance, True);
方案二:使用普通包装函数作为中间层
定义一个普通的stdcall函数作为包装层,将对象实例通过CallbackState传递,在包装函数中调用目标实例方法:
type TTestObject = class public // 定义实例方法,去掉callbackState参数(因为实例本身就是Self) function Window_AtobImpl(callee: JsValueRef; isConstructCall: bool; arguments: PJsValueRef; argumentCount: Word): JsValueRef; end; // 实现实例方法 function TTestObject.Window_AtobImpl(callee: JsValueRef; isConstructCall: bool; arguments: PJsValueRef; argumentCount: Word): JsValueRef; begin // 这里写原本的业务逻辑 end; // 定义包装函数,严格匹配JsNativeFunction签名 function Window_AtobWrapper(callee: JsValueRef; isConstructCall: bool; arguments: PJsValueRef; argumentCount: Word; callbackState: Pointer): JsValueRef; stdcall; begin // 将CallbackState转换为TTestObject实例,调用实例方法 Result := TTestObject(callbackState).Window_AtobImpl(callee, isConstructCall, arguments, argumentCount); end; // 注册回调时传入包装函数地址和实例 JsSetCallback(Instance, 'atob', @Window_AtobWrapper, TestObjectInstance, True);
关键注意事项
- 所有作为回调的函数必须严格遵循
stdcall调用约定,与JsNativeFunction的定义一致; - 不要直接尝试获取非静态成员方法的地址,其隐含的
Self参数会导致签名不匹配,触发编译错误。
内容的提问来源于stack exchange,提问作者Pascal Bergeron
相关产品推荐
相关产品推荐

