0

我遇到了函数指针的问题,我在网上找到的任何东西都没有帮助我解决这个问题。

我有一个来自 C API 的函数,它采用 void 函数的指针:

extern int APIFunction(int, void (*func)(int));

我有一个类,其中包含我在调用 API 函数时想要放置的函数。

class MyClass
{
   public:
      void myFunction(int status, otherAPi arguments...);
};

然后,我创建了一个指向我的成员函数的指针并创建了我的类的一个新实例

typedef  void (MyClass::*MyClassFunctionPointer)(int stat, otherAPi arguments...);
MyClassFunctionPointer fctPointer= &MyClass::myFunction; 
LicenseSecurity instance;  

当我尝试使用我创建的函数指针调用我的 APi 函数时出现错误:

int stat = APIFunction(5, fctPointer ); // -> error 1
int stat = APIFunction(5, instance.*fctPointer ); // -> error 2

在第一种和第二种情况下我分别得到了错误:

E2034 Impossible to convert 'void (MyClass::*)(int, otherAPITypes...)' into 'void (*) (int, otherAPITypes...)'
E2342 Bad type correspondence in the parameter 'func' ('void (*)(int, otherAPITypes...)' desired, 'void(int, otherAPITypes...)' obtained)

我无权访问 API 函数,因此无法修改它。总结问题:如何从我的类的成员函数中获取“简单”的 C 函数指针以放入函数的参数?

谢谢

4

4 回答 4

2

不幸的是,你不能。对不起。

理想情况下,您的 API 将接受std::function允许您包装自由函数或成员函数的内容。但是如果你不能修改API,那么你别无选择,只能提供一个免费的功能。

于 2013-04-11T20:48:13.783 回答
0

您无法获得指向非静态成员函数的“简单”函数指针,因为该函数在调用时需要 this 指针。如果您要创建这样的函数指针,那么当调用该函数时,将没有 this 指针可供它引用。

于 2013-04-11T20:50:02.107 回答
0

您可以将回调声明为独立函数或类的静态方法。棘手的部分是访问回调中的类实例指针。

理想情况下,设计良好的 API 允许您为回调指定用户定义的值。这使您可以轻松地传入一个类实例并直接在回调中访问它。但听起来您没有使用这样的 API,因此您需要使用解决方法。

如果您一次只有一个与 API 一起使用的类实例,您可以将实例指针存储到全局变量中,并让回调使用全局变量来访问该实例。

但是,如果您同时使用多个类实例,您正在寻找一种类似于 VCL 的MakeObjectInstance()函数的 thunking 解决方案,它允许TWndMethod将 -signatured 类方法用作 Win32 窗口过程回调。本质上,一块可执行内存是动态分配的,存根汇编代码被写入块中,实例指针和类方法指针也存储在块中。然后将该块传递给 API,就好像它是一个函数指针一样。当 API 调用“函数”时,存根代码被执行,它必须操纵调用堆栈和 CPU 寄存器来调用存储的类方法指针,并将存储的实例指针作为其隐藏this参数,同时保留其他参数的语义,调用堆栈,函数结果等。

C++ 中没有任何东西能真正实现原生的那种 thunking。手动实现并不难,但也不是微不足道的(查看MakeObjectInstance()VCL 的 Classes.pas 源文件中的源代码)。最困难的部分是提出与特定类方法签名的语义相匹配的必要存根代码。

于 2013-04-13T05:17:35.600 回答
0

不幸的是,使用这样的古老 C API,您没有任何方法可以做到这一点。

您要做的是创建一个静态或非成员函数来接受回调,然后找出要调用该成员的对象的哪个实例。一些 C API 允许将用户数据传递给回调,在这种情况下,您可以使用它来存储有this问题的指针。如果这不是一个选项,您可以使用全局或单例对象,并且只允许注册一个这样的回调。

于 2013-04-11T20:58:08.887 回答