将unicode字符串复制到剪贴板是不行的

时间:2016-11-17 20:58:44

标签: c++ winapi unicode clipboard ollydbg

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

#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);
}

4 个答案:

答案 0 :(得分:4)

更改此部分:

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

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

2*分配WCHAR个字节数。而不是char,请使用WCHAR。而不是strcpy,请使用wcscpy。而不是CF_TEXT,请使用CF_UNICODETEXT

答案 1 :(得分:4)

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

if (OpenClipboard(0)) {

您需要提供有效的窗口句柄,以取得剪贴板的所有权。所有权是必需的,因此您可以更改剪贴板的内容。

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

有2个错误,需要修复。如Memory and the Clipboard中所述,将对象放入剪贴板时,应使用带有 GMEM_MOVEABLE 标志的GlobalAlloc函数分配内存。另一方面, GMEM_DDESHARE 会被忽略,如果没有传递任何标记,则调用默认使用 GMEM_FIXED 。这将返回一个内存指针,并将其传递给GlobalLock将随后失败。

其次,此API调用需要 bytes 中的大小。 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

<小时/> 参考文献:

答案 2 :(得分:1)

strcpy(pchData, LPCSTR(strData));  

不是UTF16数据的好选择。

使用wcscpy并移除演员。

答案 3 :(得分:0)

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

我发现wcscpy_s用法HERE,修改为使用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);
    }
}