据我所知,这是不可能的。方法不是“在那里”的字段,除此之外,使用虚拟方法创建一个结构将在您的对象中创建一个vtable指针,您在c#镜像类中没有考虑到这一点。
你可以做的是PInvoke方法,它需要一个functionPointer(在C++中)并在那里传递一个委托(C#)。然后你可以使用这个函数指针从本地代码中调用它,你的委托将会启动。
然后,您可以更改您的stateChange方法定义以将Callback *作为第一个参数,因此当您从本机代码调用它时,您可以传递一个对象指针,该对象指针负责该更改并将其归还到C#中的Callback 。
//编辑时没有原生dll的源代码,在c#和C++之间建立一座桥梁就是我想到的。这可以用C++/CLI或C++来进行,坚持原生我的想法是这样的:
//c++ <--> new c++ dll <--> c#
struct CallbackBridge : public Callback
{
void (*_stateChanged)(int);
virtual void stateChanged(int state)
{
if (_stateChanged)
_stateChanged(this, state);
}
};
void* CreateCallback() { return new CallbackBridge(); }
void DeleteCallback(void* callback); { delete callback; }
void setStateChanged(void* callback, void (*ptr)(void*, int))
{
CallbackBridge* bridge = (CallbackBridge*)callback;
bridge->stateChanged = ptr;
}
///... other helper methods
这里的想法是把你的对象作为一个黑盒子(因此无效*无处不在 - 它可以是任何指针,但从C#中,你只会看到这一个SafeHandle/IntPtr和编写助手方法,你可以PInvoke来创建/删除和修改对象,你可以通过给你的对象通过这样的方法代理虚拟这些虚拟调用
从c#的用法可能看起来像这样:(IntPtr为简单起见,可以使用SafeHandle):
IntPtr callback = CreateCallback();
SetStateChanged(callback, myCallback);
//somewhere later:
DeleteCallback(callback);
void MyCallback(IntrPtr callback, int state)
{
int someData = SomeOtherHelperMethod(callback);
ConsoleWrite("SomeData of callback is {0} and it has changed it's state to {1}", someData, state);
}
我知道,这是一个有点笨拙的更大的物体,但没有C++/CLI包装我从来没有发现任何更好的办法能够处理所有这些棘手的情况下,像
您需要制作一个C++/CLI包装器。 – 2011-12-16 12:29:19
@Alex Burtsev,您在C#中的回调定义不正确。您正尝试传递C#类的实例,同时在C++ API中接受指针。 C++中的Callback结构基本上是一个(纯粹的)抽象类,尽管您跳过了其余的代码。该结构只包含一个指向虚函数表的指针,所以对于32位进程,大小只有4个字节,对于64位进程,大小只有8个字节。如果您将虚拟函数表中的地址指向C#中的StateChanged指针。你的代码可以工作。 – xInterop 2015-12-13 04:46:40