第一章 错误处理
1、$err, hr 在vs的watch窗口中监视这个可以获得刚执行的windows api 的错误代码及详细解释。
2、自定义消息码
Bits: | 31-30 | 29 | 28 | 27-16 | 15-0 |
Contents | Severity | Microsoft/customer | Reserved | Facility code | Exception code |
Meaning | 0=Success 1 = Informational 2 = Warning 3 = Error | 0 = Microsoft-defined code 1 = customer-defined code | Must be 0 | The first 256 values are reserved by Microsoft | Microsoft/customer-defined code |
注意第29位,自定义的消息码必须为1。
3、FormatMessage函数可以把消息码格式化成其对应的字符串。
第二章 字符和字符串处理
1、在Windows vista中,每个Unicode字符都使用UTF-16编码,UTF-16将每个字符编码为两个字节。16位不足以表示某些语言的所有字符,对于这些语言UTF-16支持使用代理,后者是用32位来表示一个字符的方式,因为只有少数程序需要支持这些字符,所以UTF-16在节省控件和简化编码之间做了一个很好的折衷。
其他的编码还有UTF-8和UTF-32,UTF-8把一个字符编码为2-4个字节,值在0x0080一下的压缩为一个字节(美国合适),0x0080到0x07FF之间的字符用两个字节(欧洲和中东),0x0800以上的字符用三个字节(东亚),使用代理的转换为四个字节表示。对值为0x0800以上的大量字符编码时不如UTF-16有效。
2、自从WindowsNT起,Windows的所有版本都完全用Unicode来构建,所有的核心函数都需要Unicode字符串,如果传入或返回的是ANSI字符串,函数内部会进行ANSI和Unicode的相互转换,为了执行这些转换,系统会产生时间和内存上的开销。例CreateWindowExA只是一个转换层,它把ANSI字符串转换成Unicode字符串然后调用CreateWindowExW,这样就会降低性能,而且,目前一直的Windows的这些转换函数中存在一些缺陷,所以避免使用它们,可以帮助你消除一些潜在的bug,使用Unicode!
3、微软开始倾向于某些函数只提供Unicode版本,比如ReadDirectoryChangesW和CreateProcessWithLogonW。所有需要字符串作为参数的COM接口方法都只接受Unicode字符串。
4、资源编译器编译的所有字符串值(字符串表、对话框模板、菜单等)都是Unicode字符串,如果你的程序没有使用Unicode,调用函数时也会进行Unicode到ANSI的转换,自然也就会影响性能。
5、C运行时库提供了两套不会互相调用的函数来处理ANSI和Unicode字符和字符串。你的代码应该包含TChar.h,并且使用_tcslen代替wcslen或者strlen,但是由于c运行时库始终为标识符附件下划线前缀,所以你的程序应该确保要么同时定义UNICODE和_UNICODE,要么一个都不要定义。
6、以前任何修改字符串的函数都存在缓冲区溢出的安全隐患,如今你应该使用StrSafe.h文件中定义的新的安全字符串函数来替代以往的函数。注意必须在包换了其他所有文件之后,才包含StrSafe.h。
7、除了新的安全字符串函数,c运行时库还提供了一些函数,用于在执行字符串处理时提供更多的控制。如StringCchCat、StringCchCatEx、StringCchCopy/ StringCchCopyEx等,自然c运行时库提供了这些函数的A版本和W版本。方法中的Cch表示字符数,一般用_countof宏来获取,另外还有一系列名称中含有Cb的函数地啊表字节数,一般用sizeof来获取。前面函数存在的Ex版本可以获取更多的控制,详情参考msdn。
8、ShlwApi.h中定义了大量方便好用的字符串函数,可以用来对操作系统有关的数值进行格式化操作,例如StrFormatKBSize和StrFormatByteSize.
9、Windows中比较字符串最理想的函数CompareString(Ex)和CompareStringOrdinal。
int CompareString(LCID locale, DWORED dwCmdFlags, PCTSTR pString1, int cch1,
PCTSTR pString2, int cch2);
第一个参数locale标志一种语言,不过这种比较比基于序数的比较(ordinal comparison)慢。可以通过api GetThreadLocale()获取当前线程的locale。第二个参数请参考msdn,其余四个参数指定了两个字符串及各自的字符长度(字符数而不是字节数)。如果比较的是编程类的字符串(路径名、注册表值、XML元素/属性等)应该使用CompareStringOrdinal,此函数只支持Unicode字符串。这两个函数的返回值有别于原来的c函数。返回值为0-3,具体意义参考msdn。
10、总结
l 将文本字符串想象为字符的数组而不是char或字节数组
l 为文本字符和字符串使用泛型(TCHAR/PTSTR)
l 为字节、字节指针和数据缓冲区使用显式数据类型(BYTE和PBYTE)
l 为literal字符和字符串使用TEXT宏
l 执行全局替换(例如用PTSTR替换PSTR)
l 修改字符串算数问题。例函数经常希望你传给她缓冲区的字符数而不是字节数,这意味着你应该传入_countof(szBuffer)而不是sizeof(szBuffer).而且如果为一个字符串分配内存块应该用malloc(nCharacters*sizeof(TCHAR)。
l UNICODE和_UNICODE要么都指定要么一个也别定义。
对于字符串处理函数应该遵循以下准则:
l 始终使用安全的字符串处理函数,比如后缀为_s的或者前缀为StringCch的,后者主要在你想明确控制截断的时候使用,否则首选前者。
l 不要使用Kernel32的方法进行字符串处理,如lstrcat和lstrcpy。
l 利用/GS和/RTCs编译器标志来自动检测缓冲区溢出。
l 比较编程类字符串的时候应该使用CompareStringOrdinal来进行比较,用户字符串一般要显示在用户界面上,这些字符串应该用CompareString(Ex)来比较,因为它会考虑区域设置。
11、IsTextUnicode函数使用乙烯类统计和决策方法来猜测缓冲区中的内容,由于并非精确的科学,所以它可能返回错误的结果。