比如我用"你好.xls"存档,实际显示“ÄãºÃ.xls”(我的工程设置Vs2008的字符集为“多字符集”)
而用Vc6.0编译 BasicExcel 操作Excel用中文“另存为”,存档文件名显示正常,真是郁闷了。
PS:
从设置选项中可以看到,工程中使用的字符集可设置为“Multi-Byte Character Set”或“Unicode Character Set”,其中“Multi-Byte Character Set”表示使用ANSI编码方式,“Unicode Character Set”表示使用UNICODE编码方式。
那么这两种编码方式有什么样的区别呢?
(1)传统的计算机使用ANSI编码,在ANSI编码模式下,英文字符都用1个字节表示,而某些其它国家的文字(如汉字、日文),无法用单个字节来表示,ANSI便采用多个字节来表示这些字符(汉字是2个字节)。
(2)UNICODE包含UTF-8、UTF-16、UTF-32等多种编码方案(目前windows一般使用UTF-16)。拿UTF-16来说,规定所有字符都使用2个字节表示(不论英文字母还是汉字),对于超出2个字节范围的字符采用代理(采用4个字节表示)。
UNICODE相比ANSI有很多方面的优势(优势体现在哪?),微软非常提倡使用UNICODE编码方式,在MS较新版本的系统中都是采用UNICODE编码的。因此,即便我们在自己写的程序中使用了ANSI编码,系统会将其转换为UNICODE再对其进行处理。
我先尝试着把BasicExcel关于mbstowcs和wcstombs的标准C库函数都改成Windows Api的MultiByteToWideChar和 WideCharToMultiByte,因为mbstowcs和wcstombs的标准C库函数对于中文支持不好,但发现发现不行
又来回折腾,弄了2天时间,跟踪代码,发现问题是fstream中的open方法,系统内部调用mbstowcs_s出现问题,wc_name 出现乱码(filename是好的)
_CRTIMP2_PURE FILE *__CLRCALL_PURE_OR_CDECL _Fiopen(const char *filename,
ios_base::openmode mode, int prot)
{ // open wide-named file with byte name
wchar_t wc_name[FILENAME_MAX];
if (mbstowcs_s(NULL, wc_name, FILENAME_MAX, filename, FILENAME_MAX - 1) != 0)
return (0);
return _Fiopen(wc_name, mode, prot);
}
该函数的调用结果依赖于程序的本地化设置。而本地化设置可以通过setlocale函数来设置,
setlocale(LC_ALL, "chinese")表示将程序本身的语言设置为中文,而程序启动时默认设置为LC_ALL="C"。在使用mbstowcs_s进行字符串转换时,只有当LC_ALL="chinese"时,含中文的字符串才能正确的转换成其对应的宽字节字符,否则(在LC_ALL="C"时),汉字会被看成2个单字节的字符,然后再转换成宽字节的字符,这样转换的结果显然是错误的!