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

Sur*_*til 3 c# pinvoke visual-studio-2012

我的WinForms项目存在问题,该项目是在VS2005 .NET Framework 2.0中创建的,我刚刚升级到VS2012 .NET Framework 4.5.在我的项目中,我使用了第三方DLL DllImport并使用了它的功能,因为我有他们的所有文档.

问题是导入的DLL中的一个函数在VS2005中工作正常.NET Framework 2.0在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,**
Run Code Online (Sandbox Code Playgroud)

上面的代码片段在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);
Run Code Online (Sandbox Code Playgroud)

为什么会这样?VS2012 .NET Framework 4.5中是否不支持自动字符串编组?

Dav*_*nan 6

考虑一下你原来的p/invoke:

[DllImport(...)]
public static extern string GetClassName();
Run Code Online (Sandbox Code Playgroud)

编组人员对返回值的处理是关键.这被编组为一个C字符串,它是一个指向以null结尾的字符数组的指针.由于数据来自本机到托管,并且未在托管代码中分配,因此框架假定它不负责解除分配.本机代码无法解除分配,因为它不再执行.

因此,策略是p/invoke marshaller假定字符数组是在共享COM堆上分配的.它呼吁CoTaskMemFree.我很确定该数组未在共享COM堆上分配.所以你的代码总是坏了.在旧版本的.net中,调用CoTaskMemFree恰好无声地失败.在最新版本中,它失败并出现错误.我不确定更改是在.net框架中,还是在底层平台上,但这很重要,因为原始代码在任何地方都被破坏了.

在.net 4.5中支持自动字符串编组与以前的版本完全相同.但你必须做得对.如果要使用string带默认编组的返回值,请通过调用在COM堆上分配字符数组CoTaskMemAlloc.

如果返回的字符串实际上是静态分配的,并且不需要重新分配,那么您有两个明显的选择:

  1. 在托管代码中,切换到使用IntPtrPtrToStringAnsi.这很容易为您做,因为您将调用移动到包装器PtrToStringAnsi内部_GetClassName并呈现与以前相同的公共接口.
  2. 在本机代码中,继续调用CoTaskMemAlloc然后将静态缓冲区复制到该堆分配的缓冲区中.

  • 该代码在VS2005中无法正常运行。如果传回给您的字符串是在堆上分配的,它会默默地失败,很可能会导致内存泄漏。如果您无法更改本机代码,那么您唯一的选择是使用“IntPtr”和“PtrToStringAnsi”。 (2认同)