@
Windows剪贴板复制消息和内容截取
解决了什么问题
在Windows应用开发的过程中,根据需求有时候会需要监控一下剪贴板,看看剪贴板的内容是否是我们应用程序感兴趣的内容。
比如下载器,往往会监控剪贴板内是否有下载链接,然后弹出下载页面
本文将一探究竟,自己实现一个当剪贴板内容有更新时立即通知到我们程序
实现思路
当剪贴板有新的内容产生时,Windows会给关注的窗口推送剪贴板内容更新消息,我们需要在我们窗口中先注册监听剪贴板相关消息,我们需要关注的是剪贴板有新的内容进入的时候怎么做的问题,所以本文主要关注 WM_DRAWCLIPBOARD 消息。
关于windows剪贴板每个消息的含义,可以查看微软的文档 WM_DRAWCLIPBOARD 消息说明和接收该消息需要的操作.
实现过程
1. 监听剪贴板内容更新消息
SetClipboardViewer(); // 在本程序中打开的窗口中监听剪贴板消息
2. 捕获剪贴板消息
代码部分示例:
BEGIN_MSG_MAP(Window)
MESSAGE_HANDLER(WM_DRAWCLIPBOARD, OnClipboardMessage)
END_MSG_MAP()
WM_DRAWCLIPBOARD 是剪贴板内容发生变动时的窗口消息,在本窗体中监听该消息,当触发这个消息时,可以获取一下剪贴板的内容。本实例中使用这个回调函数 OnClipboardMessage 来处理。
3. 获取剪贴板内容
获取剪贴板文本信息
CString result; //存放剪贴板文本信息
if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard())
{
HANDLE hClipboard = GetClipboardData(CF_UNICODETEXT);
if (hClipboard)
{
wchar_t* ptr = reinterpret_cast<wchar_t*>(GlobalLock(hClipboard));
if (ptr != NULL)
{
result = ptr;
GlobalUnlock(hClipboard);
}
}
CloseClipboard();
}
获取剪贴板文件复制消息
if (IsClipboardFormatAvailable(CF_HDROP) && OpenClipboard())
{
HDROP hDrop = HDROP(::GetClipboardData(CF_HDROP)); //获取剪切板中复制的文件列表相关句柄
if (hDrop)
{
WCHAR szFilePathName[MAX_PATH + 1] = { 0 };
UINT nNumOfFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); //得到文件个数
// 考虑到用户可能同时选中了多个对象(可能既包含文件也包含文件夹),以要循环处理
for (UINT i = 0; i < nNumOfFiles; ++i)
{
memset(szFilePathName, 0, MAX_PATH + 1);
DragQueryFile(hDrop, i, szFilePathName, MAX_PATH); //得到文件名
std::wstring ss = szFilePathName;
std::wcout << TEXT("文件:") << ss << std::endl; // 打印复制的文件名
}
}
CloseClipboard();
}
剪贴板粘贴消息的一些思考
由于没有剪贴板粘贴时触发的相应消息,在粘贴时,是由应用进程来读取剪贴板内容来完成的粘贴操作,所以无法像捕获消息一样通过监听消息来直接捕获到粘贴操作。
根据日常的粘贴操作情况,需要捕获键盘 CTRL+V 消息,或者hook粘贴板读取函数
键盘钩子通过SetWindowsHookEx()或RegisterRawInputDevices()可以监视Ctrl+V击键。经由消息挂钩SetWindowsHookEx()可以监视与粘贴的窗口消息,如WM_PASTE,EM_PASTESPECIAL,WM_COMMAND等,但即使是这样,也没有检测每一个可能的粘贴操作的保证。
可能不得不求助于将代码注入目标进程,以直接挂钩查询剪贴板数据的各种 Win32 API 函数。然后,当目标进程尝试在任何类型的粘贴操作期间检索数据时,可以修改这个过程(例如让应用程序认为没有可粘贴的数据):
CountClipboardFormats()
EnumClipboardFormats()
IsClipboardFormatAvailable()
GetPriorityClipboardFormat()
GetUpdatedClipboardFormats()
GetClipboardData() 和 OleGetClipboard()
参考:https://stackoverflow.com/questions/46699066/clipboard-viewer-doesnt-get-paste-notification