我在 VS2005 .NET Framework 2.0 中创建的 WinForms 项目有问题,我刚刚升级到 VS2012 .NET Framework 4.5。在我的项目中,我使用了 DllImport
的第三方 DLL 并使用了它的函数,因为我有它们的所有文档。
问题是在 VS2005 .NET Framework 2.0 中运行良好的导入 DLL 中的函数之一在 VS2012 .NET 4.5 中无法运行。
以下是我项目中的代码片段:
[DllImport("W5EditLD.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "K5GetClassName")]
public static extern string GetClassName();//Dll import definition
public string _GetClassName()
{
return GetClassName();//wrapper function to DLL import function
}
string sClassName = _GetClassName();//where i call API via wrapper method,**
以上代码片段在 VS2005 .NET Framework 2.0 中运行良好 但是当我将项目升级到 VS2012 .NET Framework 4.5 时,我必须按以下方式进行:
[DllImport("W5EditLD.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "K5GetClassName")]
public static extern IntPtr GetClassName();//Dll import definition
public IntPtr _GetClassName()
{
return GetClassName();//wrapper function to DLL import function
}
IntPtr ptr = _GetClassName();//where i call API via wrapper method,
string sClassName = System.Runtime.InteropServices.Marshal. PtrToStringAnsi(ptr);
这是为什么? VS2012 .NET Framework 4.5 是否不支持自动字符串编码?
最佳答案
考虑您的原始 p/invoke:
[DllImport(...)]
public static extern string GetClassName();
编码器对返回值的处理是关键。这被编码为 C 字符串,即指向以 null 结尾的字符数组的指针。因为数据是从 native 到托管的,并且没有在托管代码中分配,所以框架假定它不负责释放它。 native 代码无法释放它,因为它不再执行。
因此,策略是 p/invoke 编码器假定字符数组是在共享 COM 堆上分配的。因此它调用 CoTaskMemFree
。我很确定该数组未分配到共享 COM 堆上。所以你的代码总是坏掉的。在旧版本的 .net 中,对 CoTaskMemFree
的调用碰巧无提示地失败了。在最新版本中,它因错误而失败。我不确定变化是在 .net 框架中还是在底层平台中,但这无关紧要,因为原始代码到处都是坏的。
.net 4.5 中支持自动字符串编码的方式与以前的版本完全相同。但你必须做对。如果要使用默认编码的 string
返回值,请通过调用 CoTaskMemAlloc
在 COM 堆上分配字符数组。
如果返回的字符串实际上是静态分配的,并且不需要释放你有两个明显的选择:
- 在托管代码中,切换到使用
IntPtr
和PtrToStringAnsi
。这对您来说很容易,因为您将调用移到_GetClassName
包装器内的PtrToStringAnsi
并提供与以前相同的公共(public)接口(interface)。 - 在 native 代码中,继续调用
CoTaskMemAlloc
,然后将静态缓冲区复制到堆分配的缓冲区中。
关于C#、DLL 导入 API 在 VS2012 .NET Framework 4.5 中无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18507600/