I am writing some code to help track GDI leaks and understand the WINAPI better. I'm doing this by detouring all of the GDI functions and logging the creation and destruction of all of the handles listed.
Turns out that a HBITMAP
is being created using CreateDIBitmap()
and is not destroyed using DeleteObject()
(or any of the other destruction function calls listed), and then sometime later a CreateBitmap()
call results in the same handle as the previously mentioned function. There are a lot of HBITMAP
s (and other handles) created in between.
I'm just wondering if there is some other way to destroy a HBITMAP
that isn't listed in the documentation? Or is there some way to generate the same HBITMAP
?
Does anybody know?
I'm a little worried that I found some sort of GDI corruption.
Edit
Just for an update, here is what I am seeing in my logs (this is only one instance, haven't checked if all other instances are the same):
21133 107110: |>Creating HBITMAP # 707/782 with function CreateDIBSection 21134 107110: |<Created HBITMAP # 707/782 0xAC057A00 with function CreateDIBSection 21135 107125: |>Creating HBITMAP # 708/783 with function CreateBitmap 21136 107125: |<Created HBITMAP # 708/783 0xA9057B85 with function CreateBitmap 21137 107125: |>Creating HDC # 16/16 with function CreateCompatibleDC 21138 107125: |<Created HDC # 16/16 0x5F01466B with function CreateCompatibleDC 21139 107125: |>Creating HICON # 35/35 with function CreateIconIndirect 21140 107125: |>Creating HBITMAP # 709/784 with function CreateDIBitmap 21141 107125: |<Created HBITMAP # 709/784 0x67055812 with function CreateDIBitmap 21142 107141: |>Creating HBITMAP # 710/785 with function CreateBitmap 21143 107141: |<Created HBITMAP # 710/785 0x9605596F with function CreateBitmap 21144 107141: |>Creating HDC # 17/17 with function CreateCompatibleDC 21145 107141: |<Created HDC # 17/17 0xD7011ACD with function CreateCompatibleDC 21146 107141: |>Destroying HDC # 17/17 0xD7011ACD with function DeleteDC 21147 107156: |<Destroyed handle 0xD7011ACD with function DeleteDC 21148 107156: |<Created HICON # 35/35 0x653526D3 with function CreateIconIndirect 21149 107156: |>Destroying HBITMAP # 710/785 0xA9057B85 with function DeleteObject 21150 107156: |<Destroyed handle 0xA9057B85 with function DeleteObject 21151 107156: |>Destroying HDC # 16/16 0x5F01466B with function DeleteDC 21152 107156: |<Destroyed handle 0x5F01466B with function DeleteDC
...and some time later (about 9 seconds)...
25319 118172: |>Creating HBITMAP # 862/937 with function CreateBitmap 25320 118172: |<Created HBITMAP # 862/937 0x9605596F with function CreateBitmap * 25321 118172: |>Creating HDC # 16/16 with function CreateCompatibleDC 25322 118172: |<Created HDC # 16/16 0x39013C5B with function CreateCompatibleDC 25323 118172: |>Creating HICON # 36/36 with function CreateIconIndirect 25324 118172: |>Creating HBITMAP # 862/937 with function CreateDIBitmap 25325 118188: |<Created HBITMAP # 862/937 0x27056374 with function CreateDIBitmap 25326 118188: |>Creating HBITMAP # 863/938 with function CreateBitmap 25327 118188: |<Created HBITMAP # 863/938 0xD20538B5 with function CreateBitmap 25328 118188: |>Creating HDC # 17/17 with function CreateCompatibleDC 25329 118188: |<Created HDC # 17/17 0xD9015812 with function CreateCompatibleDC 25330 118188: |>Destroying HDC # 17/17 0xD9015812 with function DeleteDC 25331 118188: |<Destroyed handle 0xD9015812 with function DeleteDC 25332 118203: |<Created HICON # 36/36 0x087718AD with function CreateIconIndirect 25333 118203: |>Destroying HBITMAP # 863/938 0x9605596F with function DeleteObject 25334 118219: |<Destroyed handle 0x9605596F with function DeleteObject
- The 1st column is the sequence count (useful when trying to order the sequence of events in multiple threads).
- The 2nd is the time in ms from the first log item.
- The
:
spaces
|
is a visual graph to see how far the calls are nested, relative to all of the ones I'm looking at. - The
>
represents just before going into the function, and the<
represents just after leaving the function. - Then it states if creating or destroying and what object is being created or destroyed.
x/y
wherex
is the number of those objects that are about to be created or the remaining number that exist after being destroyed, andy
is the same thing, except it represents the base type (the type that is deleted).- The hex number is the handle value
- Then the function used to create/destroy the object
- If the line ends in a
*
it means that this handle has been given out before but hasn't been destroyed.
It's kind of interesting how much information is there and how the nesting works (really great for tracking window messages).
One other thing I noticed was this:
25349 118250: |>Destroying HICON # 36/36 0x087718AD with function DestroyIcon 25350 118250: |<Destroyed handle 0x087718AD with function DestroyIcon
The HICON
gets destroyed, but the contained HBITMAP
s don't, and they aren't referenced again anywhere in the logs (except when they are unexpectedly recycled). So, if this only occurs for HICON
s, then it could be that DestroyIcon()
isn't playing nice and is using some undocumented function. I'll have to investigate the rest of the logs.
DestroyIcon
callDeleteObject
or some other method to dispose of icon bitmaps? – user7860670