none
To marshal or not to marshal - that is the question! RRS feed

  • Question

  • I have an Outlook VSTO add-in written in C# that does a lot of its work on background threads. This work involves calling into the Outlook COM objects (Explorer, Item), creating, deleting and modifying items, setting properties, that sort of thing. I've been trying to figure out over the last couple of days if I need to marshal these objects, but I haven't found a definitive answer. Some docs seem to suggest that marshalling is not needed on the managed side, that the .NET magic does it automatically... but I'm not so sure. I have corrupted my mailbox quite a few times during development and had to recreate it and occasionally I'll get unexplained error when trying to do simple operations, such as Item.Delete() will throw an E_ABORT. These intermitent errors make me believe that maybe I do need to marshal...

    In my code, I keep references to a few objects that I don't want destroyed because I'm subscribed to certain events they trigger, such as Explorer.SelectionChanged, BeforeItemDelete, etc. So basically during Startup I have code like this:

    private Outlook.Explorer _explorer;
    private Outlook.Folder _deleted;
    private Outlook.Items _deletedItems;

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        _explorer = Application.ActiveExplorer();
        _deleted = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems) as Outlook.Folder;
        _deletedItems = _deleted.Items;
    }

    So the question is, can I use _explorer, _deleted and _deletedItems for instance, from different threads? Do I need to marshal them? If I do, are these objects basically interface pointers underneath, will they be marshaled correctly to IUnknown* as expected by CoMarshalInterThreadInterfaceInStream?

    Does anyone have any sample code in C# on this? I found some PInvoke declarations for the CoMarshal methods, but I haven't tried them yet, don't know if they'll work.

    Any help would be much appreciated.

    Thanks,
    Florin

    Thursday, August 18, 2011 5:28 PM

Answers

  • Hello,

    In a thread other than the main one, you cannot use things from the Outlook object model.

    You can use a timer to perform a part of your job in the UI thread.

    You may also want to implement the approach implemented in Add-in Express. It creates a hidden Win32 API window: you post a custom Windows message to that window and when the message is received, the corresponfing event occurs. Using several windows messages you can implement a mechanism supporting all aspects of your job. 


    Regards from Belarus (GMT + 2),

    Andrei Smolin
    Add-in Express Team Leader
    • Marked as answer by Florin F Micle Thursday, August 25, 2011 10:23 PM
    Friday, August 19, 2011 9:41 AM

