Access Violation Exception in "Marshal.StructureToPtr" on Windows 7 + .NET 4.0 (Windows XP + .NET 3.5 Works Great)

Here is my code:

internal void Show() { if (Parent == null) throw new NullReferenceException(); EDITBALLOONTIP ebt = new EDITBALLOONTIP(); ebt.cbStruct = Marshal.SizeOf(ebt); ebt.pszText = Text; ebt.pszTitle = Caption; ebt.ttiIcon = (int)Icon; IntPtr ptrStruct = Marshal.AllocHGlobal(Marshal.SizeOf(ebt)); Marshal.StructureToPtr(ebt, ptrStruct, true); // Here we go. // Access violation exception in Windows 7 + .NET 4.0 // In Windows XP + .NET 3.5, it works just fine. // ... Some other code ... Marshal.FreeHGlobal(ptrStruct); } 

And here is the structure:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct EDITBALLOONTIP { internal int cbStruct; internal string pszTitle; internal string pszText; internal int ttiIcon; } 

Why does this work fine in Windows XP and .NET 3.5 and throw exceptions in Windows 7 and .NET 4.0? Maybe this is a CharSet problem?

====================== solvable ======================= =

Solution and explanation

As you can see Marshal.StructureToPtr (ebt, ptrStruct, true ); has a third parameter equal to true. This means that the system will try to free the last allocated memory for ptrStruct. But when the Show() method is called for the first time, there was no allocated memory for this structure (ptrStruct = IntPtr.Zero). Therefore, the system will try to free memory located with a null pointer. And of course, this will throw an exception. Windows XP ignores this, but Windows 7 does not.

And here is the best IMHO solution:

  Marshal.StructureToPtr(ebt, ptrStruct, false); //Working... //Free resources Marshal.FreeHGlobal(ptrStruct); 
+4
source share
1 answer

I did not want to add the answer here, since you already solved your problem, and I will say that I will not provide any answer to the problem you have, but this will not fit well as a comment, since I provide some code. Therefore, I must publish it here as an answer.

Perhaps you already know this (and did not write in such a way that the code in your question was simpler), but I just wanted to say that the best practice that should be used everywhere when unmanaged memory is allocated is to encapsulate the code in a try / finally block to ensure that memory is always freed , even if an exception is thrown:

 private static void Test() { IntPtr ptrStruct = IntPtr.Zero; try { Marshal.AllocHGlobal(0x100); // Some code here // At some point, an exception is thrown throw new IndexOutOfRangeException(); } finally { // Even if the exception is thrown and catch // from the code that calls the Test() method, // the memory will be freed. if (ptrStruct != IntPtr.Zero) { Marshal.FreeHGlobal(ptrStruct); } } } try { Test(); } catch (IndexOutOfRangeException) { // Catches the exception, so the program won't crash // but it'll exit the Test() method, so the try/finally // ensures it won't leave without freeing the memory Debugger.Break(); } 
+1
source

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


All Articles