Results 1 to 31 of 31

Thread: Hitting GDI Count

  1. #1

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Hitting GDI Count

    I have a VB6 application that after a couple of days of continual running exceeds the GDI count and fails, I have increased the gdiprocesshandlequota to 65,536 and this makes the program run for longer but again fails, I have worked out it is do with the same picture that we are continualy showing, doing a test program, the GDI count increases whe doing


    For x = 1 To 100
    arrow.Picture = frmMycroftImages.imgSort.ListImages("iAcceptArrow").Picture
    Next

    But does not decrease when clearing

    For x = 1 To 100
    arrow.Picture = Nothing
    arrow.Cls
    arrow.Refresh
    Next

    Any ideas how can get the GDI count to go back down

  2. #2
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,998

    Re: Hitting GDI Count

    The last loop is pointless because you are destroying the same object over and over.

    Are you sure there is not additional code in the first loop causing the GDI leak?
    Because also in the first loop you are reusing the same picture object over and over

  3. #3

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    The second loop is called from button to see if GDI count goes down, yes am displayinfg the same picture multiple times so put in a loop on a test pogram to see if the GDI count goes up and down, it goes up on the first loop, but not down on the second loop

  4. #4
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,998

    Re: Hitting GDI Count

    What if you destroy the picture object first before assigning a new object?
    Code:
    For x = 1 To 100
      Set arrow.Picture = Nothing
      arrow.Picture = frmMycroftImages.imgSort.ListImages("iAcceptArrow").Picture
    Next

  5. #5
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,230

    Re: Hitting GDI Count

    Post a complete ZIP with stubbed project demonstarting the GDI leak for anyone to make advises or to find workarounds.

    Currently your question is non-actionable. Yes, we know it's possible to leak GDI objects and apps tend to fail after non-stop work for couple of days in this case.

    cheers,
    </wqw>

  6. #6

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    Attachment 191003

    Have now added code to display the GDI count, before the picture, after the picture and clear, the clear is increasing the GDI Count

    Private Declare Function GetGuiResources Lib "user32" (ByVal hProcess As Long, ByVal uiFlags As Long) As Long
    Private Declare Function GetCurrentProcess Lib "kernel32" () As Long

    Private Const GR_GDIOBJECTS = 0
    Private Const GR_USEROBJECTS = 1

    Private Sub Command1_Click()
    For x = 1 To 100
    arrow = Nothing
    arrow.Picture = Nothing
    arrow.Cls
    arrow.Refresh
    DoEvents
    DoEvents
    Next

    Label5.Caption = "Clear - GDI objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS)
    Label6.Caption = "Clear - User objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_USEROBJECTS)
    End Sub

    Private Sub Form_Load()

    Label1.Caption = "B4 - GDI objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS)
    Label2.Caption = "B4 - User objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_USEROBJECTS)

    For x = 1 To 100
    'arrow.Picture = frmMycroftImages.imgSort.ListImages("iAcceptArrow").Picture

    'arrow.Picture = Picture2.Picture
    Set arrow.Picture = Nothing
    arrow.Picture = LoadPicture("c:\temp\temp.bmp")
    Next

    DoEvents
    DoEvents

    Label3.Caption = "AF - GDI objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS)
    Label4.Caption = "AF - User objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_USEROBJECTS)
    End Sub

  7. #7

  8. #8
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,998

    Re: Hitting GDI Count

    For posting pictures in a post use "Go Advanced" -> "Manage Attachments"
    Also mark a piece of text in your posting as a code block using the "#" in the toolbar

  9. #9

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    Name:  GDI.png
Views: 190
Size:  5.4 KB
    Have now added code to display the GDI count, before the picture, after the picture and clear, the clear is increasing the GDI Count

    Code:
    Private Declare Function GetGuiResources Lib "user32" (ByVal hProcess As Long, ByVal uiFlags As Long) As Long
    Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
    
    Private Const GR_GDIOBJECTS = 0
    Private Const GR_USEROBJECTS = 1
    
    Private Sub Command1_Click()
    For x = 1 To 100
    arrow = Nothing
    arrow.Picture = Nothing
    arrow.Cls
    arrow.Refresh
    DoEvents
    DoEvents
    Next
    
    Label5.Caption = "Clear - GDI objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS)
    Label6.Caption = "Clear - User objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_USEROBJECTS)
    End Sub
    
    Private Sub Form_Load()
    
    Label1.Caption = "B4 - GDI objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS)
    Label2.Caption = "B4 - User objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_USEROBJECTS)
    
    For x = 1 To 100
    'arrow.Picture = frmMycroftImages.imgSort.ListImages("iAcceptArrow").Picture
    
    'arrow.Picture = Picture2.Picture
    Set arrow.Picture = Nothing
    arrow.Picture = LoadPicture("c:\temp\temp.bmp")
    Next
    
    DoEvents
    DoEvents
    
    Label3.Caption = "AF - GDI objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS)
    Label4.Caption = "AF - User objects used by this application: " & GetGuiResources(GetCurrentProcess, GR_USEROBJECTS)
    End Sub

  10. #10
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,199

    Re: Hitting GDI Count

    Quote Originally Posted by wqweto View Post
    Posting attachments in these forums is like an IQ test -- few succeed.
    Posting an animated GIF is even more challenging, one I've yet to figure out.

    (Ahhh, yayy, I figured it out.)

    Sorry for off-topic post.
    Last edited by Elroy; Apr 2nd, 2024 at 09:52 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  11. #11

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    Is there anyway I can clear the GDI count when it reaches x

  12. #12
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,998

    Re: Hitting GDI Count

    No, because it's about the GDI handles.
    You need to "have" them before you can release them

    /* edit: have you played with AutoRedraw property?
    Last edited by Arnoutdv; Apr 2nd, 2024 at 11:00 AM.

  13. #13

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    Thanks, I tried setting Autodraw to True but did not make any difference, I have however noticed using an ImageBox instead of a PictureBox uses less GDI resources

  14. #14
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,230

    Re: Hitting GDI Count

    Quote Originally Posted by mikethelad View Post
    Thanks, I tried setting Autodraw to True but did not make any difference, I have however noticed using an ImageBox instead of a PictureBox uses less GDI resources
    Your code does not leak anything here. Here is my best effort to recreate the form you are testing with: NoLeak.zip -- there are no leaks both in IDE and compiled.

    I already told you -- ZIP your complete repro project and upload it here. Obviously the problem is in some design-time setting you are using on your form or your picturebox or something even more obscure -- it's not straighforward to reproduce by copy/pasting your code.

    cheers,
    </wqw>

  15. #15

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    Name:  GDI 2.jpg
Views: 153
Size:  16.1 KB

    The GDI count does not go back down on pressing the button

  16. #16

  17. #17

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    It goes continually upto the registry key value GDIProcessHandleQuota, I can increase to 65,536 and it last longer but still fails.

  18. #18
    Frenzied Member VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    1,539

    Re: Hitting GDI Count

    That doesn't make any sense, setting the Picture property of a PictureBox should not increase any GDI count. Why don't you post the rest of your code?

  19. #19
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,230

    Re: Hitting GDI Count

    Quote Originally Posted by mikethelad View Post
    It goes continually upto the registry key value GDIProcessHandleQuota, I can increase to 65,536 and it last longer but still fails.
    This happens by pressing Command1 in my repro above or some other way?

    I've been pressing it continuously for 5 minutes already but it stays at 29 here.

    cheers,
    </wqw>

  20. #20
    PowerPoster
    Join Date
    Feb 2017
    Posts
    5,119

    Re: Hitting GDI Count

    Yes, it is impossible to know what is happening there without a sample project that reproduces the issue.

    Want help? Work for it.

  21. #21

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    I have changed the PictureBox to an Imagebox and this seems to have reduced the GDI resources, so am currently testing this.

    The code is huge, hence I created a simple test program

  22. #22
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,199

    Re: Hitting GDI Count

    Mike,

    I can't say it's the most fun aspect of programming. However, when I've got a problem in a huge application (of which I have several), if I can't solve it quickly, I'll create a new project and start copy-pasting code from the problem area from the huge project into this new project, copy-pasting enough code until this new project can run on its own.

    That process often takes writing some test code to exercise the problem area.

    What's interesting is that, about 50% of the time, while doing that, I often find the root cause of my problem. However, even when I don't, I've now got a much smaller chunk of code on which to test and debug, to find the problem. If that doesn't find the problem, I'll possibly post the code here for others to stare at.

    Personally, I think you're just mis-handling GDI handles, and that's your problem. But nobody is going to be able to identify the exact pieces of code that do that mis-handling, until you post enough code to show what you're actually doing ... from creating those handles to releasing them.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  23. #23
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,998

    Re: Hitting GDI Count

    @Elroy post #9 contains a sample project with the results Mike sees
    Increasing GDI count when refreshing the Picture object of a PictureBox control.

  24. #24
    Frenzied Member VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    1,539

    Talking Re: Hitting GDI Count

    Quote Originally Posted by Arnoutdv View Post
    Increasing GDI count when refreshing the Picture object of a PictureBox control.
    PictureBoxes are unlikely to have any effect on the GDI count at all unless you're creating a new bitmap every time and never destroying the old copies... In his case the images appear to come from some sort of ImageList control but more code is needed to pinpoint the issue.

  25. #25
    PowerPoster
    Join Date
    Feb 2017
    Posts
    5,119

    Re: Hitting GDI Count

    Quote Originally Posted by VanGoghGaming View Post
    PictureBoxes are unlikely to have any effect on the GDI count at all
    Off course, PictureBoxes don't leak handles.
    LoadPicture either.

    Quote Originally Posted by VanGoghGaming View Post
    In his case the images appear to come from some sort of ImageList control but more code is needed to pinpoint the issue.
    Who knows what is that. An ImageList? An ImageList from VBAccelerator or other custom Imagelist control?

    I don't think a normal ImageList from the Common Controls would leak any handle.

    BTW, does the OP have SP6 installed?

  26. #26

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    12

    Re: Hitting GDI Count

    Have still got the issue, however going back to a build of the system from 2015 does not have this problem and the images then were in a ListImages object as per current, looking at GDI view it is the DC count that increases, so trying to work out when I do a rebuild it causes this but the original build does not.

  27. #27
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,655

    Re: Hitting GDI Count

    I don't know the depth of what OP is doing but if you're deep into GDI to the point where you're calling stuff like SelectObject, CreateCompatibleDC, CreateBitmap etc often, I can personally testify that GDI almost begs us to leak handles somewhere. You have to be extremely disciplined to not leak handles when writing GDI code.

    For example, a very easy mistake to make is to select an object into a device context and later destroy the device context without destroying the selected object also. This is a not only a mistake an experienced programmers can make but it's also easy for a newcomer to GDI to assume that destroying a device context implicitly destroys all objects selected into it. I mean it only seems natural. Add that to the fact that manual resource management has always been a nuisance, even to the most battle-hardened C programmers, and you have a damn near guarantee that you will leak something somewhere. This is one of the reasons that Rust is so popular all of a sudden. The Rust compiler, at all times, forces you to do the responsible thing when managing resources.

    I don't envy anyone the task of having the hunt down GDI leaks. God knows I had my share of this torture back in day. One of the things was eternally grateful for when I moved to .Net was that MS added safe handles and finalizers which can effectively eliminate this class of bugs completely, giving us one less thing to worry about when hunting bugs.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  28. #28
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,230

    Re: Hitting GDI Count

    Quote Originally Posted by Niya View Post
    For example, a very easy mistake to make is to select an object into a device context and later destroy the device context without destroying the selected object also.
    Btw, it's worse than this: for instance if you have a brush selected in a device context and destroy it before deselecting it from the device context then DeleteObject actually fails and the brush leaks.

    This got alleviated during Win9x -> NT transition but still not deselecting GDI objects from temporary or other device contexts is considered potential leak.

    cheers,
    </wqw>

  29. #29
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,655

    Re: Hitting GDI Count

    Quote Originally Posted by wqweto View Post
    Btw, it's worse than this: for instance if you have a brush selected in a device context and destroy it before deselecting it from the device context then DeleteObject actually fails and the brush leaks.

    This got alleviated during Win9x -> NT transition but still not deselecting GDI objects from temporary or other device contexts is considered potential leak.

    cheers,
    </wqw>
    Well look at that. It proves my point as even I didn't know that. I'm pretty sure I have a lot of GDI code in my old VB6 projects that does exactly that. Mostly I did it out of laziness when dealing with memory device contexts that were uses as scratch pads. I figured since I was destroying everything anyway what is the point of giving myself the extra work of first deselecting everything. I mean GDI code was already verbose as it is and I was very loathe to make it even more so.

    Also it wasn't until very late in the game, did I start checking the return value of my DeleteObject calls because I assumed I always used it correctly and it will never fail. Such hubris I had.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  30. #30
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,230

    Re: Hitting GDI Count

    Well, pretty sure on Win2000+ you can get away *not* deselecting GDI objects before deleting these until you can't for some obscure reason. On Win9x this was a hard leak, not sure about NT4.

    That's the reason most "hardened" code is littered with hPrevBrush, hPrevDIB and hPrevPen variables so one can compose calls to DeleteObject(SelectObject(hMemDC, hPrevBrush)), etc. cleanup code.

    cheers,
    </wqw>

  31. #31
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,655

    Re: Hitting GDI Count

    Quote Originally Posted by wqweto View Post
    That's the reason most "hardened" code is littered with hPrevBrush, hPrevDIB and hPrevPen variables so one can compose calls to DeleteObject(SelectObject(hMemDC, hPrevBrush)), etc. cleanup code.
    God I hate writing such boilerplate. If I were writing GDI code in VB6 today, I'd just bite bullet and wrap as much of GDI as I need into classes and code against those classes instead of the raw API endpoints. I wish this had occurred to me back then. It would have saved me a lot of pain.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width