ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

windows(剪切板测试程序)(原生api)

windows(剪切板测试程序)(原生api) 剪贴板测试程序// clipboard_test.cpp // 编译MSVC // cl /EHsc /utf-8 clipboard_test.cpp user32.lib // 编译MinGW // g -stdc17 -municode clipboard_test.cpp -o clipboard_test.exe -luser32 #include windows.h #include iostream #include string // UTF-8 - UTF-16 转换剪贴板 API 仍需 UTF-16 std::wstring Utf8ToWide(const std::string s) { if (s.empty()) return std::wstring(); int needed MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0); std::wstring out(needed, 0); MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), out[0], needed); return out; } std::string WideToUtf8(const std::wstring s) { if (s.empty()) return std::string(); int needed WideCharToMultiByte(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0, nullptr, nullptr); std::string out(needed, 0); WideCharToMultiByte(CP_UTF8, 0, s.c_str(), (int)s.size(), out[0], needed, nullptr, nullptr); return out; } // 写剪贴板输入为 UTF-8 bool SetClipboardText(const std::string text) { if (!OpenClipboard(nullptr)) { std::cout [错误] OpenClipboard 失败, err GetLastError() std::endl; return false; } std::cout [信息] OpenClipboard 成功 std::endl; if (!EmptyClipboard()) { std::cout [错误] EmptyClipboard 失败, err GetLastError() std::endl; CloseClipboard(); return false; } std::cout [信息] EmptyClipboard 成功 std::endl; // 转成 UTF-16 后再放进剪贴板 std::wstring wide Utf8ToWide(text); const size_t bytes (wide.size() 1) * sizeof(wchar_t); HGLOBAL hMem GlobalAlloc(GMEM_MOVEABLE, bytes); if (!hMem) { std::cout [错误] GlobalAlloc 失败, err GetLastError() std::endl; CloseClipboard(); return false; } void* p GlobalLock(hMem); if (!p) { std::cout [错误] GlobalLock 失败 std::endl; GlobalFree(hMem); CloseClipboard(); return false; } memcpy(p, wide.c_str(), bytes); GlobalUnlock(hMem); // 注意SetClipboardData 返回 HANDLE不是 BOOL HANDLE result SetClipboardData(CF_UNICODETEXT, hMem); if (result nullptr) { std::cout [错误] SetClipboardData 失败, err GetLastError() std::endl; GlobalFree(hMem); // 失败时自己释放 CloseClipboard(); return false; } // 成功后 hMem 所有权归系统不要再 GlobalFree std::cout [信息] SetClipboardData 成功 std::endl; CloseClipboard(); std::cout [信息] CloseClipboard 完成 std::endl; return true; } // 读剪贴板输出为 UTF-8 std::string GetClipboardText() { std::string result; if (!OpenClipboard(nullptr)) { std::cout [错误] 读: OpenClipboard 失败, err GetLastError() std::endl; return result; } if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) { std::cout [信息] 读: 没有 CF_UNICODETEXT 格式 std::endl; CloseClipboard(); return result; } HANDLE hData GetClipboardData(CF_UNICODETEXT); if (!hData) { std::cout [错误] 读: GetClipboardData 失败, err GetLastError() std::endl; CloseClipboard(); return result; } wchar_t* p static_castwchar_t*(GlobalLock(hData)); if (p) { std::wstring wide(p); result WideToUtf8(wide); GlobalUnlock(hData); } CloseClipboard(); return result; } int main() { // 控制台代码页切到 UTF-8配合 UTF-8 源文件和 std::cout SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); std::cout 剪贴板测试程序 std::endl; // 1. 写入 std::cout \n[步骤 1] 写入剪贴板... std::endl; if (!SetClipboardText(clipboard_test_2024)) { std::cout 写入失败程序结束 std::endl; std::cout 按回车退出...; std::cin.get(); return 1; } // 2. 立即回读 std::cout \n[步骤 2] 立即回读... std::endl; std::string readBack GetClipboardText(); std::cout 回读内容: [ readBack ] std::endl; // 3. 提示用户去记事本粘贴 std::cout \n[步骤 3] 现在打开记事本按 CtrlV 粘贴。 std::endl; std::cout 如果粘不出来说明系统层面拒绝了这个写入。 std::endl; std::cout 粘完后按回车退出... std::endl; std::cin.get(); // 4. 退出前再读一次看是否被别的程序改写 std::cout \n[步骤 4] 退出前再读一次... std::endl; readBack GetClipboardText(); std::cout 回读内容: [ readBack ] std::endl; std::cout \n按回车退出...; std::cin.get(); return 0; }说一下写剪切板函数和读剪切板函数都分别干了什么是什么样的逻辑链路写剪贴板函数SetClipboardText逻辑链路打开 → 清空 → 分配内存 → 锁定 → 拷贝 → 解锁 → 交给系统 → 关闭步骤API 调用作用失败处理1OpenClipboard(nullptr)取得剪贴板独占权。Windows 规定同一时刻只有一个进程能打开剪贴板返回 false函数退出2EmptyClipboard()清空原内容并释放旧内存让新数据干净进入CloseClipboard 返回 false3Utf8ToWide(text)UTF-8 → UTF-16。因为CF_UNICODETEXT只认 UTF-16—4GlobalAlloc(GMEM_MOVEABLE, bytes)申请一块可移动的全局堆内存。GMEM_MOVEABLE表示系统可以重定位这块内存剪贴板数据必须用这种类型CloseClipboard 返回 false5GlobalLock(hMem)锁定内存拿到指针。锁定期间内存不会被系统移动可以安全写入GlobalFreeCloseClipboard 返回 false6memcpy(p, wide.c_str(), bytes)把 UTF-16 字符串含结尾\0拷进全局堆—7GlobalUnlock(hMem)解锁。注意这之后p指针失效但数据已经在堆里—8SetClipboardData(CF_UNICODETEXT, hMem)关键一环把这块内存的所有权转移给系统。从此hMem不能再用GlobalFree释放失败时自己GlobalFree释放并CloseClipboard9CloseClipboard()关闭剪贴板让其他进程可以访问。注意必须先SetClipboardData再CloseClipboard否则数据进不去—读剪贴板函数GetClipboardText逻辑链路打开 → 检查格式 → 借数据 → 锁定 → 拷贝出来 → 解锁 → 关闭 → 转码步骤API 调用作用失败处理1OpenClipboard(nullptr)打开剪贴板只读访问也必须打开返回空字符串2IsClipboardFormatAvailable(CF_UNICODETEXT)检查剪贴板里有没有UTF-16 文本格式剪贴板可能只存图片、文件等CloseClipboard 返回空3GetClipboardData(CF_UNICODETEXT)借一块系统的内存句柄。注意这块内存所有权还是系统的我们只是借来读绝不能 freeCloseClipboard 返回空4GlobalLock(hData)锁定拿到指针。读到的是 UTF-16 字节流按wchar_t*解释—5std::wstring wide(p)关键一环把系统内存里的字符串拷贝到自己拥有的 wstring。从此以后不依赖系统内存—6GlobalUnlock(hData)解锁借来的句柄只是减引用不释放内存—7CloseClipboard()关闭剪贴板。关键必须在GlobalUnlock之后但尽量早地关闭缩短占用时间否则别的程序粘不出来—8WideToUtf8(wide)UTF-16 → UTF-8返回给调用方—
返回列表