Windows 剪贴板不会保留 ASCII 字符

Windows Clipboard won't preserve ASCII character

我正在为 TS3 客户端编写一个插件,但我 运行 遇到了问题...

其中一个频道名称中有一个特殊符号(╠),这是扩展ascii的特殊字符table我认为。

在 teamspeak 中记录它时,该字符显示正常,但当尝试使用其 C 接口将其复制到 windows 剪贴板时,它 returns 完全不同的字符 (â)。

在得知扩展 ascii table 使用的字节数比常规字符多后,我曾尝试将其转换为 WCHAR,但这也不起作用。

我使用以下代码将 char* 复制到我在某处找到的剪贴板,并用我发现的使用 WCHAR 的其他代码进行了修改:

void SaveClipboard(char* tx)
{
    WCHAR text[140];
    swprintf(text, 140, L"%hs", tx);

    if(OpenClipboard(NULL))
    {
        EmptyClipboard();
        HGLOBAL global = GlobalAlloc(GMEM_DDESHARE, 2 * (wcslen(text) + 1)); //text size + [=11=] character

        WCHAR* pchData;
        pchData = (WCHAR*)GlobalLock(global);
        wcscpy(pchData, text);
        GlobalUnlock(pchData);

        SetClipboardData(CF_UNICODETEXT, global);
        CloseClipboard();
    }
}

wchar_tUTF-16编码的,但是你得到的数据是UTF-8编码的。您不需要在这两种编码之间进行转换,您只需重新解释字节即可。

查看这些字符的代码点,应该清楚发生了什么: 的 UTF-8 代码点是 0xE2 0x95 0xA0,[=17= 的 UTF-16 代码点] 是 0x00 0xE2,而 的 UTF-16 代码点是 0x25 0x60.

swprintf(text, 140, L"%hs", tx); <- 这只是将每个 char 转换为一个 wchar_t,将 3 字节 UTF-8 代码点 0xE2 0x95 0xA0 转换为三个 2 字节 UTF-16 代码点:0x00 0xE20x00 0x950x00 0xA0.

要从 0xE2 0x95 0xA0 得到 0x25 0x60,您需要实际转换数据:

std::wstring_convert<std::codecvt_utf8_utf16<char16_t>> converter;
std::wstring text = converter.from_bytes(tx);

或者,由于您已经在使用 WINAPI,您可以使用 MultiByteToWideChar:

WCHAR text[140];
int length = MultiByteToWideChar(CP_UTF8, 0, tx, -1, (LPWSTR)text, 140);