win32剪贴板操作

参考
https://blog.csdn.net/gjtboa/article/details/50562614

因为最近有使用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              8ANSI字符组成的文本
CF_TIFF              TIFF格式的位图
CF_UNICODETEXT       16Unicode字符组成的文本
CF_WAVE              WAV格式的音频数据
CF_HDROP             文件和文件夹
  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值