分类 调试 下的文章

简介

DBG_TERMINATE_PROCESS表示进程被调试器终止。值为0x40010004。其定义如下:

//
// MessageId: DBG_TERMINATE_PROCESS
//
// MessageText:
//
// Debugger terminated process.
//
#define DBG_TERMINATE_PROCESS            ((NTSTATUS)0x40010004L)    // winnt

说明

当调试器附加到应用程序然后终止它时,将出现此退出代码。

实际上,最有可能是由于系统关闭。 Windows关闭时,它将尝试正常退出正在运行的程序。如果它们拒绝退出,它们可能会被系统以退出代码 0x40010004 终止。例如,如果您有一个显示模式对话框的GUI程序,然后尝试关闭系统,则系统将提示您 xy.exe阻止了关闭。如果单击强制关闭,则该进程将被退出,退出代码为 0x40010004

这时软件拿到的是 ExitCode 是 1073807364 (0x40010004) 这个值相当于 -1073741510 (0xc000013a) 表示应用程序是在系统关闭的时候关闭,或者软件收到了 ctrl+C 或 ctrl+Break 关闭。

通过《Win32 Error》、《COM Error---HRESULT》和《NTSTATUS》等我们知道了一些win32错误基础知识,下面我们说点其他的东西。

1、GetLastError()返回一个winapi错误代码.从1开始的简单数字.它们通常从底层本机api错误代码映射。Winapi错误代码在WinError.h SDK头文件中声明.您可以指望使用FORMAT_MESSAGE_FROM_SYSTEM选项从FormatMessage()获取描述性字符串。

2、HRESULT是COM错误代码.它由三个基本部分构成,高位表示严重性,中间位编码指示错误源的工具,低16位编码错误编号.HRESULT_FROM_WIN32()宏是一个帮助宏,用于将winapi错误代码映射到COM错误代码.它只将严重性设置为"失败",设施代码设置为7(winapi)并将错误代码复制到低位.有许多可能的COM错误代码,并且只有少数可以通过FormatMessage()转换为字符串.您应该使用ISupportErrorInfo接口来询问COM服务器是否可以通过IErrorInfo提供错误的描述。

3、内核和Native API则一般使用NTSTATUS类型的错误码。它们记录在ntstatus.h SDK标头中.winapi应该包装原生api。FormatMessage()可以将常用的转换为字符串,只要它不是驱动程序生成的自定义错误代码即可.有几种api使用这些错误代码,即使它们在用户模式下运行,获取此类错误代码的字符串需要使用FormatMessage和FORMAT_MESSAGE_FROM_HMODULE选项。

另外,这三者之间是可以相互转换的:

GetLastError->HRESULT: HRESULT_FROM_WIN32
NTSTATUS -> Win32:LsaNtStatusToWinError()
NTSTATUS -> HRESULT:HRESULT_FROM_WIN32( LsaNtStatusToWinError())

还有其他一些全局的函数可以帮到我们:

名称说明
AtlHresultFromLastError 以 HRESULT 的形式返回 GetLastError 错误代码。
AtlHresultFromWin32 将 Win32 错误代码转换为 HRESULT。
AtlReportError 设置 IErrorInfo 可向客户端提供错误详细信息。
AtlThrow 引发 CAtlException
AtlThrowLastWin32 调用此函数可根据 Windows 函数 GetLastError 的结果发出错误。


 

系统API或COM调用,会产生错误。设置一个错误代码,可以由GetLastError检索。有几种方法可以破译此代码:

  • 使用命令行 net helpmsg
  • 从VS菜单中,选择工具/错误查找并粘贴代码
  • 在VS的监视窗口上输入“$err,hr”!
  • 在VS的监视窗口上输入 *(int*)(@tib+0x34),hr 

其实最后两种方法是一样的。

当我们的程序出了问题,想要观察程序的执行过程,这时有两种进入调试的方式:

  • 附加到进程
  • 调试器启动进程

这是我们常用的两种方式,那么有什么差别呢?有差别,今天我就谈一点:那就是堆内存的不同。通过附加到进程的方式(排除用其他工具做了设置)内存是标准堆;而直接用调试器启动的方式内存是系统调试堆。

我们用Windbg来观察一下

直接启动进程

看到,直接启动进程进行调试,堆内存被做了很多设置:htc、hfc、hpc等

而附加的方式如下

可见少了很多设置项。

通过上面的差别,我们就明白了两种方式的同步。由于调试堆或多或少会影响性能,如果我们想不管哪种方式都想用标准堆,可以做如下设置:

  • 在系统环境变量里设置_NO_DEBUG_HEAP=1(这个是系统全局性,对任何调试器都可以禁止)
  • 如果是Windbg,可以在命令行使用 -hd选项
  • 如果是VS IDE,可以在项目属性里设置环境变量_NO_DEBUG_HEAP=1
    这个在VS2015以前的版本是管用的,2015及其以后的版本不需要了,已经自动禁止了