locked
Difficulty assigning Categories to Public Folder items from Add-In RRS feed

  • Question

  • All,

    I wrote the (doctored) code snippet below to assign a category to items in a (favorite) public folder.   Everything seems to work.  No exceptions are raised.  Etc, Etc.  However only the 'one item' actually visible in Outlook preview window receives the new category.  Oddly enough if I toggle the "UnRead" in the same loop, I see these changes to every item in the list.

    foreach (dynamic item in folder.Items)
    {
        try
        {
            if (worker.CancellationPending)
                return;
    
            string categories = item.Categories;
            bool unread = item.UnRead;
            
            /*
             * Add category to 'read' items without it
             */
            if (!unread && !HasTargetCategory(categories))
            {
                item.Categories = AddTargetCategory(categories);
    // the indicated line } } finally { Marshal.ReleaseComObject(item); } }

    I tried adding a call to item.Save() at "// the indicated line", and that seems to work.  But that seems like overkill, and either way doesn't really explain why the UnRead and Categories property behave so differently, nor why the one item visible in the preview window is updated correctly.

    Help / Guidance would be appreciated.


    This signature unintentionally left blank.

    Friday, August 30, 2013 3:13 PM

Answers

  • Save is required when you set any item property. Unread is strictly speaking is not an item property. This is implementation specific, but for the PF store in Exchange read/unread state is stored on the per-user basis separately from the item itself. Another reason is that marking an item read/unread should not change the last modified date, which will change if you call Save.

    Say hi to Jocelyn!


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Friday, August 30, 2013 8:21 PM

All replies

  • Use of the Outlook object model from a background worker or other background thread is not supported and may cause all sorts of problems.

    Use of a foreach() loop creates one instance of the item for each loop pass and the objects aren't and can't be released until sometime later when the garbage collector runs. Use a counted for() loop and declare the variable before the loop. Then assign it in each loop pass, set it to null at the end of each pass. You may also need to call the garbage collector explicitly, as Exchange usually has a 256 RPC channel limit per user and each object and property are an RPC channel.

    You should use Save() on any item where you change the properties.


    Ken Slovak MVP - Outlook

    Friday, August 30, 2013 4:51 PM
  • Thanks Ken,

    Save makes sense, but doesn't explain the mixed behavior (I hate not understanding "Why")

    RE: for vs. foreach, I'm curios to know if that will make a difference at the IL level (and will see for myself) Would I still need to call Marshal.ReleaseCOMObject each pass of the loop? [Edit] Wait, were you referring to the lifetime of an Item or the Items collection?

    RE: background processing.  You make a good point, however because I have 2500 items in my sample folder, I can see that Outlook is doing it's own background work when I select-all and click "remove all categories".  So for the moment, I'm willing to live in the crowded space between "supported" and "works in this case."  Locking up the GUI during this update isn't really an option I want to consider unless necessary.

    And finally, Jocelyn says Hi


    This signature unintentionally left blank.


    • Edited by Nick F. _ Friday, August 30, 2013 5:29 PM
    Friday, August 30, 2013 5:26 PM
  • Jocelyn Fiorello? Say hi to her too, I didn't realize you were her husband.

    Usually what I do is set the object to null in each pass, then at about 200 passes I call Marshal.ReleaseComObject() and possibly WaitForPendingFinalizers(). The question is really the committed RPC channels, those are limited by Exchange and if you run out you start getting out of memory errors.

    Background processing in Outlook is done using Extended MAPI, not the object model. Background use of the Outlook object model is *evil* to borrow a phrase from my Exchange MVP friends. in fact it's explicitly forbidden in Outlook 2013: http://msdn.microsoft.com/en-us/library/office/jj228679.aspx. To quote from Randy's article (another old friend of Jocelyn's):

    "Be aware that all calls to the Outlook object model execute on Outlook’s main foreground thread. Avoid making long-running Outlook object model calls if possible. Note that in Outlook 2013, calls to the Outlook object model return E_RPC_WRONG_THREAD when the Outlook object model is called from a background thread."

    What I do with long-running operations is to use Redemption in a background thread. I pass the thread the hidden NameSpace.MAPIOBJECT object property and instantiate an RDOSession in the background thread, setting RDOSession.MAPIOBJECT to the passed NameSpace.MAPIOBJECT object property. That allows the background thread Redemption MAPI session to use the same MAPI logon as Outlook is using.

    Doing that avoids the background threading problem, as well as locking up the UI. I've successfully used that methodology to regularly import over 2500 contacts from database files downloaded from a Web service into Outlook contacts in the background without impacting the Outlook UI at all.


    Ken Slovak MVP - Outlook

    Friday, August 30, 2013 6:05 PM
  • Wasn't aware of the changes for 2013.  That makes it all interesting again. 

    Redemption sounds like a good plan.  Thanks.


    This signature unintentionally left blank.

    Friday, August 30, 2013 6:36 PM
  • Save is required when you set any item property. Unread is strictly speaking is not an item property. This is implementation specific, but for the PF store in Exchange read/unread state is stored on the per-user basis separately from the item itself. Another reason is that marking an item read/unread should not change the last modified date, which will change if you call Save.

    Say hi to Jocelyn!


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Friday, August 30, 2013 8:21 PM
  • Thanks Dimitry.  That does explain why I was seeing different behavior.

    This signature unintentionally left blank.

    Sunday, September 1, 2013 6:25 PM