windows 核心编程之 错误处理 -----学习笔记

来源:互联网 发布:wdcp 查看mysql版本 编辑:程序博客网 时间:2024/04/29 20:36

第一章 错误处理

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。

3FormatMessage函数可以把消息码格式化成其对应的字符串。

第二章 字符和字符串处理

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的转换,自然也就会影响性能。

5C运行时库提供了两套不会互相调用的函数来处理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。

8ShlwApi.h中定义了大量方便好用的字符串函数,可以用来对操作系统有关的数值进行格式化操作,例如StrFormatKBSize和StrFormatByteSize.

9Windows中比较字符串最理想的函数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)来比较,因为它会考虑区域设置。

11IsTextUnicode函数使用乙烯类统计和决策方法来猜测缓冲区中的内容,由于并非精确的科学,所以它可能返回错误的结果。