春暖花开
雪化了,花开了,春天来了
posts - 149,comments - 125,trackbacks - 0

      过年前,从china-pub买的。一直也没有安下心来读。看今年找工作的境况,也不得不抓把紧了。也愿与c++博客的各位朋友分享我的学习心得。
       步入主题。

         这一章开篇介绍了windows函数的几种返回值:VOID,BOOL,HANDLE,PVOID,LONG/DWORD。让我们明白,仅仅通过返回值,我们是不能清楚函数调用为什么会失败的。

         windows内部,函数检测到错误会采用什么机制呢?它是采用“线程本地存储区”的机制来讲相应的错误代码与“主调线程”关联到一起。它可以使不同的线程能独立运行,不会出现相互干扰对方的错误代码的情况。

         函数返回的时候,其返回值会指出已发生的一个错误。

         我们查看具体是什么错误,在相应的函数执行完成后调用GetLastError()即可。

         windows中,错误有三种表示:
         一个消息ID(如ERROR_PATH_NOT_FOUND)
            消息文本(如the system cannot find the path specified)
         一个编号(尽量避免使用)

         调试程序的时候,我们可以配置watch窗口,让它始终显示线程的上一个错误代码和错误的文本描述。如$err,hr。hr是要显示错误代码的消息文本。不过我在windows mobile的环境下没有成功,没有弄清楚为什么。

         那么我们怎么在自己的程序中显示消息文本呢?文章介绍了利用FormatMessage函数。这里我也介绍一下这个函数的用法:
         (下面的介绍摘自:http://www.cppblog.com/bidepan2023/archive/2008/02/03/42433.html
         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();

    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))
    
{
        OutputDebugString((PCTSTR) LocalLock(hlocal));
        LocalFree(hlocal);
    }

}



      这个是书中的例子的代码,我只是将它归结为了一个函数ErrorShow。这样我们在一个函数的后面调用,直接可以知道错误的原因。不过环境我是在smart device 的DEBUG环境下调时的,OutputDebugString会输出相应的字符串。

      这个例子中同时展示了FormatMessage的两种用法。观察一下第二个参数就明白了。

      visual studio 也提供了一个查询错误的小工具,为Error Lookup。通过以上的示例,我们就知道其相应的工作原理呢。

      这本书的源码的下载地址:http://wintellect.com/Books.aspx 
      大家如果对windows 编程感兴趣的话,不妨下来看看。

posted on 2009-02-20 00:24 Sandy 阅读(2233) 评论(4)  编辑 收藏 引用 所属分类: windows学习

FeedBack:
# re: Windows核心编程:第一章错误处理学习笔记
2009-02-23 16:25 | 深邃者
不错 我也再看这本书 看到第七章了 可以一起讨论 呵呵  回复  更多评论
  
# re: Windows核心编程:第一章错误处理学习笔记
2009-02-24 09:30 | Sandy
@深邃者
呵呵,好.一起研究
  回复  更多评论
  
# re: Windows核心编程:第一章错误处理学习笔记
2009-03-11 19:46 | 凤凰羽翼
您好,我也是看了核心编程,有个小问题,就是输出的时候为什么要用localLock呢,我不用的话也可以输出啊。
另:你也毕业生?  回复  更多评论
  
# re: Windows核心编程:第一章错误处理学习笔记
2009-03-12 10:19 | Sandy
@凤凰羽翼
这个我也是看例子这么写的。你这么一说,我还专门查了一下。
http://www.cic.tsinghua.edu.cn/jdx/book4/dlz.htm
中提到加锁与解锁,它是这样说的 :
“不管是可移动对象还是可删除对象,在它分配后其内存句柄是不变的,它是内存对象的恒定引用。但是,应用程序无法通过内存句柄直接存取内存对象,应用程序要存取内存对象还必须获得它的近地址,这通过调用LocalLock函数实现。LocalLock函数将局部内存对象暂时固定在局部堆的某一位置,并返回该地址的近地址值,此地址可供应用程序存取内存对象使用,它在应用程序调用 LocalUnlock函数解锁此内存对象之前有效。”

它的例子如果这样用的话,那么在
FormatMessage中调用系统LocalAlloc分配,需要对内存对象进行加锁与解锁。

呵呵,这只是我的理解而已。

另:你也毕业生?
对啊,不过我明年才会毕业呢!  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理