I have some sort of a concurrency problem that has me stumped.

I have a form (actually several) that run background worker threads
from the OnLoad method. Sometimes... occasionally... I get a crash
dump from a user that indicates that I "cannot call Invoke or
InvokeAsync on a control until the window handle has been created."
Now, never mind that by the time OnLoad runs, the window handle should
already be created. I decided that, hey, if that's the problem then
I'll just patch it. My patched code is below.

As you can see, in the DoBackgroundWork method I added a test for
control.IsHandleCreated, and then if it's not I do a
control.CreateControl. However, even after this patch I had a crash
this morning with this same annoying message.

2007-03-01 06:36:54Z User mm_tboos on PRICTX99, running M:\program
files\StockCodeGenerator\StockCodeGenerator.exe (StockCodeGenerator
version 2.4.2615.30559) received the following exception:
2007-03-01 06:36:54Z System.InvalidOperationException: Cannot call
Invoke or InvokeAsync on a control until the window handle has been
created.
2007-03-01 06:36:54Z at
System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate
method, Object[] args, Boolean synchronous)
2007-03-01 06:36:54Z at
System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
2007-03-01 06:36:54Z at
Agama.Controls.BackgroundWorkParameters.DoBackgroundWork(Object
parameter)

Do I have misconceptions about when handle creation happens? Am I
missing something here?

Code follows.

public delegate void BackgroundWorkDelegate(params object[]
parameter);

public delegate void ControlEnableDelegate(bool enable);

private class BackgroundWorkParameters
{
private Control _callingControl;
private BackgroundWorkDelegate _backgroundJob;
private BackgroundWorkDelegate _finishJob;
private object[] _parameters;
private ControlEnableDelegate _enableControls;
private Exception _finishException;

public BackgroundWorkParameters(Control callingControl,
BackgroundWorkDelegate backgroundJob,
BackgroundWorkDelegate finishJob,
object[] parameters,
ControlEnableDelegate enableControls)
{
this._callingControl = callingControl;
this._backgroundJob = backgroundJob;
this._finishJob = finishJob;
this._parameters = parameters;
this._enableControls = enableControls;
this._finishException = null;
}

public void ScheduleBackgroundJob()
{
this._callingControl.Cursor = Cursors.WaitCursor;
if (this._enableControls != null)
{
this._enableControls(false);
}
ThreadPool.QueueUserWorkItem(
new WaitCallback(DoBackgroundWork), null);
}

private void DoBackgroundWork(object parameter)
{
try
{
this._backgroundJob(this._parameters);
}
finally
{
if (!this._callingControl.IsHandleCreated)
{
this._callingControl.CreateControl();
}
this._callingControl.Invoke(
new MethodInvoker(FinishWork), null);
if (this._finishException != null)
{
throw new ApplicationProgrammingErrorException(
"Exception trapped while finishing background
task.",
this._finishException);
}
}
}

private void FinishWork()
{
this._finishException = null;
try
{
if (this._finishJob != null)
{
try
{
this._finishJob(this._parameters);
}
catch (Exception ex)
{
this._finishException = ex;
}
}
}
finally
{
this._callingControl.Cursor = Cursors.Default;
if (this._enableControls != null)
{
try
{
this._enableControls(true);
}
catch (Exception ex)
{
this._finishException = ex;
}
}
}
}
}

public static void BackgroundWork(Control callingControl,
BackgroundWorkDelegate backgroundJob,
BackgroundWorkDelegate finishJob,
object[] parameters,
ControlEnableDelegate enableControls)
{
BackgroundWorkParameters p = new
BackgroundWorkParameters(callingControl, backgroundJob, finishJob,
parameters, enableControls);
p.ScheduleBackgroundJob();
}

Re: Cannot call Invoke or InvokeAsync on a control by Patrick

Patrick
Mon Mar 05 21:47:16 CST 2007

In article <1172801643.688327.183510@p10g2000cwp.googlegroups.com>,
brucewood@canada.com says...
> I have some sort of a concurrency problem that has me stumped.
>
> I have a form (actually several) that run background worker threads
> from the OnLoad method. Sometimes... occasionally... I get a crash
> dump from a user that indicates that I "cannot call Invoke or
> InvokeAsync on a control until the window handle has been created."
> Now, never mind that by the time OnLoad runs, the window handle should
> already be created.

Instead of OnLoad, try starting the background worker in the
OnHandleCreated method. At least that way you'll know *for sure* that
handle has been created.

--
Patrick Steele
http://weblogs.asp.net/psteele

Re: Cannot call Invoke or InvokeAsync on a control by Bruce

Bruce
Fri Mar 09 11:57:01 CST 2007

On Mar 5, 7:47 pm, Patrick Steele <patr...@mvps.org> wrote:
> In article <1172801643.688327.183...@p10g2000cwp.googlegroups.com>,
> brucew...@canada.com says...
>
> > I have some sort of a concurrency problem that has me stumped.
>
> > I have a form (actually several) that run background worker threads
> > from the OnLoad method. Sometimes... occasionally... I get a crash
> > dump from a user that indicates that I "cannot call Invoke or
> > InvokeAsync on a control until the window handle has been created."
> > Now, never mind that by the time OnLoad runs, the window handle should
> > already be created.
>
> Instead of OnLoad, try starting the background worker in the
> OnHandleCreated method. At least that way you'll know *for sure* that
> handle has been created.

According to this thread:

http://groups.google.com/group/microsoft.public.dotnet.framework.windowsforms/browse_frm/thread/f931af78c2bf5328

CreateControl doesn't create the Form handle! Scary! I am trying the
solution suggested in that thread: use Control.Handle in conjunction
with CreateControl to ensure that the handle is created. Here's
hoping....