Win32 剪貼板操作遵循「開啟→清空/讀取→關閉」流程,資料透過 HGLOBAL 可移動記憶體區塊傳遞。本文詳細實作 Unicode 文字複製與貼上,解析記憶體鎖定/解鎖機制。
// 複製到剪貼板
OpenClipboard(hWnd);
EmptyClipboard();
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, size);
LPVOID pData = GlobalLock(hGlobal);
memcpy(pData, source, size);
GlobalUnlock(hGlobal);
SetClipboardData(CF_UNICODETEXT, hGlobal); // 所有權轉移給系統
CloseClipboard();
// 從剪貼板貼上
OpenClipboard(hWnd);
if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
HGLOBAL hGlobal = GetClipboardData(CF_UNICODETEXT);
LPVOID pData = GlobalLock(hGlobal);
// 使用 pData...
GlobalUnlock(hGlobal);
}
CloseClipboard();
GlobalLock 返回當前實際位址,使用前必須鎖定,用畢解鎖。GMEM_FIXED,GlobalLock 直接返回固定位址,但系統無法移動,SetClipboardData 會失敗。SetClipboardData 成功後,**記憶體所有權歸系統**,呼叫端不得釋放或寫入。CloseClipboard 前必須 GlobalUnlock,否則系統無法存取。EmptyClipboard、進程結束)釋放記憶體。| 格式常數 | 資料類型 | 編碼 | 優先序 |
|---|---|---|---|
CF_UNICODETEXT | Unicode 文字 | UTF-16LE | 最高(現代首選) |
CF_TEXT | ANSI 文字 | 系統代碼頁 | 相容舊版 |
CF_HTML | HTML 片段 | UTF-8/UTF-16 | 富文本 |
CF_RTF | RTF 文件 | ASCII | 富文本 |
CF_HDROP | 檔案路徑清單 | - | 拖放檔案 |
case IDC_BTN_COPY: {
HWND hEditSrc = GetDlgItem(hDlg, IDC_EDIT_SRC);
int len = GetWindowTextLength(hEditSrc);
std::wstring text(len + 1, L'\0');
GetWindowText(hEditSrc, &text[0], len + 1);
OpenClipboard(hDlg);
EmptyClipboard();
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, (text.size()) * sizeof(wchar_t));
wchar_t* pDst = (wchar_t*)GlobalLock(hGlobal);
wcscpy(pDst, text.c_str());
GlobalUnlock(hGlobal);
SetClipboardData(CF_UNICODETEXT, hGlobal);
CloseClipboard();
break;
}
case IDC_BTN_PASTE: {
HWND hEditDst = GetDlgItem(hDlg, IDC_EDIT_DST);
OpenClipboard(hDlg);
if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
HGLOBAL hGlobal = GetClipboardData(CF_UNICODETEXT);
wchar_t* pSrc = (wchar_t*)GlobalLock(hGlobal);
if (pSrc) SetWindowText(hEditDst, pSrc);
GlobalUnlock(hGlobal);
}
CloseClipboard();
break;
}

Windows::ApplicationModel::DataTransfer::Clipboard 非同步、支援多格式。System.Windows.Forms.Clipboard / System.Windows.Clipboard 封裝完整。OleSetClipboard/OleGetClipboard 支援 COM 物件、資料物件、延遲渲染。GlobalUnlock → 系統無法讀取、資源洩漏。SetClipboardData 後又 GlobalFree → 雙重釋放崩潰。IsClipboardFormatAvailable 直接 GetClipboardData → 返回 NULL 導致崩潰。CF_TEXT (ANSI) 與 Unicode 字串 → 亂碼。OpenClipboard 失敗 → 需重試機制。