C# 将结构的数组封送到Ptr

C# 将结构的数组封送到Ptr,c#,C#,我正在从C代码调用C库。我调用的函数将包含struct数组的struct作为参数: struct Example1Struct { char* a; uint16_t b; AnotherStruct* c; } 这里是指向另一个结构的指针数组 我的C代码中的结构如下所示 public struct Example1Struct { public IntPtr StationName;//is c

我正在从C代码调用C库。我调用的函数将包含struct数组的struct作为参数:

    struct Example1Struct
    {
        char* a;
        uint16_t b;
        AnotherStruct* c; 
    }
这里是指向另一个结构的指针数组

我的C代码中的结构如下所示

public struct Example1Struct
    {
        public IntPtr StationName;//is char*
        public UInt16 IdCode;
        public IntPtr AnotherStruct; //array of struct  AnotherStruct
    }




public static IntPtr MarshalToPointer(object data)
    {
        Type valueType = data.GetType();
        IntPtr buf = IntPtr.Zero;

        if (valueType.IsArray)
        {
            if (data is char[])
            {
                var d = data as char[];
                buf = Marshal.AllocHGlobal(Marshal.SizeOf(d.GetType().GetElementType()) * d.Length);
            }
            else if (data is char[,])
            {
                var d = data as char[,];
                buf = Marshal.AllocHGlobal(Marshal.SizeOf(d.GetType().GetElementType()) * d.Length);
            }
            else
            {
                buf = Marshal.AllocHGlobal(Marshal.SizeOf(data.GetType().GetElementType()) * count);

                long LongPtr = buf.ToInt64(); // Must work both on x86 and x64
                for (int I = 0; I < data.Lenght; I++)
                {
                    IntPtr RectPtr = new IntPtr(LongPtr);
                    Marshal.StructureToPtr(data[I], RectPtr, false); // You do not need to erase struct in this case
                    LongPtr += Marshal.SizeOf(typeof(Rect));
                }

            }

            return buf;
        }
        else
            buf = Marshal.AllocHGlobal(Marshal.SizeOf(data));
        Marshal.StructureToPtr(data, buf, false);
        return buf;
    }
公共结构示例1结构
{
public IntPtr StationName;//是字符*
公共UInt16识别码;
public IntPtr AnotherStruct;//struct AnotherStruct的数组
}
公共静态IntPtr MarshallTopoInter(对象数据)
{
类型valueType=data.GetType();
IntPtr buf=IntPtr.0;
if(valueType.IsArray)
{
if(数据为字符[])
{
var d=数据为字符[];
buf=Marshal.AllocHGlobal(Marshal.SizeOf(d.GetType().GetElementType())*d.Length);
}
else if(数据为字符[,])
{
var d=数据为字符[,];
buf=Marshal.AllocHGlobal(Marshal.SizeOf(d.GetType().GetElementType())*d.Length);
}
其他的
{
buf=Marshal.AllocHGlobal(Marshal.SizeOf(data.GetType().GetElementType())*count);
long LongPtr=buf.ToInt64();//必须同时在x86和x64上工作
对于(int I=0;I
这里的问题是,我无法将数据(另一个结构的数组)强制转换为对象[],IEnumerable中也不能。因此,我无法访问数据[I],并且没有数据。长度


有什么想法吗?

你可以这样得到数组的长度:

if (data is Array a) 
    Console.WriteLine(a.Length);
c#中的数组总是派生自
数组
,因此您可以将其强制转换为该数组


但是如果可能,在实际代码中,我建议使用属性,而不是编写手动编组代码。它看起来像:

public struct Example1Struct
{
    public IntPtr StationName;//is char*
    public UInt16 IdCode;
    public IntPtr AnotherStruct; //array of struct  AnotherStruct
}
可以是:

public struct Example1Struct
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string StationName;
    public UInt16 IdCode;
    [MarshalAs(UnmanagedType.LPArray)]
    public AnotherStruct[] OtherStructs;
}

当您将其传递给非托管代码时,封送处理程序应该为您做正确的事情。

您是否考虑过将
marshallas
属性应用于您的结构?让封送拆收器处理分配等[Marshallas(UnmanagedType.LPArray)]在运行时给我以下错误:System.TypeLoadException:“无法封送类型为“AnotherStruct”的字段“OtherStructs”:无效的托管/非托管类型组合(数组字段必须与ByValArray或SafeArray成对)。”