1

我通过将带有字符串数据的结构从 C# 代码传递到 C++ dll 陷入困境。

c++代码

typedef struct 
{
    LPCSTR lpLibFileName;
    LPCSTR lpProcName;
    LPVOID pPointer1;
    LPVOID pPointer2;
} ENTITY, *PENTITY, *LPENTITY;
extern "C" __declspec(dllexport) int Test(LPENTITY entryList, int size);

int Test(LPENTITY entryList, int size)
{
    for (int i = 0; i < size; i++)
    {
        ENTITY e = entryList[i];
        // the char* value doesn't get passed correctly.
        cout << e.lpLibFileName << e.lpProcName << endl;
    }
    return 0;
}

c# 代码

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private class Entity
{
    public string lpLibFileName;
    public string lpProcName;
    public IntPtr pPointer1;
    public IntPtr pPointer2;
}

[DllImport("cpp.dll")]
private static extern int Test(
    [In, Out, MarshalAs(UnmanagedType.LPArray)]Entity[] entities,
    int size);

static void Main(string[] args)
{
    var entries = new[]
        {
            new Entity
                {
                    lpLibFileName = "comdlg32",
                    lpProcName = "PrintDlgExW",
                    pPointer1 = Marshal.GetFunctionPointerForDelegate(new PrintDlgEx(PrintDlgExCallback)),
                    pPointer2 = IntPtr.Zero,
                },
            new Entity
                {
                    lpLibFileName = "shell32",
                    lpProcName = "ShellAboutW",
                    pPointer1 = Marshal.GetFunctionPointerForDelegate(new ShellAbout(ShellAboutCallback)),
                    pPointer2 = IntPtr.Zero,
                },
        };
    var ret = Test(entries, entries.Length);
}

PINVOKE 已触发,但无法正确传递 lpLibFileName 和 lpProcName 等 char* 数据。我错过了什么?如何纠正它?

谢谢。

4

2 回答 2

0

在传递自定义结构数组等参数时,在定义自己的数据结构时使用“struct”而不是“class”。在我将它改回结构后,一切正常。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct Entity
{
    public string lpLibFileName;
    public string lpProcName;
    public IntPtr pPointer1;
    public IntPtr pPointer2;
}
于 2013-06-29T14:01:27.080 回答
0

您的代码将 C# 类映射到本机结构。因为 C# 类是引用类型,所以它将被编组为引用。因此,您的代码传递了一个引用数组,这些引用数组被编组到本机端的指针数组。

但是本机代码需要一个指向值类型结构数组的指针。所以最简单的解决方案是将声明更改Entity为 astruct而不是 a class

我可以看到的其他问题:

  1. 本机代码似乎正在使用cdecl调用约定。您需要更改 C# 代码以匹配。
  2. 您正在用 装饰数组参数Out。您不能将对string字段的修改封送回托管代码。
  3. 您需要确保让您传递给的代表保持活动 状态,GetFunctionPointerForDelegate以阻止它们被收集。
于 2013-06-29T17:43:22.107 回答