Outlook Banter

Outlook Banter (http://www.outlookbanter.com/)
-   Add-ins for Outlook (http://www.outlookbanter.com/add-ins-outlook/)
-   -   Multithreading with C# (http://www.outlookbanter.com/add-ins-outlook/78169-multithreading-c.html)

Dorian September 5th 08 05:19 PM

Multithreading with C#
 
I've looked over a few posts on multi threading with the OOM and I understand
that the OOM itself is restricted to being single threaded. I could use some
information on how this works.

What I currently have is a MailItem object being passed to a new background
thread every time an event occurs (Explorer.SelectionChange for example). In
the thread I access things like SenderEmailAddress, ReplyRecipients. Is this
thread safe?

What happens if I access a OOM object from the worker thread that wasn't
explicitly passed to it (Example: changing the visibility of a button on a
ribbon bar). I'm guessing this isn't thread safe.

Is there any way to trigger an event on the main thread once the worker
thread has finished running? I am used to doing this with forms, and having a
worker thread invoke a delegate on the main form. Since we're not working
with forms, or even controls for that matter, how would I go about doing this?

Ken Slovak - [MVP - Outlook] September 5th 08 06:52 PM

Multithreading with C#
 
Using the Outlook object model from anywhere but your main thread, without
marshaling calls to the object model back to that thread, is a great way to
crash or hang Outlook.

You really shouldn't be passing an Outlook object to the background thread.

What you should do is set up a struct or something with the properties you
need from that Outlook object and passing the struct to your background
worker thread. That way all calls to the object model are done from the main
thread.

I use delegate event handlers in my main code to receive events fired by the
worker thread when the work is finished.

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
I've looked over a few posts on multi threading with the OOM and I
understand
that the OOM itself is restricted to being single threaded. I could use
some
information on how this works.

What I currently have is a MailItem object being passed to a new
background
thread every time an event occurs (Explorer.SelectionChange for example).
In
the thread I access things like SenderEmailAddress, ReplyRecipients. Is
this
thread safe?

What happens if I access a OOM object from the worker thread that wasn't
explicitly passed to it (Example: changing the visibility of a button on a
ribbon bar). I'm guessing this isn't thread safe.

Is there any way to trigger an event on the main thread once the worker
thread has finished running? I am used to doing this with forms, and
having a
worker thread invoke a delegate on the main form. Since we're not working
with forms, or even controls for that matter, how would I go about doing
this?



Dorian September 5th 08 07:38 PM

Multithreading with C#
 
Using a struct for the MailItem information makes sense, and if I am able to,
using a delegate event handler to return to the main thread makes sense. In
my previous experiences I've used the Invoke method of the control that the
main thread is being run on. Unfortunately I don't use any forms in the my
addin. Any hints on how to invoke an event on a main thread without having
access to Control.Invoke?

"Ken Slovak - [MVP - Outlook]" wrote:

Using the Outlook object model from anywhere but your main thread, without
marshaling calls to the object model back to that thread, is a great way to
crash or hang Outlook.

You really shouldn't be passing an Outlook object to the background thread.

What you should do is set up a struct or something with the properties you
need from that Outlook object and passing the struct to your background
worker thread. That way all calls to the object model are done from the main
thread.

I use delegate event handlers in my main code to receive events fired by the
worker thread when the work is finished.

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
I've looked over a few posts on multi threading with the OOM and I
understand
that the OOM itself is restricted to being single threaded. I could use
some
information on how this works.

What I currently have is a MailItem object being passed to a new
background
thread every time an event occurs (Explorer.SelectionChange for example).
In
the thread I access things like SenderEmailAddress, ReplyRecipients. Is
this
thread safe?

What happens if I access a OOM object from the worker thread that wasn't
explicitly passed to it (Example: changing the visibility of a button on a
ribbon bar). I'm guessing this isn't thread safe.

Is there any way to trigger an event on the main thread once the worker
thread has finished running? I am used to doing this with forms, and
having a
worker thread invoke a delegate on the main form. Since we're not working
with forms, or even controls for that matter, how would I go about doing
this?




Ken Slovak - [MVP - Outlook] September 5th 08 08:28 PM

Multithreading with C#
 
Something like this for the delegate events:

// In the class for the background worker:

internal delegate void HelloUserDoneEventHandler(object sender,
EventArgs e);

internal event HelloUserDoneEventHandler HelloUserDone;

// make a call in the code that handles worker done to OnHelloUserDone()

protected virtual void OnHelloUserDone(EventArgs e)
{

HelloUserDoneEventHandler handler = HelloUserDone;
if (handler != null)
{
// Invokes the delegate.
handler(this, e);
}
}

// in the code in the main class or wherever

private void HelloUser(object sender, EventArgs e)
{
if (e.Result != null)
{
// event fired, work done
}
}

Of course in the main code you'd need to instantiate the HelloUser event
handler, something like this, where myWorker is the class that has the
background worker:

_worker.HelloUserDone += new myWorker.HelloUserDoneEventHandler(HelloUser);

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
Using a struct for the MailItem information makes sense, and if I am able
to,
using a delegate event handler to return to the main thread makes sense.
In
my previous experiences I've used the Invoke method of the control that
the
main thread is being run on. Unfortunately I don't use any forms in the my
addin. Any hints on how to invoke an event on a main thread without having
access to Control.Invoke?



Dorian September 5th 08 08:54 PM

Multithreading with C#
 
That's exactly what I have, but when the event is fired, and I breakpoint the
event code, visual studio shows it's still running in the worker thread. Is
VS being a little misleading in it's thread monitoring?

One thing I want to be clear about in your example: the OnHelloUserDone
method is actually called on the worker thread, correct?

"Ken Slovak - [MVP - Outlook]" wrote:

Something like this for the delegate events:

// In the class for the background worker:

internal delegate void HelloUserDoneEventHandler(object sender,
EventArgs e);

internal event HelloUserDoneEventHandler HelloUserDone;

// make a call in the code that handles worker done to OnHelloUserDone()

protected virtual void OnHelloUserDone(EventArgs e)
{

HelloUserDoneEventHandler handler = HelloUserDone;
if (handler != null)
{
// Invokes the delegate.
handler(this, e);
}
}

// in the code in the main class or wherever

private void HelloUser(object sender, EventArgs e)
{
if (e.Result != null)
{
// event fired, work done
}
}

Of course in the main code you'd need to instantiate the HelloUser event
handler, something like this, where myWorker is the class that has the
background worker:

_worker.HelloUserDone += new myWorker.HelloUserDoneEventHandler(HelloUser);

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
Using a struct for the MailItem information makes sense, and if I am able
to,
using a delegate event handler to return to the main thread makes sense.
In
my previous experiences I've used the Invoke method of the control that
the
main thread is being run on. Unfortunately I don't use any forms in the my
addin. Any hints on how to invoke an event on a main thread without having
access to Control.Invoke?




Dorian September 5th 08 10:02 PM

Multithreading with C#
 
I noticed that the only difference was that you mentioned the worker thread
should maintain a separate class. I think that should make the difference.
I'll make some changes and check in again. Thanks for the help so far, it's
much appreciated.

Dorian September 5th 08 10:25 PM

Multithreading with C#
 
Putting it in a different class doesn't fix the problem. The event gets
triggered on the worker thread.

"Dorian" wrote:

That's exactly what I have, but when the event is fired, and I breakpoint the
event code, visual studio shows it's still running in the worker thread. Is
VS being a little misleading in it's thread monitoring?

One thing I want to be clear about in your example: the OnHelloUserDone
method is actually called on the worker thread, correct?

"Ken Slovak - [MVP - Outlook]" wrote:

Something like this for the delegate events:

// In the class for the background worker:

internal delegate void HelloUserDoneEventHandler(object sender,
EventArgs e);

internal event HelloUserDoneEventHandler HelloUserDone;

// make a call in the code that handles worker done to OnHelloUserDone()

protected virtual void OnHelloUserDone(EventArgs e)
{

HelloUserDoneEventHandler handler = HelloUserDone;
if (handler != null)
{
// Invokes the delegate.
handler(this, e);
}
}

// in the code in the main class or wherever

private void HelloUser(object sender, EventArgs e)
{
if (e.Result != null)
{
// event fired, work done
}
}

Of course in the main code you'd need to instantiate the HelloUser event
handler, something like this, where myWorker is the class that has the
background worker:

_worker.HelloUserDone += new myWorker.HelloUserDoneEventHandler(HelloUser);

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
Using a struct for the MailItem information makes sense, and if I am able
to,
using a delegate event handler to return to the main thread makes sense.
In
my previous experiences I've used the Invoke method of the control that
the
main thread is being run on. Unfortunately I don't use any forms in the my
addin. Any hints on how to invoke an event on a main thread without having
access to Control.Invoke?




Ken Slovak - [MVP - Outlook] September 6th 08 09:04 PM

Multithreading with C#
 
OnHelloUserDone() is a virtual method in the worker class. It calls to any
event handlers that match the signature of the HelloUserDoneEventHandler
delegate. Those handlers are in other classes and have registered to handle
the event. If they do not match the signature or haven't registered for the
event they won't get called.

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
That's exactly what I have, but when the event is fired, and I breakpoint
the
event code, visual studio shows it's still running in the worker thread.
Is
VS being a little misleading in it's thread monitoring?

One thing I want to be clear about in your example: the OnHelloUserDone
method is actually called on the worker thread, correct?



Ken Slovak - [MVP - Outlook] September 6th 08 09:07 PM

Multithreading with C#
 
The work complete event fires in the worker thread. Then you call the
virtual event handler in the worker thread. That calls the delegates which
are located in other classes. The delegates must be registered to handle the
event.

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
Putting it in a different class doesn't fix the problem. The event gets
triggered on the worker thread.



Dorian September 8th 08 03:15 PM

Multithreading with C#
 
Ok, so here's what I do:

// Main Class
public partial class ThisAddIn
{
private void Explorer_SelectionChange()
{
ReceivedMailHandler rmh = new ReceivedMailHandler();
// Do some stuff (Add data to the object)

rmh.SupportExceptionThrown += new
ReceivedMailHandler.SupportExceptionDelegate(rmh_S upportExceptionThrown);
rmh.SupportIgnoreChanged += new
ReceivedMailHandler.SupportIgnoreDelegate(rmh_Supp ortIgnoreChanged);

Thread th = new Thread(rmh.ParseAndInsertReceivedMail);
th.IsBackground = true;
th.Start();
}

void rmh_SupportIgnoreChanged(bool IsVisible)
{
btnExpIgnore.Visible = IsVisible; //Breakpoint here
}

void rmh_SupportExceptionThrown(Exception ex)
{
string blah = "asd"; //Breakpoint here
}
}

// Worker Class
class ReceivedMailHandler
{
public delegate void SupportExceptionDelegate(Exception ex);
public delegate void SupportIgnoreDelegate(bool IsVisible);

public void ParseAndInsertReceivedMail()
{
// Do work (no OOM objects)
RaiseIgnoreChange(true);
RaiseException(new Exception("blah"));
}

private void RaiseException(Exception ex)
{
SupportExceptionDelegate sed = SupportExceptionThrown;
if (sed != null) sed(ex);
}

private void RaiseIgnoreChange(bool isVisible)
{
SupportIgnoreDelegate sid = SupportIgnoreChanged;
if (sid != null) sid(isVisible);
}
}

When it hits the breakpoints on rmh_SupportIgnoreChanged and
rmh_SupportExceptionThrown, both are still in the worker thread.

"Ken Slovak - [MVP - Outlook]" wrote:

OnHelloUserDone() is a virtual method in the worker class. It calls to any
event handlers that match the signature of the HelloUserDoneEventHandler
delegate. Those handlers are in other classes and have registered to handle
the event. If they do not match the signature or haven't registered for the
event they won't get called.

--
Ken Slovak
[MVP - Outlook]
http://www.slovaktech.com
Author: Professional Programming Outlook 2007.
Reminder Manager, Extended Reminders, Attachment Options.
http://www.slovaktech.com/products.htm


"Dorian" wrote in message
...
That's exactly what I have, but when the event is fired, and I breakpoint
the
event code, visual studio shows it's still running in the worker thread.
Is
VS being a little misleading in it's thread monitoring?

One thing I want to be clear about in your example: the OnHelloUserDone
method is actually called on the worker thread, correct?





All times are GMT +1. The time now is 12:26 PM.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 2.4.0
Copyright ©2004-2006 OutlookBanter.com