将 unicode 字符串复制到剪贴板不起作用

Copy unicode string to clipboard isn't working

我不知道为什么这段代码不能正常工作:

#define UNICODE

#include <iostream>
#include <sstream>
#include <windows.h>

void main(void)
{
    wchar_t* strData = L"CreateWindowExA";

    MessageBox(NULL, strData, L"Warning", MB_OK);

    if (OpenClipboard(0)) {
        EmptyClipboard();
        HGLOBAL hClipboardData;
        hClipboardData = GlobalAlloc(GMEM_DDESHARE,
                                     wcslen(strData) + 1);
        char* pchData;
        pchData = (char*)GlobalLock(hClipboardData);
        strcpy(pchData, LPCSTR(strData));
        GlobalUnlock(hClipboardData);
        SetClipboardData(CF_TEXT, hClipboardData);
        CloseClipboard();
    }

    MessageBox(NULL, L"Copied to Clipboard", L"Title", MB_OK);
}
strcpy(pchData, LPCSTR(strData));  

不是 UTF16 数据的好选择。

使用 wcscpy 并移除演员表。

更改此部分:

hClipboardData = GlobalAlloc(GMEM_DDESHARE, sizeof(WCHAR) * (wcslen(strData) + 1));

WCHAR* pchData;
pchData = (WCHAR*)GlobalLock(hClipboardData);
wcscpy(pchData, strData);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_UNICODETEXT, hClipboardData);

WCHAR 分配 2* 字节数。使用 WCHAR 而不是 char。使用 wcscpy 而不是 strcpy。使用 CF_UNICODETEXT.

而不是 CF_TEXT

您需要应用以下更改来修复您的代码:

if (OpenClipboard(0)) {

您需要提供有效的 window 句柄,才能获得剪贴板的所有权。需要所有权,以便您可以更改剪贴板的内容。

    HGLOBAL hClipboardData;
    hClipboardData = GlobalAlloc(GMEM_DDESHARE,
                                 wcslen(strData) + 1);

有 2 个错误需要修复。正如使用 GMEM_MOVEABLE 标志的 Memory and the Clipboard, when placing an object into the clipboard, memory should be allocated by using the GlobalAlloc 函数中所解释的那样。另一方面,GMEM_DDESHARE 被忽略,并且在不传递任何标志的情况下调用默认使用 GMEM_FIXED。这将 return 一个内存指针,并将其传递给 GlobalLock 随后将失败。

其次,此 API 调用需要 字节 的大小。 Windows中的一个Unicode编码单元是2个字节。你需要 (wcslen(strData) + 1) * sizeof(wchar_t).

    char* pchData;
    pchData = (char*)GlobalLock(hClipboardData);
    strcpy(pchData, LPCSTR(strData));

strcpy 复制单字节单元,直到第一个 NUL 字符。使用 UTF-16LE 编码(在 Windows 中使用),您正在复制单个字符。您应该改用 wcscpy,并将目标转换为 wchar_t*:

    wchar_t* pchData;
    pchData = (wchar_t*)GlobalLock(hClipboardData);
    wcscpy(pchData, strData);

    SetClipboardData(CF_TEXT, hClipboardData);

由于您复制了 UTF-16LE 编码的文本,因此剪贴板格式应为 CF_UNICODETEXT


参考文献:

我在 C++ MFC 中尝试了@Joseph Willcoxson 的回答,感谢您的代码,我发现第一次调用剪贴板功能时有效。但是当第二次调用时,它会抛出没有特定错误消息的奇怪异常。经过一番查找和测试,我发现 wcscpy 会出现编译错误 C4996 : function may be unsafe. Consider using wcscpy_s instead.

而且我发现wcscpy_s用法,修改为使用wcscpy_s,另外注释掉GlobalFree()使剪贴板功能可以多次成功调用不报错:

void toClipboardWStr(const wchar_t* strData) {
    if (OpenClipboard(0)) {
        EmptyClipboard();
        int size_m = sizeof(WCHAR) * (wcslen(strData) + 1);
        HGLOBAL hClipboardData = GlobalAlloc(GMEM_DDESHARE, size_m);
        WCHAR* pchData;
        pchData = (WCHAR*)GlobalLock(hClipboardData);
        //wcscpy(pchData, strData);
        wcscpy_s(pchData, size_m / sizeof(wchar_t), strData);
        GlobalUnlock(hClipboardData);
        SetClipboardData(CF_UNICODETEXT, hClipboardData);
        CloseClipboard();
        // if you need to call this function multiple times, I test no need to GlobalFree, or will occur error
        //GlobalFree(hClipboardData);
    }
}