Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 567
  • Last Modified:

How do I manually dispose of this GDI object?

I am having a terrible time trying to manually dispose of this gdi object.  Any suggestions would be appreciated
ptStartLineAt = New Point(objLayoutDetails("Left") + 2, intWarningLineTop)

Open in new window

0
rev0304
Asked:
rev0304
  • 7
  • 6
  • 2
  • +1
1 Solution
 
ToddBeaulieuCommented:
Any object that implements IDisposable can be disposed simply by calling the Dispose() method when you're done with it.

Could be elaborate on what the problem is?
0
 
HugoHiaslCommented:
Did you try

ptStartLineAt.Dispose();


?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
You can't Dispose() a Point structure...

You can "reset" a Point by setting it to Nothing.  Then IsEmpty() will return true:  
Dim ptStartLineAt As New Point(25, 50)
        Debug.Print(ptStartLineAt.IsEmpty & " --> " & ptStartLineAt.ToString)
        ptStartLineAt = Nothing
        Debug.Print(ptStartLineAt.IsEmpty & " --> " & ptStartLineAt.ToString)

Open in new window


Output:
False --> {X=25,Y=50}
True --> {X=0,Y=0}

Open in new window

0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
rev0304Author Commented:
Good Morning -
- ToddBeaulieu: - IDisposable grants access to dispose methods in which the developer manually disposes of unmanaged objects. The problem is we don't know how to manually dispose GDI objects.  So although IDispose could offer a venue for our solution - we are still trapped by the missing piece - how to delete the GDI Object.

HugoHiasl: - as Idle_Mind mentioned there is no .dispose to a Point object

Idle_mind - Setting the variable that holds the reference to the Point object effectively causes us to lose the reference to said Point in memory.  If the GC included GDI objects then this would be sufficient.  As it stands, further in our code we do something similar by creating new objects using the same variable.  Because the GC doesn't see these GDI objects all that does is orphan the object in memory with no possible way to reach it. This is the crux of our problem.  Without being able to manually/programatically destroy the Point object, we end up with lost objects in memory causing a memory leak.

Thanks for all of your suggestions.  I'm hoping with this further detail you'll have other suggestions that will resolve this issue.   Thanks again.
0
 
ToddBeaulieuCommented:
Admittedly, I've never worked wit GDI.

But, if a GDI object doesn't support IDisposable, to me that infers it's a managed object.

If that's the case, then setting the sole reference to it in your application marks it for garbage collection.

In this article on Disposing GDI objects, he breaks them out into those that support IDisposable and those that do not.

So again, anything that supports IDisposble must be disposed of when you're done with them. Anything that doesn't support it, should behave like managed references. That's what it seems like to me, anyway. Why would you release a refernce to a Point if you still need it? If you don't then it will be collected for you.

It's objects with handles that you need to worry about. The above article lists those. I really don't see the issue with non-IDisposable objects. Am I missing something?


0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
"Because the GC doesn't see these GDI objects all that does is orphan the object in memory with no possible way to reach it. This is the crux of our problem.  Without being able to manually/programatically destroy the Point object, we end up with lost objects in memory causing a memory leak."

Can you show the declaration for "ptStartLineAt"?

If it is a MANAGED .Net Point:
http://msdn.microsoft.com/en-us/library/system.drawing.point.aspx

...then it will get AUTOMATICALLY garbage collected.

If we are talking about a true GDI object, then yes, you'd have to manually dispose of it.  If this were the case, though, then you'd be using a low level windows API to both create and destroy the object.  Based on the tiny snippet supplied I don't think this applies to your situation.

Show us more code so we can narrow down what it is were dealing with here...  =)
0
 
rev0304Author Commented:
Thanks again for helping with this. I've attached the method that we suspect is causing the issue.

The first time I run the job It previewed 2475 records - no problem.  If I then try to do the preview a second time, it dies on record 2,470.  We've run this test several times and it always seems to work the first time but crash the second.

We are using in this code the Point, Rectangle, drawString Method and Draw Line method.  

Maybe I'm not looking in the right area - not sure.  Running the same method several times seems to crash the GDI.

