C#, DLL import API not working properly in VS2012 .NET Framework 4.5

喜欢而已 提交于 2019-12-21 20:22:16

问题


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.

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,**

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);

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


回答1:


Consider your original p/invoke:

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

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.

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.

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. 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.



回答2:


This doesn't have anything to do with the framework, everything to do with the Windows version. Your old 2.0 project probably ran on XP. We know that you've got a newer operating system now since 4.5 is not available for XP.

XP has a much more lenient heap manager, it just shrugs when the pinvoke marshaller calls CoTaskMemFree() to release the string and ignores the invalid pointer. Starting with Vista, it no longer shrugs and throws an AccessViolation so misbehaving programs are taken out of their misery. This no-nonsense attitude is one reason that Vista got such a bad name. It is now considered normal, after programmers had enough time to fix the bugs in their programs.

The workaround you found is the correct one, the marshaller isn't going to try to release the memory for an IntPtr. Do note that this will only actually come to a good end if the C code returns a const char* that doesn't need to be released. You have a permanent memory leak if that's not the case.



来源:https://stackoverflow.com/questions/18507600/c-dll-import-api-not-working-properly-in-vs2012-net-framework-4-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!