All replies

  • The Outlook object model is not suited, suitable or supported for use in anything other than the main thread. No background threading operations are supported at all, and if used will end up crashing or hanging Outlook, possibly corrupting things, and crashing other code that integrates with Outlook. It's a remarkably bad idea to do that.
     
    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "Florin F Micle" <=?utf-8?B?RmxvcmluIEYgTWljbGU=?=> wrote in message news:5abc19ae-59b8-4562-ad57-cff6b8a7b195...

    I have an Outlook VSTO add-in written in C# that does a lot of its work on background threads. This work involves calling into the Outlook COM objects (Explorer, Item), creating, deleting and modifying items, setting properties, that sort of thing. I've been trying to figure out over the last couple of days if I need to marshal these objects, but I haven't found a definitive answer. Some docs seem to suggest that marshalling is not needed on the managed side, that the .NET magic does it automatically... but I'm not so sure. I have corrupted my mailbox quite a few times during development and had to recreate it and occasionally I'll get unexplained error when trying to do simple operations, such as Item.Delete() will throw an E_ABORT. These intermitent errors make me believe that maybe I do need to marshal...

    In my code, I keep references to a few objects that I don't want destroyed because I'm subscribed to certain events they trigger, such as Explorer.SelectionChanged, BeforeItemDelete, etc. So basically during Startup I have code like this:

    private Outlook.Explorer _explorer;
    private Outlook.Folder _deleted;
    private Outlook.Items _deletedItems;

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        _explorer = Application.ActiveExplorer();
        _deleted = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems) as Outlook.Folder;
        _deletedItems = _deleted.Items;
    }

    So the question is, can I use _explorer, _deleted and _deletedItems for instance, from different threads? Do I need to marshal them? If I do, are these objects basically interface pointers underneath, will they be marshaled correctly to IUnknown* as expected by CoMarshalInterThreadInterfaceInStream?

    Does anyone have any sample code in C# on this? I found some PInvoke declarations for the CoMarshal methods, but I haven't tried them yet, don't know if they'll work.

    Any help would be much appreciated.

    Thanks,
    Florin


    Ken Slovak MVP - Outlook
    Thursday, August 18, 2011 5:45 PM
  • Well, obviously, I think you are right, otherwise I wouldn't be looking for a solution :-) I did notice such crashes, hangs and mailbox corruptions myself. So, I am actually looking at 3 possible solutions:

    1. Create a hidden window or control in my add-in so I can use the BeginInvoke mechanism, which would ensure that the code runs on the UI thread.

    2. Use a timer and let all the background threads post the work to the UI thread through this timer.

    3. Try to marshall the Outlook objects so I can call them from background threads - not for the faint of heart, right?

    Which path should I go? I wonder if #1 could work without creating who-knows-what other problems.

    Any thoughts?

    Thursday, August 18, 2011 6:01 PM
  • What exactly does your codeon the background thread? Is it mostly UI work or processing the Outlook items/folders/etc?
    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Thursday, August 18, 2011 9:30 PM
  • It's processing items/folders/etc. For instance when certain events are triggered from our server, I create/delete items into/from Inbox and Deleted folders (using Redemption by the way ;-)) to keep some things in sync between our server and the user's mailbox.

    Some processing is triggered by user actions (user deletes an item, replies, forwards, etc) and this processing is usually fine, but some actions are triggered by our server and those are happening on whatever the calling thread happens to be (coming from a thread pool) - these are the ones that fail occasionally.

    Thursday, August 18, 2011 11:21 PM
  • Hello,

    In a thread other than the main one, you cannot use things from the Outlook object model.

    You can use a timer to perform a part of your job in the UI thread.

    You may also want to implement the approach implemented in Add-in Express. It creates a hidden Win32 API window: you post a custom Windows message to that window and when the message is received, the corresponfing event occurs. Using several windows messages you can implement a mechanism supporting all aspects of your job. 


    Regards from Belarus (GMT + 2),

    Andrei Smolin
    Add-in Express Team Leader
    • Marked as answer by Florin F Micle Thursday, August 25, 2011 10:23 PM
    Friday, August 19, 2011 9:41 AM
  • With Redemption you can use the object model in background threads.
     
    Create a new RDOSession object and set RDOSession.MAPIOBJECT to the NameSpace.MAPIOBJECT from the main thread. That makes sure Redemption is on the same MAPI session as Outlook.

    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "Florin F Micle" <=?utf-8?B?RmxvcmluIEYgTWljbGU=?=> wrote in message news:7359fcce-1c8a-4e7b-b7c3-7f9710994e34...

    It's processing items/folders/etc. For instance when certain events are triggered from our server, I create/delete items into/from Inbox and Deleted folders (using Redemption by the way ;-)) to keep some things in sync between our server and the user's mailbox.

    Some processing is triggered by user actions (user deletes an item, replies, forwards, etc) and this processing is usually fine, but some actions are triggered by our server and those are happening on whatever the calling thread happens to be (coming from a thread pool) - these are the ones that fail occasionally.


    Ken Slovak MVP - Outlook
    Friday, August 19, 2011 8:41 PM
  • Hi Florin,

    Have you solved the problem?

    If you have any further concern, please feel free to follow up.


    Best Regards, Calvin Gao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, August 25, 2011 5:56 AM
    Moderator
  • Only time (and QA) will tell... if I solved the problem :-) It's looking good so far though, I'm quite confident :-)
    Thursday, August 25, 2011 10:22 PM