gpt4 book ai didi

c# - 使用 C# P/Invoke 的方法编码(marshal)结构

转载 作者:搜寻专家 更新时间:2023-10-31 00:44:31 24 4
gpt4 key购买 nike

我正在尝试将 PInvoke 调用到这个 C++ 库函数中:

int Initialize(Callback* callback);

struct Callback
{
//.......
void virtual StateChanged(int state) = 0;
};

我试过这个简单的 C# 代码,但它不起作用。

[DllImport("CPlusPlusLibrary.dll", SetLastError = true, EntryPoint = "?Initialize@CPlusPlusLibrary@@YAHPAUCallback@1@@Z")]
public static extern int Initialize(Callback callback);

[StructLayout(LayoutKind.Sequential)]
public class Callback
{
//....
public delegate void IntDelegate(int state);
public IntDelegate StateChanged(int state);
}
var callback = new Callback();
var result = Initialize(callback);

最佳答案

据我所知,这样做是不可能的。方法不像字段那样“在那里”,除此之外,使用虚方法创建结构将在您的对象中创建一个 vtable 指针,您在 c# 镜像类中没有考虑到这一点。

您可以做的是 PInvoke 到采用函数指针(在 C++ 中)的方法并在那里传递一个委托(delegate) (C#)。然后,您可以使用此函数指针从 native 代码调用它,您的委托(delegate)将启动。

然后您可以更改 stateChange 方法定义以将 Callback* 作为第一个参数,因此当您从 native 代码调用它时,您可以传递负责该更改的对象指针并将其编码回 C# 中的 Callback。

//在没有 native 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

这里的想法是将您的对象视为一个黑盒子(因此 void* 无处不在 - 它可以是任何指针,但是从 c# 中您只会看到它是一个 SafeHandle/IntPtr 并编写可以 PInvoke 来创建的辅助方法/删除和修改对象。您可以通过此类方法为对象提供委托(delegate)来模拟这些虚拟调用。

在 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# - 使用 C# P/Invoke 的方法编码(marshal)结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8533157/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com