2

我的代码有效,但我害怕 P/Invoke 中的内存。

这是我将从本机 C++ 代码调用的委托。

[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public delegate string CommandCallbackDelegate([MarshalAs(UnmanagedType.LPWStr)] string command
    , [MarshalAs(UnmanagedType.LPWStr)] string arg1
    , [MarshalAs(UnmanagedType.LPWStr)] string arg2
    );

在 C# 中,我将委托传递给本机 DLL。

private static GCHandle _gcHandle;
public static void RegisterCommandCallback(CommandCallbackDelegate fun) { _gcHandle = GCHandle.Alloc(fun);

    if (IntPtr.Size == 8)
        RegisterCommandCallback_x64(fun);
    else
        RegisterCommandCallback_x86(fun);
}

而在原生DLL中,我得到函数指针后,就可以成功调用方法,并得到StringC#的返回值。

typedef LPCWSTR (WINAPI* PFN_CommandCallback)( LPCWSTR wszCommand, LPCWSTR wszArg1, LPCWSTR wszArg2);
PFN_CommandCallback g_pfnCommandCallback = ....;

LPCWSTR wszRet = g_pfnCommandCallback( L"CMD", L"ARG1", L"ARG2");

如您所见,C#方法返回String到本机DLL,我不确定返回的非托管内存是否被GC释放。

虽然我上面的代码有效,但恐怕它正在访问刚刚释放的内存。

4

1 回答 1

1

在这种情况下,pinvoke 编组器使用共享 COM 分配器分配字符串返回值。因此,您的本机代码应该调用CoTaskMemFree本机 DLL 返回的指针。因此,您可能需要在释放内存之前获取内容的副本!

顺便说一句,没有必要用它来装饰参数,[MarshalAs(UnmanagedType.LPWStr)]因为它只是重新声明了默认值。删除后,您的代码会更容易阅读。

于 2013-01-10T12:05:18.383 回答