Heap corrupted while using P/Invoked GlobalSize
Asked Answered
F

1

6

I`m developing an application in C# associated with Windows clipboard. As there are many disadvantages in Dot Net Clipboard library (STA, Fail to Open Clipboard, etc. ) I dicided to use system API directly.

What I want to do is backup data of each format ( as many as possible, if not all) , push them into a stack, and later pop out to clipboard again. If you tried AutoHotKey,this is what "ClipboardAll" in it will do.

Problem presents when I tried to get the data, this is How I write for Pinvoke:

[DllImport("user32.dll", SetLastError = true)]
public static extern bool OpenClipboard(IntPtr hWndNewOwner);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool CloseClipboard();

[DllImport("user32.dll")]
public static extern IntPtr GetClipboardData(uint uFormat);

[DllImport("user32.dll", SetLastError = true)]
public static extern uint EnumClipboardFormats(uint format);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GlobalLock(IntPtr hMem);

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GlobalUnlock(IntPtr hMem);

[DllImport("kernel32.dll")]
public static extern UIntPtr GlobalSize(IntPtr hMem);

And this is how I use them:

var x = GetFormats(); // a list returned from EnumClipboardFormats
foreach (uint format in x)
{
    IntPtr p = NativeMethods.GetClipboardData(format);
    int length = (int) NativeMethods.GlobalSize(p);
    IntPtr memPtr = NativeMethods.GlobalLock(p);
    byte[] buffer = new byte[length];
    Marshal.Copy(memPtr, buffer, 0, length);
    NativeMethods.GlobalFree(p);
    dataObject.Data[format] = buffer;//My data object
}
WinApi.CloseClipBoard();
return dataObject;

Then when I copy something in Microsoft Office Excel , I got: A Heap corrupted Exception at "GlobalSize" Method.

And after I tried to skip the format that triggered the Exception:

if(format==14||format==2) continue;

then everything worked fine.

The format 2 repsents CF_BITMAP and format 14 is CF_ENHMETAFILE, I guess they may use so-called "delay rendering" technology in clipboard, that is to say their data were null when first created and were filled when someone tried to get them, I wonder if the handle of data will change when rendering invoke, but I'm not sure.

So is there anyone can help, to find out the reason, and tell me how to fix.

Firearm answered 28/10, 2016 at 16:4 Comment(2)
olivierlanglois.net/metafile-clipboard.htmlGummous
That code stopped working 23 years ago. You have to use IDataObject to access the clipboard data.Pruinose
K
2

From the documentation:

The clipboard controls the handle that the GetClipboardData function returns, not the application. The application should copy the data immediately. The application must not free the handle nor leave it locked. The application must not use the handle after the EmptyClipboard or CloseClipboard function is called, or after the SetClipboardData function is called with the same clipboard format.

You fail to adhere to these rules. Instead of unlocking you free the handle. Don't free the handle, unlock it.

You don't perform any error checking at all. So perhaps some of the API calls fail and you do not know. Perhaps GetClipboardData is returning NULL. How would you know? Always check return values for error conditions.

There could be other errors in your program, you've not shown all the code. We can't see where you open the clipboard for instance.

Kingwood answered 29/10, 2016 at 3:48 Comment(3)
Thanks. I had the same problem. Using GlobalUnlock instead of GlobalFree did the trick.Hokeypokey
@ChristianJunk Do you mean to say you need to GlobalUnlock before you call GlobalSize?Nicknickel
@Nicknickel Take a look at the initial example. I was referring to the second last line in the foreach-loop: NativeMethods.GlobalFree(p);.Hokeypokey

© 2022 - 2024 — McMap. All rights reserved.