conflict between 2 outlook-add-ins

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

conflict between 2 outlook-add-ins
 
Beate Veith




Posts: 2
Joined: 2023-03-02
I have an outlook-add-in that works fine.
now another add-in from another company has been installed on my computer and my add-in does not work anymore.


Error-Massages from my add-in:
Exception Source:
Exception Type: System.Runtime.InteropServices.COMException
Exception Message: Vorgang abgebrochen (Ausnahme von HRESULT: 0x80004004 (E_ABORT))
Exception Target Site: Forward

---- Stack Trace ----
Microsoft.Office.Interop.Outlook._MailItem.Forward()
Outlook_Plugin_Valuemation5.DLL: N 00000 (0x0) JIT
Outlook_Plugin_Valuemation5.Commands.ForwardMail(exporter As IExporterMailin, typ As String)
Outlook_Plugin_Valuemation5.DLL: N 0273 (0x111) IL
Outlook_Plugin_Valuemation5.Commands.NewTicket()
Outlook_Plugin_Valuemation5.DLL: N 0007 (0x7) IL
Outlook_Plugin_Valuemation5.AddinModule.cmdNewTicket_Click(sender As Object)
Outlook_Plugin_Valuemation5.DLL: N 0012 (0xC) IL
Outlook_Plugin_Valuemation5.AddinModule.cmdNewTicketRibbon_OnClick(sender As Object, control As IRibbonControl, pressed As Boolean)
Outlook_Plugin_Valuemation5.DLL: N 0001 (0x1) IL
AddinExpress.MSO.ADXRibbonButton.DoInternalAction(e As ADXRibbonOnActionEventArgs)
Outlook_Plugin_Valuemation5.DLL: N 0035 (0x23) IL

my environment:
Visual Studio 2022
Adxnet-v1001-b4703-vs-pro
Outlook 2016

have your any idea how the two add-in can affect each other?

Thanks
Posted 02 Mar, 2023 07:02:09 Top
Andrei Smolin


Add-in Express team


Posts: 18895
Joined: 2006-05-11
Hello Beate,

Do you click the Ribbon button in an inspector to forward the email that inspector shows? If so, consider doing this asynchronously:
- in the Click event of the button, perform all operations required for forwarding,
- call SendMessage as described in section Wait a little; see the PDF file in the folder {Add-in Express}\Docs on your development PC
- quit the event handler.

When the OnSendMessage event occurs, filter out your message and perform the forward.

I remember that MailItem.Reply() produces an email which is different from what you get by clicking the Reply button. I assume the same applies to forwarding.

The difference... some useful unnoticeable things were missing. Among them were the spell check not done and the bookmark holding your signature. I suppose there may be other details. Say, I'd check if the original text is included in the same fashion.

This said, I suggest that you invoke the Reply command on that inspector's Commandbars object: get Inspector.CommandBars, call {the CommandBars object}.ExecuteMso("Forward"). This creates a reply email and opens it in another Inspector. Use the corresponding event to get that inspector and that item; if this is required.

Regards from Poland (GMT+1),

Andrei Smolin
Add-in Express Team Leader
Posted 02 Mar, 2023 11:16:37 Top
Beate Veith




Posts: 2
Joined: 2023-03-02
Hello Andrei,

thanks for your answer.
I "inherited" this project and did not work with add-in express before, therefore I am actually looking for a quick solution with as few changes as possible just to fix the actual problems.

I analysed my method, there are always these steps:

klick on a button in the ribbon to start my method
read the mail and search for some informations
create a string with parameters with these informations
create a new mail with mailitem.Forward()
insert the parameter string at the top of the body of this new mail
send the new mail
MessageBox.Show("Mail generated")

Do you have a suggestion how to change this?

Regards
Beate



C
Posted 03 Mar, 2023 04:27:51 Top
Andrei Smolin


Add-in Express team


Posts: 18895
Joined: 2006-05-11
Hello Beate,

Beate Veith writes:
create a new mail with mailitem.Forward()


In my previous message I assumed you forward the email that is opened in the Inspector window where you click the Ribbon button. Is this so?

