第1章 错误处理
void | 这个函数返回值不会失败,只有很少函数返回值是void |
bool | 函数失败,返回值为0;否则,返回值为非0 |
handle | 函数失败,返回值为NULL;否则,handle将标识一个可操纵的对象; 某些函数失败了,会返回为INVALD_HANDLE_VALUE的一个句柄值,被定义为-1; 函数的Platform SDK文档会说明函数是用NULL还是INVALD_HANDLE_VALUE来标识失败; |
pvoid | 函数失败返回值为NULL,否则pvoid将标识一个内存地址 |
long/dword | 通常返回0或-1 |
- windows函数的错误代码都是32位;
- GetLastError函数 返回上一个函数的错误代码;
- 函数失败后,应马上调用GetLastError,如果又调用了另一个函数,错误代码的值会被改写,成功调用的函数可能用Error_Success改写此值;
- FormatMessage函数 将错误代码转换为相应的文本描述;
1.1 定义自己的错误代码
Void SetLastError(DWORD dwErrCode); //设置线程的上一个错误代码;
位 | 31-30 | 29 | 28 | 27-26 | 15-0 |
内容 | 严重性 | Microsoft/客户 | 保留 | Facility代码 | 异常代码 |
含义 | 0=成功 1=信息(提示) 2=警告 3=错误 |
0=Microsoft定义的代码 1=客户定义的代码 |
必须为0 | 前256个值由Microsoft保留 | Microsoft/客户定义的代码 |
1.2 ErrorShow示例程序
第2章 字符和字符串处理
2.1 字符编码
双字节字符集(DBCS) | 每个字符由1或2个字符组成 |
UTF-16 | 每个字符由2个字节编码,支持4字节表示的代理(surrogate)方式,是节省空间和简化编码的折衷 |
UTF-8 | 每个字符可由1/2/3/4个字节编码,对大量字符编码是不如UTF-16高效 |
UTF-32 | 每个字符都由4字节编码,不用考虑代理的问题 |
2.2 ANSI字符和Unicode字符与字符串数据类型
(1)char表示一个8位ANSI字符
//pointer to 8-bit character(s)
typedef char *pchar;
typedef char *pstr;
typedef const char *pcstr;
(2)wchar_t表示一个16位的UTF-16字符
//pointer to 16-bit character(s)
typedef wchar *pwchar;
typedef wchar *pwstr;
typedef const wchar *pcwstr;
(3)WinNT.h定义了以下宏
#if Unicode
typedef WCHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST CHAR *PCTSTR;
#define _TEXT(quote) quote
#define _TEXT(quote) L##quote
#else
typedef CHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#define _TEXT(quote) quote
#endif
#define quote _TEXT(quote)
2.3 Windows中的Unicode函数和ANSI函数
(1)CreatWindowEx有2个版本:CreatWindowExW(接受Unicode字符串),CreatWindowExA(接受ASNI字符串(2)CreatWindowEx是一个宏,定义如下:
#if Unicode
#define CreatWindowEx CreatWindowExW
#else
#define CreatWindowEx CreatWindowExA
#endif
2.4 C运行库中的Unicode函数和ANSI函数
和windows函数不同,C库函数的Unicode函数和ANSI函数都不会把字符串相互转换
2.5 C运行库中的安全字符串函数
2.5.1 初识新的安全字符串函数
后缀为_s代表secure,前缀为StringCch的为安全函数
2.5.2 在处理字符串时如何获得更多控制
前缀为StringCch的安全函数用来控制截断;
Cch表示Count of characters,即字符数;Cb表示函数要求用字节数来指定大小;
S_OK | 成功,目标缓冲区包含原字符串,并以'\0'终止 |
STRSAFE_E_INVALID_PARAMETER | 失败,将NULL值传给了一个参数 |
STRSAFE_E_INSUFFICIENT_BUFFER | 失败,目标缓冲区太小,无法容纳源字符串 |
函数扩展(EX)版本的参数:size_t *pcchRemaining, LPTSTR *ppszDestEnd
DWORD dwplags, STRSAFE_FILL_BEHIND_NULL
STRASTE_IGNORE_NULLS, STRSAFE_FILL_ON_FAILURE
STRSAFE_NULL_ON_FAILURE,STRSAFE_NO_TRUNCATION
2.5.3 Windows字符串函数
(1)CompareString函数原型:
int CompareString(LCID locale, //以符合用户语言习惯的方式来显示字符串
DWORD dwCmdFlags,
PCTSTR pString1,
int cch1,
PCTSTR pString2,
int cch2);
第1个参数:LCID(licale ID)指定一个区域设置ID,是一个32位值,用来标识一种语言;
可以用Windows函数GetThreadLocale来获得主调线程的LCID
LCID GetThreadLocale();
第2个参数:是一组标志,用于修改函数比较字符串时采用的方法
NORM_IGNORECASE LINGUISTIC_IGNORECASE | 忽略大小写 |
NORM_IGNOREKANATYPE | 不区分平假名和片假名字符 |
NORM_IGNORENONSPACE LINGUISTIC_IGNOREDIACRITIC | 忽略读音字符 |
NORM_IGNORESYMBOLS | 忽略符号 |
NORM_IGNOREWIDTH | 不区分同一字符的单双字节形式 |
SORT_STRINGSORT | 将标点符号当作符号处理 |
其余参数:指定了2个字符串及其字符个数;
(2)CompareStringOrdinal函数原型:
//用于比较程序内部所用的字符串,是码位比较,不用考虑区域设置,函数只支持Unicode字符串
int CompareStringOrdinal(PCWSTR pString1,
int cchCount1,
PCWSTR pString2,
int cchCount2,
BOOL bIgnoreCase);
2.6 为何要用Unicode
2.7 推荐的字符和字符串处理方式
- 将文本字符串想象为字符数组,而不是char或字节的数组;
- 用TCHAR/PTSTR来表示文本字符和字符串;
- 用BYTE和PBYTE来表示字节、字节指针和数据缓冲区;
- 用TEXT或_T宏来表示字面量字符和字符串,避免两者混用;
- 执行全局替换,如:用PTSTR替换PSTR;
- 修改字符有关的计算,如:
给函数传缓冲区大小的字符数,应用_countof(szBuffer),而不是sizeof(szBuffer);
为字符串分 配内存块且知道字符数,应用malloc(nCharacters* sizeof(TCHAR)),而不是malloc(nCharacters);
定义一个宏来避免犯错:
#define chmalloc(nCharacters) (TCHAR*)malloc(nCharacters* sizeof(TCHAR))
- 避免使用printf函数,尤其不要用%s和%S来进行ANSI和Unicode字符串之间的相互转换,应用MultiByteToWideChar和 WideCharToMultiByte函数(详情见2.8节);
- UNICODE和_UNICODE符号要么同时指定,要么都不指定;
2.8 Unicode与ANSI字符串的转换
int MultiByteToWideChar( //将多字节字符串转换为宽字符字符串
UINT uCodePage, //字符串所处的页值
DWORD dwFlags, //进行额外控制,一般不使用,为0
PCSTR pMultiByteStr, //要转换的字符串
int cbMultiByte, //源字符串的字节数,为-1可自动判断
PWSTR pWideCharStr, //转换所得的Unicode字符串写入的内存地址
int cchWideChar); //缓冲区可容纳的字符数,若为0则不执行转换,返回目标缓冲区需要的大小,乘以sizeof(wchar_t)
WideCharToMultiByte( //将宽字符字符串转换为多字节字符串
UINT uCodePage,
DWORD dwFlags,
PCWSTR pWideCharStr, //要转换字符串的内存地址
int cchWideChar //要转换字符串的字节数,为-1可自动判断
PSTR pMultiByteStr
int cbMultiByte, //缓冲区可容纳的字符数,若为0则不执行转换,返回目标缓冲区需要的大小,不用乘法运算
PCSTR pDefaultChar, //指定页码中只有一个字符没有对应的表示时,才用最后2个参数
PBOOL pfUsedDefaultChar);
2.8.1 导出ANSI和Unicode DLL函数
//一个函数的Unicode版本
BOOl StringReverseW(PWSTR pWideCharStr,DWORD cchLength){
PWSTR pEndOfStr = pWideCharStr + wcsnlen_s(pWideCharStr,cchLength) - 1; //获取指向最后一个字符的指针
wchar_t cCharT;
//循环直到获取字符串的中间字符
while(pWideCharStr < pEndOdStr){
cCharT = *pWideCharStr; //在临时变量中存入一个字符
*pWideCharStr = *pEndOfStr; //把最后一个字符存入第一个字符
*pEndOfStr cCharT; //把临时变量存入最后一个字符
pWideCharStr++; //从左边移入一个字符
pEndOfStr--; //从右边移入一个字符
}
return (TRUE); //字符串被逆转,返回成功
}
2.8.2 判断文本是ANSI还是Unicode
IsTextUnicode函数能分辨文件是ANSI字符还是Unicode字符,由AdvApi.dll导出并在WinBase.h中声明
//缓冲区包含Unicode文本返回True,否则返回False
BOOL IsTextUnicode(CONST PVOID pvBuffer, //标识了要测试的缓冲区地址
int cb, //指定pvBuffer指向的缓冲区字节数
PINT pResult); //可为NULL