CTOCIO IT专家网

天极传媒 比特网 | 天极网 | IT专家网 | IT商网 | 52PK游戏网 | 手机天极 | IT分众 |
IT专家网搜索

您现在的位置: IT专家网 > WinSystem子站 > 技巧

XP两种工具在代码中检测并堵塞 GDI 泄漏

作者: Christophe Nasarre ,  出处:微软, 责任编辑: 韩博颖, 
2008-05-20 13:13
  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);
  }
  }
  这意味着还需要有使用 GetObject 的额外测试代码(可能会很长)来获得一个可靠的列表。循环周期使得该方法不可用。本文提供了两种其他的解决方案。第一种方案使用 GDI 管理的句柄表,而第二种方案通过挂钩来自 GDI API 的函数进行工作。值得一提的是,第一种解决方案在未来的 OS 版本中既得不到支持也不能保证具有相同的行为。找到另一种可获得真正 GDI 对象列表的方法是要解决的首要问题。

  对于 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;
  每一项都存储了 GDI 句柄的详细信息,句柄的值很容易计算。它的低 16 位是在表中的索引,其高 16 位保存在 nUpper 字段中。顾名思义,ProcessID 字段包含创建对象的进程 ID。有了这些信息,简单的循环就可以允许您列出某个特定进程正在使用的对象,而这也正是 GDIndicator 所做的事情。
共10页。 9 1 2 3 4 5 6 7 :

网友评论

笔名 
请您注意:遵守国家有关法律、法规,尊重网上道德,承担一切因您的行为而直接或间接引起的法律责任。    IT专家网友拥有管理笔名和留言的一切权利。
  • 周排行榜
  • 月排行榜

邮件订阅

天极服务 | 关于我们 | 网站律师 | 加入我们 | 联系我们 | 广告业务 | 友情链接 | 我要挑错
All Rights Reserved, Copyright 2004-2008, Ctocio.com.cn
渝ICP证B2-20030003号 如有意见请与我们联系 powered by 天极内容管理平台CMS4i