2016-11-17 79 views
-1

我不知道为什么此代码不能正常工作:复制unicode字符串到剪贴板不工作

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

指定'GlobalAlloc'分配的数量的参数分配**字节数**,而不是字符数(在你的情况下是2个字节宽)。你需要弄清楚要分配多少个字节。其次,您不需要将宽字符串转换为ANSI字符串,反之亦然。那('LPCSTR)'演员阵容不会奏效。如果你在代码的其他部分做了类似的事情,那么你不会向我们展示,那么就停止这样做,因为你的程序将注定失败。 – PaulMcKenzie

+1

“SetClipboardData()”的返回值是什么? DId你在下面看到我的评论并链接到API文档?如果您使用NULL窗口句柄,请尝试跳过EmptyClipboard()。 –

+1

你似乎并不被阅[文件]大风扇(https://msdn.microsoft.com/en-us/library/windows/desktop/aa366574.aspx):*“下面的值是过时的,但提供与16位Windows兼容** **忽略**'GMEM_DDESHARE' [*]“*。此外,在你的代码中几乎没有错误检查。为什么我们必须猜测,哪个API调用失败?应仅在可移动内存上调用'GlobalLock'(当您请求固定内存时)。它用于将句柄转换为指针,但您已将其传递给有效的内存指针。不好。 – IInspectable

回答

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的字节数。 WCHAR代替char。而不是strcpy,wcscpy。而不是CF_TEXT,CF_UNICODETEXT。

+1

来自文档:如果应用程序调用OpenLipboard并将hwnd设置为NULL,** EmptyClipboard将剪贴板所有者设置为NULL;这会导致SetClipboardData失败。** https://msdn.microsoft.com/en-us/library/windows/desktop/ms649048(v=vs.85).aspx –

+1

IOW,请勿调用EmptyClipboard( )'。或者,如果你这样做,用有效的HWND调用'OpenClipboard()'。 –

+1

我会使用'sizeof(wchar_t)'(或与您的答案'sizeof(WCHAR)')一致,而不是魔术常量'2',但这只是一种风格。 –

1
strcpy(pchData, LPCSTR(strData)); 

不是UTF16数据一个不错的选择。

使用wcscpy,取下石膏。

+0

@BPL因为缺少记忆,就像其他答复者告诉你的那样(先没有看到它)。但是,你也需要这个。 – deviantfan

3

您需要采用以下修改,来解决你的代码:

if (OpenClipboard(0)) { 

您需要提供一个有效的窗口句柄,把剪贴板的所有权。所有权是必需的,以便您可以更改剪贴板的内容。

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

有2个错误,需要修复。作为Memory and the Clipboard下所解释的,将对象放置到剪贴板时,存储器应当通过使用GlobalAlloc功能与GMEM_MOVEABLE标志分配。 GMEM_DDESHARE,在另一方面,被忽略,并且不经过任何标志调用默认使用GMEM_FIXED。这将返回一个内存指针,并将其传递给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


参考文献: