因为最近有使用QQ截图的内容的需求,所以看了下剪贴板的操作,参考了很多文章,基本都是MFC版本的,所以写个win32版本的,供自己以后使用
这次画图和DC相关的内容也被整的够呛,CSDN编辑页面提交错误,写完整片文章内容全部丢失一次,所以这一次可能质量没有第一次的高
将数据放入剪贴板需要四个步骤:
调用OpenClipboard打开剪贴板。
调用EmptyClipboard清空剪贴板。
调用SetClipboardData向剪贴板传递全局内存块或其它包含剪贴板数据的对象的句柄。
调用CloseClipboard关闭剪贴板。
从剪贴板获取数据也需要四个步骤是:
调用OpenClipboard打开剪贴板。
调用GetClipboardData获取全局内存块或其它包含剪贴板数据的对象的句柄。
将数据从全局内存块复制到局部变量。
调用CloseClipboard关闭剪贴板。
注意不用EmptyClipboard
1.操作文本
复制文本到剪贴板
TCHAR szText[] = L"Hello World!";
if (OpenClipboard(hWnd)) {
EmptyClipboard();
HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(szText));
LPWSTR pData = (LPWSTR)GlobalLock(hData);
CopyMemory(pData, szText, sizeof(szText));
GlobalUnlock(hData);
SetClipboardData(CF_UNICODETEXT, hData);
CloseClipboard();
}
从剪贴板复制文本
TCHAR szText[100] = {0};
if (OpenClipboard(hWnd)) {
HANDLE hData = GetClipboardData(CF_TEXT);
if (hData != NULL) {
LPWSTR pData = (LPWSTR)GlobalLock(hData);
int size = wcslen(pData) * sizeof(LPWSTR);
int b = wcslen(pData);//注意这个是不对的
if (size < 1000)
CopyMemory(szText, pData, size);
GlobalUnlock(hData);
}
CloseClipboard();
}
2.操作图像
从剪贴板获取位图,QQ截图结果可用
if (OpenClipboard (m_hWnd)) {
HBITMAP hBitmap = (HBITMAP) GetClipboardData (CF_BITMAP);
if (hBitmap != NULL) {
// Make a local copy of the bitmap.
}
CloseClipboard ();
}
将桌面截取,放入剪贴板
HWND hwnd_desk = GetDesktopWindow();
HDC hdcSrc = GetDC(hwnd_desk);
HDC hDCMem = ::CreateCompatibleDC(hdcSrc);
RECT rect;
GetClientRect(hwnd_desk, &rect);
HBITMAP hbitmap = CreateCompatibleBitmap(hdcSrc, rect.right, rect.bottom);
SelectObject(hDCMem, hbitmap);
// 注意是把桌面dc拷贝给memDC,桌面dc有图片内容,memDC里没有
BitBlt(hDCMem, 0, 0, rect.right, rect.bottom, hdcSrc, 0, 0, SRCCOPY);
if (OpenClipboard(hWnd)) {
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbitmap);
CloseClipboard();
}
DeleteObject(hbitmap);
DeleteDC(hdcSrc);
DeleteDC(hDCMem);
DeleteDC(hdc);
注意绘图的时候BitBlt是反过来的,是在memDC里画图,画完之后把memDC粘贴到hdc里面
打开一张图片,放入剪贴板
// 这样可以选择一个图片路径,放到剪贴板里面
HBITMAP hbitmap = (HBITMAP)::LoadImage(hInst, _T("cap.bmp"),
IMAGE_BITMAP, 1400, 700, LR_LOADFROMFILE);
if (OpenClipboard(hWnd)) {
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbitmap);
CloseClipboard();
}
DeleteObject(hbitmap);
DeleteDC(hdc);
3.操作文件/文件夹
把剪贴板里的文件/文件夹路径取出
vector<wstring> listFileName;
if (OpenClipboard(hWnd)) {
// HDROP的头文件shellapi.h
HDROP hDrop = (HDROP)GetClipboardData(CF_HDROP);
if (hDrop != NULL) {
// Find out how many file names the HDROP contains.
int nCount = DragQueryFile(hDrop, (UINT)-1, NULL, 0);
// Enumerate the file names.
if (nCount) {
TCHAR szFile[MAX_PATH];
for (int i = 0; i<nCount; i++) {
DragQueryFile(hDrop, i, szFile, sizeof(szFile) / sizeof(TCHAR));
listFileName.push_back(szFile);
}
}
}
CloseClipboard();
}
把文件/文件夹路径放入剪贴板
//注意用\0分隔多个路径
TCHAR szFiles[300] = _T("natives_blob.bin\0snapshot_blob.bin\0locales\0");
if (OpenClipboard(hWnd)) {
EmptyClipboard();
// DROPFILES的头文件Shlobj.h
int nSize = sizeof(DROPFILES) + sizeof(szFiles);
HANDLE hData = GlobalAlloc(GHND, nSize);
LPDROPFILES pDropFiles = (LPDROPFILES)GlobalLock(hData);
pDropFiles->pFiles = sizeof(DROPFILES);
#ifdef UNICODE
pDropFiles->fWide = TRUE;
#else
pDropFiles->fWide = FALSE;
#endif
LPBYTE pData = (LPBYTE)pDropFiles + sizeof(DROPFILES);
CopyMemory(pData, szFiles, sizeof(szFiles));
GlobalUnlock(hData);
SetClipboardData(CF_HDROP, hData);
CloseClipboard();
}
4.查询剪贴板内容
CountClipboardFormats 返回可用格式的个数
EnumClipboardFormats 枚举可用的格式
IsClipboardFromatAvailable 指示某一格式是否有效
GetPriorityClipboardFormat 获取一个具有优先级别的列表,表示哪一个最先有效
注意查询的时候一定要先打开剪贴板再执行查询语句,不然查询完了之后打开,可能已经改变了
// 这段代码是存在问题的,内外两层if应该反过来放
if (IsClipboardFormatAvailable (CF_TEXT)) {
if (OpenClipboard (m_hWnd)) {
HANDLE hData = GetClipboardData (CF_TEXT);
LPCSTR pData = (LPCSTR) GlobalLock (hData);
...
CloseClipboard ();
}
}
GetPriorityClipboardFormat函数的使用,根据数组中的排列优先级返回
UINT nFormats[3] = {
nID, // First choice
CF_TEXT, // Second choice
CF_BITMAP // Third choice
};
if (OpenClipboard (m_hWnd)) {
UINT nFormat = GetPriorityClipboardFormat (nFormats, 3);
if (nFormat > 0) {
// nFormat holds nID, CF_TEXT, or CF_BITMAP.
}
CloseClipboard ();
}
剪贴板监听
首先需要定义一个剪贴板用的hwndClip,窗口初始化的时候要让窗口成为剪贴板链的一部分hwndClip = SetClipboardViewer(hwnd);
然后添加两个消息
//更新剪切板
case WM_DRAWCLIPBOARD:
//让每个剪切板都更新,重画
if(hwndNextViewer)
SendMessage(hwndNextViewer,WM_DRAWCLIPBOARD,wParam,lParam);
InvalidateRect(hwnd,NULL,true);
return 0;
//当剪切板查看器链中有一个退出时,更新链
case WM_CHANGECBCHAIN:
if((HWND)wParam == hwndNextViewer)
hwndNextViewer = (HWND)lParam;
//如果下一个不为空,那么将下一个更改
else if(hwndNextViewer)
SendMessage(hwndNextViewer,WM_CHANGECBCHAIN,wParam,lParam);
return 0;
窗口关闭时要改变剪贴板链
case WM_DESTROY:
//加这一句
ChangeClipboardChain(hwnd,hwndNextViewer);
PostQuitMessage(0);
return 0;
一些别的
自定义剪贴格式和延迟提交没怎么研究,目前没用到,可以查RegisterClipboardForamt和WM_RENDERFORMAT
往剪贴板里放数据是可以一次放多种类型的,比如,多次调用SetClipboardData
SetClipboardData (CF_BITMAP, hBitmap);
SetClipboardData (CF_TEXT, hTextData);
常用的剪贴格式
CF_BITMAP Windows位图
CF_DIB 设备无关位图
CF_ENHMETAFILE GDI增强型元文件
CF_METAFILEPICT 旧的GDI元文件,带有大小和映射模式附加信息
CF_HDROP HDROP 格式的文件名列表
CF_PALETTE GDI调色板
CF_TEXT 8位ANSI字符组成的文本
CF_TIFF TIFF格式的位图
CF_UNICODETEXT 16位Unicode字符组成的文本
CF_WAVE WAV格式的音频数据
CF_HDROP 文件和文件夹