c# – 使用P / Invoked GlobalSize时堆已损坏

我正在开发一个与
Windows剪贴板相关的C#应用​​程序.由于Dot Net剪贴板库(STA,无法打开剪贴板等)存在许多缺点,我决定直接使用系统API.

我想要做的是备份每种格式的数据(尽可能多,如果不是全部),将它们推入堆栈,然后再次弹出到剪贴板.如果您尝试过AutoHotKey,那么它就是“ClipboardAll”.

当我试图获取数据时出现问题,这就是我为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);

这就是我使用它们的方式:

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;

然后当我在Microsoft Office Excel中复制一些东西时,我得到了:
A Heap corrupted Exception at “GlobalSize” Method.

在我尝试跳过触发异常的格式之后:

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

一切都很好.

格式2代表CF_BITMAP,格式14是CF_ENHMETAFILE,我猜他们可能在剪贴板中使用所谓的“延迟渲染”技术,也就是说他们的数据在第一次创建时为空,当有人试图获取它们时填充,我想知道如果渲染调用时数据句柄会改变,但我不确定.

那么有没有人可以帮助,找出原因,并告诉我如何解决.

最佳答案 从文档:

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.

您未能遵守这些规则.而不是解锁你释放手柄.不要释放手柄,解锁它.

您根本不执行任何错误检查.所以也许有些API调用失败了,你不知道.也许GetClipboardData返回NULL.你怎么知道的?始终检查错误条件的返回值.

程序中可能存在其他错误,您没有显示所有代码.例如,我们无法看到您打开剪贴板的位置.

点赞