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

位圖複製到剪貼板:CF_BITMAP、CF_DIB、CF_PALETTE 三種格式完整實作

     編輯:關於C語言

核心原則

剪貼板資料格式標準化:**提供方呼叫 OpenClipboard → EmptyClipboard → SetClipboardData (可多次,不同格式) → CloseClipboard**。設定後 GDI 物件所有權移交剪貼板,**必須 Detach 避免雙重釋放**。

函式一:複製裝置相關位圖 (DDB) — CF_BITMAP


void CopyBitmapToClipboard(const CWnd* pWnd, CBitmap& bitmap, CPalette* pPal = NULL) {
    if (!::OpenClipboard(pWnd->GetSafeHwnd())) return;
    ::EmptyClipboard();

    if (pPal) {
        ::SetClipboardData(CF_PALETTE, pPal->GetSafeHandle());
        pPal->Detach(); // 所有權移交
    }
    ::SetClipboardData(CF_BITMAP, bitmap.GetSafeHandle());
    bitmap.Detach(); // 關鍵!

    ::CloseClipboard();
}
  • 適用:已有 CBitmap (資源載入、螢幕截圖 CreateCompatibleBitmap)。
  • 缺點:DDB 依賴顯示裝置,貼上到不同色深/解析度環境可能色彩失真。

函式二:複製裝置無關位圖 (DIB) — CF_DIB


void CopyDIBToClipboard(const CWnd* pWnd, HGLOBAL hDIB, CPalette* pPal = NULL) {
    if (!::OpenClipboard(pWnd->GetSafeHwnd())) return;
    ::EmptyClipboard();

    if (pPal) {
        ::SetClipboardData(CF_PALETTE, pPal->GetSafeHandle());
        pPal->Detach();
    }
    ::SetClipboardData(CF_DIB, hDIB); // hDIB 包含 BITMAPINFOHEADER + 像素資料
    // 注意:此處原文有誤 bitmap.Detach(),應為 hDIB 由 GlobalAlloc 配置,剪貼板接管釋放
    // 正確做法:hDIB 為 GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE) 配置,SetClipboardData 後不再手動釋放

    ::CloseClipboard();
}

DIB 記憶體區塊結構:


// 配置
DWORD dwSize = sizeof(BITMAPINFOHEADER) + nPaletteSize + dwImageSize;
HGLOBAL hDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dwSize);
LPVOID pData = GlobalLock(hDIB);
BITMAPINFOHEADER* pBmi = (BITMAPINFOHEADER*)pData;
// 填充 pBmi...
// 複製像素資料至 pData + sizeof(BITMAPINFOHEADER) + nPaletteSize
GlobalUnlock(hDIB);
  • 優點:裝置無關,攜帶完整色彩資訊 (調色盤/位欄位遮罩),跨應用程式/機器貼上保真。
  • 標準格式:CF_DIB (舊)、CF_DIBV5 (新,含色域/ICC 設定檔)。

函式三:複製視窗畫面到剪貼板 (螢幕截圖)


void CopyWndToClipboard(CWnd* pWnd) {
    CBitmap bitmap;
    CClientDC dc(pWnd);
    CDC memDC; memDC.CreateCompatibleDC(&dc);

    CRect rect; pWnd->GetClientRect(&rect);
    bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
    CBitmap* pOldBmp = memDC.SelectObject(&bitmap);
    memDC.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, 0, 0, SRCCOPY);
    memDC.SelectObject(pOldBmp);

    CopyBitmapToClipboard(pWnd, bitmap); // 復用函式一
}

關鍵細節與避坑

問題說明解決
忘記 DetachCBitmap 解構時 DeleteObject,剪貼板持有無效控制代碼 → 貼上失敗/當機SetClipboardData 後立即 Detach()
DIB 記憶體旗標錯誤未用 GMEM_DDESHARE 或 GMEM_MOVEABLE,剪貼板無法跨行程存取GlobalAlloc 必須包含 GMEM_MOVEABLE | GMEM_DDESHARE
調色盤未提供8-bit 位圖貼上到 24-bit 環境顏色錯誤同時 SetClipboardData(CF_PALETTE, ...)
大位圖配置失敗GlobalAlloc 失敗返回 NULL檢查返回值,考慮分塊或用檔案映射
非主執行緒操作剪貼板OpenClipboard 失敗必須在 UI 執行緒呼叫,或用 OleSetClipboard (OLE 資料物件)

現代替代:OLE 資料物件 (COleDataSource)


void CopyBitmapOLE(const CWnd* pWnd, CBitmap& bitmap) {
    COleDataSource* pDataSrc = new COleDataSource;
    // 封裝位圖為 CF_BITMAP/CF_DIB 格式
    // 需自行實作 IDataObject::GetData 或用現成封裝
    pDataSrc->SetClipboard(); // 非同步,支援延遲渲染
}

優點:支援延遲渲染 (使用者貼上時才生成資料)、多格式並存、拖放支援、非 UI 執行緒安全。

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