none
Outlook 2010 VBA: Changing Sent Message's MessageClass to custom form does not immediately apply to the selected object

    Question

  • I've created a custom form that users can switch to in order to print Bcc field. It's not very complex at all:

    Public Sub Print_BCC()
     
    Dim CurItem
    Dim CurFolder As Outlook.Folder
    Dim NewMC As String
    Dim SelectedItems As Items
    NewMC = "IPM.Note.Print_Bcc"
      
      Set CurFolder = Application.ActiveExplorer.CurrentFolder
      Set SelectedItems = CurFolder.Items
      
      If CurFolder.Name <> "Sent Items" Then
        MsgBox "This Command Can Only Be Used Selected Items In The 'Sent Items' Folder", vbOKOnly, "INCORRECT FOLDER"
        Exit Sub
      End If
     
      For Each CurItem In Application.ActiveExplorer.Selection
        CurItem.MessageClass = NewMC
        CurItem.Save
      Next
      
      Set CurFolder = Nothing
      Set SelectedItems = Nothing
        
      MsgBox "Done."
      
    End Sub

    When the code has completed, the items will show the new icon. However, opening the selected item still shows the previous form. Running the code again confirms that the message class is indeed the custom form 'IPM.Note.Print_Bcc'. This also happens for the sub that sets the item back to the default form.

    Here's the weird part. Switching from the Sent Items folder to any other mail folder, then back will trigger some action. Opening the mail item after this folder change will then show the correct custom form.

    Odd thing about changing folders: It only works, guaranteed if you switch to another mail folder. I've tried switching to Calendar, Tasks and Contact sections, then selecting a folder in there and checking. Sometimes works the first time, sometimes not. Also, it will sometimes 'refresh' if I collapse the group in the view and click around to other mail items, but it's not guaranteed.

    I've also tried to manually switch from Sent Items to Inbox then back to Sent Items in the code after the update. This does not help. I'm not sure what it causing this, but I'd rather my users not have to 'Click away and back' in order to use the change.

    Any help would be appreciated. Thanks. ~R


    Robert Ogden

    Wednesday, December 18, 2013 4:18 PM

Answers

  • It appears there are no Inspectors, as the Explorer.Selection collection is being iterated. Outlook also caches items in a Selection, and that's where this problem is happening.

    Unreleased references are being created by use of a For Each loop. You should use a counted For loop and explicitly release CurItem in each loop pass.

    This is a well-known problem, and the fix is to switch folders and wait for an Unload() event on the originally selected items. That's when Outlook releases it's cached copy of the item.


    Ken Slovak MVP - Outlook

    Thursday, December 19, 2013 5:56 PM
    Moderator
  • Hello Robert and Ken,

    @Ken, setting RCW object references to null just breaks the chain between the object pointers (to the heap) and allocated memory in the heap. Therefore, the underlying COM objects stay alive. Only when the garbage collector runs "disconnected" (set to null) objects are released.

    @Robert, I would recommend using the Marshal.ReleaseComObject method for releasing underlying COM objects instantly. It should help you to bridge the gap. Please read more about this in the Systematically Releasing Objects article in MSDN.

    Sunday, December 22, 2013 8:38 PM

All replies

  • Hello Robert,

    Sometimes Outlook caches inspector windows in memory.

    Do you have the reading pane turned on in Outlook? If so, please try to turn it off and see the results. Does it help?

    Wednesday, December 18, 2013 5:28 PM
  • Thanks for the recommendation. I had thought this the Reading Pane may be causing a catch onto was was already visible and turned it off with no better results.

    I had done some research and saw mention of 'Inspectors'. Not sure if I should pursue this aspect and try to find a way to 'flush' them.


    Robert Ogden

    Thursday, December 19, 2013 4:49 PM
  • Hi Robert,

    You tried to turn off the Reading pane and it didn't help. Am I on the right avenue?

    Thursday, December 19, 2013 5:16 PM
  • Correct.

    Robert Ogden

    Thursday, December 19, 2013 5:22 PM
  • It appears there are no Inspectors, as the Explorer.Selection collection is being iterated. Outlook also caches items in a Selection, and that's where this problem is happening.

    Unreleased references are being created by use of a For Each loop. You should use a counted For loop and explicitly release CurItem in each loop pass.

    This is a well-known problem, and the fix is to switch folders and wait for an Unload() event on the originally selected items. That's when Outlook releases it's cached copy of the item.


    Ken Slovak MVP - Outlook

    Thursday, December 19, 2013 5:56 PM
    Moderator
  • Okay, good information Ken. So, should I target changing to a 'For' and not 'For Each' loop, Programatically swithc folders and place a counter in there before switching back, or should I try both of these items?

    Robert Ogden


    • Edited by ROgden Thursday, December 19, 2013 6:15 PM
    Thursday, December 19, 2013 6:12 PM
  • So, I changed the original 'Fow Each' sectino to the folowing:

      For intItemCur = 1 To Application.ActiveExplorer.Selection.Count
          Set CurItem = Application.ActiveExplorer.Selection.Item(intItemCur)
          CurItem.MessageClass = NewMC
          CurItem.Save
          Set CurItem = Nothing
      Next

    It did not generate any different results though. However, I put the orignal code back, then wrapped the 'Done' notification like this:

      Set Application.ActiveExplorer.CurrentFolder = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
      
      MsgBox "Done."
      
      Set Application.ActiveExplorer.CurrentFolder = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderSentMail)

    It seems to have done the trick. I had the two CurrentFolder refocuses originally before the 'Done' msgbox, but I guess that was happening too quick for the cache to dump.

    Althoug this isn't ideal (for instance, I don't know if this will work on a slow machine, and I still don't know how to manually change the root-cause), it will be enough to send on.


    Robert Ogden

    Thursday, December 19, 2013 8:17 PM
  • That relies on a MsgBox being displayed long enough for Outlook to release it's cached items.

    You do need to release all possible references to anything so Outlook releases its cache as soon as possible. So compound dot operators are bad(Application.ActiveExplorer.CurrentFolder) creates an Application, an Explorer and a Folder reference for example. Try to use a separate object variable for each object and declare loop objects outside the loop so only 1 object variable instance is created. Then set all references to Nothing. That won't clear the cache immediately, but it will allow it to be cleared as soon as possible.


    Ken Slovak MVP - Outlook

    Thursday, December 19, 2013 8:33 PM
    Moderator
  • Thanks Ken. I'll restructure to compensate for these items. Do you know of any resources that I may reference to learn a bit more about the pros and cons of compund dot operators? Thanks~R

    Robert Ogden


    • Edited by ROgden Friday, December 20, 2013 4:20 PM
    Friday, December 20, 2013 4:17 PM
  • Not offhand, but there are no pros to compound dot operators other than laziness. It just takes a bit more work to not use them but it pays off in the end.

    Ken Slovak MVP - Outlook

    Friday, December 20, 2013 4:44 PM
    Moderator
  • Hello Robert and Ken,

    @Ken, setting RCW object references to null just breaks the chain between the object pointers (to the heap) and allocated memory in the heap. Therefore, the underlying COM objects stay alive. Only when the garbage collector runs "disconnected" (set to null) objects are released.

    @Robert, I would recommend using the Marshal.ReleaseComObject method for releasing underlying COM objects instantly. It should help you to bridge the gap. Please read more about this in the Systematically Releasing Objects article in MSDN.

    Sunday, December 22, 2013 8:38 PM