【问题标题】:Passing a struct pointer as paramater in C#在 C# 中将结构指针作为参数传递
【发布时间】:2020-12-14 23:40:28
【问题描述】:

我需要包含一个 .dll,其中包含以下 C/C++ 函数原型和结构定义:

typedef struct
{
    unsigned short us1;
    unsigned short us2;
    unsigned short data[16];
} myStruct;
int myFunc(myStruct *MYSTRUCT);

为了使用这个函数,我创建了一个新类:

static class DLL
{
public struct MyStruct
    {
     public ushort us1;
     public ushort us2; 
     public ushort[] data;
     public PDPORT(ushort[] temp1, ushort temp2, ushort temp3)
     {
         us1 = temp2;
         us2 = temp3;
         data = temp1;
     }
    };
    [DllImport("PDL65DLL.dll")]
    public static extern int mvb_PutPort(ref MyStruct CommData);
}

在我的主类中,我初始化结构变量并像这样调用函数:

    DLL.MyStruct communicationData = new DLL.MyStruct(new ushort[16], new ushort(), new ushort());
             DLL.MyFunc( ref communicationData);

但是,这似乎不起作用。该函数正在传递一些东西,但不是正确的值,我建议它与指针使用有关。也许 struct* 与 ref struct 不一样......有人能解释一下问题是什么吗?

【问题讨论】:

  • 轻微观察:导出为myFuncexternmvb_PutPort,没有什么可以告诉它的新名称;那只是复制/粘贴的东西吗?因为:那也不会让事情变得快乐

标签: c# c++ pointers struct parameters


【解决方案1】:

C/C++ 结构更像是一个“固定缓冲区”:

    unsafe struct MyStruct
    {
        ushort us1, us2;
        fixed ushort data[16];
    }

这与数组不同,在 C# 代码中使用起来有点尴尬,但是:这是可能的。

我不是 100% 确定,但我相信您还应该在 P/Invoke 层中使用非托管指针:

public static extern int mvb_PutPort(MyStruct* CommData);

这意味着您需要通过以下方式调用它:

fixed (MyStruct* ptr = whateverYouWereGoingToPass)
{
    mvb_PutPort(ptr);
}

【讨论】:

  • 我会避免使用unsafe,而是使用[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 作为固定大小的数组。
  • @MatthewWatson 然后将其发布为答案 :) 就个人而言,我会使用固定缓冲区
  • 我不会使用fixed,因为您必须为该项目启用unsafe - 然后它将传播到使用该类的所有其他项目。
  • @MatthewWatson 是的,我很熟悉其中的含义(我将这些类型本地化为直接使用它们的所有很好的理由),再说一次:如果你有更好的方法 - 那' d 做一个很好的第二个答案
  • 假设我有一个函数,我在其中初始化“MyStruct test_struct”并将 test_struct.data[0] 设置为 10。如何将它作为指向固定块的指针传递?
【解决方案2】:

您可能需要指定结构的打包(取决于 C++ 代码使用的默认打包)。您还可以使用[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 为编组指定一个固定大小的数组。

你也不需要 C# 实现来使用 struct 并且确实对于相当大的数据我建议使用一个类。

这是一个例子:

[StructLayout(LayoutKind.Sequential, Pack=4)]
public sealed class MyStruct
{
    public ushort   us1;
    public ushort   us2;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public ushort[] data;

    public MyStruct(ushort[] temp1, ushort temp2, ushort temp3)
    {
        us1  = temp2;
        us2  = temp3;
        data = new ushort[16];
        Array.Copy(temp1, data, Math.Min(temp1.Length, data.Length));
    }
}

注意构造函数如何确保数组的大小是正确的。您必须始终确保数组的大小与 SizeConst 声明相匹配。

有了这些变化,Marshaller 应该会为你处理好事情。

【讨论】:

  • 如果我使用类对象指针作为参数(参考对象),程序会崩溃。
  • 没关系,我意识到类对象已经是引用,需要按值传递。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-02
  • 2013-11-18
  • 1970-01-01
  • 2019-04-22
  • 2014-04-23
  • 2019-03-22
相关资源
最近更新 更多