Link to home
Start Free TrialLog in
Avatar of riceman0
riceman0

asked on

How am I running into this "Object is Currently In Use elsewhere" exception?

I have an object that has a custom "HandlePaint(pe as PaintEventArgs)" that I call downstream from my Form.Paint event.  It does some moderately complex rendering, and it is sometimes advantageous (as a speed tweak) to, instead of rendering it normally, render it to a bitmap object (freeze it) and thereafter just paint that bitmap (to avoid the math that goes into the calculating of the appearance).  Basically I call the "Freeze" function below, you get the idea.

Quite often (usually when I call "Freeze" in quick succession with other operations -- that might cause repaints; however haven't strongly correlated the problem yet) I run into the exception "Object is Currently In Use Elsewhere" with the description:

"If you are using the Graphics object after the GetHdc method, call the ReleaseHdc method.
This will release the context handle obtained by a previous call to the GetHdc method of the Graphics object. "

However as you can see I am not using GetHdc, I'm using Graphics.Image.  But regardless  I don't know how I'm hitting this -- my rendering is complex (maybe time consuming), but Freeze command is a discrete function, is it colliding somehow with some framework Paint activity?  How is that?  Any thoughts on how to bypass this problem and how to avoid it in the future?

Thanks for any help.
Public Sub Handle_Paint(ByVal pe As System.Windows.Forms.PaintEventArgs)

  If m_Frozen Then
      pe.Graphics.DrawImageUnscaled(m_FrozenBitmap, m_X, m_Y)
  Else
     ' does some moderately complex GDI rendering
  Endif

End Sub


Public m_Frozen as Boolean = False
Public m_FrozenBitmap As Bitmap

Public Sub Freeze(ByVal sz As Size)


  m_FrozenBitmap = New Bitmap(sz.Width + 1, sz.Height + 1)
  Dim g2 As Graphics = Graphics.FromImage(m_FrozenBitmap)
  Dim pe As New PaintEventArgs(g2, New Rectangle(0, 0, sz.Width + 1, sz.Height + 1))

  ptr_Object.Handle_Paint(pe, False)

  m_Frozen = True


End Sub

Open in new window

Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Try something like this:
Public Sub Freeze(ByVal sz As Size)
        m_FrozenBitmap = New Bitmap(sz.Width + 1, sz.Height + 1)
        Using g2 As Graphics = Graphics.FromImage(m_FrozenBitmap)
            Dim pe As New PaintEventArgs(g2, New Rectangle(0, 0, sz.Width + 1, sz.Height + 1))
            ptr_Object.Handle_Paint(pe, False)
            m_Frozen = True
        End Using
    End Sub

Open in new window

Avatar of riceman0
riceman0

ASKER


That did not seem to fix it.

Actually I've never understood the purpose of the "Using" keyword -- does that just make it go out of scope?

I think you have a problem caused by more than one thread running the Freeze or Handle_Paint methods which is leading to collision in using the m_freezebitmap graphics creating and drawing.

The best practice for refreshing control canvas is using Control.invalidate() instead of invoking the paint event directly. I also realized that you can suffer from memory leaks in your code. If you describe your senario more, I could help you with the design:

is Handle_Paint () binded with an event ?
is the m_FreezeBitmap drawn on a control (picturebox, form, ...)
is the m_FreezeBitmap used anywhere other than the code you submited above

If you can provide me with more of your code so I can see the bigger picture


I do not call a framework Paint command directly, I am calling my own function that happens to be called Handle_Paint.  I have an object (*not* a .NET Control -- I basically don't use them, I just draw to a Form using GDI) such as:

Class MyClass
     public sub Handle_Paint(pe as PaintEventArgs)
    ... rendering
    end sub

End Class

and I call the HandlePaint from a form Paint event when I want to draw that object.  Likewise when I "Freeze" the image I call *my* HandlePaint above with a fabricated PaintEventArgs from my bitmap object.

Actually I did manage to just fix it by placing SyncLocks around the calls to my Handle_Paint command, both those from the Form.Paint event and my Freeze command.  So yes, this was  a collision between those two.  But I am still burning with curiosity as to how this happened.  why is the framework allowed to "preempt" my Freeze function halfway through?  When is the framework allowed to do this?  I need to understand better to avoid this in the future.


To summarize, I have not written multiple threads.  The "Freeze" is triggered conditionally by a mouse event (i.e., Form.OnMouseDown) and the "Paint" is triggered by the Form.Paint event.

Freeze applies the rendering commands to a fabricated PaintEventArgs derived from a Bitmap.
Paint applies the same rendering commands to its Form object's graphics context.

I don't understand either (a) how one can preempt the other in time nor (b) how they are using the same objects.  Each pass should instantiate its own graphics objects, I would think.

Yet they are colliding.
Yes, each pass is using it's own graphics object, but these graphics objects are all referencing to the same bitmap. This is what's causing the collision.

But if you'll notice, I don't set "m_Frozen" until after I'm done rendering to the Bitmap.  Even a paint event that preempts the Freeze in time shouldn't access the bitmap until it is done being operated on by the freeze.

And as I said I would like to understand better whether the Paint is actually preempting the freeze in time.  

Well this is still a mystery to me, but I'll close it.  Can someone answer that side question, which is whether the "using" keyword has a purpose beyond readability, does it cause a variable to go out of scope that much sooner which might minimize the chance of such conflicts?
ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial