代码之家  ›  专栏  ›  技术社区  ›  Neil Weicher

环境变量和本地化

  •  0
  • Neil Weicher  · 技术社区  · 6 年前

    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 回复  |  直到 6 年前
        1
  •  1
  •   Barmak Shemirani    6 年前

    显然,此字符串中不支持某些字符。通过将字符串转换为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;
    }