none
InvalidOperation on Dispose / Threadsafty RRS feed

  • Question

  • Hi, after changing some Invoke Calls to BeginInvoke in my App, I get a lot of Exceptions like this in my CleanUp Code:

    Exception: 'System.InvalidOperationException: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement iplKnoten erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.
       bei System.Windows.Forms.Control.get_Handle()
       bei System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       bei System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.SetBounds(Rectangle bounds, BoundsSpecified specified)
       bei System.Windows.Forms.Layout.DefaultLayout.xLayoutDockedControl(IArrangedElement element, Rectangle newElementBounds, Boolean measureOnly, Size& preferredSize, Rectangle& remainingBounds)
       bei System.Windows.Forms.Layout.DefaultLayout.LayoutDockedControls(IArrangedElement container, Boolean measureOnly)
       bei System.Windows.Forms.Layout.DefaultLayout.xLayout(IArrangedElement container, Boolean measureOnly, Size& preferredSize)
       bei System.Windows.Forms.Layout.DefaultLayout.LayoutCore(IArrangedElement container, LayoutEventArgs args)
       bei System.Windows.Forms.Layout.LayoutEngine.Layout(Object container, LayoutEventArgs layoutEventArgs)
       bei System.Windows.Forms.Control.OnLayout(LayoutEventArgs levent)
       bei System.Windows.Forms.ScrollableControl.OnLayout(LayoutEventArgs levent)
       bei System.Windows.Forms.Control.PerformLayout(LayoutEventArgs args)
       bei System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement, String affectedProperty)
       bei System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout, IArrangedElement elementCausingLayout, String property)
       bei System.Windows.Forms.Control.OnResize(EventArgs e)
       bei System.Windows.Forms.Panel.OnResize(EventArgs eventargs)
       bei System.Windows.Forms.Control.OnSizeChanged(EventArgs e)
       bei System.Windows.Forms.Control.UpdateBounds(Int32 x, Int32 y, Int32 width, Int32 height, Int32 clientWidth, Int32 clientHeight)
       bei System.Windows.Forms.Control.UpdateBounds(Int32 x, Int32 y, Int32 width, Int32 height)
       bei System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       bei System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.SetBounds(Rectangle bounds, BoundsSpecified specified)
       bei System.Windows.Forms.Layout.DefaultLayout.xLayoutDockedControl(IArrangedElement element, Rectangle newElementBounds, Boolean measureOnly, Size& preferredSize, Rectangle& remainingBounds)
       bei System.Windows.Forms.Layout.DefaultLayout.LayoutDockedControls(IArrangedElement container, Boolean measureOnly)
       bei System.Windows.Forms.Layout.DefaultLayout.xLayout(IArrangedElement container, Boolean measureOnly, Size& preferredSize)
       bei System.Windows.Forms.Layout.DefaultLayout.LayoutCore(IArrangedElement container, LayoutEventArgs args)
       bei System.Windows.Forms.Layout.LayoutEngine.Layout(Object container, LayoutEventArgs layoutEventArgs)
       bei System.Windows.Forms.Control.OnLayout(LayoutEventArgs levent)
       bei System.Windows.Forms.ScrollableControl.OnLayout(LayoutEventArgs levent)
       bei System.Windows.Forms.Form.OnLayout(LayoutEventArgs levent)
       bei System.Windows.Forms.Control.PerformLayout(LayoutEventArgs args)
       bei System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement, String affectedProperty)
       bei System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout, IArrangedElement elementCausingLayout, String property)
       bei System.Windows.Forms.Control.ControlCollection.Remove(Control value)
       bei System.Windows.Forms.Form.ControlCollection.Remove(Control value)
       bei System.Windows.Forms.Control.Dispose(Boolean disposing)
       bei System.Windows.Forms.ToolStrip.Dispose(Boolean disposing)
       bei System.Windows.Forms.StatusStrip.Dispose(Boolean disposing)
       bei System.ComponentModel.Component.Dispose()
       bei ITS.Tasks.modMain.DisposeControl(Control ctl) in D:\Projekte\ITS.Xt\ITS.App\ITS.Taskbar\Module\modMain.vb:Zeile 512.'

    Here the Code of the procedure modMain.DisposeControl(Control ctl):
        Private Delegate Sub WithControlCallback(ByVal clt As Control)
       
    Private Sub DisposeControl(ByVal ctl As Control)
            Dim ctlChild As Control
            Dim frm As Form
            Try
                If ctl.InvokeRequired Then
                    ctl.BeginInvoke(New WithControlCallback(AddressOf DisposeControl), ctl)
                Else
                    For Each ctlChild In ctl.Controls
                        If ctlChild IsNot Nothing Then
                            DisposeControl(ctlChild)
                        End If
                    Next
                    frm = TryCast(ctl, Form)
                    If frm IsNot Nothing Then
                        frm.Close()
                    End If
                    ctl.Dispose()
                End If
            Catch ex As Exception
                m_GenerateError(-1, ex, Name, "DisposeControl")
            End Try
        End Sub

    As fare as I understand the Dispose/Threadsafty logic, it shoud be ok to call Control.Dispose, if Control.InvokeRequired is false.
    If checking for
    InvokeRequired isn't enough would you point me to some documentation on this matter ?

    Am I mistaken ?
    Tuesday, February 24, 2009 4:11 PM

All replies

  • Well I think i found the reason for this Error:
    Some of my Forms contain ToolStrips/StatusStrips.
    If i don't call Form.Show on them, some Controls(ToolStrip?) are not compleatly created, even if i call Form.CreateControl!
    Now when I try to dispose my Forms/Contained Controls, the Resize/Layout happens, as seen in the stack trace above.
    This Calls Control.Handle witch was created in an different handle!

    I already found the workaround, to call Form.Show + Form.hide, but this makes dosn't look good.
    Another way would be not to call the Dispose at all, but this isn't good either, does anyone know another solution ?
    Tuesday, February 24, 2009 4:54 PM
  • What the heck is an "iplKnoten"?  Disposing controls or forms while you've got an active running thread is asking for trouble.  The next time it makes that callback, InvokeRequired will be false because the window handle is invalid.  Stop the thread first.
    Hans Passant.
    Wednesday, February 25, 2009 1:27 AM
    Moderator
  • Thank you for your replay.

    iplKnoten is juast an Pannel.

    Well i still have an thread running, the main thread, in witch the cleanup is executed, in order to allow an normal exit of the process.
    the procedure modMain.DisposeControl(Control ctl) above gets called for every loaded form (System.Windows.Forms.Application.OpenForms) once,

    In other words, there shoudn't be any callbacks anymore, since all other threads i know off are already stopped.

    The reason for this procedure(DisposeControl) is, that i notices with an Memory Profiler(ANTS Profiler) that not all Controls/Forms are getting disposed, even ~ h after the Call to Form.Close.
    Off course i checked if they are still referenced anywhere, and ANTS Profiler only showed references from Events/Framework Components, and in some cases from Contained Controls(not my source).

    Or can i understand this, that it is not necresarry/important to manually close/dispose all my Forms/Controls before exiting the process, but simbly call Process.GetCurrentProcess.Kill() ?
    Wednesday, February 25, 2009 12:00 PM