基于WINAPI与C语言实现剪贴板数据的读取与恢复
Great question! Working with the Windows clipboard can feel a bit counterintuitive at first, especially when dealing with unknown data types. Let's break this down into two key parts: finding a universal approach for data types, and properly saving/restoring clipboard content.
1. Universal Data Types & Flexible Format Handling
For most everyday use cases (like copying text from documents, websites, or apps), CF_UNICODETEXT is the most universal data type. It supports full Unicode characters, so it works with nearly all text-based content you'll encounter. If you need to support legacy systems that use ANSI encoding, CF_TEXT is an option—but CF_UNICODETEXT is the modern, preferred choice.
If you need to handle any clipboard content (not just text—like images, file paths, or custom app-specific formats), there's no single "one-size-fits-all" data type. Instead, you can enumerate all available formats in the clipboard and prioritize the ones you want to save. Use the EnumClipboardFormats() function to loop through every format currently present, then pick the highest-priority format (e.g., check for CF_UNICODETEXT first, then CF_BITMAP, then CF_HDROP for files).
2. Saving and Restoring Clipboard Content
A critical thing to remember: you can't just save the pointer returned by GetClipboardData()—once you close the clipboard, that pointer becomes invalid. You must copy the data into your own memory buffer to preserve it.
Step 1: Save Clipboard Data (Example with CF_UNICODETEXT)
Here's a C++ example that saves text from the clipboard:
#include <windows.h> #include <wchar.h> // Global variables to store saved clipboard data (adjust scope as needed) wchar_t* savedClipboardText = nullptr; size_t savedTextLength = 0; void SaveClipboardText() { // Open the clipboard (NULL means our process owns it temporarily) if (!OpenClipboard(NULL)) { return; } // Get the text data handle from the clipboard HANDLE hClipData = GetClipboardData(CF_UNICODETEXT); if (hClipData == nullptr) { CloseClipboard(); return; } // Lock the global memory to access the data wchar_t* pClipText = static_cast<wchar_t*>(GlobalLock(hClipData)); if (pClipText == nullptr) { CloseClipboard(); return; } // Copy the text to our own buffer savedTextLength = wcslen(pClipText) + 1; // Include null terminator savedClipboardText = new wchar_t[savedTextLength]; wcscpy_s(savedClipboardText, savedTextLength, pClipText); // Cleanup: unlock memory and close clipboard GlobalUnlock(hClipData); CloseClipboard(); }
Step 2: Restore Clipboard Data
To put the saved data back into the clipboard, follow this flow:
void RestoreClipboardText() { if (savedClipboardText == nullptr) { return; } if (!OpenClipboard(NULL)) { return; } // Clear existing clipboard content first EmptyClipboard(); // Allocate shared global memory (required for clipboard access) HANDLE hNewClipData = GlobalAlloc(GHND | GMEM_SHARE, savedTextLength * sizeof(wchar_t)); if (hNewClipData == nullptr) { CloseClipboard(); return; } // Lock the memory and copy our saved text into it wchar_t* pNewClipText = static_cast<wchar_t*>(GlobalLock(hNewClipData)); if (pNewClipText != nullptr) { wcscpy_s(pNewClipText, savedTextLength, savedClipboardText); GlobalUnlock(hNewClipData); // Pass the memory handle to the clipboard (system manages it now) SetClipboardData(CF_UNICODETEXT, hNewClipData); } else { // Cleanup if allocation failed GlobalFree(hNewClipData); } CloseClipboard(); } // Don't forget to free your saved memory when done! void CleanupSavedClipboardData() { delete[] savedClipboardText; savedClipboardText = nullptr; }
Key Notes for All Data Types
- Always pair
OpenClipboard()withCloseClipboard()—failing to close the clipboard blocks other apps from accessing it. - When allocating memory for
SetClipboardData(), useGMEM_SHARE(orGHND | GMEM_SHARE). The clipboard requires shared memory so other processes can access the data. - For non-text formats (like images), the flow is identical: get the data handle, lock it, copy the raw bytes to your buffer, then restore by allocating shared memory, copying bytes, and calling
SetClipboardData()with the correct format ID.
内容的提问来源于stack exchange,提问作者Omer Friedlander

