Переменные среды и локализация - PullRequest
0 голосов
/ 09 мая 2018

Похоже, что в MSDN нет документации по этому поводу, но очевидно, что SetEnvironmentVariableA и GetEnvironmentVariableA работают по-разному со специальными символами в зависимости от локализации, и мне было интересно, ожидалось ли это.

Я собрал эту простую консольную программу на C:

#include <windows.h>
#include <stdio.h>
int main()
{
    PUCHAR binIn = "\x06\xC7\x86\xC1\x99\x93\xCF";
    UCHAR binUt[16] = {0};
    SetEnvironmentVariable("MYVAR", binIn);
    GetEnvironmentVariable("MYVAR", binUt, 16);
    printf("%X %X %X %X %X %X %X\n", binUt[0], binUt[0], binUt[1], binUt[2], binUt[3], binUt[4], binUt[5], binUt[6]);
}

При запуске с языком системы, установленным на английском языке, отображаются те же байты, что и входящие, т. Е .:

06 C7 86 C1 99 93 CF

Тем не менее, при запуске с языком системы как японским он отображает немного другой вывод:

06 C7 81 45 99 93 CF

Это ожидается? Есть ли способ заставить его возвращать одно и то же значение независимо от локали?

1 Ответ

0 голосов
/ 10 мая 2018

Очевидно, что некоторые символы не поддерживаются в этой строке. Вы можете продублировать проблему, преобразовав строку в UTF16 и обратно:

wchar_t* get_unicode(const char* ansi, UINT codepage)
{
    if(!ansi) return 0;
    int size = MultiByteToWideChar(codepage, 0, ansi, -1, 0, 0);
    wchar_t* unicode = malloc(size * sizeof(wchar_t));
    MultiByteToWideChar(codepage, 0, ansi, -1, unicode, size);
    return unicode;
}

char* get_char(const wchar_t* unicode, UINT codepage)
{
    if(!unicode) return 0;
    int size = WideCharToMultiByte(codepage, 0, unicode, -1, 0, 0, 0, 0);
    char* ansi = malloc(size);
    WideCharToMultiByte(codepage, 0, unicode, -1, ansi, size, 0, 0);
    return ansi;
}

int main()
{
    //932 for Japanese code page
    wchar_t* unicode = get_unicode("\x06\xC7\x86\xC1\x99\x93\xCF", 932);
    char* ansi = get_char(unicode, 932);
    for(int i = 0, len = strlen(ansi); i < len; i++)
        printf("%02X ", ansi[i]&0xFF);
    printf("\n");
    return 0;
}

Это тот же неправильный результат:

06 C7 81 45 99 93 CF

Возможно, ты мало что можешь сделать здесь. Возможно, оригинальная японская строка не была преобразована должным образом, или некоторые символы не поддерживаются.

Используйте Unicode, чтобы легко решить проблему:

int main()
{
    SetEnvironmentVariableW(L"MYVAR", L"日本語 ελληνικά");
    wchar_t buf[100];
    GetEnvironmentVariableW(L"MYVAR", buf, _countof(buf));
    MessageBoxW(0, buf, 0, 0);
    return 0;
}

Если остальная часть вашей программы не является Unicode или не может быть преобразована, вы можете сохранить широкую строку символов в формате UTF8 вместо UTF16, как показано в примере ниже:

int main()
{
    char* utf8 = get_char(L"日本語", CP_UTF8);

    wchar_t* unicode = get_unicode(utf8, CP_UTF8);
    SetEnvironmentVariableW(L"MYVAR", unicode);
    wchar_t buf[100];
    GetEnvironmentVariableW(L"MYVAR", buf, _countof(buf));

    MessageBoxW(0, buf, 0, 0);

    free(utf8);
    free(unicode);

    return 0;
}
...