首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

VC++/MFC 剪貼板操作完整教學:文字、繪圖、位圖、自訂格式與變更通知

     編輯:更多程式設計知識

剪貼板是 Windows 應用程式間資料交換的核心通道。MFC 封裝 OpenClipboard/EmptyClipboard/SetClipboardData/GetClipboardData 等 API,支援標準格式(文字、繪圖、位圖)與自訂格式。本文系統講解六大操作場景,附完整代碼範例。

核心流程模板


if (OpenClipboard()) {
    EmptyClipboard(); // 寫入前必須清空
    // ... 準備 HGLOBAL 資料 ...
    SetClipboardData(format, hGlobal);
    CloseClipboard();
}
所有剪貼板操作必須成對呼叫 OpenClipboard/CloseClipboard,否則導致其他程式無法存取。

一、文字內容操作 (CF_TEXT / CF_UNICODETEXT)

寫入文字 (ANSI 範例,Unicode 專案建議用 CF_UNICODETEXT)


CString strSource = _T("要複製的文字內容");
if (OpenClipboard()) {
    EmptyClipboard();
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (strSource.GetLength() + 1) * sizeof(TCHAR));
    LPTSTR pBuf = (LPTSTR)GlobalLock(hGlobal);
    _tcscpy(pBuf, strSource);
    GlobalUnlock(hGlobal);
    SetClipboardData(CF_UNICODETEXT, hGlobal); // Unicode 版本
    CloseClipboard();
}

讀取文字


CString strFromClipboard;
if (OpenClipboard()) {
    HANDLE hData = GetClipboardData(CF_UNICODETEXT);
    if (hData) {
        LPTSTR pBuf = (LPTSTR)GlobalLock(hData);
        strFromClipboard = pBuf;
        GlobalUnlock(hData);
    }
    CloseClipboard();
}

二、繪圖檔操作 (CF_ENHMETAFILE)

寫入增強繪圖檔


if (OpenClipboard()) {
    EmptyClipboard();
    CMetaFileDC *pDC = new CMetaFileDC();
    pDC->CreateEnhanced(NULL, NULL, NULL, _T("MyMetaFile"));
    // 繪圖指令...
    // pDC->Rectangle(...); pDC->TextOut(...);
    HENHMETAFILE hMF = pDC->CloseEnhanced();
    SetClipboardData(CF_ENHMETAFILE, hMF);
    CloseClipboard();
    delete pDC; // 注意:刪除 DC 不會刪除 metafile handle
}

讀取並繪製到視窗


if (OpenClipboard()) {
    HENHMETAFILE hMF = (HENHMETAFILE)GetClipboardData(CF_ENHMETAFILE);
    if (hMF) {
        CClientDC dc(this);
        CRect rect(0, 0, 200, 200);
        dc.PlayMetaFile(hMF, rect);
    }
    CloseClipboard();
}

三、位圖操作 (CF_BITMAP)

寫入位圖


if (OpenClipboard()) {
    EmptyClipboard();
    CClientDC cdc(this);
    CDC memDC;
    memDC.CreateCompatibleDC(&cdc);
    CBitmap bmp;
    bmp.CreateCompatibleBitmap(&cdc, 200, 200);
    CBitmap *pOld = memDC.SelectObject(&bmp);
    // 繪製內容
    // DrawImage(&memDC, _T("Bitmap"));
    memDC.SelectObject(pOld);
    SetClipboardData(CF_BITMAP, bmp.Detach()); // 傳遞 HBITMAP
    CloseClipboard();
}

讀取並顯示位圖


if (OpenClipboard()) {
    HBITMAP hBmp = (HBITMAP)GetClipboardData(CF_BITMAP);
    if (hBmp) {
        CBitmap bmp;
        bmp.Attach(hBmp);
        CClientDC cdc(this);
        CDC memDC;
        memDC.CreateCompatibleDC(&cdc);
        CBitmap *pOld = memDC.SelectObject(&bmp);
        BITMAP bmInfo;
        bmp.GetBitmap(&bmInfo);
        cdc.BitBlt(0, 0, bmInfo.bmWidth, bmInfo.bmHeight, &memDC, 0, 0, SRCCOPY);
        memDC.SelectObject(pOld);
        bmp.Detach(); // 避免析構時刪除共享 handle
    }
    CloseClipboard();
}

