Event enqueing in PostMessage style

J

John Lafrowda

Dear all,

I'm currently having some trouble with the event mechanisms in the .net
framework. What I am looking for is a way to schedule events like it is done
with PostMessage in the WinAPI: When I raise an event, the raising code
should be continued. The scheduled event should just be called after
execution of the current function has terminated. In WinAPI programming,
this could be done by posting a message through PostMessage which would be
invoked not earlier as the calling thread returns to the central message
loop.
The .net framework, however, handles events more in a "SendMessage" style,
meaning that the event handler is called immediately and interrupts the
calling code.

Cosider the following simple example in VB.net (the mechanism would be
slightly different in C# as the RaiseEvent statement is missing here - the
effect is nevertheless the same with C# techniques):

Provide a form class (Form1) with a single button (Button1) on it:
==================================================================
Public Class Form1
Inherits System.Windows.Forms.Form

[#Region " Windows Form Designer generated code "]

Private WithEvents MyEventObj As New MyEventClass

Private Sub MyHandler() Handles MyEventObj.MyEvent
MsgBox("During Event")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
Button1.Click
MsgBox("Before Call")
MyEventObj.RaiseIt()
MsgBox("After Call")
End Sub
End Class

==================================================================

In addition, the MyEventClass is needed with following contents:
==================================================================
Public Class MyEventClass

Public Event MyEvent()

Public Sub RaiseIt()
RaiseEvent MyEvent()
End Sub
End Class

==================================================================

Now, the message boxes are appearing in the sequence "Before Call" ->
"During Event" -> "After Call", where I would like to see the sequence
"Before Call" -> "After Call" -> "During Event".
Probably the .net event model is the wrong way to go, but I don't see any
other at the moment except for going back to the WinAPI with PostMessage,
which does not provide the features of managed code (and object/contents
transmission) and is thus not exactly what I want, either.

Maybe I don't see the obvious here... Any solutions?

Best regards,

John
 
B

Brian Newtz

Wouldn't the obvious answer be to raise the event at the end of the method?

-Brian
 
J

John Lafrowda

Dear Brian,

the actual problem is a bit more complicated than the given example. So the
constraint is really to finalise the calling method before entering the
event handler - just like WinAPI coders [like me] would do it by
PostMessage.

Maybe the answer is less obvious than I thought...

Thanks,

John


Brian Newtz said:
Wouldn't the obvious answer be to raise the event at the end of the method?

-Brian


John Lafrowda said:
Dear all,

I'm currently having some trouble with the event mechanisms in the .net
framework. What I am looking for is a way to schedule events like it is done
with PostMessage in the WinAPI: When I raise an event, the raising code
should be continued. The scheduled event should just be called after
execution of the current function has terminated. In WinAPI programming,
this could be done by posting a message through PostMessage which would be
invoked not earlier as the calling thread returns to the central message
loop.
The .net framework, however, handles events more in a "SendMessage" style,
meaning that the event handler is called immediately and interrupts the
calling code.

Cosider the following simple example in VB.net (the mechanism would be
slightly different in C# as the RaiseEvent statement is missing here - the
effect is nevertheless the same with C# techniques):

Provide a form class (Form1) with a single button (Button1) on it:
==================================================================
Public Class Form1
Inherits System.Windows.Forms.Form

[#Region " Windows Form Designer generated code "]

Private WithEvents MyEventObj As New MyEventClass

Private Sub MyHandler() Handles MyEventObj.MyEvent
MsgBox("During Event")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
Button1.Click
MsgBox("Before Call")
MyEventObj.RaiseIt()
MsgBox("After Call")
End Sub
End Class

==================================================================

In addition, the MyEventClass is needed with following contents:
==================================================================
Public Class MyEventClass

Public Event MyEvent()

Public Sub RaiseIt()
RaiseEvent MyEvent()
End Sub
End Class

==================================================================

Now, the message boxes are appearing in the sequence "Before Call" ->
"During Event" -> "After Call", where I would like to see the sequence
"Before Call" -> "After Call" -> "During Event".
Probably the .net event model is the wrong way to go, but I don't see any
other at the moment except for going back to the WinAPI with PostMessage,
which does not provide the features of managed code (and object/contents
transmission) and is thus not exactly what I want, either.

Maybe I don't see the obvious here... Any solutions?

Best regards,

John
 
B

Brian Newtz

To me, it almost sounds like you just want to do an asyncronous call,
correct? (bear with me, I'm not a winapi guy). You could always raise the
event on a separate thread if that's all you want to do.

-Brian

John Lafrowda said:
Dear Brian,

the actual problem is a bit more complicated than the given example. So the
constraint is really to finalise the calling method before entering the
event handler - just like WinAPI coders [like me] would do it by
PostMessage.

Maybe the answer is less obvious than I thought...

Thanks,

John


Brian Newtz said:
Wouldn't the obvious answer be to raise the event at the end of the method?

-Brian


is
done
would
be
invoked not earlier as the calling thread returns to the central message
loop.
The .net framework, however, handles events more in a "SendMessage" style,
meaning that the event handler is called immediately and interrupts the
calling code.

Cosider the following simple example in VB.net (the mechanism would be
slightly different in C# as the RaiseEvent statement is missing here - the
effect is nevertheless the same with C# techniques):

Provide a form class (Form1) with a single button (Button1) on it:
==================================================================
Public Class Form1
Inherits System.Windows.Forms.Form

[#Region " Windows Form Designer generated code "]

Private WithEvents MyEventObj As New MyEventClass

Private Sub MyHandler() Handles MyEventObj.MyEvent
MsgBox("During Event")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
Button1.Click
MsgBox("Before Call")
MyEventObj.RaiseIt()
MsgBox("After Call")
End Sub
End Class

==================================================================

In addition, the MyEventClass is needed with following contents:
==================================================================
Public Class MyEventClass

Public Event MyEvent()

Public Sub RaiseIt()
RaiseEvent MyEvent()
End Sub
End Class

==================================================================

Now, the message boxes are appearing in the sequence "Before Call" ->
"During Event" -> "After Call", where I would like to see the sequence
"Before Call" -> "After Call" -> "During Event".
Probably the .net event model is the wrong way to go, but I don't see any
other at the moment except for going back to the WinAPI with PostMessage,
which does not provide the features of managed code (and object/contents
transmission) and is thus not exactly what I want, either.

Maybe I don't see the obvious here... Any solutions?

Best regards,

John
 
J

John Lafrowda

To me, it almost sounds like you just want to do an asyncronous call,
correct? (bear with me, I'm not a winapi guy). You could always raise the
event on a separate thread if that's all you want to do.

More or less, an asynchronous call performed by another thread is exactly
what I want to prevent. Situation is as follows: My programme structure
consists of a central module loading several plug-ins during run-time. these
plug-ins provides service code which may be called by the thread of the
central module. If operation of the services can be concluded in short time,
the thread of the central module enters, performs the service operations and
leaves again. In case, operation will take long time, the plug-in services
may start their own threads after which the main thread can return
immediately.
Now, the event is needed to inform the main module that operations of a
service of any kind have finished. From the concept of exceptions, I've
expected that I could pack all the results of the services in objects that
are passed to a RaiseEvent function (or similar C#-construct). Furthermore,
I've expected that these events are queued and invoked by the cental
module's thread only. Thus, I've expected this could be a way to synchronise
the receipt of service results.
If this does not work, I could manually create a results-queue and hack in
some PostMessage that notifies the central module of the arrival of service
results in the queue.

My main question, however, may be reformulated much simpler: Where is the
point in using events and RaiseEvent if you could invoke the corresponding
event handler by invoking the associated handler function. From what I see
now, this would result in the same application flow which may easily result
in conflicts like re-entrant code. The only advantage from events would then
be that modules may offer standardised event interfaces that may be imported
in different software solutions when re-using the object. The exectution
sequence of directly jumping to the event handler code, however, appears
very unpracticable to most the situations where I would use events.

Any further ideas?

Best regards,

Peter
 
J

John Lafrowda

To me, it almost sounds like you just want to do an asyncronous call,
correct? (bear with me, I'm not a winapi guy). You could always raise the
event on a separate thread if that's all you want to do.

More or less, an asynchronous call performed by another thread is exactly
what I want to prevent. Situation is as follows: My programme structure
consists of a central module loading several plug-ins during run-time. these
plug-ins provides service code which may be called by the thread of the
central module. If operation of the services can be concluded in short time,
the thread of the central module enters, performs the service operations and
leaves again. In case, operation will take long time, the plug-in services
may start their own threads after which the main thread can return
immediately.
Now, the event is needed to inform the main module that operations of a
service of any kind have finished. From the concept of exceptions, I've
expected that I could pack all the results of the services in objects that
are passed to a RaiseEvent function (or similar C#-construct). Furthermore,
I've expected that these events are queued and invoked by the cental
module's thread only. Thus, I've expected this could be a way to synchronise
the receipt of service results.
If this does not work, I could manually create a results-queue and hack in
some PostMessage that notifies the central module of the arrival of service
results in the queue.

My main question, however, may be reformulated much simpler: Where is the
point in using events and RaiseEvent if you could invoke the corresponding
event handler by invoking the associated handler function. From what I see
now, this would result in the same application flow which may easily result
in conflicts like re-entrant code. The only advantage from events would then
be that modules may offer standardised event interfaces that may be imported
in different software solutions when re-using the object. The exectution
sequence of directly jumping to the event handler code, however, appears
very unpracticable to most the situations where I would use events.

Any further ideas?

Best regards,

John
 
B

Brian Newtz

Ok, if I understand you correctly, you have a main module that is the
subscriber to the events of the service modules (aka plugins). You want the
events fired by the services to be received by the main module in order
(i.e. - always handled by the main thread of the main module).

Here's a bare bones implementation of a sample windows forms app that does
what you want. (Hopefully all of the code won't have to formatting butchered
TOO much :)

First, the form.cs file that has the main windows form. In particular, pay
attention to MyHandler_MethodFinished and MainThreadhandler:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace EventSyncronizationWindows
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.RichTextBox rtbOutput;
private System.Windows.Forms.Button btnLoadPlugins;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

Thread.CurrentThread.Name = "Main Thread";
}

private void btnLoadPlugins_Click(object sender, System.EventArgs e)
{
PlugInA a = new PlugInA();
PlugInB b = new PlugInB();

a.MethodFinished += new MethodFinishedDelegate(MyHandler_MethodFinished);
b.MethodFinished += new MethodFinishedDelegate(MyHandler_MethodFinished);

rtbOutput.AppendText("Calling PluginA MethodShort\n");
a.MethodShort();
rtbOutput.AppendText("Calling PluginB MethodShort\n");
b.MethodShort();
rtbOutput.AppendText("Calling PluginA MethodLong\n");
a.MethodLong();
rtbOutput.AppendText("Calling PluginA MethodLong\n");
b.MethodLong();
}

private void MyHandler_MethodFinished(object sender, MethodFinishedArgs e)
{
this.Invoke(new MethodFinishedDelegate(this.MainThreadhandler), new
object[] {sender, e});
}

private void MainThreadhandler(object sender, MethodFinishedArgs e)
{
string methodFinished = (string)e.EventData.Data;
rtbOutput.AppendText(Thread.CurrentThread.Name + " : " + methodFinished +
"\n");
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.rtbOutput = new System.Windows.Forms.RichTextBox();
this.btnLoadPlugins = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// rtbOutput
//
this.rtbOutput.Dock = System.Windows.Forms.DockStyle.Top;
this.rtbOutput.Location = new System.Drawing.Point(0, 0);
this.rtbOutput.Name = "rtbOutput";
this.rtbOutput.ScrollBars =
System.Windows.Forms.RichTextBoxScrollBars.ForcedBoth;
this.rtbOutput.Size = new System.Drawing.Size(488, 360);
this.rtbOutput.TabIndex = 0;
this.rtbOutput.Text = "";
this.rtbOutput.WordWrap = false;
//
// btnLoadPlugins
//
this.btnLoadPlugins.Location = new System.Drawing.Point(400, 376);
this.btnLoadPlugins.Name = "btnLoadPlugins";
this.btnLoadPlugins.TabIndex = 1;
this.btnLoadPlugins.Text = "Load Plugins";
this.btnLoadPlugins.Click += new
System.EventHandler(this.btnLoadPlugins_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(488, 414);
this.Controls.Add(this.btnLoadPlugins);
this.Controls.Add(this.rtbOutput);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}

END CODE FOR FORM. Now, here's the code for the simplified plugin classes,
delegates, eventargs, etc:

using System;
using System.Threading;

namespace EventSyncronizationWindows
{
delegate void MethodFinishedDelegate(object sender, MethodFinishedArgs e);

class PlugInA
{
public event MethodFinishedDelegate MethodFinished;

public void MethodShort()
{
for(int i = 0; i < 100; i++)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginA -
MethodShortFinished")));
}

public void MethodLong()
{
ThreadStart ts = new ThreadStart(this.AsyncMethod);
Thread t = new Thread(ts);

t.Name = "PluginA Thread";
t.Start();
}

private void AsyncMethod()
{
DateTime future = DateTime.Now.AddSeconds(10);
while (DateTime.Now < future)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginA -
AsyncMethodFinished")));
}

protected virtual void OnMethodFinished(MethodFinishedArgs e)
{
if (this.MethodFinished != null)
{
this.MethodFinished(this, e);
}
}
}

class PlugInB
{
public event MethodFinishedDelegate MethodFinished;

public void MethodShort()
{
for(int i = 0; i < 100; i++)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginB -
MethodShortFinished")));
}

public void MethodLong()
{
ThreadStart ts = new ThreadStart(this.AsyncMethod);
Thread t = new Thread(ts);

t.Name = "PluginB Thread";
t.Start();
}

private void AsyncMethod()
{
DateTime future = DateTime.Now.AddSeconds(5);
while (DateTime.Now < future)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginB -
AsyncMethodFinished")));
}

protected virtual void OnMethodFinished(MethodFinishedArgs e)
{
if (this.MethodFinished != null)
{
this.MethodFinished(this, e);
}
}
}

class EventData
{
private object data;

public EventData(object data)
{
this.data = data;
}

public object Data
{
get
{
return this.data;
}
}
}

class MethodFinishedArgs : EventArgs
{
private EventData eventData;

public MethodFinishedArgs(EventData arbitraryEventData)
{
this.eventData = arbitraryEventData;
}

public EventData EventData
{
get
{
return this.eventData;
}
}
}
}


END CODE. I know this is a bunch to chew on, but basically, you can copy the
form code to a cs file, then copy the plugin classes and such to another
file, plop them in a solution and build it, and you will see that the
richtextbox on the form will echo what thread is handling the events in what
order.

Let me know if this helps!
-Brian
 
J

John Lafrowda

Thanks a lot!

The code works perfectly and does what I want. As I find it a bit too
complex for what I am doing, I tried to modify some bits and now I get a
similar procedure where I use only delegate functions without the need for
events.
My main problem was obviously derived from missunderstanding the "invoke"
method, which is now clear to me from what I've seen in your code. It is
exactly this feature that I need to make the server's thread handling a data
delivered by the plug-in threads and to prevent the plug-ins' threads
entering the server's binary code.

So far for the big knot in my head...

Best regards,

John


Brian Newtz said:
Ok, if I understand you correctly, you have a main module that is the
subscriber to the events of the service modules (aka plugins). You want the
events fired by the services to be received by the main module in order
(i.e. - always handled by the main thread of the main module).

Here's a bare bones implementation of a sample windows forms app that does
what you want. (Hopefully all of the code won't have to formatting butchered
TOO much :)

First, the form.cs file that has the main windows form. In particular, pay
attention to MyHandler_MethodFinished and MainThreadhandler:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace EventSyncronizationWindows
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.RichTextBox rtbOutput;
private System.Windows.Forms.Button btnLoadPlugins;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

Thread.CurrentThread.Name = "Main Thread";
}

private void btnLoadPlugins_Click(object sender, System.EventArgs e)
{
PlugInA a = new PlugInA();
PlugInB b = new PlugInB();

a.MethodFinished += new MethodFinishedDelegate(MyHandler_MethodFinished);
b.MethodFinished += new MethodFinishedDelegate(MyHandler_MethodFinished);

rtbOutput.AppendText("Calling PluginA MethodShort\n");
a.MethodShort();
rtbOutput.AppendText("Calling PluginB MethodShort\n");
b.MethodShort();
rtbOutput.AppendText("Calling PluginA MethodLong\n");
a.MethodLong();
rtbOutput.AppendText("Calling PluginA MethodLong\n");
b.MethodLong();
}

private void MyHandler_MethodFinished(object sender, MethodFinishedArgs e)
{
this.Invoke(new MethodFinishedDelegate(this.MainThreadhandler), new
object[] {sender, e});
}

private void MainThreadhandler(object sender, MethodFinishedArgs e)
{
string methodFinished = (string)e.EventData.Data;
rtbOutput.AppendText(Thread.CurrentThread.Name + " : " + methodFinished +
"\n");
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.rtbOutput = new System.Windows.Forms.RichTextBox();
this.btnLoadPlugins = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// rtbOutput
//
this.rtbOutput.Dock = System.Windows.Forms.DockStyle.Top;
this.rtbOutput.Location = new System.Drawing.Point(0, 0);
this.rtbOutput.Name = "rtbOutput";
this.rtbOutput.ScrollBars =
System.Windows.Forms.RichTextBoxScrollBars.ForcedBoth;
this.rtbOutput.Size = new System.Drawing.Size(488, 360);
this.rtbOutput.TabIndex = 0;
this.rtbOutput.Text = "";
this.rtbOutput.WordWrap = false;
//
// btnLoadPlugins
//
this.btnLoadPlugins.Location = new System.Drawing.Point(400, 376);
this.btnLoadPlugins.Name = "btnLoadPlugins";
this.btnLoadPlugins.TabIndex = 1;
this.btnLoadPlugins.Text = "Load Plugins";
this.btnLoadPlugins.Click += new
System.EventHandler(this.btnLoadPlugins_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(488, 414);
this.Controls.Add(this.btnLoadPlugins);
this.Controls.Add(this.rtbOutput);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}

END CODE FOR FORM. Now, here's the code for the simplified plugin classes,
delegates, eventargs, etc:

using System;
using System.Threading;

namespace EventSyncronizationWindows
{
delegate void MethodFinishedDelegate(object sender, MethodFinishedArgs e);

class PlugInA
{
public event MethodFinishedDelegate MethodFinished;

public void MethodShort()
{
for(int i = 0; i < 100; i++)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginA -
MethodShortFinished")));
}

public void MethodLong()
{
ThreadStart ts = new ThreadStart(this.AsyncMethod);
Thread t = new Thread(ts);

t.Name = "PluginA Thread";
t.Start();
}

private void AsyncMethod()
{
DateTime future = DateTime.Now.AddSeconds(10);
while (DateTime.Now < future)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginA -
AsyncMethodFinished")));
}

protected virtual void OnMethodFinished(MethodFinishedArgs e)
{
if (this.MethodFinished != null)
{
this.MethodFinished(this, e);
}
}
}

class PlugInB
{
public event MethodFinishedDelegate MethodFinished;

public void MethodShort()
{
for(int i = 0; i < 100; i++)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginB -
MethodShortFinished")));
}

public void MethodLong()
{
ThreadStart ts = new ThreadStart(this.AsyncMethod);
Thread t = new Thread(ts);

t.Name = "PluginB Thread";
t.Start();
}

private void AsyncMethod()
{
DateTime future = DateTime.Now.AddSeconds(5);
while (DateTime.Now < future)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginB -
AsyncMethodFinished")));
}

protected virtual void OnMethodFinished(MethodFinishedArgs e)
{
if (this.MethodFinished != null)
{
this.MethodFinished(this, e);
}
}
}

class EventData
{
private object data;

public EventData(object data)
{
this.data = data;
}

public object Data
{
get
{
return this.data;
}
}
}

class MethodFinishedArgs : EventArgs
{
private EventData eventData;

public MethodFinishedArgs(EventData arbitraryEventData)
{
this.eventData = arbitraryEventData;
}

public EventData EventData
{
get
{
return this.eventData;
}
}
}
}


END CODE. I know this is a bunch to chew on, but basically, you can copy the
form code to a cs file, then copy the plugin classes and such to another
file, plop them in a solution and build it, and you will see that the
richtextbox on the form will echo what thread is handling the events in what
order.

Let me know if this helps!
-Brian


John Lafrowda said:
More or less, an asynchronous call performed by another thread is exactly
what I want to prevent. Situation is as follows: My programme structure
consists of a central module loading several plug-ins during run-time. these
plug-ins provides service code which may be called by the thread of the
central module. If operation of the services can be concluded in short time,
the thread of the central module enters, performs the service operations and
leaves again. In case, operation will take long time, the plug-in services
may start their own threads after which the main thread can return
immediately.
Now, the event is needed to inform the main module that operations of a
service of any kind have finished. From the concept of exceptions, I've
expected that I could pack all the results of the services in objects that
are passed to a RaiseEvent function (or similar C#-construct). Furthermore,
I've expected that these events are queued and invoked by the cental
module's thread only. Thus, I've expected this could be a way to synchronise
the receipt of service results.
If this does not work, I could manually create a results-queue and hack in
some PostMessage that notifies the central module of the arrival of service
results in the queue.

My main question, however, may be reformulated much simpler: Where is the
point in using events and RaiseEvent if you could invoke the corresponding
event handler by invoking the associated handler function. From what I see
now, this would result in the same application flow which may easily result
in conflicts like re-entrant code. The only advantage from events would then
be that modules may offer standardised event interfaces that may be imported
in different software solutions when re-using the object. The exectution
sequence of directly jumping to the event handler code, however, appears
very unpracticable to most the situations where I would use events.

Any further ideas?

Best regards,

John
 
B

Brian Newtz

Glad I could help!
-Brian


John Lafrowda said:
Thanks a lot!

The code works perfectly and does what I want. As I find it a bit too
complex for what I am doing, I tried to modify some bits and now I get a
similar procedure where I use only delegate functions without the need for
events.
My main problem was obviously derived from missunderstanding the "invoke"
method, which is now clear to me from what I've seen in your code. It is
exactly this feature that I need to make the server's thread handling a data
delivered by the plug-in threads and to prevent the plug-ins' threads
entering the server's binary code.

So far for the big knot in my head...

Best regards,

John


Brian Newtz said:
Ok, if I understand you correctly, you have a main module that is the
subscriber to the events of the service modules (aka plugins). You want the
events fired by the services to be received by the main module in order
(i.e. - always handled by the main thread of the main module).

Here's a bare bones implementation of a sample windows forms app that does
what you want. (Hopefully all of the code won't have to formatting butchered
TOO much :)

First, the form.cs file that has the main windows form. In particular, pay
attention to MyHandler_MethodFinished and MainThreadhandler:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace EventSyncronizationWindows
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.RichTextBox rtbOutput;
private System.Windows.Forms.Button btnLoadPlugins;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

Thread.CurrentThread.Name = "Main Thread";
}

private void btnLoadPlugins_Click(object sender, System.EventArgs e)
{
PlugInA a = new PlugInA();
PlugInB b = new PlugInB();

a.MethodFinished += new MethodFinishedDelegate(MyHandler_MethodFinished);
b.MethodFinished += new MethodFinishedDelegate(MyHandler_MethodFinished);

rtbOutput.AppendText("Calling PluginA MethodShort\n");
a.MethodShort();
rtbOutput.AppendText("Calling PluginB MethodShort\n");
b.MethodShort();
rtbOutput.AppendText("Calling PluginA MethodLong\n");
a.MethodLong();
rtbOutput.AppendText("Calling PluginA MethodLong\n");
b.MethodLong();
}

private void MyHandler_MethodFinished(object sender,
MethodFinishedArgs
e)
{
this.Invoke(new MethodFinishedDelegate(this.MainThreadhandler), new
object[] {sender, e});
}

private void MainThreadhandler(object sender, MethodFinishedArgs e)
{
string methodFinished = (string)e.EventData.Data;
rtbOutput.AppendText(Thread.CurrentThread.Name + " : " +
methodFinished
+
"\n");
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.rtbOutput = new System.Windows.Forms.RichTextBox();
this.btnLoadPlugins = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// rtbOutput
//
this.rtbOutput.Dock = System.Windows.Forms.DockStyle.Top;
this.rtbOutput.Location = new System.Drawing.Point(0, 0);
this.rtbOutput.Name = "rtbOutput";
this.rtbOutput.ScrollBars =
System.Windows.Forms.RichTextBoxScrollBars.ForcedBoth;
this.rtbOutput.Size = new System.Drawing.Size(488, 360);
this.rtbOutput.TabIndex = 0;
this.rtbOutput.Text = "";
this.rtbOutput.WordWrap = false;
//
// btnLoadPlugins
//
this.btnLoadPlugins.Location = new System.Drawing.Point(400, 376);
this.btnLoadPlugins.Name = "btnLoadPlugins";
this.btnLoadPlugins.TabIndex = 1;
this.btnLoadPlugins.Text = "Load Plugins";
this.btnLoadPlugins.Click += new
System.EventHandler(this.btnLoadPlugins_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(488, 414);
this.Controls.Add(this.btnLoadPlugins);
this.Controls.Add(this.rtbOutput);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}

END CODE FOR FORM. Now, here's the code for the simplified plugin classes,
delegates, eventargs, etc:

using System;
using System.Threading;

namespace EventSyncronizationWindows
{
delegate void MethodFinishedDelegate(object sender, MethodFinishedArgs e);

class PlugInA
{
public event MethodFinishedDelegate MethodFinished;

public void MethodShort()
{
for(int i = 0; i < 100; i++)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginA -
MethodShortFinished")));
}

public void MethodLong()
{
ThreadStart ts = new ThreadStart(this.AsyncMethod);
Thread t = new Thread(ts);

t.Name = "PluginA Thread";
t.Start();
}

private void AsyncMethod()
{
DateTime future = DateTime.Now.AddSeconds(10);
while (DateTime.Now < future)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginA -
AsyncMethodFinished")));
}

protected virtual void OnMethodFinished(MethodFinishedArgs e)
{
if (this.MethodFinished != null)
{
this.MethodFinished(this, e);
}
}
}

class PlugInB
{
public event MethodFinishedDelegate MethodFinished;

public void MethodShort()
{
for(int i = 0; i < 100; i++)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginB -
MethodShortFinished")));
}

public void MethodLong()
{
ThreadStart ts = new ThreadStart(this.AsyncMethod);
Thread t = new Thread(ts);

t.Name = "PluginB Thread";
t.Start();
}

private void AsyncMethod()
{
DateTime future = DateTime.Now.AddSeconds(5);
while (DateTime.Now < future)
{
}

this.OnMethodFinished(new MethodFinishedArgs(new EventData("PluginB -
AsyncMethodFinished")));
}

protected virtual void OnMethodFinished(MethodFinishedArgs e)
{
if (this.MethodFinished != null)
{
this.MethodFinished(this, e);
}
}
}

class EventData
{
private object data;

public EventData(object data)
{
this.data = data;
}

public object Data
{
get
{
return this.data;
}
}
}

class MethodFinishedArgs : EventArgs
{
private EventData eventData;

public MethodFinishedArgs(EventData arbitraryEventData)
{
this.eventData = arbitraryEventData;
}

public EventData EventData
{
get
{
return this.eventData;
}
}
}
}


END CODE. I know this is a bunch to chew on, but basically, you can copy the
form code to a cs file, then copy the plugin classes and such to another
file, plop them in a solution and build it, and you will see that the
richtextbox on the form will echo what thread is handling the events in what
order.

Let me know if this helps!
-Brian


John Lafrowda said:
To me, it almost sounds like you just want to do an asyncronous call,
correct? (bear with me, I'm not a winapi guy). You could always
raise
the
event on a separate thread if that's all you want to do.

More or less, an asynchronous call performed by another thread is exactly
what I want to prevent. Situation is as follows: My programme structure
consists of a central module loading several plug-ins during run-time. these
plug-ins provides service code which may be called by the thread of the
central module. If operation of the services can be concluded in short time,
the thread of the central module enters, performs the service
operations
and
leaves again. In case, operation will take long time, the plug-in services
may start their own threads after which the main thread can return
immediately.
Now, the event is needed to inform the main module that operations of a
service of any kind have finished. From the concept of exceptions, I've
expected that I could pack all the results of the services in objects that
are passed to a RaiseEvent function (or similar C#-construct). Furthermore,
I've expected that these events are queued and invoked by the cental
module's thread only. Thus, I've expected this could be a way to synchronise
the receipt of service results.
If this does not work, I could manually create a results-queue and
hack
in would
then
 

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