gpt4 book ai didi

c# - 当结构仅在运行时已知时,将结构从 C++ 传递到 C#

转载 作者:太空宇宙 更新时间:2023-11-04 11:46:19 24 4
gpt4 key购买 nike

我有以下问题:

我有一个从非托管 C++ dll 调用函数的 C# 应用程序。 dll 中有一个初始化函数,它在 C# 和 C++ 之间创建一个接口(interface)(基本上是一个值及其类型的列表),该接口(interface)将存储在一个结构中。

之后,C# 应用程序向 dll 发送一个回调函数,dll 每隔一段时间调用一次,并返回一个在接口(interface)中定义的结构变量(或字节数组)。

我的问题:您将如何传递和编码此结构?是否可以传递结构本身,或者我应该传递一个字节数组?

如果您传递一个字节数组,当返回到 C# 应用程序时您将如何编码它?

我现在拥有的:

在 C# 应用中:

编码回调函数:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ProcessOutputDelegate(???); // not sure what should be here.

导入dll函数:

[DllImport("MyDLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void Test(ProcessOutputDelegate ProcessOutput);

调用dll函数:

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):

struct
{
int x;
double y;
double z;
} typedef Interface;

以及 C# 应用程序调用的函数:

__declspec(dllexport) void Test(void (*ProcessOutput)(Interface* output))
{
int i;
Interface* output = (Interface*)malloc(sizeof(Interface));

for (i = 0; i < 100; i++)
{
sleep(100);
output->x = i;
output->y = i / 2;
output->z = i / 3;
ProcessOutput(output); // or generate a bytes array out of the struct
}
}

编辑:

C# 应用程序是一个通用的 GUI,它假设显示一些由某些 c++ dll 执行的繁重计算。在初始化过程中,dll 告诉 GUI 应该显示的变量(及其类型),GUI 是根据这些指示构建的(同样,计算和变量可能会改变,值可能是整数、 float 、字符...)。之后,dll 运行并在每几个时间步中调用回调函数来更新 GUI。这应该适用于任何实现这个想法的 dll:生成一个接口(interface),然后根据这个接口(interface)发送信息。

最佳答案

我不知道,这是否是对你问题的直接回答,但我是通过以下方式解决的。

  1. 您在 DLL 中调用 GetResource 并获得一个 IntPtr:

    (...)
    IntPtr res = Native.GetResource();
  2. 然后,您为此 IntPtr 实例化一个通用包装器:

    ResourceWrapper rw = new ResourceWrapper(res);
  3. 如果您想访问结构的特定字段,您可以在包装器上调用适当的方法:

    int field = rw.GetField();
  4. Wrapper 调用 DLL 中的一个函数:

    (...)
    int result = Native.GetField(res);
  5. DLL“重新对象化”调用:

    __declspec(dllexport) int __stdcall GetField(MyStructure * s)
    {
    return s->GetField();
    }
  6. Struct 获取数据(或抛出异常或设置错误标志或返回错误等)

    int MyStructure::GetField()
    {
    return this->field;
    }

此解决方案需要进行以下更改:

  • 你的数据结构应该派生自同一个基类
  • 如果可能的话,它们应该成为具有虚拟方法的类,允许访问它们的不同字段
  • 您必须实现某种安全机制,检查是否可以访问特定字段。最简单的如下:

    __declspec(dllexport) BOOL __stdcall GetField(MyStruct * s, int & result)
    {
    result = 0;
    try
    {
    result = s->GetField();
    }
    catch(...)
    {
    return FALSE;
    }

    return TRUE;
    }

    和:

    protected class Native
    {
    [DllImport("MyDll.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetField(IntPtr res, out int result);
    }

    和:

    // Wrapper
    int GetField()
    {
    int result;
    if !(Native.GetField(res, out result))
    throw new InvalidOperationException("Resource does not support field!");
    }

关于c# - 当结构仅在运行时已知时,将结构从 C++ 传递到 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19752425/

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