我的代码有效,但我害怕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中,在我获得函数指针后,我可以成功调用该方法并从C#中获取返回的String
。
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充满。
虽然上面的代码有效,但我担心它正在访问刚刚发布的内存。
答案 0 :(得分:1)
在这种情况下,pinvoke marshaller使用共享COM分配器分配字符串返回值。因此,您的本机代码应该在本机DLL返回的指针上调用CoTaskMemFree
。因此,在释放内存之前,您可能需要复制内容!
顺便说一句,没有必要用[MarshalAs(UnmanagedType.LPWStr)]
来装饰参数,因为这只是重新声明了默认值。删除后,您的代码将更容易阅读。