If yes, split your sequence in two parts. Part 1 contains these steps:
- click on a button in the ribbon to start my method
- read the mail and search for some information
- create a string with parameters with these information AND store the string globally
- send a message (see section Wait a little in the manual).

To perform the second part, handle the OnSendMessage event of the add-in module. In the event handler you do these steps *if* the message is yours (there may be a lot of other messages):
- get the Inspector object representing the Outlook window holding your email; the window should be active, so you can use OutlookApp.ActiveInspector()
- get the mailitem via Inspector.CurrentItem
- create a new mail with mailitem.Forward()
- insert the parameter string at the top of the body of this new mail
- send the new mail
- MessageBox.Show("Mail generated")

If you have Marshal.ReleaseComObject() calls in your code, I strongly suggest that you follow the pattern below.

Every call producing an Outlook-related object actually creates a COM object. Examples would be OutlookApp.ActiveInspector() and mailitem.Forward(): they return objects and the objects are COM objects. On the other hand, mailitem.Body produces a string, not an object; Inspectors.Count produces an integer, not an object. The goal is: every COM object that *you* create should be released as soon as you don't need it. Therefore, if you write

Outlook.MailItem responseEmail = (OutlookApp.ActiveInspector().CurrentItem as Outlook.MailItem).Forward(); 


you won't be able to release the COM objects returned by OutlookApp.ActiveInspector() and Inspector.CurrentItem. Also, this code line will fail if there's no inspectors or the active inspector opens a task or meeting request.

To avoid consequences the code line above should be rewritten as follows:


Outlook.Inspector inspector = OutlookApp.ActiveInspector();
object item = null;
Outlook.MailItem responseEmail = null;
try 
{
    if (inspector != null) 
    {
        item = inspector.CurrentItem;
        if (item is Outlook.MailItem)
        {
            // casting doesn't create a COM object; mail & item point to the same COM object
            Outlook.MailItem mail = item as Outlook.MailItem; 
            responseEmail = mail.Forward();
        }
    }
}
catch (Exception ex) 
{
    // log the exception; otherwise you won't know about it
}
finally
{
    if (inspector != null) Marshal.ReleaseComObject(inspector); inspector = null;
    if (item != null) Marshal.ReleaseComObject(item); item = null;
}

if (responseEmail != null) 
{
    // change the email and send it
    Marshal.ReleaseComObject(responseEmail); responseEmail = null;
}



That is, here I demonstrated the first of the three rules given in section "Release all COM objects created in your code": ???? Don't chain COM calls.

The other two are:
???? Don't use foreach loops on COM collections.
???? Never release COM objects obtained through the parameters of events provided by Add-in Express.

The rules start with these paragraphs:


Office was designed and built on COM, not .NET. This means that an add-in creates COM objects when dealing with the object model of its host application. All such objects require to be released in the COM way.

If a COM object is unreleased for any reason, you may run into an issue. The worst-case scenario is: the issue shows itself sometimes and on some machines only. Often, such an issue is associated with running the add-in's host application programmatically. In most cases you can't reproduce it on wish. The issue may have several manifestations; this adds to your potential expenses.

Nevertheless, leaving a COM object unreleased doesn???t usually create a directly visible effect. This occurs because the reaction to an unreleased COM object is defined by the host application. Imagine a COM object not released (by mistake) in a specific scenario. Note that your add-in supports several past and future Office versions and builds. The problem is: you can't predict how these Office versions react to that COM object. The only way to find this out is testing that scenario in all Office versions; such expenses cannot be allowed. The solution is to release that COM object.

How to prevent leaving COM objects unreleased by your code?

But before that, how do you find if a method/property returns a COM object? A mnemonic rule is: every method/property returning an object type (not a string, Boolean, enum) creates a COM object. Say, Attachments.Add(), ExcelApp.Workbooks, etc. The only exception we know is the rarely used OutlookBarShortcut.Target property; it may return a string or an object.


We have an impressing history of issues resolved by releasing COM objects. So I repeat this sentence once again:

leaving a COM object unreleased doesn???t usually create a directly visible effect


Regards from Poland (GMT+1),

Andrei Smolin
Add-in Express Team Leader
Posted 03 Mar, 2023 05:48:51 Top