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);
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 of CF_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;
}
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, ...)