在 VC++/MFC 中操作剪貼板其實相當簡單。本文系統介紹六大核心場景:文本、WMF 圖元文件、位圖、自定義格式、剪貼板變更監聽、自動粘貼到他應用窗口。
CString source = _T("要複製的文本內容");
if (OpenClipboard()) {
EmptyClipboard();
HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (source.GetLength() + 1) * sizeof(TCHAR));
LPTSTR pBuf = (LPTSTR)GlobalLock(hGlob);
_tcscpy_s(pBuf, source.GetLength() + 1, source);
GlobalUnlock(hGlob);
SetClipboardData(CF_UNICODETEXT, hGlob); // Unicode 版本
CloseClipboard();
}
關鍵點: 必須使用 GMEM_MOVEABLE | GMEM_DDESHARE 分配可移動共享內存;Unicode 程序用 CF_UNICODETEXT,ANSI 程序用 CF_TEXT。
CString fromClipboard;
if (OpenClipboard()) {
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData) {
LPTSTR pBuf = (LPTSTR)GlobalLock(hData);
fromClipboard = pBuf;
GlobalUnlock(hData);
}
CloseClipboard();
}
if (OpenClipboard()) {
EmptyClipboard();
CMetaFileDC* pDC = new CMetaFileDC();
pDC->CreateEnhanced(NULL, NULL, NULL, _T("MetaFile Description"));
// 在 pDC 上繪圖...
HENHMETAFILE hEMF = pDC->CloseEnhanced();
SetClipboardData(CF_ENHMETAFILE, hEMF);
CloseClipboard();
delete pDC;
}
if (OpenClipboard()) {
HENHMETAFILE hEMF = (HENHMETAFILE)GetClipboardData(CF_ENHMETAFILE);
if (hEMF) {
CClientDC dc(this);
CRect rect(0, 0, 200, 200);
dc.PlayMetaFile(hEMF, rect);
}
CloseClipboard();
}
if (OpenClipboard()) {
EmptyClipboard();
CBitmap bmp;
CClientDC screenDC(this);
CDC memDC;
memDC.CreateCompatibleDC(&screenDC);
CRect rect(0, 0, 200, 200);
bmp.CreateCompatibleBitmap(&screenDC, rect.Width(), rect.Height());
CBitmap* pOldBmp = memDC.SelectObject(&bmp);
// 在 memDC 上繪圖...
memDC.SelectObject(pOldBmp);
SetClipboardData(CF_BITMAP, bmp.Detach()); // 傳遞 HBITMAP 所有權
CloseClipboard();
}
if (OpenClipboard()) {
HBITMAP hBmp = (HBITMAP)GetClipboardData(CF_BITMAP);
if (hBmp) {
CBitmap bmp;
bmp.Attach(hBmp); // 不獲取所有權,僅包裝
CClientDC dc(this);
CDC memDC;
memDC.CreateCompatibleDC(&dc);
CBitmap* pOld = memDC.SelectObject(&bmp);
BITMAP bmInfo;
bmp.GetBitmap(&bmInfo);
dc.BitBlt(0, 0, bmInfo.bmWidth, bmInfo.bmHeight, &memDC, 0, 0, SRCCOPY);
memDC.SelectObject(pOld);
bmp.Detach(); // 釋放包裝,不刪除對象
}
CloseClipboard();
}
使用 RegisterClipboardFormat 註冊唯一格式名,實現任意結構體數據的跨進程傳遞。
struct MyFormatData {
long val1;
int val2;
};
// 寫入
UINT uFmt = RegisterClipboardFormat(_T("MY_CUSTOM_FORMAT"));
if (OpenClipboard()) {
EmptyClipboard();
MyFormatData data = { 100, 200 };
HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(MyFormatData));
MyFormatData* pBuf = (MyFormatData*)GlobalLock(hGlob);
*pBuf = data;
GlobalUnlock(hGlob);
SetClipboardData(uFmt, hGlob);
CloseClipboard();
}
// 讀取
if (OpenClipboard()) {
HANDLE hData = GetClipboardData(uFmt);
if (hData) {
MyFormatData* pBuf = (MyFormatData*)GlobalLock(hData);
MyFormatData data = *pBuf;
GlobalUnlock(hData);
// 使用 data...
}
CloseClipboard();
}
通過設置剪貼板查看器鏈,接收 WM_DRAWCLIPBOARD 消息:
// 初始化時調用
SetClipboardViewer(); // 將當前窗口加入查看器鏈
// 消息映射
ON_MESSAGE(WM_DRAWCLIPBOARD, OnClipChange)
// 處理函數
afx_msg LRESULT OnClipChange(WPARAM, LPARAM) {
CTime time = CTime::GetCurrentTime();
SetDlgItemText(IDC_CHANGED_DATE, time.Format(_T("%a, %b %d, %Y -- %H:%M:%S")));
DisplayClipboardText(); // 自定義顯示函數
return 0;
}
// 退出時調用 ChangeClipboardChain 移除鏈節點
獲取目標窗口句柄後發送粘貼消息:
SendMessage(hTargetWnd, WM_PASTE, 0, 0);
前提是目標窗口已獲得焦點並處理 WM_PASTE 消息。