【发布时间】: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