Thanks again.    
Private Sub PrintWarningLine(ByVal e As Graphics, ByVal objPrintArea As Rectangle, ByVal objLayoutDetails As DataRow)
'************************************************************************
        ' Procedure/Function: PrintWarningLine()
        ' Description:
        '       Prints the WarningLine
        '************************************************************************

        '***************************************
        ' Initialize Variables
        '***************************************
        Dim objStringFormat As New StringFormat
        Dim sngTextWidth As Single
        Dim sngTextHeight As Single
        Dim intWarningLineLength As Integer
        Dim intWarningLineTop As Integer
        Dim ptStartLineAt As Point
        Dim ptEndLineAt As Point

        '***************************************
        ' Set String Alignment
        '***************************************
        With objStringFormat
            .Alignment = StringAlignment.Center
            .LineAlignment = StringAlignment.Center
        End With

        '***************************************
        ' Draw Warning String
        '***************************************
        e.DrawString("DO NOT WRITE ABOVE THIS LINE", Me._objFontWarning, Brushes.Black, objPrintArea, objStringFormat)

        '***************************************
        ' Calculate Line Positions
        '***************************************
        With e.MeasureString("DO NOT WRITE ABOVE THIS LINE", Me._objFontWarning)
            sngTextWidth = .Width
            sngTextHeight = .Height
        End With
        intWarningLineLength = (objLayoutDetails("Width") - sngTextWidth - 24) / 2
        intWarningLineTop = objLayoutDetails("Top") + ((objLayoutDetails("Height") - 4) / 2)

        '***************************************
        ' Print Left Top Line
        '***************************************
        ptStartLineAt = New Point(objLayoutDetails("Left") + 2, intWarningLineTop)
        ptEndLineAt = New Point(ptStartLineAt.X + intWarningLineLength, intWarningLineTop)
        e.DrawLine(Pens.Black, ptStartLineAt, ptEndLineAt)
        'deleteobject(New IntPtr(&ptStartLineAt))
        'releaseobject(ptStartLineAt)
        'ptStartLineAt.finalize()
        ptStartLineAt = Nothing
        ptEndLineAt = Nothing

        '***************************************
        ' Print Left Bottom Line
        '***************************************
        ptStartLineAt = New Point(objLayoutDetails("Left") + 2, intWarningLineTop + 2)
        ptEndLineAt = New Point(ptStartLineAt.X + intWarningLineLength, intWarningLineTop + 2)
        e.DrawLine(Pens.Black, ptStartLineAt, ptEndLineAt)
        ptStartLineAt = Nothing
        ptEndLineAt = Nothing

        '***************************************
        ' Print Right Top Line
        '***************************************
        ptStartLineAt = New Point(objLayoutDetails("Left") + 2 + intWarningLineLength + 10 + sngTextWidth + 10, intWarningLineTop)
        ptEndLineAt = New Point(ptStartLineAt.X + intWarningLineLength, intWarningLineTop)
        e.DrawLine(Pens.Black, ptStartLineAt, ptEndLineAt)
        ptStartLineAt = Nothing
        ptEndLineAt = Nothing

        '***************************************
        ' Print Right Bottom Line
        '***************************************
        ptStartLineAt = New Point(objLayoutDetails("Left") + 2 + intWarningLineLength + 10 + sngTextWidth + 10, intWarningLineTop + 2)
        ptEndLineAt = New Point(ptStartLineAt.X + intWarningLineLength, intWarningLineTop + 2)
        e.DrawLine(Pens.Black, ptStartLineAt, ptEndLineAt)
        ptStartLineAt = Nothing
        ptEndLineAt = Nothing
    End Sub

Open in new window

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Where is the Graphics "e"  being passed into this method coming from?

That's probably where the problem lies...

Show us how this puppy gets called...and how often is it called?
0
 
rev0304Author Commented:
e is a parameter coming from a method that handles the event OnPagePrint. (see code for prototype)

The below method is not called directly, it's called with each page print.  This varies with number of records that the user selects.  In this particular case, it's 2,475 times.

Thinking about what you just said -- we just added an e.Graphics.Dispose at the end of this method - I'm testing that right now - I'll update as soon as the test finishes

Thanks!
Private Sub _objPrinterInterface_OnPagePrint(ByRef e As System.Drawing.Printing.PrintPageEventArgs) Handles _objPrinterInterface.OnPagePrint

Open in new window

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
For Paint() type events, you are not supposed to call Dispose() on default supplied graphics objects.

You should only be disposing of Graphics that YOU create, as with CreateGraphics().

At any rate, the Point() is simply a STRUCTURE that holds two values.  It doesn't have a GDI handle associated with it.

What is the actual error you're getting?
0
 
rev0304Author Commented:
Here it is.   Thanks again
Error.jpg
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Ok...can you show us more code around the printing process?
0
 
rev0304Author Commented:
We used code from www.codeproject.com to give the users an alternative print preview. I just went back to the site to get the code to send to you and see that there is now a note that addresses this very problem.

 "If the document contains several thousand pages, caching all those images may cause problems. Windows has a limit of 10,000 GDI objects, and each page image represents at least one. If you use too many GDI objects, your application may crash, or cause other apps to crash. Not nice..."

The author suggests that we convert the page images into streams, store the stread and the create the images on demand.  What do you think of this?  This sounds like a big change to me.  Now I'm wondering if the problem is just with this "enhanced dialog".
(http://www.codeproject.com/KB/printing/CoolPrintPreviewDialog.aspx?display=Mobile&fid=1544884&df=90&mpp=10&noise=3&sort=Position&view=None&fr=71)

Any suggestions would be appreciated but if you want to bail out at this point I totally understand.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I haven't played with it...but the author seems to imply that you can simply replace the normal List<Image> with his newer List<PageImageList>.

Does the downloadable source not have the "fix" in it?
0
 
rev0304Author Commented:
I found that alternate code - it is commented out in the download.  I'm going to try and play with that.  Thanks so much for all of your help.
0
 
rev0304Author Commented:
Thanks so much for all of your help
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 7
  • 6
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now