如何从 C 调用 C# 以传递将数组作为成员的结构数组

本文关键字:数组 成员 结构 调用 | 更新日期: 2023-09-27 18:36:59

我有一个本机结构:

typedef struct
{
    char Message[STR_MAX];
    char Params[10][STR_MAX];
    int GetParamStr[10];
    int ParamCount;
} FormattedMessage_t;

和回调类型:

typedef void(*FormatMsgCB_t)(FormattedMessage_t *FormatMsgs, int FormatMsgCount);

静态数组:

static FormattedMessage_t gFormattedMessages[10];

回调集函数:

extern "C" __declspec(dllexport) void DllGuiSetFormatMsgCB(FormatMsgCB_t pCB)
{
    gFormatMsgCB = pCB;
}   

从本机呼叫到托管呼叫:

void DllGuiSetFormatMessage()
{
    gFormatMsgCB(gFormattedMessages, gFormattedMsgIndex);
}

在托管中:

    [StructLayout(LayoutKind.Sequential)]
    public struct FormattedMessage_t
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxStrLength)]
        public string Message;
        public string[] ParamStrings;
        public int[] GetParamStrs;
        public int ParamCount;
        public const int MaxStrLength = StrMax;
    }
    public static T[] GetArray<T>(IntPtr aTblPtr, int nRows)
    {
        var entrySize = Marshal.SizeOf(typeof(T));
        IntPtr oneRowPtr = new IntPtr(aTblPtr.ToInt64());
        T[] array = new T[nRows];
        for (int i = 0; i < nRows; i++)
        {
            array[i] = (T)Marshal.PtrToStructure(oneRowPtr, typeof(T));
            oneRowPtr = new IntPtr(oneRowPtr.ToInt64() + entrySize);
        }
        return array;
    }
    private void OnSetFormatMsg(IntPtr formatMsg, int nFormatMsg)
    {
        var array = GetArray<FormattedMessage_t>(formatMsg, nFormatMsg);
        foreach (var msg in array)
        {
            var str = msg.Message;
            // and so on
        }
    }

此 GetArray 适用于作为结构成员的简单类型。这远远超出了我的 P/Invoke 和本机互操作技能。

这在很多方面可能是错误的。任何提示应该如何做到这一点(更改两个结构都没有问题)将不胜感激。

如何从 C 调用 C# 以传递将数组作为成员的结构数组

您需要像这样声明 C# 结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct FormattedMessage_t
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxStrLength)]
    public string Message;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10*MaxStrLength)]
    public byte[] ParamStrings;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public int[] GetParamStrs;
    public int ParamCount;
    public const int MaxStrLength = StrMax;
}

然后,您需要通过手动执行索引从ParamStrings中挑选出每个项目。第 i值从索引 i*MaxStrLength 运行到 (i+1)*MaxStrLength-1 。您需要将其挑出,找到空终止符,然后使用 Encoding.Default.GetString