Outlook is not updating UI when programatically removing attachments

Add-in Express™ Support Service
That's what is more important than anything else

Outlook is not updating UI when programatically removing attachments
 
Bert Sinnema


Guest


Hi All,

I have a question about removing Attachments. I have an add-in with a button. When I press the button I want it to save all attachments to a TEMP folder and then remove it from the attachments.

Here is my code:


            try
            {
                foreach (Outlook.Attachment attachment in attachments)
                {
                    if (attachment.Type == OlAttachmentType.olByValue)
                    {
                        attachment.SaveAsFile(Path.Combine(Path.GetTempPath(), attachment.FileName));
                        Marshal.ReleaseComObject(attachment);
                    }
                }

                while (attachments.Count > 0)
                    attachments.Remove(1);

            }
            finally
            {
                if (attachments != null) Marshal.ReleaseComObject(attachments);
                if (mailItem != null) Marshal.ReleaseComObject(mailItem);
            }


If i remove the attachment in the foreach loop by using attachment.Delete(), somehow after 4 attachments the foareach loop breaks and I'm stuck with unprocessed attachments. The attachments that are processed are deleted nicely though.

In this example I first save all attachments and then remove them from the attachments in a while loop. In the backend this works. In Debug i can see there are no more attachments and from the Outlook UI i cannot open or save the files anymore, but they are still in the UI, somehow Outlook does not update this. Does anyone have an idea what could go wrong?
Posted 21 Apr, 2015 09:48:26 Top
Andrei Smolin


Add-in Express team


Posts: 18825
Joined: 2006-05-11
Hello Bert,

We strongly recommend releasing every COM object that your code creates. In https://www.add-in-express.com/docs/net-office-tips.php#releasing, we describe the rules. One of them is "don't use foreach loops on COM collections".

You need to remove attachments in a FOR loop scanning the collection in the reverse order. Below is a raw sketch:

if (attachments != null) {
    for (int iAttachment=attachments.Count; iAttachment--; iAttachment>0) {
        Outlook.Attachment attachment = attachments[iAttachment];
        if (attachment.Type == OlAttachmentType.olByValue) {
            attachment.SaveAsFile(Path.Combine(Path.GetTempPath(), attachment.FileName)); 
        }
        attachment.Remove(iAttachment);
        Marshal.ReleaseComObject(attachment); 
    }
    Marshal.ReleaseComObject(attachments);
}


Does this help?


Andrei Smolin
Add-in Express Team Leader
Posted 22 Apr, 2015 04:01:54 Top
Bert Sinnema


Guest


Hello Andrei,

Thank you this helped. I guess Outlook is picky like that. Changing the order of the remove loop helps. I just made one change because the attachments.Remove() has a side-effect. The attachments remains in the UI but is inaccessible. Using attachment.Delete() fixes this and works now with the changed order.

One very weird side-effect is happening though. When I havent added any content to the MailItem, and I run this function, the Signature is deleted from the email body. Do you have any idea what this could be?
Posted 22 Apr, 2015 04:32:08 Top
Andrei Smolin


Add-in Express team


Posts: 18825
Joined: 2006-05-11
I suppose the signature is an attachment in your case. Is this so?


Andrei Smolin
Add-in Express Team Leader
Posted 22 Apr, 2015 06:21:12 Top
Bert Sinnema


Guest


No, it is just text, It has an embedded image but this is a different Attachment type and does not appear in the delete loop.
Once I re-add the signature and run the operation again it sticks. It looks like its only happening when the Body is untouched
Posted 22 Apr, 2015 07:33:20 Top
Andrei Smolin


Add-in Express team


Posts: 18825
Joined: 2006-05-11
Does the same occurs if you save the item before deleting the attachments?


Andrei Smolin
Add-in Express Team Leader
Posted 22 Apr, 2015 07:35:33 Top
Bert Sinnema


Guest


If i save the Item to a msg file, add an attachment and run the operation the signature remains, only the image in the signature is removed.

I also tried a signature with text only. This also gets deleted unless i save the item to disk.
Posted 22 Apr, 2015 08:07:07 Top
Andrei Smolin


Add-in Express team


Posts: 18825
Joined: 2006-05-11
I meant using MailItem.Save. May I ask you to show the code that you use? You can send it to the support email address; find it in {Add-in Express installation folder}\readme.txt. Please make sure your email contains a link to this topic.


Andrei Smolin
Add-in Express Team Leader
Posted 22 Apr, 2015 08:14:58 Top
Andrei Smolin


Add-in Express team


Posts: 18825
Joined: 2006-05-11
Bert,

Thank you for sending me the code.

An Outlook add-in must release COM objects. You never release inspector objects that you create: MailItem.GetInspector, OutlookApp.ActiveInspector(). I believe this might cause the issue.

I would rewrite the code in this way:

Dictionary<IntPtr, MyButtonWrapper> myDictionary = new Dictionary<IntPtr, MyButtonWrapper>();

private void adxRibbonButton1_OnClick(object sender, IRibbonControl control, bool pressed)
{
    // Get the inspector
    Outlook.Inspector inspector = OutlookApp.ActiveInspector();
    if (inspector == null) return;
    ProcessAttachments(inspector);
    myDictionary.Add(this.OutlookwindowHandle(inspector), new MyButtonWrapper(enabled: true, caption:"handled", pressed: true, etc.);
    Marshal.ReleaseComObject(inspector);
}

private void adxRibbonButton1_PropertyChanging(object sender, ADXRibbonPropertyChangingEventArgs e)
{
    // Get the inspector
    Outlook.Inspector inspector = e.Context as Outlook.Inspector;
    if (inspector == null) return;

    // Get the wrapper
    MyButtonWrapper wrapper = myDictionary[this.OutlookwindowHandle(inspector)];
    if (wrapper == null) return;

    switch (e.PropertyType)
    {
        case ADXRibbonControlPropertyType.Pressed:
            e.Value = wrapper.Pressed;
            break;
    }
    // Marshal.ReleaseComObject(inspector); - don't need to release it as it is handled by ADX
}



Andrei Smolin
Add-in Express Team Leader
Posted 22 Apr, 2015 09:13:10 Top
Bert Sinnema


Guest


Thanks, that helped a lot.

I do have one more question but ill put it in a new post.
Posted 22 Apr, 2015 09:59:53 Top