C# PInvoke封送常量char*失败,为UnmanagedType.LPStr
我无法理解为什么.NET核心编组无法使用一种marshakking方法而不是另一种方法。在下面的示例中,C# PInvoke封送常量char*失败,为UnmanagedType.LPStr,c#,pinvoke,C#,Pinvoke,我无法理解为什么.NET核心编组无法使用一种marshakking方法而不是另一种方法。在下面的示例中,Marshal.PtrToStringAnsi可以成功地从本机dll封送字符串,但是使用[return:MarshalAs(UnmanagedType.LPStr)]属性的相同调用无法成功?还是来自IntPtr的封送只是运气好,还可能访问无效内存,具体取决于操作系统内存管理 C库代码是(编译为C而不是C++): static const char str[]=“你好世界”; __declspe
Marshal.PtrToStringAnsi
可以成功地从本机dll封送字符串,但是使用[return:MarshalAs(UnmanagedType.LPStr)]
属性的相同调用无法成功?还是来自IntPtr的封送只是运气好,还可能访问无效内存,具体取决于操作系统内存管理
C库代码是(编译为C而不是C++):
static const char str[]=“你好世界”;
__declspec(dllexport)const char*getstr(){
返回str;
}
C#测试程序:
使用系统;
使用System.Runtime.InteropServices;
名称空间CLibraryPinvoke
{
班级计划
{
public const string LIB_NAME=“CLibrary”;
[DllImport(LIB_NAME,EntryPoint=“getstr”)]
公共静态外部程序IntPtr getstrgood();
[DllImport(LIB_NAME,EntryPoint=“getstr”)]
[返回:Marshallas(UnmanagedType.LPStr)]
公共静态外部字符串getstrbad();
静态void Main(字符串[]参数)
{
WriteLine($“getstr={Marshal.PtrToStringAnsi(getstrgood())}”);
//撞车。
WriteLine($“getstr={getstrbad()}”);
}
}
}
执行结果:
getstr=Hello World.
CLibraryPinvoke\bin\Debug\netcoreapp3.1\CLibraryPinvoke.exe (process 31848) exited with code -1073740940.
PtrToStringAnsi
从返回值指向的缓冲区复制字符串
UnmanagedType.LPStr
从返回值指向的缓冲区复制字符串,然后释放它。使用CoTaskMemFree
释放static const char[]
会使程序崩溃
这是因为返回值的语义是,保存结果的内存是在被调用方分配的
同样,如果内存是在被叫端分配的,但不应使用CoTaskMemFree
释放,则必须将其封送为IntPtr
,并使用适当的方法自行释放。对于由
静态常量char[]
备份的内存,适当的方法是不使用它
这要求函数的用户了解函数的实现细节,这不是一件好事。当然,您可以将该函数记录为永远不会释放的返回内存,但它可能不是一个非常有用的函数,如果将来要更改其行为,您将不得不返回一个可能的静态常量char[]
s.通过每次分配内存并让.NET运行时管理其余部分,或者让函数接受一个
char*
参数以将响应复制到其中,可以避免所有这一切。PtrToStringAnsi
从缓冲区复制字符串UnmanagedType.LPStr
从缓冲区复制字符串并释放它。使用CoTaskMemFree
释放static const char[]
会使程序崩溃。@GSerg-您应该回答:-)