问题
Tell me please, why I get this issues:
if clipboard contains unicode chars (e.q. russian) I get only first selected word. First word before "space" character.
if clipboard not contains unicode chars (english only) I get first character of the selected text.
Get selected text:
CStringA getClipboard()
{
CStringA strData;
if (OpenClipboard(NULL)){
HANDLE hClipboardData = GetClipboardData(CF_UNICODETEXT);
char *pchData = (char*)GlobalLock(hClipboardData);
strData = pchData;
GlobalUnlock(hClipboardData);
CloseClipboard();
}
return strData;
}
Set text:
bool setClipboard(CStringA textToclipboard)
{
bool success = true;
if (OpenClipboard(NULL)){
EmptyClipboard();
HGLOBAL hClipboardData;
size_t size = (textToclipboard.GetLength()+1) * sizeof(TCHAR);
hClipboardData = GlobalAlloc(NULL, size);
TCHAR* pchData = (TCHAR*)GlobalLock(hClipboardData);
memcpy(pchData, LPCTSTR(textToclipboard.GetString()), size);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
GlobalUnlock(hClipboardData);
CloseClipboard();
}
return success;
}
Simply get and set clipboard contents.
CStringA str = getClipboard();
setClipboard(str);
回答1:
CF_UNICODETEXT
uses UTF-16. On Windows, wchar_t
data elements are used for UTF-16, but your code is using char
instead. CStringA
is not compatible with UTF-16. You are mismatching the data in both functions, that is why you do not get the results you are expecting.
One solution is to use CStringW
instead of CStringA
:
CStringW getClipboard()
{
CStringW strData;
if (OpenClipboard(NULL))
{
HANDLE hClipboardData = GetClipboardData(CF_UNICODETEXT);
if (hClipboardData)
{
WCHAR *pchData = (WCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
strData = pchData;
GlobalUnlock(hClipboardData);
}
}
CloseClipboard();
}
return strData;
}
bool setClipboard(CStringW textToclipboard)
{
bool success = true;
if (OpenClipboard(NULL))
{
EmptyClipboard();
size_t size = (textToclipboard.GetLength()+1) * sizeof(WCHAR);
HGLOBAL hClipboardData = GlobalAlloc(NULL, size);
if (hClipboardData)
{
WCHAR* pchData = (WCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
memcpy(pchData, (WCHAR*) textToclipboard.GetString(), size);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
}
}
CloseClipboard();
}
return success;
}
If you need to stick with CStringA
, then either:
use
CF_TEXT
instead ofCF_UNICODETEXT
and let the clipboard handle conversions between Ansi and Unicode for you:CStringA getClipboard() { CStringA strData; if (OpenClipboard(NULL)) { HANDLE hClipboardData = GetClipboardData(CF_TEXT); if (hClipboardData) { CHAR *pchData = (CHAR*) GlobalLock(hClipboardData); if (pchData) { strData = pchData; GlobalUnlock(hClipboardData); } } CloseClipboard(); } return strData; } bool setClipboard(CStringA textToclipboard) { bool success = true; if (OpenClipboard(NULL)) { EmptyClipboard(); size_t size = (textToclipboard.GetLength()+1) * sizeof(CHAR); HGLOBAL hClipboardData = GlobalAlloc(NULL, size); if (hClipboardData) { CHAR* pchData = (CHAR*) GlobalLock(hClipboardData); if (pchData) { memcpy(pchData, (CHAR*) textToclipboard.GetString(), size); GlobalUnlock(hClipboardData); SetClipboardData(CF_TEXT, hClipboardData); } } CloseClipboard(); } return success; }
convert to/from UTF-16 manually when using
CF_UNICODETEXT
:CStringA getClipboard() { CStringW strData; if (OpenClipboard(NULL)) { HANDLE hClipboardData = GetClipboardData(CF_UNICODETEXT); if (hClipboardData) { WCHAR *pchData = (WCHAR*) GlobalLock(hClipboardData); if (pchData) { strData = pchData; GlobalUnlock(hClipboardData); } } CloseClipboard(); } return CStringA((WCHAR*)strData.GetString()); } bool setClipboard(CStringA strData) { CStringW textToclipboard((CHAR*)strData.GetString()); bool success = true; if (OpenClipboard(NULL)) { EmptyClipboard(); size_t size = (textToclipboard.GetLength()+1) * sizeof(WCHAR); HGLOBAL hClipboardData = GlobalAlloc(NULL, size); if (hClipboardData) { WCHAR* pchData = (WCHAR*) GlobalLock(hClipboardData); if (pchData) { memcpy(pchData, (WCHAR*) textToclipboard.GetString(), size); GlobalUnlock(hClipboardData); SetClipboardData(CF_UNICODETEXT, hClipboardData); } } CloseClipboard(); } return success; }
Another solution is to use CString
instead of either CStringA
or CStringW
, and then use CF_TEXT
or CF_UNICODETEXT
depending on whether TCHAR
is Ansi or Unicode:
#ifdef UNICODE
#define CF_TEXT_T CF_UNICODETEXT
#else
#define CF_TEXT_T CF_TEXT
#endif
CString getClipboard()
{
CString strData;
if (OpenClipboard(NULL))
{
HANDLE hClipboardData = GetClipboardData(CF_TEXT_T);
if (hClipboardData)
{
TCHAR *pchData = (TCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
strData = pchData;
GlobalUnlock(hClipboardData);
}
}
CloseClipboard();
}
return strData;
}
bool setClipboard(CString textToclipboard)
{
bool success = true;
if (OpenClipboard(NULL))
{
EmptyClipboard();
size_t size = (textToclipboard.GetLength()+1) * sizeof(TCHAR);
HGLOBAL hClipboardData = GlobalAlloc(NULL, size);
if (hClipboardData)
{
TCHAR* pchData = (TCHAR*) GlobalLock(hClipboardData);
if (pchData)
{
memcpy(pchData, (TCHAR*) textToclipboard.GetString(), size);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_TEXT_T, hClipboardData);
}
}
CloseClipboard();
}
return success;
}
回答2:
Both of them are Unicode...
But in Unicode, more that one byte represents a character. For example maybe 2 bytes is used for a character. Therefore:
When it's Russian, the string is like
'\0'
----
0x04 0x3F 0x04 0x40 0x04 0x38 0x04 0x32 0x04 0x35 0x04 0x42 0x00 0x20
~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~
п р и в е т space
It reads until space.
When it's English, the string is like
'\0'
----
0x00 0x48 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F 0x00 0x20
~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~
H e l l o space
It reads nothing. (If you read first, it's because of order of storing bytes, LE or BE)
Note: Maybe I'm not precision in choosing words (Unicode, UTF, ...)
来源:https://stackoverflow.com/questions/15362859/getclipboarddata-cf-unicodetext