C#、DLL 导入 API 在 VS2012 .NET Framework 4.5 中无法正常工作

标签 c# visual-studio-2012 pinvoke

我在 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 堆上分配字符数组。

如果返回的字符串实际上是静态分配的,并且不需要释放你有两个明显的选择:

  1. 在托管代码中,切换到使用 IntPtrPtrToStringAnsi。这对您来说很容易,因为您将调用移到 _GetClassName 包装器内的 PtrToStringAnsi 并提供与以前相同的公共(public)接口(interface)。
  2. 在 native 代码中,继续调用 CoTaskMemAlloc,然后将静态缓冲区复制到堆分配的缓冲区中。

关于C#、DLL 导入 API 在 VS2012 .NET Framework 4.5 中无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18507600/

相关文章:

c# - Unity - CommandInvokationFailure : Gradle build failed

c# - 当应用程序位于 xamarin.ios native 应用程序的前台时,如何获取推送/远程通知?

c# - 一个组内的 LINQ-to-objects 索引 + 用于不同的分组(又名 ROW_NUMBER 与 PARTITION BY 等效)

c# - C# 中的编码(marshal)处理 - 将指针传递给结构 ("double ref"的引用?)

c# - 如何在 WPF 中将 ItemsSource 与 ObservableCollection 绑定(bind)

c# - 如何在 C# 中对 if-else 语句进行单元测试?

asp.net - 如何修复 "unable to set field/property...on entity type"

c++ - 资源窗口在其他系统上无法正常工作 (Visual Studio 2012)

c# - C DLL 中的 PInvoke char* 在 C# 中处理为字符串。空字符问题

.net - IIS 托管 -> 非托管 -> 托管 -> StackOverflowException