Control.BeginInvoke vs. delegate.BeginInvoke

V

Valerie Hough

I'm not entirely sure what the difference is between these two approaches.

In order to avoid reentrant code, I was using Control.BeginInvoke in my UI
to cause an asynchronous activity to be done on the UI's message loop. I
began to get System.ExecutionEngineException errors so (on the theory of do
something different if what you're doing isn't working) I switched to using
delegate.BeginInvoke with the appropriate EndInvoke and the problem
disappeared.

Does this make sense?

Is it possible to use Control.BeginInvoke with a matching EndInvoke ?

From my reading of the documentation, it seems as though
delegate.BeginInvoke is using a separate thread, in which case the invoked
code is not running on the UI's thread and therefore I have not solved my
reentrant code worries.

If it sounds like I am confused, it is probably because I am!

Thanks in advance for any help.
Valerie Hough
 
N

Nicholas Paldino [.NET/C# MVP]

Valerie,

See inline:
I began to get System.ExecutionEngineException errors so (on the theory of
do something different if what you're doing isn't working)

With all due respect, this is a horrible way to fix problems. Gaining
understanding of why the errors are happening, and then addressing them is
the more prudent course of action, and saves you a headache in the
long-term.
I switched to using delegate.BeginInvoke with the appropriate EndInvoke
and the problem disappeared.

This will not solve your problem. When you call Control.BeginInvoke,
the call to Control.Invoke is made on a threadpool thread and the call to
BeginInvoke returns immediately. So, in effect, you have a worker thread
calling BeginInvoke. The threadpool thread then takes over and calls
Control.Invoke, waiting on the return value. The delegate passed to Invoke
is then invoked on the UI thread.

If you call Delegate.BeginInvoke, then you go from your worker thread to
the threadpool thread, where the method pointed to by the delegate gets
executed. If you are accessing UI elements on this thread, you are going to
get unpredictable results.
Is it possible to use Control.BeginInvoke with a matching EndInvoke ?

To what end do you want to use them? They just allow processing to
continue on the thread that called them, not waiting for the UI to update.
From my reading of the documentation, it seems as though
delegate.BeginInvoke is using a separate thread, in which case the invoked
code is not running on the UI's thread and therefore I have not solved my
reentrant code worries.

I'm not sure how reentrancy plays into this. Basically, call
Control.Invoke when you want processing to be done on the UI thread.
Typically, if you want to update the UI, call it, but don't do any long-term
processing in the delegate passed to Invoke.

Hope this helps.
 
V

Valerie Hough

I agree that this is not a good way to solve problems.

Can you suggest a way to diagnose the cause of these
System.ExecutionEngineException errors? I don't know where to look in the
developer studio help. Searching with no filter produced no results, so I
googled this error and all I found was that the problem was thread related
and the suggestion was to set the thread to single threaded apartment model.
I was not sure how to apply that thought to my problem.

What I am doing is:
- I have a System.Windows.Forms.Form application that uses a certain set of
code upon certain user actions.
- I want to invoke some of the same activities under ceratain circumstances
after a System.Timers.Timer object expires.

Any help would be appreciated. I was acting on a suggestion from Nicholas
Paldino (C# MVP) when I started to use Invoke. An article I saw said that in
effect BeginInvoke was doing a PostMessage, which is what I would have done
in C++, so I decided to use that.

Thanks for any help.
 
N

Nicholas Paldino [.NET/C# MVP]

Valerie,

In case you didn't notice, I'm the same guy =)

Do you have a sample project that you can post which shows the error?
It's kind of impossible to tell without seeing the code.

The ExecutionEngineException is a pretty broad exception, so its hard to
tell what exactly is going on, hence the request for the project.

At the least, can you post some (well-formatted) code?
 
W

Willy Denoyette [MVP]

Valerie Hough said:
I agree that this is not a good way to solve problems.

Can you suggest a way to diagnose the cause of these
System.ExecutionEngineException errors? I don't know where to look in the
developer studio help. Searching with no filter produced no results, so I
googled this error and all I found was that the problem was thread related
and the suggestion was to set the thread to single threaded apartment
model. I was not sure how to apply that thought to my problem.

What I am doing is:
- I have a System.Windows.Forms.Form application that uses a certain set
of code upon certain user actions.
- I want to invoke some of the same activities under ceratain
circumstances after a System.Timers.Timer object expires.

Any help would be appreciated. I was acting on a suggestion from Nicholas
Paldino (C# MVP) when I started to use Invoke. An article I saw said that
in effect BeginInvoke was doing a PostMessage, which is what I would have
done in C++, so I decided to use that.

Thanks for any help.

ExecutionEngineException are mostly the result of failures during interop
calls ,do you happen to call into native code using PInvoke? How does the
call stack looks like when you get this exception?


Willy.
 
V

Valerie Hough

Sorry Nicholas, I'm embarassed to say didn't notice!

I would love to post some code, but unfortunately I am a small part of a
large project that involves SQL Server, Sockets, etc. I have the dubious
distinction of having been put in charge of trying to straighten this mess
out, so no matter how bad the code might be, there is a belief that it can
be made to work without a complete rewrite or redesign. But such is the lot
of a support person...

I have already tried to make a simple project that exhibits the problem, but
I have not succeeded yet. However, I can always produce the problem in the
debugger with exactly the same set of actions. I wondered if there was
anything to be looked at when execution stops. I did notice that try/catch
did not seem to pause execution gracefully as it would with a more 'normal'
crash, even when I specifically tried catch (
System.ExecutionEngineException ).

Another reply from Willy Denoyette asked about calls to PInvoke. There is
some of that going on before the code executes that causes the crash, but
not directly in the call stack at the time of the crash. From what I've seen
so far, the most likely candidate is the code that follows: it is used to
calculate the length of a string (and came from a member in the MS GDI
group), and it is called in many places. As I understand it, this code is
necessary (says my boss) to get exact string length - the C# calls all had
some caveat or another. Is there any particular kind of mistake that can be
made with PInvoke that I could look for?

I'm sure I have not made anything clearer, but I would be grateful for any
ideas.
Valerie Hough

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MyCompany.Win32API
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class Win32
{
[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;
}

[DllImport("user32.dll")] public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")] public static extern IntPtr GetDC( IntPtr hWnd );
[DllImport("gdi32.dll")] public static extern bool GetTextExtentPoint32(
IntPtr hdc, string str, int len, ref SIZE size );
[DllImport("gdi32.dll")] public static extern IntPtr SelectObject( IntPtr
hdc, IntPtr hNewObj );
[DllImport("user32.dll")] public static extern int ReleaseDC( IntPtr hWnd,
IntPtr hDc );
[DllImport("gdi32.dll")] public static extern bool DeleteObject( IntPtr
hObj );

public Size GetTextExtent( string str, Font f )
{
SIZE size = new SIZE();

IntPtr hwndDesktop = GetDesktopWindow();
IntPtr hDc = GetDC( hwndDesktop );

size.cx = size.cy = 0;

IntPtr hFont = f.ToHfont();
IntPtr hOldFont = SelectObject( hDc, hFont );

GetTextExtentPoint32( hDc, str, str.Length, ref size );

SelectObject( hDc, hOldFont );
ReleaseDC( hwndDesktop, hDc );
DeleteObject( hFont );

return( new Size( size.cx, size.cy ));
}
}
}
 
D

David Levine

When you call Control.BeginInvoke, the call to Control.Invoke is made
on a threadpool thread and the call to BeginInvoke returns immediately.
So, in effect, you have a worker thread calling BeginInvoke. The
threadpool thread then takes over and calls Control.Invoke, waiting on the
return value. The delegate passed to Invoke is then invoked on the UI
thread.

Slight change in subject....what are yours (and everyone else's) thoughts on
using control.BeginInvoke versus control.Invoke? One call is blocking versus
non-blocking; which call do you use in your product code?

Typical use case:
void SomeCallback(object state)
{
if ( myControl.InvokeRequired) )
{
myControl.BeginInvoke( new SomeCallbackDelegate(SomeCallback,new
object[] { state } ) );
// or
myControl.Invoke( new SomeCallbackDelegate(SomeCallback,new object[] {
state } ) );
}
else
{
// update myControl
}
}
 

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