1

Given

Action closeLoadingAction = new Action(() =>
{
  loadingForm.Close();
  #region - may need to put into second Action
  panelOnMainForm.Controls.AddRange(physdocControls.ToList<Control>().ToArray());
  if (Handle != IntPtr.Zero)
    User32DLL.SetForegroundWindow(this.Handle);//Handle is a property of the mainForm.
  #endregion
});

Sometimes I get handle not created exceptions even though I check the Invoke required.

if(loadingForm.InvokeRequired)
   loadingForm.Invoke(closeLoadingAction);
else
   closeLoadingAction();

The loading form runs on the same thread as the main form. The code you see above runs in a seperate thread. I suspect that I need another check for invoke against the main form. Do I need a second check or is what I have already safe?

Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
  • Where does `Handle` come from, is this run inside a control? Is the control already created (has a handle available)? There is also a handy extension method you could make to reduce the verbosity of the `InvokeRequired` checks on forms controls but that is a different story. – Quintin Robinson Nov 06 '12 at 02:00
  • @QuintinRobinson - Updated question. The verbosity thing would be nice...I use this many times in my code. – P.Brian.Mackey Nov 06 '12 at 02:03
  • 1
    WRT the extension method: take a look at this answer http://stackoverflow.com/a/12179408/12707 You can change the signature to `Action` instead of `MethodInvoker` if you are so inclined but should work as-is. – Quintin Robinson Nov 06 '12 at 02:05
  • When you say "I suspect that I need another check for invoke against the main form," is there any code in specific you're referring to? Nothing above seems to touch the main form other than the check against (what I assume is) the main form's `Handle` property. – Patrick Quirk Nov 06 '12 at 02:05
  • @PatrickQuirk - Look at the first line after the region. `panelOnForm1.Controls.Add...` panelOnForm1 is a member of the main form. I probably should have named it `panelOnMainForm`. – P.Brian.Mackey Nov 06 '12 at 02:08

3 Answers3

2

The code you see above runs in a seperate thread

Using InvokeRequired like this when you know that the code runs on another thread is a bad anti-pattern. You can do much more useful things with it. Like:

if (!loadingForm.InvokeRequired) {
    throw new InvalidOperationException("Threading race detected");
}
loadingForm.Invoke(closeLoadingAction);

Or the more practical one if you meant to start the loading thread before the loading form's Load event fired:

while (!loadingForm.InvokeRequired) Thread.Sleep(50);
loadingForm.Invoke(closeLoadingAction);

Or just do it the right way and have the form's Load event start the thread.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
1

You should only get those "handle not created" exceptions if the form hasn't been shown or was closed before you try to Invoke the delegate. Not enough code to determine if that's the case though, so if I were in your shoes I'd try to determine if the loading form's (since that's the invoker) Closed event is being called before the method actually gets invoked.

Because both forms are on the same thread, you should be safe just checking the loading form's InvokeRequired property. Though in general, if you're going to operate on the main form, you should check that form's InvokeRequired property. Likewise, if you're going to operate on the loading form (like calling Close above), you should check the loading form's InvokeRequired property. Above you're changing panelOnMainForm so I'd check that to be totally safe, but I don't believe it's necessary.

Patrick Quirk
  • 23,334
  • 2
  • 57
  • 88
  • The error has to be coming from something. Im not closing the loading form. What if the MainForm loaded and the loading form had no handle? Wouldnt that be an issue? – P.Brian.Mackey Nov 06 '12 at 03:23
  • The loading form has no handle _only_ when it has yet to be shown (via `Show` or `ShowDialog`) or has been closed already (via `Close` or through its GUI). I agree with @MrBlue, it's a race of some sort, but there isn't enough code for us to see how it's happening. – Patrick Quirk Nov 06 '12 at 12:50
1

Sounds like a race between the handle being created for loadingForm and the call to loadingForm.Close().

One way around this is to start the thread that has your .Invoke/.Close code when the loadingForm.HandleCreated event fires.

private void loadingForm_HandleCreated(object sender, EventArgs e)
{
    var t = new Thread(DoLoadingStuff);
    t.Start();
}

private void DoLoadingStuff()
{
    // ...

    if(loadingForm.InvokeRequired)
       loadingForm.Invoke(closeLoadingAction);
    else
       closeLoadingAction();
}
MrBlue
  • 830
  • 6
  • 13