125 lines
3.7 KiB
C++
125 lines
3.7 KiB
C++
#include <windows.h>
|
|
#include <string>
|
|
#include <mutex>
|
|
|
|
namespace clip {
|
|
using format = UINT;
|
|
|
|
inline CRITICAL_SECTION& GetClipLock() {
|
|
static CRITICAL_SECTION cs;
|
|
static std::once_flag flag;
|
|
std::call_once(flag, [] { InitializeCriticalSection(&cs); });
|
|
return cs;
|
|
}
|
|
|
|
inline format text_format() {
|
|
return CF_TEXT;
|
|
}
|
|
|
|
inline bool has(format f) {
|
|
return IsClipboardFormatAvailable(f) != FALSE;
|
|
}
|
|
|
|
inline bool set_text(const std::string& value) {
|
|
EnterCriticalSection(&GetClipLock());
|
|
|
|
bool result = false;
|
|
if (OpenClipboard(NULL)) {
|
|
EmptyClipboard();
|
|
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, value.size() + 1);
|
|
if (hMem) {
|
|
char* p = (char*)GlobalLock(hMem);
|
|
if (p) {
|
|
memcpy(p, value.c_str(), value.size() + 1);
|
|
GlobalUnlock(hMem);
|
|
SetClipboardData(CF_TEXT, hMem);
|
|
result = true;
|
|
}
|
|
else {
|
|
GlobalFree(hMem);
|
|
}
|
|
}
|
|
CloseClipboard();
|
|
}
|
|
|
|
LeaveCriticalSection(&GetClipLock());
|
|
return result;
|
|
}
|
|
|
|
inline bool get_text(std::string& value) {
|
|
EnterCriticalSection(&GetClipLock());
|
|
|
|
bool result = false;
|
|
if (OpenClipboard(NULL)) {
|
|
// 优先尝试 Unicode
|
|
HANDLE h = GetClipboardData(CF_UNICODETEXT);
|
|
if (h) {
|
|
const wchar_t* pw = (const wchar_t*)GlobalLock(h);
|
|
if (pw) {
|
|
int len = WideCharToMultiByte(CP_UTF8, 0, pw, -1, NULL, 0, NULL, NULL);
|
|
if (len > 0) {
|
|
value.resize(len - 1);
|
|
WideCharToMultiByte(CP_UTF8, 0, pw, -1, &value[0], len, NULL, NULL);
|
|
}
|
|
GlobalUnlock(h);
|
|
result = true;
|
|
}
|
|
}
|
|
else {
|
|
// 回退 ANSI
|
|
h = GetClipboardData(CF_TEXT);
|
|
if (h) {
|
|
const char* p = (const char*)GlobalLock(h);
|
|
if (p) {
|
|
SIZE_T size = GlobalSize(h);
|
|
value.assign(p, strnlen(p, size));
|
|
GlobalUnlock(h);
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
CloseClipboard();
|
|
}
|
|
|
|
LeaveCriticalSection(&GetClipLock());
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 将 UTF-8 字符串安全地设置到 Windows 剪切板
|
|
*/
|
|
inline bool set_text_utf8(const std::string& utf8_str) {
|
|
if (utf8_str.empty()) return false;
|
|
|
|
// 1. 将 UTF-8 转换为 UTF-16 (因为 Windows 剪切板原生支持 UTF-16)
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8_str.c_str(), -1, NULL, 0);
|
|
if (wlen <= 0) return false;
|
|
|
|
// 2. 分配全局内存
|
|
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, wlen * sizeof(wchar_t));
|
|
if (!hMem) return false;
|
|
|
|
// 3. 执行转换并锁定内存
|
|
wchar_t* pMem = (wchar_t*)GlobalLock(hMem);
|
|
MultiByteToWideChar(CP_UTF8, 0, utf8_str.c_str(), -1, pMem, wlen);
|
|
GlobalUnlock(hMem);
|
|
|
|
// 4. 操作剪切板
|
|
bool success = false;
|
|
if (OpenClipboard(NULL)) {
|
|
EmptyClipboard();
|
|
if (SetClipboardData(CF_UNICODETEXT, hMem)) {
|
|
success = true;
|
|
}
|
|
CloseClipboard();
|
|
}
|
|
|
|
// 如果 SetClipboardData 失败,需要手动释放内存;成功则由系统接管
|
|
if (!success) {
|
|
GlobalFree(hMem);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
} // namespace clip
|