《windows核心编程》读书笔记2-chapter2
如果调用任何windows函数,并传递给他一个ANSI字符串,系统会先将这个字符串转换为unicode字符串,然后将这个unicode字符串传递给操作系统。这样你就理解,为什么在windows平台上,使用unicode的效率要相对更高一些。
所以,我们可以通过在一开始就是用unicode开发应用程序,使程序执行更有效率。
1.1 Windows ce和unicode
为了保持windows ce的精致,ms决定不支持ansi的windows函数。所以,如果要进行windows ce上的程序开发,必须了解并在整个应用程序中使用unicde。
1.2 关于COM
Ms在将COM组建从16位移植到32位系统使,作出了一个决定:素有需要字符串的COM接口方法只支持unicode字符串。
1.3 如何编写unicode源代码
1.3.1 C运行库的unicode支持
标准c的string.h头文件中个定义了一个wchar_t的unicode字符数据类型。
typdef unsigned long wchar_t;
标准c还专门为wchar_t定义了一组函数。
char* strcat(char*, const char*);
wchar_t* wcscat(wchat_t* , const wchar_t*);
size_t strlen(const char*);
size_t wcslen(const wchar_t*);
…
所有的unicode字符串都以wcs开头,代表宽字符。为了调用unicode,简单的将ansi字符串的str替换为wcs即可。
TChar.h头文件主要为为了帮助ANSI/Unicode通用源代码文件的编写,他主要由一系列的宏组成,在编写源代码时,可以使用这些宏来替代对str或wcs函数直接的调用。
Ms的c++编译器将所有的字符串默认都认为是ansi字符串,而不是unicode字符串。所以,对于下面的这句话:
TCHAR *szError = “Error”;
如果没有定义_UNICODE宏,则能够编译通过,但是如果定义了该宏,则会出现编译错误。
为了生成一个UNICODE字符串而非一个ansi字符串,需要将以上的一句改为:
TCHAR *szError = L”Error”;
那么为了同时兼容上面的两种情况,我们定义一个宏
#ifdef _UNICODE
#define _TEXT(x) L ## x
#else
#define _TEXT(x) x
#endif
这样我们就可以重写以上的语句:
TCHAR* szError = _TEXT(“Error);
1.3.2 Windows定义的unicode数据类型
WCHAR Unicode字符
PWSTR 指向Unicode字符串的 指针
PCWSTR 指向Unicode字符串常量的指针
Windows.h中同样定义了ansi/Unicode通用的数据类型
PTSTR
PCTSTR
在编译这个模块时,是否定义了UNICODE宏决定了这些数据类型指向ansi还是unicode。
注意, _UNICODE是标准c的unicode开关;
而UNICODE是windows的unicode开关。
所以,一般来说,这两个宏要么同时定义,要么同时不定义。
1.3.3 Windows系统中的unicode函数和ansi函数
在windows2000下,CreateWindowsExA只是一个简单的转换层,他实现内存分配并把ansi字符串转换为unicode字符串,然后调用CreateWindowsExW函数,把转换后unicode字符串传递给该函数。当CreateWindowsExW返回时,CreateWindowsExA释放内存缓冲区,并且返回其窗口句柄。
1.4 让应用程序符合ansi和unicode规范
下面是一些基本规则:
l 对于文本字符和串使用通用数据类型;
l 对字节、字节指针和数据缓冲区使用显式数据类型;
l 对文字字符和字符串使用TEXT宏;
l 修改字符串运行问题, 使用sizeof(szbuffer)/sizeof(TCHAR)而不是sizeof(szbuffer);
l 分配内存时,使用malloc(len*sizeof(TCHAR)) 而不是malloc(len);
1.4.1 Windows字符串函数
第一个CompareString参数指定一个32位的位置ID(LCID),用来识别具体的语言种类,CompareString使用LCID,通过检查适用于特定语言的字符的意义来比较字符串。
sprintf()系列函数的应用
char szA[100];
wchar_t szW[100];
//normal
sprintf(szA, “%s”, “ANSI Str”);
//convert Unicode to ansi
sprintf(szA, “%S”, L”ANSI Str”);
//normal
swprintf(szW, L“%s, L”ANSI Str”);
//convert Ansi To unicode
swprintf(szW, L”%S”, “ANSI Str”);
这里要注意格式化字符串的中s字符的大小写;
1.4.2 资源
Vc程序的内部资源字符串其实也是unicode的,在使用LoadString来加载资源时,如果是ansi,则其实是现将内部的unicode转换为ansi,然后在返回。
1.4.3 确定文本是ansi还是unicode
DWORD IsTextUnicode(CONST PVOID pvBuffer, int cb, PINT pResult);
用于判断指定的文本为ansi还是unicode;
这个函数使用的是统计的方法论来分析缓冲区内的文本是ansi还是unicode,所以他也有可能返回一个错误的结果。
1.4.4 在unicode和ansi之间转换
这里其实就是涉及到两个函数
WideCharToMultiByte()
MultiByteToWideChar()
通过查看函数的原型,我们可以发现 WideCharToMulteByte 比 MultiByteToWideChar 多了两个参数, pDefaultChar, pfUsedDefaultChar ,如果宽字符不能转换某字符,则函数应该使用参数 pDefaultChar 指向的字符,如果该参数为 NULL ,函数使用系统默认的字符。默认的字符为问号(这就是为什么在英文系统下,中文字符总是显示为问号的原因),问号用于文件名是危险的,因为问好是一种通配符。