Cannot call Invoke or InvokeAsync on a control

B

Bruce Wood

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();
}
 
P

Patrick Steele

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.
 
B

Bruce Wood

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/micr...ndowsforms/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....
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top