PInvoke 编组 const char * 失败并显示 UnmanagedType.LPStr
PInvoke marshalling const char * fails with UnmanagedType.LPStr
我不明白为什么 .NET Core 编组无法使用一种编组方法而不是另一种方法。在下面的示例中,Marshal.PtrToStringAnsi
可以成功编组来自本机 dll 的字符串,但是使用 [return: MarshalAs(UnmanagedType.LPStr)]
属性的相同调用不能吗?还是来自 IntPtr 的编组只是运气好并且还可以根据 OS 内存管理访问无效内存?
C 库代码是(编译为 C 而不是 C++):
static const char str[] = "Hello World";
__declspec(dllexport) const char* getstr() {
return str;
}
C#测试程序:
using System;
using System.Runtime.InteropServices;
namespace CLibraryPinvoke
{
class Program
{
public const string LIB_NAME = "CLibrary";
[DllImport(LIB_NAME, EntryPoint = "getstr")]
public static extern IntPtr getstrgood();
[DllImport(LIB_NAME, EntryPoint ="getstr")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string getstrbad();
static void Main(string[] args)
{
Console.WriteLine($"getstr={Marshal.PtrToStringAnsi(getstrgood())}.");
// Crash.
Console.WriteLine($"getstr={getstrbad()}.");
}
}
}
执行结果:
getstr=Hello World.
CLibraryPinvoke\bin\Debug\netcoreapp3.1\CLibraryPinvoke.exe (process 31848) exited with code -1073740940.
PtrToStringAnsi
从 return 值指向的缓冲区复制字符串。
UnmanagedType.LPStr
从 return 值指向的缓冲区复制字符串,并释放它 with CoTaskMemFree
。使用 CoTaskMemFree
释放 static const char[]
会使程序崩溃。
这是因为return值的语义是保存结果的内存是在被调用端分配的。
如documented,如果内存是在被调用端分配的,但不应该用CoTaskMemFree
释放,则必须将其编组为IntPtr
并使用适当的方法。
由 static const char[]
备份的内存的适当方法是不要管它。
这要求您的功能的用户了解您的功能的实现细节,这不是一件好事。当然,您可以将该函数记录为 returning 永远不应释放的内存,但这样它可能不是一个非常有用的函数,如果您将来要更改它的行为,您将被卡住使用 returning 可能的 static const char[]
s.
之一
您可以通过每次分配内存并让 .NET 运行时管理其余部分,或者让函数接受一个 char*
参数来将响应复制到
来避免所有这些情况。
我不明白为什么 .NET Core 编组无法使用一种编组方法而不是另一种方法。在下面的示例中,Marshal.PtrToStringAnsi
可以成功编组来自本机 dll 的字符串,但是使用 [return: MarshalAs(UnmanagedType.LPStr)]
属性的相同调用不能吗?还是来自 IntPtr 的编组只是运气好并且还可以根据 OS 内存管理访问无效内存?
C 库代码是(编译为 C 而不是 C++):
static const char str[] = "Hello World";
__declspec(dllexport) const char* getstr() {
return str;
}
C#测试程序:
using System;
using System.Runtime.InteropServices;
namespace CLibraryPinvoke
{
class Program
{
public const string LIB_NAME = "CLibrary";
[DllImport(LIB_NAME, EntryPoint = "getstr")]
public static extern IntPtr getstrgood();
[DllImport(LIB_NAME, EntryPoint ="getstr")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string getstrbad();
static void Main(string[] args)
{
Console.WriteLine($"getstr={Marshal.PtrToStringAnsi(getstrgood())}.");
// Crash.
Console.WriteLine($"getstr={getstrbad()}.");
}
}
}
执行结果:
getstr=Hello World.
CLibraryPinvoke\bin\Debug\netcoreapp3.1\CLibraryPinvoke.exe (process 31848) exited with code -1073740940.
PtrToStringAnsi
从 return 值指向的缓冲区复制字符串。
UnmanagedType.LPStr
从 return 值指向的缓冲区复制字符串,并释放它 with CoTaskMemFree
。使用 CoTaskMemFree
释放 static const char[]
会使程序崩溃。
这是因为return值的语义是保存结果的内存是在被调用端分配的。
如documented,如果内存是在被调用端分配的,但不应该用CoTaskMemFree
释放,则必须将其编组为IntPtr
并使用适当的方法。
由 static const char[]
备份的内存的适当方法是不要管它。
这要求您的功能的用户了解您的功能的实现细节,这不是一件好事。当然,您可以将该函数记录为 returning 永远不应释放的内存,但这样它可能不是一个非常有用的函数,如果您将来要更改它的行为,您将被卡住使用 returning 可能的 static const char[]
s.
之一
您可以通过每次分配内存并让 .NET 运行时管理其余部分,或者让函数接受一个 char*
参数来将响应复制到