API 的问题,其中 char* return 在 P/invoke 中被 IntPtr 捕获
Issue with API with char* return being caught by IntPtr in P/invoke
我正在尝试 P/Invoke C++ API 返回一个 char*,它是 C# 中的一个字符串。我知道这应该被 IntPtr 捕获,然后像这样使用 Marshaler 将指针转换为字符串,
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;
}
输出参数字符串正常。但返回的字符串(从 IntPtr 转换而来)是垃圾。
我可以修改 C++ API 以将 char* 分配给任务内存,然后在 C# Wrapper 中释放它,但是更改本机代码不是一个选项。如果在没有包装器的情况下使用 API,它也有内存泄漏的风险。
我想知道当 API 调用结束时指针发生了什么?
感谢 David,我能够解决我的问题。由于函数的return值是指向basebuf参数的指针,所以在函数returns.
时获取垃圾值
basebuf 应该是 IntPtr 而不是 IntPtr 的字符串 return 才能在调用后获得正确的值。所以应该是这样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;
}
我正在尝试 P/Invoke C++ API 返回一个 char*,它是 C# 中的一个字符串。我知道这应该被 IntPtr 捕获,然后像这样使用 Marshaler 将指针转换为字符串,
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;
}
输出参数字符串正常。但返回的字符串(从 IntPtr 转换而来)是垃圾。
我可以修改 C++ API 以将 char* 分配给任务内存,然后在 C# Wrapper 中释放它,但是更改本机代码不是一个选项。如果在没有包装器的情况下使用 API,它也有内存泄漏的风险。
我想知道当 API 调用结束时指针发生了什么?
感谢 David,我能够解决我的问题。由于函数的return值是指向basebuf参数的指针,所以在函数returns.
时获取垃圾值basebuf 应该是 IntPtr 而不是 IntPtr 的字符串 return 才能在调用后获得正确的值。所以应该是这样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;
}