• CreateSolidBrush (GDI32) - how to "cache" it ?

    From R.Wieser@21:1/5 to All on Sat Apr 3 10:25:29 2021
    Hello all,

    I'm currently playing around with giving a dialog different colors than the standard one, and have ran into a bit of a problem:

    I want to mix using the results of CreateSolidBrush and GetSysColorBrush.
    The thing is that while the latter handles do need to be deleted, the former ones must be (otherwise GDI resource leakage will occur).

    While calling DeleteObject on a GetSysColorBrush handle doesn't do anything, accidentily prematurily deleting a CreateSolidBrush handle causes "bad
    things" to happen.

    So:

    tl;dr:

    I would like to cache (lock?) my CreateSolidBrush handle just like the GetSysColorBrush handle is said to be. How do I do that ?

    Regards,
    Rudy Wieser

    P.s.
    I tried to take a peek into the CreateSolidBrush result handle (in an
    attempt to compare the cached and non-cached brush in search for a "lock"
    bit), but alas, it seems to be stored somewhere where I am not allowed to
    even look at it ....

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Sat Apr 3 22:27:49 2021
    On Sat, 3 Apr 2021 10:25:29 +0200, R.Wieser wrote:
    Hello all,

    I'm currently playing around with giving a dialog different colors than the standard one, and have ran into a bit of a problem:

    I want to mix using the results of CreateSolidBrush and GetSysColorBrush.
    The thing is that while the latter handles do need to be deleted, the former ones must be (otherwise GDI resource leakage will occur).

    While calling DeleteObject on a GetSysColorBrush handle doesn't do anything, accidentily prematurily deleting a CreateSolidBrush handle causes "bad things" to happen.

    So:

    tl;dr:

    I would like to cache (lock?) my CreateSolidBrush handle just like the GetSysColorBrush handle is said to be. How do I do that ?

    Regards,
    Rudy Wieser

    P.s.
    I tried to take a peek into the CreateSolidBrush result handle (in an
    attempt to compare the cached and non-cached brush in search for a "lock" bit), but alas, it seems to be stored somewhere where I am not allowed to even look at it ....

    There's no way to lock GDI handles. You'll just have to conditionally delete the handles, or create a new brush with the same color as the system brush.

    The statement that system color brush handles must not be deleted, only
    applies to early Windows 95. Here's the last paragraph of the Remarks
    section of the GetSysColorBrush in different SDK dicumentation versions.

    Windows 95 SDK:
    "An application must not register a window class for a window using a system brush."

    MSDN Library 2008:
    "System color brushes are owned by the system and must not be destroyed."

    MSDN website:
    "System color brushes are owned by the system so you don't need to destroy them. Although you don't need to delete the logical brush that
    GetSysColorBrush returns, no harm occurs by calling DeleteObject."

    Notice the significant change of the statement in MSDN Library 2008. It no longer state about window class registration. Meaning that Microsoft has
    added some protection to allow the system color brush to be used with window class registration. And in current MSDN website, it states that it's OK to delete system color brushes. Meaning that more protection has been added.

    I have no Windows 95 to test with, but in Windows 98, Windows 2000, and
    newer versions, the system won't delete system color brush handles. DeleteObject() will give a success report, but it won't produce any effect.

    System brush handles and probably other system GDI handles also, are part of the system. They're not listed in the process' GDI handles list within the process TEB (check with Nirsoft GDIView). Processes will see the system GDI handles as if they're predefined handles. FYI, the handle values are
    identical across different process - both 32-bit and 64-bit.

    When I debug DeleteObject(), the kernel function for deleting GDI objects
    seems to be responsible for protecting the system GDI objects. But DeleteObject() is the one which protects stock objects.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Sat Apr 3 18:49:19 2021
    JJ,

    There's no way to lock GDI handles.

    Damn!

    You'll just have to conditionally delete the handles, or create
    a new brush with the same color as the system brush.

    Creating multiple copies of the same brush is what I'm trying to evade.
    And it wouldn't really solve the problem either :

    I intend to use a single brush at different places (including as the
    background of controls placed on the dialog), but still want to be able to replace the brush at some places with another. (example : WM_CTLCOLORDLG)

    After such a replacement should or should I call DeleteObject on the
    returned old brush ? If I don't I could get a resource leak, if I do
    other places may suddenly lose their brush ... Catch22 :-(

    "System color brushes are owned by the system so you don't
    need to destroy them. Although you don't need to delete the
    logical brush that GetSysColorBrush returns, no harm occurs
    by calling DeleteObject."

    Thats the info I'm currently working with/by.

    They're not listed in the process' GDI handles list within the
    process TEB (check with Nirsoft GDIView).

    Thanks for the GDIView suggestion. Might come in handly as a resource-leak viewer.

    But DeleteObject() is the one which protects stock objects.

    Does it ? I wonder ...

    The best way to "protect" something is just not to give it to the one who
    can trash it. In the above case I could imagine that DeleteObject simply doesn't get the list of stock objects, meaning that it can't find the to-be-deleted object and thus doesn't do anything.

    Than again, I was hoping I would be able to find a "don't delete" flag in
    the object itself - which certainly does need the cooperation of
    DeleteObject.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Sun Apr 4 22:07:52 2021
    JJ,

    DeleteObject() at least, actively protects them. The kernel function
    may or may not protect them. I don't bother to check because
    debugging the kernel is a pain in Windows NT.

    Thanks for the explanation.

    Though I'll probably still try what I should have done in the first place : disassemble that function and see what I can learn from it. :-)

    Even if there is such flag, it would be within the internal data structure
    of the GDI object. But in Windows NT, GDI object's data is within the
    kernel address space. So, there's no way to reach it from the user mode application without custom driver, or without undocumented function (if
    there is any).

    I noticed. :-\ Than again, I just tried to use the handle as a memory pointer. Maybe looking at the disassembly of the function will shed a bit more light on it.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Mon Apr 5 02:22:20 2021
    On Sat, 3 Apr 2021 18:49:19 +0200, R.Wieser wrote:
    But DeleteObject() is the one which protects stock objects.

    Does it ? I wonder ...

    DeleteObject() at least, actively protects them. The kernel function may or
    may not protect them. I don't bother to check because debugging the kernel
    is a pain in Windows NT.

    In the above case I could imagine that DeleteObject simply
    doesn't get the list of stock objects, meaning that it can't find the to-be-deleted object and thus doesn't do anything.

    Apparently, DeleteObject() can actually detect whether a handle is a stock object or not. The detection is not based on whether the handle is in the process TEB or not. Because if it is, system GDI objects would be detected
    too. But they don't. When system GDI handle is passed to DeleteObject(), DeleteObject() will pass it to the kernel function. This doesn't apply if
    the handle is a stock object.

    Than again, I was hoping I would be able to find a "don't delete" flag in
    the object itself - which certainly does need the cooperation of DeleteObject.

    Even if there is such flag, it would be within the internal data structure
    of the GDI object. But in Windows NT, GDI object's data is within the kernel address space. So, there's no way to reach it from the user mode application without custom driver, or without undocumented function (if there is any).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to You on Fri Apr 9 10:16:16 2021
    JJ,

    You wrote a few days ago :

    They're not listed in the process' GDI handles list within the
    process TEB (check with Nirsoft GDIView).

    FYI:

    While disassembling DeleteObject I found the GDI object array (all 65536 of them), and was allowed to read them (already tried writing, but was not
    allowed :-) ).

    Retrieving all GDI object records of the current process is rather easy, as
    the process id is stored at offset 4. As you can recreate the GDI object handle from that record its also easy to show the objects type.

    And just now I found the functions to retrieve the above GDI object array (GdiQueryTable) and the one which seems to recreate the GDI object handle (GdiFixUpHandle).

    IOW, at least under XPsp3 * writing a simple "leakage" detector falls under
    the possibilities.

    *As I (unknowingly, still) used an old gdi32.lib I found out that W98se
    doesn't seem to have the GdiQueryTable function - or at least not by that
    name.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)