您现在的位置: IT专家网 > WinSystem子站 > 技巧
XP两种工具在代码中检测并堵塞 GDI 泄漏
Windows 需要一种不太相同的 GDI 泄漏方法,他构建并说明了两种工具,这两种工具旨在检测并消除在 Windows XP、Windows 2000 和 Windows NT 上运行的应用程序中的 GDI 泄漏。
接着,在新的 DLL 需要修补时调用 FillStubs。用 APIR STATE ENABLE 作为参数,DoReflect调用 FillStubs。它将由模块进行的每个系统调用 (GetDC) 重定向到相应的静态存根方法(本示例中为 _GetDC),而模块的加载地址作为参数被传递。该方法遵循与 MFC 消息映射相同的模式:
| BEGIN_IMPLEMENT_API_REFLECT() ••• IMPLEMENT_API_REFLECT(hModule, "USER32.DLL", GetDC); ••• END_IMPLEMENT_API_REFLECT() |
现在有了 CGDIReflect 类,它允许您将由特定模块发出的任一调用重定向到存根方法,该方法的唯一作用是将新建的 GDI 对象存储到映射中。但是该实现有一个缺陷 — 它不是线程安全的。如果您需要检查的应用程序是多线程的,几个线程都在调用 GDI 函数,产生的行为可能不确定,因为跨线程访问句柄映射是不同步的。
利用堆栈跟踪监视分配
每次对重要函数的调用 都终止于一个存根,该存根完成两项操作。第一项是将分配的句柄及其类型包装到 GDIReflect.h 中声明的一个 CHandleInfo 对象中。第二项操作更有趣。在 CHandleInfo 对象中,当前调用堆栈的每个函数地址都存储在 m_pStack 中 — 分配的 DWORDs 数组 — 而 m_pStack 中保存的地址数保存在 m Depth 中。因此,除了以图形方式表示 GDI 对象外,还可能显示导致分配特定 GDI 对象的函数调用堆栈,如图 4 所示。

图 4 导致分配对象的单元
当需要浏览堆栈时,imagehlp.dll 和 dbghelp.dll 是您最好的朋友。为了便于您的使用,John Robbins 已经将该引擎包装到了 CSymbolEngine 类中,该类的发展历程在 1998 年 4 月和 1999 年 2 月的 MSJ Bugslayer 专栏中有所介绍。在 John Robbins 的 Debugging Applications 一书中详细地介绍了使用了 DBGHELP 的最后一个版本,该书我在前面提到过。
CSymbolEngine 类是一个在由 DBGHELP 导出的许多函数顶部的低级层。StackManager.cpp(位于本文顶部链接处代码下载中的 /Common 目录内)中实现的 CstackManager 提供了只有三个有趣方法的更高级功能。第一个是 DoStackAddressDump,它利用 CSymbolEngine 分配并填充一组当前的调用堆栈。该方法由每个存根调用,并存储导致对象分配的每个函数地址。
十六进制地址对计算机有好处,但对人没什么好处。为了将由 DoStackAddressDump 返回的地址数组转换为可读的格式,必需调用 DumpStackAllocation。该方法接受堆栈转储及其深度,然后在一个 CString 中返回转换后的堆栈。该方法的调用方能够选择他希望在每个地址间使用的行分隔符,要么是选择 \r\n 在编辑框中显示 CString,要么是选择 \n,利用 Trace 或 OutputDebugString简单地将其进行记录。该方法背后并没有什么魔法,对于给定数组中的每个地址,它都调用 ConvertStackAddressIntoFunctionName。
- 本文关键词:
- API
- IT技术
- Windows
- Windows XP
- 操作系统

