剪貼板不只是純文字或圖片的暫存區。現代應用程式 (Word、Excel、瀏覽器、設計軟體) 會將資料以多種格式同時放入剪貼板:標準格式 (CF_TEXT, CF_BITMAP, CF_HDROP 等) 與自訂格式 (如 Excel 的 XML Spreadsheet、RTF 的 Rich Text Format)。開發「貼上」功能時,必須先偵測剪貼板內容,才能決定啟用哪些貼上選項、或進行格式轉換。
Windows 提供 EnumClipboardFormats 迭代剪貼板所有格式:
UINT EnumClipboardFormats(UINT format);
0,取得第一個格式 ID。0 表示列舉結束或錯誤 (需配合 GetLastError 判斷)。系統預定義格式值範圍通常在 1..17 (視 OS 版本),常見者:
| 常數 | 值 | 說明 |
|---|---|---|
| CF_TEXT | 1 | ANSI 文字 |
| CF_BITMAP | 2 | 位圖控制代碼 |
| CF_METAFILEPICT | 3 | 中繼檔圖片 |
| CF_DIB | 8 | 裝置無關位圖 (DIB) |
| CF_UNICODETEXT | 13 | Unicode 文字 (WinNT+) |
| CF_HDROP | 15 | 拖放檔案清單 |
| CF_LOCALE | 16 | 地區設定識別碼 |
格式 ID > CF_MAX (通常 17) 即為應用程式向系統註冊的自訂格式 (RegisterClipboardFormat)。需呼叫 GetClipboardFormatName 取得其字串名稱。
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ListBox1->Clear();
if (!OpenClipboard(Handle)) return; // 開啟剪貼板,傳入視窗句柄建立擁有權
try
{
UINT fmt = EnumClipboardFormats(0);
while (fmt != 0)
{
AnsiString name;
if (fmt < 18) // 標準格式範圍 (視實際 CF_MAX 調整)
name = StandardFormatName(fmt); // 查表函式
else
name = GetCustomFormatName(fmt); // 呼叫 GetClipboardFormatName
ListBox1->Items->Add(Format("%u: %s", ARRAYOFCONST((fmt, name))));
fmt = EnumClipboardFormats(fmt); // 取下一個
}
}
__finally
{
CloseClipboard(); // 必須在 finally 區塊釋放,避免例外導致剪貼板鎖死
}
}
// 查表標準格式名稱
AnsiString StandardFormatName(UINT fmt) {
static const char* names[] = {
"CF_TEXT", "CF_BITMAP", "CF_METAFILEPICT", "CF_SYLK", "CF_DIF",
"CF_TIFF", "CF_OEMTEXT", "CF_DIB", "CF_PALETTE", "CF_PENDATA",
"CF_RIFF", "CF_WAVE", "CF_UNICODETEXT", "CF_ENHMETAFILE",
"CF_HDROP", "CF_LOCALE", "CF_MAX"
};
if (fmt >= 1 && fmt <= 17) return names[fmt - 1];
return "UNKNOWN_STD";
}
// 取得自訂格式名稱
AnsiString GetCustomFormatName(UINT fmt) {
char buf[256];
if (GetClipboardFormatName(fmt, buf, sizeof(buf)))
return buf;
return "-----None------";
}
Rich Text Format、HTML Format 等自訂格式。CF_HDROP (15) 及 Shell IDList Array 等格式。XML Spreadsheet、CSV 等專屬格式。OpenClipboard 失敗時 (回傳 FALSE) 通常是其他程式正在存取,應重試或放棄,切勿強制等待導致 UI 凍結。try/__finally 確保 CloseClipboard 被呼叫,否則系統剪貼板會被永久鎖定,需重啟 explorer.exe 或登出才能恢復。RegisterClipboardFormat 或列舉時取得名稱比對。GetClipboardData 取得大量資料 (如高解析度圖片),需考慮非同步處理或進度提示。結合本技術,可打造類似 Office 的「選擇性貼上」對話框:
if (HasFormat(CF_HDROP)) EnableMenuItem(pasteFiles);
if (HasFormat(CF_UNICODETEXT)) EnableMenuItem(pasteText);
if (HasFormat("HTML Format")) EnableMenuItem(pasteHtml);
if (HasFormat("Rich Text Format")) EnableMenuItem(pasteRtf);
// ...
甚至可依優先順序自動選擇最佳格式貼上 (如優先 HTML > RTF > Unicode Text > ANSI Text)。