【问题标题】:Is there a way that a HBITMAP can be deleted other than by using DeleteObject()?除了使用 DeleteObject() 之外,还有其他方法可以删除 HBITMAP 吗?
【发布时间】:2018-03-01 18:10:29
【问题描述】:

我正在编写一些代码来帮助跟踪 GDI 泄漏并更好地理解 WINAPI。我通过绕过所有GDI functions 并记录所有列出的句柄的创建和销毁来做到这一点。

原来HBITMAP 是使用CreateDIBitmap() 创建的,而不是使用DeleteObject()(或列出的任何其他销毁函数调用)销毁的,然后稍后某个CreateBitmap() 调用会产生相同的结果处理为前面提到的函数。中间创建了很多HBITMAPs(和其他句柄)。

我只是想知道是否还有其他方法可以销毁文档中未列出的HBITMAP?或者有什么方法可以生成相同的HBITMAP? 有人知道吗?

我有点担心我发现了某种 GDI 损坏。

编辑

只是为了更新,这是我在日志中看到的(这只是一个实例,尚未检查所有其他实例是否相同):

21133 107110:|>使用函数 CreateDIBSection 创建 HBITMAP #707/782 21134 107110:|使用函数 CreateBitmap 创建 HBITMAP #708/783 21136 107125:|使用函数 CreateCompatibleDC 创建 HDC # 16/16 21138 107125:|使用函数 CreateIconIndirect 创建 HICON #35/35 21140 107125:|>使用函数 CreateDIBitmap 创建 HBITMAP #709/784 21141 107125:|使用函数 CreateBitmap 创建 HBITMAP #710/785 21143 107141:|使用函数 CreateCompatibleDC 创建 HDC # 17/17 21145 107141:|使用功能 DeleteDC 破坏 HDC # 17/17 0xD7011ACD 21147 107156:|使用函数 DeleteObject 破坏 HBITMAP # 710/785 0xA9057B85 21150 107156:|使用功能 DeleteDC 破坏 HDC # 16/16 0x5F01466B 21152 107156:|

...一段时间后(大约 9 秒)...

25319 118172:|>使用函数 CreateBitmap 创建 HBITMAP #862/937 25320 118172:|使用函数 CreateCompatibleDC 创建 HDC # 16/16 25322 118172:|使用函数 CreateIconIndirect 创建 HICON #36/36 25324 118172:|>使用函数 CreateDIBitmap 创建 HBITMAP #862/937 25325 118188:|使用函数 CreateBitmap 创建 HBITMAP #863/938 25327 118188:|使用函数 CreateCompatibleDC 创建 HDC # 17/17 25329 118188:|使用功能 DeleteDC 破坏 HDC # 17/17 0xD9015812 25331 118188:|使用函数 DeleteObject 破坏 HBITMAP # 863/938 0x9605596F 25334 118219:|
  • 第一列是序列计数(在尝试对多个线程中的事件序列进行排序时很有用)。
  • 第二个是从第一个日志项开始的时间,以毫秒为单位。
  • :spaces| 是一个可视化图表,用于查看相对于我正在查看的所有调用而言,调用的嵌套程度。
  • > 表示刚进入函数之前,< 表示刚离开函数之后。
  • 然后它说明是创建还是销毁以及正在创建或销毁什么对象。
  • x/y 其中x 是那些即将被创建的对象的数量或者被销毁后还存在的数量,和y 是一样的,只是它代表基类型(被删除的类型) )。
  • 十六进制数是句柄值
  • 然后是用于创建/销毁对象的函数
  • 如果该行以* 结尾,则表示此句柄之前已发出但尚未销毁。

其中有多少信息以及嵌套是如何工作的(非常适合跟踪窗口消息),这有点有趣。

我注意到的另一件事是:

25349 118250: |> 使用 DestroyIcon 函数破坏 HICON # 36/36 0x087718AD 25350 118250:|

HICON 被销毁,但包含的 HBITMAPs 不会,并且它们不会在日志中的任何地方再次引用(除非它们被意外回收)。因此,如果这只发生在HICONs 上,那么可能是DestroyIcon() 表现不佳并且正在使用一些未记录的功能。我必须调查其余的日志。

【问题讨论】:

  • 我认为您观察到的是 Windows 操作系统的一些句柄缓存功能。
  • @VuVirt,以及它是如何工作的。这些不是命名对象。它如何确定应该使用 same 句柄?
  • HGDIOBJ 不是地址(意味着不唯一),而是某个有限大小表中的插槽索引。所以从技术上讲,当该表溢出时,您可以获得相同的 HGDIOBJ 值。
  • @c-smile,但这会导致错误,这很糟糕。只有当任何预先存在的句柄被破坏时,才应创建相同的句柄。
  • 可能是因为您只绕开了公开可用的 GDI 功能?我敢打赌,内部使用了一堆未记录的 API。例如DestroyIcon 是否调用DeleteObject 或其他方法来处理图标位图?

标签: winapi


【解决方案1】:

好的。仔细查看日志,并用GetGuiResources() 记录周围有多少GDI 对象,似乎在创建HICON 时创建了HBITMAPs。但是,DestroyIcon() 函数在销毁它们时会绕过 DestoryObject() 函数调用。

我猜 MS 有人想通过这样做来节省几个周期?随便。

不过,这是一个有趣的练习,而且日志记录似乎工作得很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-08
    • 2019-09-14
    • 2017-07-18
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    相关资源
    最近更新 更多