问题API与char *返回被IntPtr在P/invoke中捕获
问题描述:
我想P /调用一个C++ API返回一个char *,它是C#中的一个字符串。我知道这应该由IntPtr的捕获,然后将指针转换为使用封送像这样的字符串,问题API与char *返回被IntPtr在P/invoke中捕获
C++ API
char* WINAPI MY_API(const char *basebuf, char *strbuf)
{
return targetfunction(basebuf, strbuf);
}
C#的P/Invoke
[DllImport("myDll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
internal static extern IntPtr MY_API([MarshalAs(UnmanagedType.LPStr)] string basebuf,
[MarshalAs(UnmanagedType.LPArray), Out] byte[] strbuf);
C#包装
public string MY_API_WRAPPER(string basebuf, out string strbuf)
{
byte[] strbufTemp = new byte[256];
IntPtr ret = MY_API(basebuf, strbufTemp);
string retstr = Marshal.PtrToStringAnsi(ret);
strbuf = MyDataConverter.ByteToString(strbufTemp);
return retstr;
}
out参数字符串是OK的。但返回的字符串(从IntPtr转换)是垃圾。
我可以修改C ++ API以将char *分配给任务内存,然后将其释放到C#Wrapper中,但更改本机代码不是选项。如果在没有包装的情况下使用API,它也有内存泄漏的风险。
我想知道当API调用结束时指针发生了什么?
答
感谢大卫,我能够解决我的问题。由于函数的返回值是指向basebuf参数的指针,因此函数返回时会获取垃圾值。
Basebuf应该是一个IntPtr而不是IntPtr返回的字符串,以便在调用后获得正确的值。所以它应该像这样P/Invoked。
C#的P/Invoke
[DllImport("myDll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
internal static extern IntPtr MY_API(IntPtr basebuf,
[MarshalAs(UnmanagedType.LPArray), Out] byte[] strbuf);
C#包装
public string MY_API_WRAPPER(string basebuf, out string strbuf)
{
byte[] strbufTemp = new byte[256];
IntPtr basebufPtr = Marshal.StringtoHGlobalAnsi(basebuf)
IntPtr ret = MY_API(basebufPtr , strbufTemp);
string retstr = Marshal.PtrToStringAnsi(ret);
strbuf = MyDataConverter.ByteToString(strbufTemp);
Marshal.FreeHGlobal(basebufPtr);
return retstr;
}
如何返回值分配呢? –
@DavidHeffernan“targetfunction”的返回值是指向basebuf元素的指针。像这样(char * ret =(char *)&basebuf [0]) –
那不行了。这是一个由pinvoke封送器管理的临时缓冲区。非托管函数返回后无效。您需要手动编组basebuf。 –