您现在的位置: IT专家网 > WinSystem子站 > 技巧
XP两种工具在代码中检测并堵塞 GDI 泄漏
Windows 需要一种不太相同的 GDI 泄漏方法,他构建并说明了两种工具,这两种工具旨在检测并消除在 Windows XP、Windows 2000 和 Windows NT 上运行的应用程序中的 GDI 泄漏。
Windows 9x 与 Windows XP
对于 Windows XP,一系列 GDI 对象均与各个进程相关,大部分由 win32k.sys 按内核模式进行托管,设备驱动程序负责 USER 和 GDI 实现。Win32 应用程序通过由 user32.dll 和 gdi32.dll 提供的 API 调用这些系统服务。因为 Windows 基于每个进程保留了 GDI 对象的记录,所以只有创建了 GDI 对象的应用程序能够使用该对象对应的 GDI 函数。
Windows 9x 版本的 GDIUsage 使用 GetObjectType API 函数,该函数提供给定句柄值的 GDI 对象的类型,以检查某个随机值是否是个有效的 GDI 句柄。然而,与 Windows 9x 不同,Windows XP GDI 对象句柄完全是个 32 位的值。其可能的范围是从 0 到 0xFFFFFFFF,为了列出所有真实的 GDI 对象,各个可能的句柄值都需提供给 GetObjectType。这就造成了实际的性能问题。下列代码需要几分钟来执行,遗憾的是,很多通过运行测试应用程序检测到的 GDI 对象都不是真的(其中有 500 多个!):
| DWORD dwObjectType; DWORD hGdi; for (hGdi = 0; hGdi < 0xFFFFFFFF; hGdi++) { dwObjectType = ::GetObjectType((HANDLE)hGdi); if (dwObjectType != 0) { TRACE("0x%08x -> %u\n", hGdi, dwObjectType); } } |
对于 Windows 9x 的 GDIUsage,有可能利用对应于每个 GDI 对象类型(如位图的 BitBlt 或画笔的 FillRect)的函数来显示 GDI 对象。但是由于当利用由另一个进程创建的 GDI 对象来调用这些 API 函数时会失败,我所开发的工具的主要功能(即能够“看到”正在泄漏的资源)消失了。另一方面,显示的代码在创建 GDI 对象的应用程序中运行正常。解决方案是显而易见的 — 显示引擎必须运行于其他进程的上下文中。本文的稍后部分将讲述一种基于将 Windows 挂钩作为进程间通信机制的实现。
最后,用 Win32 调试 API 将这些方法结合起来,因此,就获得了可以运行于 Windows XP 和其他 32 位 Windows 平台上的 GDIUsage 版本的实现。
GDI 如何管理句柄
在我 2002 年 8 月 的文章中,WinDBG 用来说明进程环境块 (PEB) 结构。在那篇文章中,GdiSharedHandleTable 字段应引起您的注意。事实上,这是一个指向表的指针,其中 GDI 存储了它的句柄,甚至那些由其他进程创建的句柄。在他撰写的 Windows Graphics Programming:Win32 GDI and DirectDraw (Prentice Hall,2002 年)一书中,Feng Huan 提供了另一种访问该表的方法,但他也描述了该表中每个 0x4000 项的结构,如下所示:
| typedef struct { DWORD pKernelInfo; // 2000/XP layout but these fields are inverted in Windows NT WORD ProcessID; WORD _nCount; WORD nUpper; WORD nType; DWORD pUserInfo; } GDITableEntry; |
- 本文关键词:
- API
- IT技术
- Windows
- Windows XP
- 操作系统

