如何在从 C 到 C# 的结构中获取非托管可变长度 C 数组?

Posted

技术标签:

【中文标题】如何在从 C 到 C# 的结构中获取非托管可变长度 C 数组?【英文标题】:How to get unmanaged variable-length C-array within a struct from C to C#? 【发布时间】:2014-05-22 14:14:49 【问题描述】:

如何返回MIB_IPFORWARDROW 数组?

struct MIB_IPFORWARDTABLE

    public uint Size;

    [MarshalAs(/* what goes here? */)]
    public IPFORWARDROW[] Table;
;

[DllImport("iphlpapi", CharSet = CharSet.Auto)]
private static extern int GetIpForwardTable(
    IntPtr /* MIB_IPFORWARDTABLE* */ pIpForwardTable,
    ref uint /* ULONG* */ pdwSize,
    bool bOrder);

public static MIB_IPFORWARDROW[] Temp()

    var fwdTable = IntPtr.Zero;
    uint size = 0;
    var result = GetIpForwardTable(fwdTable, ref size, true);
    fwdTable = Marshal.AllocHGlobal((int) size);
    result = GetIpForwardTable(fwdTable, ref size, true);

    /*
    what now ?
    I tried:

    var table = (MIB_IPFORWARDTABLE) Marshal.PtrToStructure(fwdTable, typeof(MIB_IPFORWARDTABLE));

    but table.Table is always null
    */

(见GetIpForwardTable)

我看过这个: How do I marshal a struct that contains a variable-sized array to C#?

但无论我做什么,fwdTable.Table 始终为 null,IntPtr.Zero 或 0。当然,如果没有抛出异常..

【问题讨论】:

检查这个:***.com/questions/162897/marshal-char-in-c-sharp @MichaelKniffen - 我不明白它是如何相关的 【参考方案1】:

这个帖子似乎正是您要找的:http://social.msdn.microsoft.com/Forums/vstudio/en-US/19a3ce21-e395-4151-86f6-723a64272f0d/calling-getipforwardtable-from-c?forum=csharpgeneral

他们的解决方案使用暴力循环将原始数组复制到 IPFORWARDROW 的 System.Array 中。

最终的代码如下所示:

    [ComVisible(false), StructLayout(LayoutKind.Sequential)]
    internal struct IPForwardTable
    
        public uint Size;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public IPFORWARDROW[] Table;
    ;

    [ComVisible(false), StructLayout(LayoutKind.Sequential)]
    internal struct IPFORWARDROW
    
        internal int /*DWORD*/ dwForwardDest;
        internal int /*DWORD*/ dwForwardMask;
        internal int /*DWORD*/ dwForwardPolicy;
        internal int /*DWORD*/ dwForwardNextHop;
        internal int /*DWORD*/ dwForwardIfIndex;
        internal int /*DWORD*/ dwForwardType;
        internal int /*DWORD*/ dwForwardProto;
        internal int /*DWORD*/ dwForwardAge;
        internal int /*DWORD*/ dwForwardNextHopAS;
        internal int /*DWORD*/ dwForwardMetric1;
        internal int /*DWORD*/ dwForwardMetric2;
        internal int /*DWORD*/ dwForwardMetric3;
        internal int /*DWORD*/ dwForwardMetric4;
        internal int /*DWORD*/ dwForwardMetric5;
    ;

    [DllImport("iphlpapi", CharSet = CharSet.Auto)]
    private extern static int GetIpForwardTable(IntPtr /*PMIB_IPFORWARDTABLE*/ pIpForwardTable, ref int /*PULONG*/ pdwSize, bool bOrder);

    [DllImport("iphlpapi", CharSet = CharSet.Auto)]
    private extern static int CreateIpForwardEntry(IntPtr /*PMIB_IPFORWARDROW*/ pRoute);

    static void Main(string[] args)
    
        var fwdTable = IntPtr.Zero;
        int size = 0;

        var result = GetIpForwardTable(fwdTable, ref size, true);
        fwdTable = Marshal.AllocHGlobal(size);

        result = GetIpForwardTable(fwdTable, ref size, true);
        var str = (IPForwardTable)Marshal.PtrToStructure(fwdTable, typeof(IPForwardTable));

        IPFORWARDROW[] table = new IPFORWARDROW[str.Size];
        IntPtr p = fwdTable + Marshal.SizeOf(str.Size);
        for (int i = 0; i < str.Size; ++i)
        
            table[i] = (IPFORWARDROW)Marshal.PtrToStructure(p, typeof(IPFORWARDROW));
            p += Marshal.SizeOf(typeof(IPFORWARDROW));
        


        Marshal.FreeHGlobal(fwdTable);
    

【讨论】:

var str = (IPForwardTable)Marshal.PtrToStructure(fwdTable, typeof(IPForwardTable)); throws NullReferenceException 哎呀。清理代码,我删除了几个重要的(比如分配存储结果所需的内存)。已编辑。

以上是关于如何在从 C 到 C# 的结构中获取非托管可变长度 C 数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何为非托管 c dll 创建 c++\cli 包装器

c# 获取非托管指针长度

C# 托管非托管代码

如何从 C# 中的非托管内存中读取数据?

将具有枚举成员的非托管结构编组到 c#

如何在托管 (C#) 和非托管 (C++) 代码之间来回传递数组内容