开发平台:Win7 32bit 英文版
开发工具:VS2008 英文版
开发语言:C++
程序编码:ANSI(MBCS)
运行平台:Win2003 英文版;Regional and Language Options—Advanced标签里面选择 Chinese(PRC);Language标签里面勾选Install files for East Asian languages,但是灰色不可 更改。
问题描述:C++程序抓取某系统值(中文的),输出到本地log文件,中文显示???。但是该程序在别的机器上没有发现该问题。而且该机器上能显示或者输入中文字,中文版本的软件也能安装,没有显示乱码。
为什么。。。
首先你得判断抓取到的字符串是否是正确的中文,
其次在输出文件的时候,你可以采用支持中文字符的字符集(不要选 GB2312,很可能 OS 没有) Unicode或UTF-8之类的来输出你的log文件。
您好,多谢回复!!
1. 怎么判断是否是正确的中文?我是抓取打印机里面的作业名,比如打印一个中文文档,别的机器我打印同一个文档能成功抓取到中文并输出。
2. 文件我输入到txt的,使用log4cplus。感觉和什么编码写文件无法,因为我把这个字串转成UTF-8再输出也是乱码。
3. 是否程序中都用使用unicode编码?
@楊彬: 1,把抓取到的文字显示到你的UI上,就能看出来是否正确。
2,我不知道log4cplus是怎么处理中文的,我只说一个关于如何在非中文操作系统下正确读写INI的例子,我假设项目字符集是UNICODE,同时项目中使用LPCTSTR来表示字符串,并且假设此字符串中的中文字符是正确的,如下:
LPCTSTR lpszText = _T("中文"); // 由于是写在代码中的,那么lpszText肯定包含正确的中文字符。
现在要写入INI文件,由于默认的API创建的INI文件在非中文操作系统下无法正确对中文字符编码,所以我在调用 WritePrivateProfileString 之前,先手动创建一个正确的 INI 文件,如下:
HRESULT hr = ::SHPathPrepareForWrite(NULL,NULL,lpszINIFileName,SHPPFW_DIRCREATE | SHPPFW_IGNOREFILENAME); if(hr != S_OK) return hr; // INI 能够正确识别的 UNICODE 字符集为 UTF16-little Endian, // 但是由 WritePrivateProfileString 自动创建的文件是 ANSI 编码, // 所以我们通过编码方式创建带有正确 BOM 信息并能够识别中文 // 字符的 INI 文件。 // UTF16-LE BOM(FFFE) WORD wBOM = 0xFEFF; DWORD dwWritten; TCHAR szComment[MAX_PATH] = _T(";**********************************************************\r\n") _T(";此 INI 文件由程序自动创建,采用 UTF16-little Endian 编码,\r\n") _T(";文件头包含 2 个字节的编码标识(0xFEFF),可在非中文操作系\r\n") _T(";统下正确读、写中文字符。禁止修改文件头!\r\n") _T(";**********************************************************\r\n\r\n"); HANDLE hFile = ::CreateFile( lpszINIFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return ::AtlHresultFromLastError(); ::WriteFile(hFile, &wBOM, sizeof(WORD),&dwWritten, NULL); ::WriteFile(hFile, szComment, (_tcslen(szComment)+1)*(sizeof(TCHAR)),&dwWritten, NULL); ::CloseHandle(hFile);
那么此后我再使用这个已经存在的文件,调用 WritePrivateProfileString 写入 lpszText 后,通过记事本,或者使用 GetPrivateProfileString ,你就能看到或得到正确的中文字符。
3,推荐设置为 UNICODE 编码,会减少很多转码的问题。
请仔细读一下 log4cplus 的源码,看看它创建文件的方式,以及它写入字符串的类型。比如ZLIB,它的所有方法都使用 char 来表示字符串,那么如果我的项目是UNICODE的,那么我就需要先把 lpszText 转换为 const char* (用CT2CA宏)然后再调用它的方法。
还有,如果你从一个文件读入字符串,ReadFile 实际读入的是 char 类型,那么你就需要知道文件的编码方式,然后根据它的编码来确定你如何把 char 类型的字符串转换成你的项目中的 TCHAR 类型的字符串。
@Launcher:
我把抓出来的内容直接输出到控制台,可以看见是正常的中文。
应该是字符集的问题,我用std:locale方法抓取系统locale出来的是English_United States.1252,但是我不知道windows什么地方可以设置。
@楊彬: 如果你能够为每个用户的OS都去设置一遍区域与语言的话,那么你可以通过在“区域与语言”中修改“当前位置”和“更改系统区域设置”来实现,如果列表不包含中文的话,你可能还需要额外的去安装中文语言包。
或者,你可以通过程序来解决,统一按照UNICODE来输出日志文件,记得在日志文件头写入正确的BOM信息。
@Launcher: 再次感谢大哥!奇怪的是我区域语言都设置了“Regional and Language Options—Advanced标签里面选择 Chinese(PRC);Language标签里面已经勾选了Install files for East Asian languages,但是灰色不可 更改。”区域也是China~~~
但是这么设置后HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Locale
"(Default)"这个值还是"409",后来我把他手动改成804就可以显示中文了。。。
@楊彬: 设置完成后要重启。Windows 2003早就不使用了,所以我们的程序都是通过程序来解决这些问题,而不是要求用户去修改它的操作系统(用户可能还有Win2000/XP/Vista/7/2008/8),因此也就不记得Windows 2003如何设置。你可以仔细阅读下Windows 2003的帮助文档。
我们只在Office上遇到过一些问题,因为OS区域,语言包,界面语言对Office版本(中文,英文)的影响还是不一样的。
@Launcher: 多谢指教。
1. 我发现了,因为我程序编译的用户locale是简体中文的,但是我测试服务器系统locale是英文的,所以造成了乱码。如果用unicode编码应该是可以解决这个问题的。
2. 设置完区域、语言等设置后,我是重启过机器的,现在我的问题变成为什么设置完过后system locale值不变。