我正在使用与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,我猜他们可能会使用所谓的"延迟渲染"剪贴板中的技术,也就是说他们的数据在第一次创建时为空,并在有人试图获取时填充,我想知道在渲染调用时数据句柄是否会改变,但我不确定。
所以有人可以提供帮助,找出原因,并告诉我如何解决。
答案 0 :(得分:2)
来自文档:
剪贴板控制GetClipboardData函数返回的句柄,而不是应用程序。应用程序应立即复制数据。应用程序不得释放手柄,也不得将其锁定。在调用EmptyClipboard或CloseClipboard函数之后,或者在使用相同的剪贴板格式调用SetClipboardData函数之后,应用程序不得使用句柄。
您未能遵守这些规则。而不是解锁你释放手柄。不要释放手柄,解锁它。
您根本不执行任何错误检查。所以也许有些API调用失败了,你不知道。也许GetClipboardData
正在返回NULL
。你怎么知道的?始终检查错误条件的返回值。
您的程序中可能存在其他错误,但您没有显示所有代码。例如,我们无法看到您打开剪贴板的位置。