四、自訂格式 (RegisterClipboardFormat)

定義專屬資料結構,跨程式交換強型別資料。

定義格式與資料結構


struct MyFormatData {
    long val1;
    int  val2;
};
UINT MY_CUSTOM_FORMAT = RegisterClipboardFormat(_T("MY_CUSTOM_FORMAT"));

寫入自訂資料


MyFormatData data = {100, 200};
if (OpenClipboard()) {
    EmptyClipboard();
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(MyFormatData));
    MyFormatData *pBuf = (MyFormatData*)GlobalLock(hGlobal);
    *pBuf = data;
    GlobalUnlock(hGlobal);
    SetClipboardData(MY_CUSTOM_FORMAT, hGlobal);
    CloseClipboard();
}

讀取自訂資料


MyFormatData data;
if (OpenClipboard()) {
    HANDLE hData = GetClipboardData(MY_CUSTOM_FORMAT);
    if (hData) {
        MyFormatData *pBuf = (MyFormatData*)GlobalLock(hData);
        data = *pBuf;
        GlobalUnlock(hData);
    }
    CloseClipboard();
}

五、偵測剪貼板內容變更 (WM_DRAWCLIPBOARD)

將視窗加入剪貼板檢視鏈,接收變更通知。

初始化加入鏈


// 在 OnInitDialog 或 OnCreate 中
SetClipboardViewer(); // 將本視窗加入檢視鏈

訊息映射與處理


BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
    ON_MESSAGE(WM_DRAWCLIPBOARD, OnClipboardChange)
END_MESSAGE_MAP()

afx_msg LRESULT CMyDlg::OnClipboardChange(WPARAM, LPARAM) {
    CTime t = CTime::GetCurrentTime();
    SetDlgItemText(IDC_TIME, t.Format(_T("%Y-%m-%d %H:%M:%S")));
    DisplayClipboardText(); // 自訂函式顯示內容
    // 必須傳遞給下一個檢視者
    SendMessage(WM_DRAWCLIPBOARD, 0, 0); 
    return 0;
}
重要:收到 WM_DRAWCLIPBOARD 後必須 SendMessage 轉發給鏈中下一個視窗,否則斷開通知鏈。視窗銷毀時呼叫 ChangeClipboardChain 移除自身。

六、自動貼上至其他應用程式視窗


// 取得目標視窗句柄 (FindWindow/EnumWindows 等)
HWND hTarget = FindWindow(_T("Notepad"), NULL);
if (hTarget) {
    // 模擬 Ctrl+V
    PostMessage(hTarget, WM_KEYDOWN, VK_CONTROL, 0);
    PostMessage(hTarget, WM_KEYDOWN, 'V', 0);
    PostMessage(hTarget, WM_KEYUP, 'V', 0);
    PostMessage(hTarget, WM_KEYUP, VK_CONTROL, 0);
}

或使用 SendInput 模擬鍵盤事件,更可靠跨進程注入。

常見格式常數對照

常數資料類型說明
CF_TEXTANSI 字串傳統格式
CF_UNICODETEXTUnicode 字串現代應用首選
CF_BITMAPHBITMAP裝置相關位圖
CF_DIBHGLOBAL (BITMAPINFO+資料)裝置獨立位圖
CF_ENHMETAFILEHENHMETAFILE增強繪圖檔
CF_HDROPHDROP檔案拖放清單

結語

掌握 MFC 剪貼板六大操作——標準格式讀寫、自訂格式強型別交換、變更通知鏈、跨程式自動貼上——即能實作豐富的資料共享功能。關鍵紀律:成對 Open/Close、寫入前 Empty、GlobalAlloc 用 GMEM_DDESHARE、自訂格式用 RegisterClipboardFormat、通知鏈必須轉發。遵循原則,剪貼板程式碼將穩健且可攜。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved