我一直在学习如何将非托管 DLL 导入编组到 C# 中......而且我遇到了一些我不太明白的事情。
在 Delphi 中,有一个函数Result := NewStr(PChar(somestring))
从Procedure SomeFunc() : PChar; Stdcall;
据我了解, NewStr 只是在本地堆上分配一个缓冲区...... SomeFunc 正在返回一个指向它的指针。
在 .NET 4.0(客户端配置文件)中,通过 C# 我可以使用:
[DllImport("SomeDelphi.dll", EntryPoint = "SomeFunc", CallingConvention = CallingConvention.StdCall)]
public static extern String SomeFunc(uint ObjID);
这在 Windows 7 .NET 4.0 客户端配置文件中可以正常工作(或者正如 David 所说,“似乎可以工作”)。在 Windows 8 中,它具有不可预测的行为,这使我走上了这条道路。
所以我决定在 .NET 4.5 中尝试相同的代码并得到堆损坏错误。好的,所以现在我知道这不是正确的做事方式。所以我进一步挖掘:
仍在 .NET 4.5 中
[DllImport("SomeDelphi.dll", EntryPoint = "SomeFunc", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr _SomeFunc();
public static String SomeFunc()
{
IntPtr pstr = _SomeFunc();
return Marshal.PtrToStringAnsi(pstr);
}
这很顺利。我(新手)担心的是 NewStr() 已经分配了这个内存,它只是永远坐在那里。我的担心不成立吗?
在 .NET 4.0 中,我什至可以做到这一点,而且它永远不会引发异常:
[DllImport("SomeDelphi.dll", EntryPoint = "SomeFunc", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr _SomeFunc();
public static String SomeFunc()
{
String str;
IntPtr pstr = _SomeFunc();
str = Marshal.PtrToStringAnsi(pstr);
Marshal.FreeCoTaskMem(pstr);
return str;
}
但是,此代码在 4.5 中引发了相同的堆异常。这让我相信问题在于在 .Net 4.5 中,编组器正在尝试 FreeCoTaskMem() ,这就是引发异常的原因。
所以问题:
为什么这适用于 .Net 4.0 而不是 4.5?
我应该担心 NewStr() 在本机 DLL 中的分配吗?
如果对#2 回答“否”,那么第二个代码示例是否有效?