C# 从c+传递结构+;当结构仅在运行时已知时
我有以下问题:C# 从c+传递结构+;当结构仅在运行时已知时,c#,c++,struct,marshalling,C#,C++,Struct,Marshalling,我有以下问题: 我有一个C应用程序,它调用来自非托管C++ DLL的函数。在DLL中有一个初始化函数,它创建C++和C++之间的接口(基本上是一个值和它们的类型的列表),这些结构将存储在Stutt.< 之后,C#app会向dll发送一个回调函数,dll会每隔一段时间调用该函数,然后返回接口中定义的结构变量(或字节数组) 我的问题:如何传递和封送此结构?是否可以传递结构本身,还是应该传递字节数组 如果传递一个字节数组,当返回到C#应用程序时,您将如何封送它 我现在所拥有的: 在C#app中: 封送
我有一个C应用程序,它调用来自非托管C++ DLL的函数。在DLL中有一个初始化函数,它创建C++和C++之间的接口(基本上是一个值和它们的类型的列表),这些结构将存储在Stutt.< 之后,C#app会向dll发送一个回调函数,dll会每隔一段时间调用该函数,然后返回接口中定义的结构变量(或字节数组)
我的问题:如何传递和封送此结构?是否可以传递结构本身,还是应该传递字节数组 如果传递一个字节数组,当返回到C#应用程序时,您将如何封送它 我现在所拥有的: 在C#app中: 封送回调函数:[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ProcessOutputDelegate(???); // not sure what should be here.
[DllImport("MyDLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void Test(ProcessOutputDelegate ProcessOutput);
ProcessOutputDelegate process = new ProcessOutputDelegate(ProcessOutput);
new thread(delegate() { Test(process); } ).Start();
导入dll函数:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ProcessOutputDelegate(???); // not sure what should be here.
[DllImport("MyDLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void Test(ProcessOutputDelegate ProcessOutput);
ProcessOutputDelegate process = new ProcessOutputDelegate(ProcessOutput);
new thread(delegate() { Test(process); } ).Start();
调用dll函数:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ProcessOutputDelegate(???); // not sure what should be here.
[DllImport("MyDLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void Test(ProcessOutputDelegate ProcessOutput);
ProcessOutputDelegate process = new ProcessOutputDelegate(ProcessOutput);
new thread(delegate() { Test(process); } ).Start();
处理输出:
public void ProcessOutput(???)
{
// Assume we have a list of values that describes the struct/bytes array.
}
<>在C++ DLL中,我有以下结构(这是一个例子,在不同的运行时间中可以调用不同的DLL):
以及C#app调用的函数:
\uuuu declspec(dllexport)无效测试(无效(*ProcessOutput)(接口*输出))
{
int i;
接口*输出=(接口*)malloc(sizeof(接口));
对于(i=0;i<100;i++)
{
睡眠(100);
输出->x=i;
输出->y=i/2;
输出->z=i/3;
ProcessOutput(output);//或从结构中生成字节数组
}
}
编辑:
C语言应用程序是一个通用的GUI,它假设显示一些C++ DLL执行的一些繁重的计算。在初始化过程中,dll会告诉GUI应该显示的变量(及其类型),GUI是根据这些方向构建的(同样,计算和变量可能会更改,值可能是int、float、chars…)。之后,dll运行,在每两个时间步中,它调用回调函数来更新GUI。这应该适用于任何实现此想法的dll:生成一个接口,然后根据此接口发送信息。
我不知道这是否是您问题的直接答案,但我用以下方法解决了它(...)
IntPtr res = Native.GetResource();
ResourceWrapper rw = new ResourceWrapper(res);
int field = rw.GetField();
(...)
int result = Native.GetField(res);
__declspec(dllexport) int __stdcall GetField(MyStructure * s)
{
return s->GetField();
}
- 数据结构应派生自同一基类
- 如果可能的话,它们应该成为具有虚拟方法的类,允许访问它们的不同字段
- 您必须实现某种安全机制,检查是否可以访问特定字段。最简单的是:
以及: 以及:__declspec(dllexport) BOOL __stdcall GetField(MyStruct * s, int & result) { result = 0; try { result = s->GetField(); } catch(...) { return FALSE; } return TRUE; }
- 在DLL中调用GetResource并获取IntPtr:
(...) IntPtr res = Native.GetResource();
- 然后,为这个IntPtr实例化一个通用包装器:
ResourceWrapper rw = new ResourceWrapper(res);
- 如果要访问结构的特定字段,请在包装器上调用适当的方法:
int field = rw.GetField();
- 包装器调用DLL中的函数:
(...) int result = Native.GetField(res);
- DLL“重新对象化”调用:
__declspec(dllexport) int __stdcall GetField(MyStructure * s) { return s->GetField(); }
- Struct获取数据(或引发异常、设置错误标志或返回错误等) 此解决方案需要进行以下更改:
- 数据结构应派生自同一基类
- 如果可能的话,它们应该成为具有虚拟方法的类,允许访问它们的不同字段
- 您必须实现某种安全机制,检查是否可以访问特定字段。最简单的是:
以及: 以及:__declspec(dllexport) BOOL __stdcall GetField(MyStruct * s, int & result) { result = 0; try { result = s->GetField(); } catch(...) { return FALSE; } return TRUE; }
- 我不知道这是否是对您问题的直接回答,但我用以下方法解决了它
sizeof(interface)
。一个值向量(类似于std::vector
)不是一个可变结构。如果C代码不知道它会得到什么,它会收到什么?我不理解C++结构“可能会改变”的部分。在普通C++中,结构是在编译时定义的。它们在运行时不会神奇地改变(当然是它们的内容,但不是它们的结构)。你能澄清一下吗?@Mat True,意思是在每个运行时可能会调用不同的dll,我将添加一个澄清。每个DLL都会实现“test”功能,但可能会构造不同的结构并执行不同的操作。因此,您尝试使用同一个C++接口,用于不同的C++ DLL,它们可能返回“完全不同的东西”。我是