您现在的位置: IT专家网 > WinSystem子站 > 技巧
XP两种工具在代码中检测并堵塞 GDI 泄漏
Windows 需要一种不太相同的 GDI 泄漏方法,他构建并说明了两种工具,这两种工具旨在检测并消除在 Windows XP、Windows 2000 和 Windows NT 上运行的应用程序中的 GDI 泄漏。
如果您有兴趣了解获得运行进程列表的不同方法,您可以阅读我在 2002 年 6 月一期上发表的文章。每个进程都有一个 ID,用来从共享的表中收集该进程使用的 GDI 对象,并利用 ProcessID 字段进行比较。得到的计数值显示在每个对象类型列下的 GDIndicator 中。
与其他列不同,第三列显示两个值。第一个值是调用 GetGuiResources 的结果(这应该返回该进程使用的 GUI 对象句柄的计数值),第二个加括号的值是在解析 GDI 句柄共享表的过程中得到的和。您可以在图 3 中看到,这两个值通常是不同的,而 GetGuiResources 总是返回较大的计数值。没有文献说明这种不同的原因,与常用对象或未发布对象也没有什么明显的关系。有可能是在您背后分配给 GDI 没有存储在共享表中的对象,因此是您没有涉及的对象。
这种隐藏分配的一个例子发生在图标操作的过程中。当您创建或加载某个图标时,Windows 需要多个位图来实现透明效果。通常一个用于掩码,一个用于可视图形。与位图不同,图标由 USER 系统组件来处理,而不是由 GDI 来处理。这可能就是当调用 GetGuiResources 来了解 GDI 的使用情况时 GetGuiResources 背后的代码好像没有跟踪这些分配的原因。
通过 API 挂钩来跟踪对象分配
您已经看到,要了解特定的过程使用哪些 GDI 对象并不容易。怎样才能知道对象是否已由应用程序代码或背后的 GDI 自身加以分配呢?如果创建 GDI 对象时 Windows 能够通知您,那么就很容易存储它的句柄值并构建由应用程序分配的对象列表。遗憾的是,Win32 API 并没有为开发人员提供这种通知机制。
如果您想知道何时创建了新对象,必须了解列出的函数调用。
幸运的是,在作者的文章“Learn System-Level Win32 Coding Techniques by Writing an API Spy Program”中(发表于 1994 年 12 月一期的 MSJ),Matt Pietrek 说明了如何编写 Win32 领域的 API 侦探引擎。给定一个特定模块(进程或 DLL),该引擎可以用您自己的函数地址替换被调用函数(由 DLL 导出)的地址。一旦执行了这种替换,每次被侦探的模块调用一个挂钩函数时,将在其所在位置执行您自己的句柄。
该 API 挂钩原则已经过多年的改进(参见 1998 年 2 月和 1999 年 6 月期 MSJ 的 John Robbins Bugslayer 专栏。)如果您需要了解不同 Windows 平台的可能实现,应该阅读 Jeffrey Richter 的 Programming Applications For Microsoft Windows Fourth Edition“(Microsoft® 出版社,1999 年)一书的第 22 章,以及 John Robbins 的 Debugging Applications(Microsoft 出版社,2000 年)一书。这里我使用了 John Robbins 的方法。

图 2 调用 GetDC 的内存布局
John 的 HookImportedFunctionsByName helper 函数接受修补函数列表、导出它们的系统 DLL 的加载地址、调用被修补函数的模块,以及要重新定向到的存根列表。关于退出,它填充了包含所有被修补函数地址的列表。例如,如果 App.exe 正从 USSER32.DLL 调用 GetDC,则您将得到如图 2 所示的内存布局。如果我用下面的输入参数调用 HookImportedFunctionsByName,它将产生如图 3 所示的不同布局。
•系统修补函数列表 (GetDC)
•导出函数的 DLL 的地址 (USER32.dll)
•模块调用(App.exe 直接调用 GetDC)
•修补函数的列表(来自于 Hook.dll 的 GetDC)
- 本文关键词:
- API
- IT技术
- Windows
- Windows XP
- 操作系统

