Microsoft对Unicode的支持:
Windows 98 :只支持ANSI
Windows 2000: 即支持Unicode也支持ANSI,但是用Unicode会更快,因为会有一个内部的转化过程,比如调用CreateWindowEx函数,参数传非Unicode字符串,那么CreateWindowEx必须分配内存(进程的默认堆中),将非Unicode字符转化成Unicode字符,然后在传给CreateWindowEx。影响效率。
Windows CE:只支持Unicode
COM:只支持Unicode
C运行时库对Unicode的支持:
在标准C头文件String.h中定义:typedef unsigned short wchar_t;
对应strcat、strcpy、strlen这样的函数都有一组对应的Unicode版本:wcscat、wcscpy、wcslen
对于包含了对str函数和wcs函数进行显示调用的代码来说,无法非常容易的同时为ANSI和Unicode对这些代码进行编译。若要建立双重功能,必须包含头文件TChar.h,而不是String.h。
TChar.h中定义了很多宏,比如_tcscpy,如果定义了_UNICODE这个宏就调用wcscpy,如果没有定义就调用strcpy函数。另外TChar.h中还定义了:
定义了_UNICODE:typedef wchar_t TCHAR;define _TEXT(x) L##x
没有定义 _UNICODE:typedef char TCHAR;define _TEXT(x) x
这样,无论有没有定义_UNICODE,都可以这么用:TCHAR *szError = _TEXT("Error");通过这种方法,只需通过_UNICODE就可以分别编译出ANSI和Unicode版本。另外: _T("") 等同于 _TEXT("")。
Windows头文件定义的数据类型:
WCHAR :Unicode字符串
PWSTR:指向Unicode字符串的指针
PCWSTR:指向一个恒定的Unicode字符串的指针
Windows也定义了ANSI/Unicode通过数据类型PTSTR和PCTSTR,这些数据类型可以指ANSI字符串,也可以指Unicode字符串,取决于是否定义了UNICODE宏。(这里没有下划线,跟C运行时库不同)
Windows提供的函数通常包含两个版本:比如CreateWindowExA和CreateWindowExW,还有一个宏CreateWindowEx,调用哪里取决于是否定义了UNICODE。而在Windows 2000下,因为没有ANSI版本,CreateWindowExA其实做了从ANSI版本到Unicode版本的转化工作。
要创建给其他开发人员使用的DLL时可以考虑提供两个版本的输出函数:ANSI版本和Unicode版本。在ANSI版本中就进行简单的字符串转化,在调用Unicode版本。Windows API中一些函数仅仅为了实现与16位Windows的兼容,像WinExec和OpenFile,应该用CreateProcess和CreateFile代替。
Windows还提供了一组操作字符串的函数:StrCat、StrChr、StrCmp、StrCpy...这些函数同样支持ANSI和UNICODE版本,取决于是否定义了UNICODE宏,书上建议使用这些函数代替C运行期字符串函数,因为这些函数被很多程序使用,比如Explorer.exe,在我们的应用程序运行时,它们可能已经被装入RAM。但是可惜没有见到过程序中使用这类函数的,所以也不知道这个说法是否正确。如果要使用这些函数,要包含头文件ShlWApi.h。
要成为符合ANSI和Unicode的应用程序,应该符合以下几条规则:
1. 将文本串视为字符数组,而不是char数组和字节数组
2. 将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串
3. 将显示数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存
4. 将TEXT宏用于原义字符和字符串
5. 执行全局性替换(用PTSTR替换PSTR)
6. 修改字符串运算操作(sizeof(szBuffer/sizeof(TCHAR))、maloc(nCharacters*sizeof(TCHAR)))
在Windows中,还提供了一组字符串操作的函数(宏):lstrcat、lstrcmp、lstrcmpi、lstrcpy、lstrlen...他们也根据UNICODE宏选择调用ANSI版本还是Unicode版本的函数。有两个函数于C运行时函数是不同的,即lstrcmp和lstrcmpi,C运行期函数strcmp、strcmpi、wcscmp、wcscmpi只是对字符串的代码点的值进行比较,这就是说,这些函数将忽略实际字符的意义。而Windows版本的函数是通过调用CompareString函数实现的。这个函数的第一个参数是LCID lcid,CompareString使用这个ID来比较这两个字符串,方法是对照一种特定的语言来查看他们的字符的含义。这个ID是通过调用LCID GetThreadLocale()函数得到的。
其他C运行时函数没有为Unicode提供很好的支持。例如,tolower和toupper函数无法正确的转换带有重音符号的字符。为了弥补C运行期库的不足,可以调用下面的Windows函数:PTSTR CharLower(PTSTR pszString)和PTSTR CharUpper(pszString),这些函数也可用于转换ANSI字符串。另外Windows还提供了IsCharAlpha(THCR ch)、IsCharLower(TCHAR ch)等函数,与C运行期函数不同的是,这些函数还要考虑用户在控制面板中指定的语言。另外Microsoft公司还提供了wsprintf等函数使我们能很容易地对ANSI和Unicode进行混合和匹配。
当资源编译器对你的所有资源进行编译时,输出文件是二进制文件。资源(字符串表、对话框模板等)中的字符信息总是Unicode字符串。如果应该程序没有定义UNICODE,那么系统会进行内部转化。比如在编译源代码模块时没有定义UNICODE,调用LoadString实际上调用了LoadStringA。这时LoadStringA就从你的资源中读取字符串,并将该字符转换成ANSI字符串。ANSI形式的字符串将从该函数返回给你的应用程序。
MultiByteToWideChar和WideCharToMultiByte用于多字节字符串和宽字符串之间的转换。用法比较复杂。可参看核心编程page 24.