Windows核心编程 第二章 字符和字符串处理
1. Windows Vista中每个Unicode字符都是用UTF-16编码。
2. Unicode 前0x7F个字符兼容ASCII编码。
UTF-8 :将一些字符编码为1个字节,一些字符编码为2个字节,一些字符编码为3个字节,一些字符编码为4个字节。
UTF-16 :将每个字符编码为2个字节(16位)。
UTF-32 :将每个字符都编码为4个字节, 较少用, 一般在应用程序内部使用。
3. C语言中的字符表示:
char : 8位 ASCII 编码
wchar_t : 16位 Unicode (UTF-16)编码
4. 使用UTF-16字符串的时候应在字符串前面加上大写字母L。表明使用一个unicode字符串。
5. Windows编程中 源代码使用的数据类型应坚持使用Windows数据类型,增加代码的可读性。
6. Windows中提供两个编码版本的函数。以W结尾的是UNICODE编码函数,以A结尾的是ANSI编码的函数
如:
CreateWindowExW
CreateWindowExA
7. Windows内部使用的是UNICODE函数,因此开发时应该尽量使用Unicode 函数以提高应用程序的效率,避免Windows在内部还要将ANSI 函数转为UNICODE函数。
8. MS的C库的ANSI和Unicode版本之间没有互相调用关系的,没有编码转换开销。
9. 宽字符函数:_tcscpy,_tcscat,_tcslen。
10. UNICODE宏是Windows API使用的,而MS的C库中,对于非标准的东西用_前缀区分,所以_UNICODE宏是MS的CRT库函数所使用。 使用C\C++编程中,要确保要么UNICODE 和 _UNICODE都define或是全部没define。
11. 使用StrSafe.h里面的安全字符处理函数。StrSafe库中提供 Cch和 Cb两种函数, Cch传入的是字符数,可用_countof取得,Cb表示的是字符串的字节数。 在源串过短时,<StrSafe.h>的函数处理方式是截断而<TChar.h>的函数则使用断言。
12. 自定义C运行库函数传入参数无效的异常处理方法:
(1) 定义一个 InvalidParameterHandler 函数,用于注册异常抛出函数。格式如下:
void InvalidParameterHandler(PCTSTR expression,
PCTSTR function,
PCTSTR file,
unsigned int line,
uintptr_t);
(2) 调用_set_invalid_parameter_handler 注册异常函数
(3) 使用_CrtSetReportMode 关系VS自带的debug dialog 。
示例代码:
1 /**************************************************************************************** 2 * 自定义C运行库函数传入参数无效的异常处理方法: * 3 * (1) 定义一个 InvalidParameterHandler 函数,用于注册异常抛出函数。格式如下: * 4 * void InvalidParameterHandler(PCTSTR expression, * 5 * PCTSTR function, * 6 * PCTSTR file, * 7 * unsigned int line, * 8 * uintptr_t); * 9 * (2) 调用_set_invalid_parameter_handler 注册异常函数 * 10 * (3) 使用_CrtSetReportMode 关系VS自带的debug dialog 。 * 11 *****************************************************************************************/ 12 13 #include <cstdio> 14 #include <cstdlib> 15 #include <iostream> 16 #include <crtdbg.h> 17 #include <tchar.h> 18 #include <windows.h> 19 #include <strsafe.h> 20 using namespace std; 21 22 void InvalidParameterHandler(PCTSTR expression, PCTSTR function, PCTSTR file, unsigned int line, uintptr_t ) 23 { 24 wcout << "自定义的C运行库异常处理 : " << endl; 25 wcout << expression << endl; //哪句表达式发生异常 26 wcout << function << endl; //哪一个函数发生异常 27 wcout << file << endl; //在哪个文件发生异常 28 wcout << line << endl; //第几行抛出异常 29 throw 0; //抛出异常 30 } 31 32 int main (void) 33 { 34 _CrtSetReportMode(_CRT_ASSERT, 0); 35 _set_invalid_parameter_handler(InvalidParameterHandler); 36 37 try{ 38 39 TCHAR szbefore[5] = L"BBBB"; 40 TCHAR szAfter[5] = L"AAAA"; 41 TCHAR buf[10] = {0}; 42 errno_t ret = _tcscpy_s(buf, _countof(buf), L"0123456789"); 43 } 44 catch(int err) 45 { 46 if ( 0 == err ) 47 cout << "接受到 InvalidParameterHandler 抛出的异常!" << endl; 48 } 49 50 51 return 0; 52 }
13. 使用Shlwapi.h的字符串处理函数, 如:需要比较向用户显示字符串的比较函数使用 CompareString , 比较程序内部使用的字符串(如路径名、注册表项/值等)应使用CompareStringOrdinal
14. 使用MultiByteToWideChar 和 WideCharToMultiByte 可以转换字符编码。其中,在宽字节转多字节的时候,如果有Unicode字符在多字节编码中没有对应项,那宽字节会被替换成参数lpDefaultChar,并且lpUsedDefaultChar 会被标记为TRUE。当用这两个函数计算结果串的大小时,返回的是字符数。
15. IsTextUnicode 可以检测字符编码是属于UNICODE还是ASCII。
16.关闭VS对不安全的字符串函数警告或报错的方法: 在源程序最顶端加上宏定义 #define _CRT_SECURE_NO_DEPRECATE 即可关闭字符串不安全函数的警告或报错。
Unicode 和 ANSI 编码相互转换示例代码:
#include <windows.h> #include <iostream> using namespace std; // Unicode编码转为ASCII 编码 int UnicodeToAnsi(wchar_t *str_wide, char *str_ansi, unsigned int cbsize) { return WideCharToMultiByte(CP_ACP, 0, str_wide, -1, str_ansi, cbsize, NULL, NULL); } // ASCII转为Unicode 编码 int AnsiToUnicode (char *str_ansi, wchar_t *str_wide, unsigned int chcount) { return MultiByteToWideChar(CP_ACP, 0, str_ansi, -1, str_wide, chcount); } int main (void) { // code conversion char str[50] = {0}; wchar_t wide[] = L"人生长恨水厂东"; cout << UnicodeToAnsi(wide, str, 50) << endl; cout << str << endl; char ansi[] = "人生长恨水厂东" ; wchar_t p[50]; AnsiToUnicode(ansi, p, _countof(p)); MessageBox(NULL, p, p, 0); return 0; }