windows核心编程 第1章 错误处理
2016-06-06 11:29
441 查看
好吧,我承认我是个很懒的人,很多内容是从别人那里复制的。。。不过加了自己的实践,有意外的地方,以后的实验的环境默认为win7x64,Visual Studio 2008,红色的一般是我出意外的地方=_=主要参考:http://www.cppblog.com/SpringSnow/archive/2009/02/20/74350.html
这一章开篇介绍了windows函数的几种返回值:VOID,BOOL,HANDLE,PVOID,LONG/DWORD。让我们明白,仅仅通过返回值,我们是不能清楚函数调用为什么会失败的。windows内部,函数检测到错误会采用什么机制呢?它是采用“线程本地存储区”的机制来讲相应的错误代码与“主调线程”关联到一起。它可以使不同的线程能独立运行,不会出现相互干扰对方的错误代码的情况。
错误代码:一个Windows函数返回的错误代码对了解该函数为什么会运行失败常常很有用。Microsoft公司编译了一个所有可能的错误代码的列表(存放在WinError.h头文件中),并且为每个错误代码分配了一个32位的号码;
线程本地存储器:thread-local storage,当一个Windows函数检测到一个错误时,它会使用一个称为线程本地存储器的机制,将相应的错误代码与调用的线程关联起来,这将使线程能够互相独立地运行,而不会影响各自的错误代码;
GetLastError函数:GetLastError函数返回一个32位的错误代码,它主要用于两种情况:1)确定是什么样的错误,此时当Windows函数运行失败时,应该立即调用GetLastError函数,如果调用了另一个Windows函数,它的值很可能被改写;2)搞清楚成功的原因是什么,有些Windows函数之所以能成功运行,其中的原因有很多,比如CreateEvent函数运行成功,既可能是因为你实际创建了该对象,也有可能是因为已经存在带有相同名字的事件内核对象,此时可以调用GetLastError函数可以搞清函数运行成功的原因;
SetLastError函数:SetLastError函数用于设定线程最后的错误代码,这个错误代码既可以是Windows系统自定义的(代码的第29位必须为0),也可以是用户自定义的(代码的第29位必须为1);
FormatMessage函数:FormatMessage函数用于将错误代码转换成它的文本描述;
函数返回的时候,其返回值会指出已发生的一个错误。 我们查看具体是什么错误,在相应的函数执行完成后调用GetLastError()即可。
windows中,错误有三种表示: 一个消息ID(如ERROR_PATH_NOT_FOUND) 消息文本(如the system cannot find the path specified) 一个编号(尽量避免使用)
调试程序的时候,我们可以配置watch窗口,让它始终显示线程的上一个错误代码和错误的文本描述。如$err,hr。hr是要显示错误代码的消息文本。
那么我们怎么在自己的程序中显示消息文本呢?文章介绍了利用FormatMessage函数。这里我也介绍一下这个函数的用法: DWORD FormatMessage( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize, va_list* Arguments );
dwFlags: # FORMAT_MESSAGE_ALLOCATE_BUFFER // 此函数会分配内存以包含描述字串。 # FORMAT_MESSAGE_FROM_SYSTEM, // 在系统的id映射表中寻找描述字串 # FORMAT_MESSAGE_FROM_HMODULE // 在其他资源模块中寻找描述字串 # FORMAT_MESSAGE_FROM_STRING // 消息ID是个字串,不是个DWORD #FORMAT_MESSAGE_IGNORE_INSERTS // 允许我们获得含有%占位符的消息,不传递这个标志,就必须在Arguments参数中提供这些占位符的信息 通常为:FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
lpSource: # 指定了FORMAT_MESSAGE_FROM_HMODULE的话,此参数表示模块的HANDLE # 指定了FORMAT_MESSAGE_FROM_STRING的话,此参数表示id字串 通常为:NULL
dwMessageId: 消息ID;如果指定FORMAT_MESSAGE_FROM_STRING,将被忽略。
dwLanguageId: 消息描述所用的语言 通常为:0表示自动选择
lpBuffer: #如果未指定FORMAT_MESSAGE_ALLOCATE_BUFFER,则为自己提供的缓冲区 #否则为系统LocalAlloc分配,需要被用户LocalFree
nSize: #如果未指定FORMAT_MESSAGE_ALLOCATE_BUFFER,则为自己提供的缓冲区大小 #否则为系统LocalAlloc分配之最小缓冲区大小
Arguments: 通常不使用 代码如下: void ShowError(){ //DWORD dwError = GetLastError(); DWORD dwError = 5L; HLOCAL hlocal = NULL;
// Use the default system locale since we look for Windows messages. // Note: this MAKELANGID combination has 0 as value DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
BOOL fOk = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, dwError, systemLocale, (PTSTR) &hlocal, 0, NULL);
if (!fOk) { // Is it a network-related error? HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL) { fOk = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, hDll, dwError, systemLocale, (PTSTR) &hlocal, 0, NULL); FreeLibrary(hDll); } }
if (fOk && (hlocal != NULL)) { //这个输出可以在VS的“输出窗口”看到 //LocalLock锁定一个本地内存项目 并且 返回一个指向内存块第一个Byte的指针 OutputDebugString((PCTSTR) LocalLock(hlocal)); //这里要把项目属性改为 多字节字符集,不然会出现乱码 cout<<(PCTSTR) LocalLock(hlocal)<<endl; LocalFree(hlocal); }}
visual studio 也提供了一个查询错误的小工具,为Error Lookup。通过以上的示例,我们就知道其相应的工作原理。在“工具”里可以找到。
这一章开篇介绍了windows函数的几种返回值:VOID,BOOL,HANDLE,PVOID,LONG/DWORD。让我们明白,仅仅通过返回值,我们是不能清楚函数调用为什么会失败的。windows内部,函数检测到错误会采用什么机制呢?它是采用“线程本地存储区”的机制来讲相应的错误代码与“主调线程”关联到一起。它可以使不同的线程能独立运行,不会出现相互干扰对方的错误代码的情况。
错误代码:一个Windows函数返回的错误代码对了解该函数为什么会运行失败常常很有用。Microsoft公司编译了一个所有可能的错误代码的列表(存放在WinError.h头文件中),并且为每个错误代码分配了一个32位的号码;
线程本地存储器:thread-local storage,当一个Windows函数检测到一个错误时,它会使用一个称为线程本地存储器的机制,将相应的错误代码与调用的线程关联起来,这将使线程能够互相独立地运行,而不会影响各自的错误代码;
GetLastError函数:GetLastError函数返回一个32位的错误代码,它主要用于两种情况:1)确定是什么样的错误,此时当Windows函数运行失败时,应该立即调用GetLastError函数,如果调用了另一个Windows函数,它的值很可能被改写;2)搞清楚成功的原因是什么,有些Windows函数之所以能成功运行,其中的原因有很多,比如CreateEvent函数运行成功,既可能是因为你实际创建了该对象,也有可能是因为已经存在带有相同名字的事件内核对象,此时可以调用GetLastError函数可以搞清函数运行成功的原因;
SetLastError函数:SetLastError函数用于设定线程最后的错误代码,这个错误代码既可以是Windows系统自定义的(代码的第29位必须为0),也可以是用户自定义的(代码的第29位必须为1);
FormatMessage函数:FormatMessage函数用于将错误代码转换成它的文本描述;
函数返回的时候,其返回值会指出已发生的一个错误。 我们查看具体是什么错误,在相应的函数执行完成后调用GetLastError()即可。
windows中,错误有三种表示: 一个消息ID(如ERROR_PATH_NOT_FOUND) 消息文本(如the system cannot find the path specified) 一个编号(尽量避免使用)
调试程序的时候,我们可以配置watch窗口,让它始终显示线程的上一个错误代码和错误的文本描述。如$err,hr。hr是要显示错误代码的消息文本。
那么我们怎么在自己的程序中显示消息文本呢?文章介绍了利用FormatMessage函数。这里我也介绍一下这个函数的用法: DWORD FormatMessage( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize, va_list* Arguments );
dwFlags: # FORMAT_MESSAGE_ALLOCATE_BUFFER // 此函数会分配内存以包含描述字串。 # FORMAT_MESSAGE_FROM_SYSTEM, // 在系统的id映射表中寻找描述字串 # FORMAT_MESSAGE_FROM_HMODULE // 在其他资源模块中寻找描述字串 # FORMAT_MESSAGE_FROM_STRING // 消息ID是个字串,不是个DWORD #FORMAT_MESSAGE_IGNORE_INSERTS // 允许我们获得含有%占位符的消息,不传递这个标志,就必须在Arguments参数中提供这些占位符的信息 通常为:FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
lpSource: # 指定了FORMAT_MESSAGE_FROM_HMODULE的话,此参数表示模块的HANDLE # 指定了FORMAT_MESSAGE_FROM_STRING的话,此参数表示id字串 通常为:NULL
dwMessageId: 消息ID;如果指定FORMAT_MESSAGE_FROM_STRING,将被忽略。
dwLanguageId: 消息描述所用的语言 通常为:0表示自动选择
lpBuffer: #如果未指定FORMAT_MESSAGE_ALLOCATE_BUFFER,则为自己提供的缓冲区 #否则为系统LocalAlloc分配,需要被用户LocalFree
nSize: #如果未指定FORMAT_MESSAGE_ALLOCATE_BUFFER,则为自己提供的缓冲区大小 #否则为系统LocalAlloc分配之最小缓冲区大小
Arguments: 通常不使用 代码如下: void ShowError(){ //DWORD dwError = GetLastError(); DWORD dwError = 5L; HLOCAL hlocal = NULL;
// Use the default system locale since we look for Windows messages. // Note: this MAKELANGID combination has 0 as value DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
BOOL fOk = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, dwError, systemLocale, (PTSTR) &hlocal, 0, NULL);
if (!fOk) { // Is it a network-related error? HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL) { fOk = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, hDll, dwError, systemLocale, (PTSTR) &hlocal, 0, NULL); FreeLibrary(hDll); } }
if (fOk && (hlocal != NULL)) { //这个输出可以在VS的“输出窗口”看到 //LocalLock锁定一个本地内存项目 并且 返回一个指向内存块第一个Byte的指针 OutputDebugString((PCTSTR) LocalLock(hlocal)); //这里要把项目属性改为 多字节字符集,不然会出现乱码 cout<<(PCTSTR) LocalLock(hlocal)<<endl; LocalFree(hlocal); }}
visual studio 也提供了一个查询错误的小工具,为Error Lookup。通过以上的示例,我们就知道其相应的工作原理。在“工具”里可以找到。
相关文章推荐
- C++类访问控制及继承
- C++虚析构函数
- struts2与页面交互参数的3种模式
- C\\C++语言杂谈
- C++ 虚函数表解析
- C++ 实现DLL注入(一)实现
- pat-函数编程题5-2(然后是几点)
- python 迭代器(转)
- 程序自我复制(c++)
- 汉诺塔实现程序(C++)
- C#中datagridview使用tooltip控件显示单元格内容的方法
- C++面试笔记--继承和接口
- 转 Python爬虫实战二之爬取百度贴吧帖子
- Eclipse中自动添加注释(作者,时间)
- (转)编码规范系列(一):Eclipse Code Templates设置
- JAVA并发-减少锁的竞争
- java中,MD5加密
- Java的GC的内部原理
- java23种设计模式提纲
- quartz单独使用,不整合spring实例