C#,DLL导入API在VS2012 .NET Framework 4.5中无法正常工作 [英] C#, DLL import API not working properly in VS2012 .NET Framework 4.5

查看:340
本文介绍了C#,DLL导入API在VS2012 .NET Framework 4.5中无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an issue with my WinForms project which was created in VS2005 .NET Framework 2.0, which I just upgraded to VS2012 .NET Framework 4.5. In my project, I used a third-party DLL by DllImport and used its functions as I had all documentation for them.

问题是导入的DLL中的功能之一,该功能在VS2005中工作正常.NETFramework 2.0在VS2012 .NET 4.5中不起作用.

The problem is one of the functions in the imported DLL which works fine in VS2005 .NET Framework 2.0 is not working in VS2012 .NET 4.5.

以下是我的项目中的代码段:

Following are my code snippets from my project:

[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时,我必须采用以下方式:

Above code snippet works fine in VS2005 .NET Framework 2.0 But when I upgraded my project to VS2012 .NET Framework 4.5 I have to do it in the following way:

[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不支持自动字符串编组吗?

Why this is? Is automatic string marshalling not supported in VS2012 .NET Framework 4.5?

推荐答案

请考虑您的原始p/调用:

Consider your original p/invoke:

[DllImport(...)]
public static extern string GetClassName();

编组对返回值的处理是关键.这被编组为C字符串,它是指向以Null结尾的字符数组的指针.因为数据是从本机发送到托管的,并且没有在托管代码中分配,所以框架假定它不负责取消分配数据.本机代码无法再分配,因为它不再执行.

The marshaller's treatment of the return value is the key. This is marshalled as a C string, that is a pointer to a null-terminated array of characters. Because the data is coming from native to managed, and was not allocated in the managed code, the framework assumes that it is not responsible for deallocating it. The native code cannot deallocate it since it is no longer executing.

因此,策略是p/调用编组假定字符数组已分配在共享COM堆上.因此它称为CoTaskMemFree.我很确定该数组未分配在共享COM堆上.所以你的代码总是坏掉的.在旧版本的.net中,对CoTaskMemFree的调用恰好以静默方式失败.在最新版本中,它因错误而失败.我不确定是在.net框架中还是在底层平台中进行了更改,但这无关紧要,因为原始代码到处都被破坏了.

The policy therefore is that the p/invoke marshaller assumes that the character array was allocated on the shared COM heap. And so it calls CoTaskMemFree. I'm pretty sure that the array was not allocated on the shared COM heap. So your code was always broken. In older versions of .net the call to CoTaskMemFree happened to fail silently. In the latest versions it is failing with an error. I'm not sure whether the change is in the .net framework, or the underlying platform, but that matters little since the original code is broken everywhere.

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

Automatic string marshalling is supported in exactly the same way in .net 4.5 as in previous versions. But you have to do it right. If you want to use a string return value with default marshalling, allocate the character array on the COM heap with a call to CoTaskMemAlloc.

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

If the returned string is in fact statically allocated, and does not need deallocation you have two obvious choices:

  1. 在托管代码中,切换为使用IntPtrPtrToStringAnsi.这很容易为您完成,因为您可以将调用移至_GetClassName包装器内的PtrToStringAnsi并提供与以前相同的公共接口.
  2. 在本机代码中,继续调用CoTaskMemAlloc,然后将静态缓冲区复制到该堆分配的缓冲区中.
  1. In the managed code, switch to using IntPtr and PtrToStringAnsi. This is easy enough to do for you because you move the call to PtrToStringAnsi inside your _GetClassName wrapper and present the same public interface as before.
  2. In the native code, go ahead and call CoTaskMemAlloc and then copy the static buffer into that heap allocated buffer.

这篇关于C#,DLL导入API在VS2012 .NET Framework 4.5中无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