ifd*_*dog 6 .net c# windows pinvoke winapi
我正在用 C# 开发一个与 Windows 剪贴板相关的应用程序。由于Dot Net Clipboard库有很多缺点(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);
Run Code Online (Sandbox Code Playgroud)
这就是我使用它们的方式:
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;
Run Code Online (Sandbox Code Playgroud)
然后,当我在 Microsoft Office Excel 中复制某些内容时,我得到: “GlobalSize”方法中的堆损坏异常。
在我尝试跳过触发异常的格式之后:
if(format==14||format==2) continue;
Run Code Online (Sandbox Code Playgroud)
然后一切正常。
格式2代表CF_BITMAP,格式14代表CF_ENHMETAFILE,我猜他们可能在剪贴板中使用了所谓的“延迟渲染”技术,也就是说它们的数据在第一次创建时为空,当有人试图获取它们时被填充,我想知道渲染调用时数据句柄是否会改变,但我不确定。
那么有没有人可以帮忙找出原因并告诉我如何解决。
从文档中:
剪贴板控制 GetClipboardData 函数返回的句柄,而不是应用程序。应用程序应立即复制数据。应用程序不得释放手柄或将其锁定。在调用 EmptyClipboard 或 CloseClipboard 函数之后,或者在使用相同的剪贴板格式调用 SetClipboardData 函数之后,应用程序不得使用该句柄。
您未能遵守这些规则。您无需解锁,而是释放手柄。不要释放手柄,将其解锁。
您根本不执行任何错误检查。因此,也许某些 API 调用失败而您并不知道。或许GetClipboardData正在回归NULL。你怎么知道的?始终检查返回值是否有错误情况。
您的程序中可能存在其他错误,您没有显示所有代码。例如,我们无法看到您在哪里打开剪贴板。
| 归档时间: |
|
| 查看次数: |
626 次 |
| 最近记录: |