【问题标题】:Marshaling a C++ two-dimensional fixed length char array as a structure member将 C++ 二维固定长度 char 数组编组为结构成员
【发布时间】:2011-01-17 00:28:54
【问题描述】:

我正在尝试调用一个非托管 C++ 函数,该函数具有一个结构作为输入参数。 该结构在头文件中定义如下:

struct MyStruct
{
int     siOrder;
char     aaszNames[6][25];
int     siId[6];
int     siTones[6];        
};

我尝试将托管结构声明如下:

[StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct MyStruct {

public int siOrder;

[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst=150)]
public string aaszNames;

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=6, ArraySubType=UnmanagedType.I4)]
public int[] siId;

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=6, ArraySubType=UnmanagedType.I4)]
public int[] siTones;
}

但没有任何成功。我猜测编组失败了,因为 aaszNames 实际上是一个由六个 25 长的空终止字符串组成的数组。 我尝试将 aaszNames 声明为

 [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=150)]
 public char[] aaszNames;

在必要时用空值填充数组。但是,再一次,什么都没有。

我有什么遗漏吗?我哪里错了?编组这个二维字符数组的最佳方法是什么?

任何提示,请。

【问题讨论】:

  • 一点也不像 C++...
  • 他想从C#调用一个C++函数
  • 我添加了一个 C# 标签,希望能更清楚地了解其含义。在我拿到代码之前,我还认为这是一个纯 C++ 问题。
  • 我认为 Matthieu 说你的非托管代码很像 C,并建议在 C++ 中使用 std::string 或类似的东西?
  • 是的,我同意它有点像 C,但这是第三方 dll,将其称为 C++ dll 的文档很差……无法真正改变这个 dll。跨度>

标签: c# c++ struct multidimensional-array marshalling


【解决方案1】:
char aaszNames[6][25];

C++类型的char是8位~

但是C#类型的char是Unicode,(16位)!

C++ 类型的so char C# 类型的字节

【讨论】:

    【解决方案2】:

    尝试使用多个 C# 结构:

    [StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
    public struct MyStruct_Name
    {
        [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 25)]
        public string name;
    }
    
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct MyStruct
    {
        public int siOrder;
    
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)]
        public MyStruct_Name aaszNames;
    
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.I4)]
        public int[] siId;
    
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.I4)]
        public int[] siTones;
    }
    

    这就是我传递 C 风格字符串数组的方式。

    不要忘记创建 aaszNames 的内容!编组器讨厌空引用。

    MyStruct foo = new MyStruct();
    for (int i = 0; i < 6; i++)
    {
        foo.aaszNames[i] = new MyStruct_Name();
        foo.aaszNames[i].name = "";
    }
    

    祝你好运!

    【讨论】:

      【解决方案3】:

      我会编写一个小的 c 程序来检查 C 结构的字节大小。
      然后我会接受另一个建议,逐个字段提取数据。
      从 C 的角度来看,/0 被视为包含在 6 个字节中的普通字符,而 C# 将使用 5 的长度并隐藏 /0。

      【讨论】:

        【解决方案4】:
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=150)]
         public char[] aaszNames;
        

        这种编组类型看起来不错。可能是函数调用问题,或者内存分配错误/

        【讨论】:

        • 我正在调用的函数,还有一个结构作为参数,我没有问题。糟糕的内存分配到底是什么意思?
        • 1.你如何为你的结构分配内存? 2. marshal struct 作为输入函数参数的最佳方式是指针(IntPtr)。典型例子: IntPtr strPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(StructType))); Marshal.StructureToPtr(struct,strPtr); Foo(strPtr); Marshal.FreeHGlobal(strPtr);
        • 我真的不会手动分配内存。我知道那个例子,但是由于我成功地将另一个(更简单的)结构作为输入参数传递给同一个函数,在其他几个函数中,我认为将它留给 .NET 也可以。
        猜你喜欢
        • 2022-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-19
        相关资源
        最近更新 更多