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

I have a problem with my WinForms project that 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 using DllImport and used its functions, since I had all the documentation for them.

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

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

The code fragment 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 like this:

 [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 is this? Is automatic string sorting not supported in VS2012.NET Framework 4.5?

+3
source share
2 answers

Consider your original p / invoke:

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

Processing the return value by the marshaller is the key. This is sorted as a string C, i.e. a pointer to an array of characters with a null character. Since the data comes from native to managed and is not allocated in managed code, the structure assumes that it is not responsible for releasing it. Native code cannot free it because it is no longer running.

So the policy is that the p / invoke marshaller assumes that the character array has been allocated on the common COM heap. And so it calls CoTaskMemFree . I am sure that the array was not allocated on the common COM heap. Thus, your code has always been broken. In older versions of .net, the CoTaskMemFree call failed. In recent versions, error with error. I’m not sure if the change is in the .net infrastructure or the underlying platform, but that doesn’t mean much since the source code is everywhere broken.

Automatic line sorting 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 the return value of string with default marshalling, allocate an array of characters in the COM heap with a call to CoTaskMemAlloc .

If the returned string is actually statically distributed and does not need to be freed, you have two obvious options:

  • In managed code, switch to using IntPtr and PtrToStringAnsi . This is simple enough for you because you move the PtrToStringAnsi call inside your _GetClassName wrapper and present the same open interface as before.
  • In the native code, continue and call CoTaskMemAlloc , and then copy the static buffer to this buffer allocated by the buffer.
+6
source

This has nothing to do with the framework, everything related to the version of Windows. Your old 2.0 project probably worked on XP. We know that you now have a new operating system, since 4.5 is not available for XP.

XP has a much softer heap manager, it just shrugs when the pinvoke marker calls CoTaskMemFree () to free the line and ignore the wrong pointer. Starting with Vista, he no longer shrugs and throws AccessViolation, so that failed programs are derived from their misfortune. This meaningless attitude is one of the reasons why Vista got such a bad name. Now this is considered normal after the programmers had time to fix errors in their programs.

The workaround you found is correct; the marshaller is not going to release memory for IntPtr. Note that this only actually comes to an end if the C code returns a const char* that does not need to be released. If this is not the case, you have a persistent memory leak.

+2
source

Source: https://habr.com/ru/post/1244295/


All Articles