.MSG file locked the second time it's opened

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

.MSG file locked the second time it's opened
 
Fabrice




Posts: 158
Joined: 2010-12-13
I finally succeeded to work around this problem with this code



private object inspectorToFinalRelease = null;

private void adxOutlookAppEvents1_InspectorClose(object sender, object inspector, string folderName)
{
    mailItemEventsInspector?.RemoveConnection();
    inspectorToFinalRelease = inspector;
    //Marshal.FinalReleaseComObject(inspector);
    this.SendMessage(11800);
}

private void AddinModule_OnSendMessage(object sender, ADXSendMessageEventArgs e)
{
    if (inspectorToFinalRelease != null)
    {
        Marshal.FinalReleaseComObject(inspectorToFinalRelease);
        inspectorToFinalRelease = null;
        gcCollect();
    }
}

private void gcCollect()
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
}



This is only working in my test project, I don't know if it would works in a real-word app.
What do you think ?
I already had a few years ago Outlook that stay blocked on the GC.WaitForPendingFinalizers line, that's why I don't use it anymore (and it's also not recommended I think)
-------------
Posted 03 May, 2021 03:32:24 Top
Andrei Smolin


Add-in Express team


Posts: 18019
Joined: 2006-05-11
Hello Fabrice,

I've read your email and understood that I tested a different scenario. That was my personal fault. Please accept my apologies.

In your code above, releasing the inspector is a mistake. The point is: this breaks the rule we give in section Release all COM objects created in your code; see the PDF file in the folder {Add-in Express}\Docs on your development PC. That rule says:
Never release COM objects obtained through the parameters of events provided by Add-in Express

Add-in Express manages that inspector object. In particular, it releases it when it decides that the object can be released. Even though this works for you this may not work on a customer's machine.

I assume that what solves the issue is the mailItemEventsInspector?.RemoveConnection() call. This call releases the MailItem COM object that you pass to ADXOutlookItemEvents.ConnectTo() method with the eventObjectReleasesComObject parameter set to true.

As to FinalReleaseComObject, it creates an illusion of safety. Every call creating a COM object should be followed by a call releasing that COM object. This logic is easy and simple. FinalReleaseComObject complicates the things immensely: it requires that you know if that COM object is used by some other code.

If we ASSUME for a moment that releasing that inspector is not a mistake, then you would need to call ReleaseComObject, not FinalReleaseComObject. This is because FinalReleaseComObject() destroys the COM object thus affecting all consumers of the COM object. This includes all parts of *your* code, including code that you'll write tomorrow!

In reality, we should remember that you can only release COM objects created in *your* code. Thus, that ReleaseComObject *IS* a mistake influencing Add-in Express.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 03 May, 2021 09:36:38 Top
Fabrice




Posts: 158
Joined: 2010-12-13
Thank you for you reply.
With the correct scenario, did you also reproduced this difference of behavior with/without and ADX add-in ?


My test were not about doing nice or recommended code, as I wrote I tried almost everything I could think of.
In the last code that "works", is not (only) the RemoveConnection, I've tried many combinaisons of almost all lines (enabled or not, at different positions), and only these are working. If I remove the FinalReleaseComObject I always have the problem. If I release the GC.Collect, I also have the problem (or maybe it'll be ok once the GC trigger after an undefined amount of time). If I do it in the InspectorClosed event, I still have the problem or ADX crash.

I know how the FinalReleaseComObject works, my goal is was just to check that indeed something doesn't release a COM reference and that's why the file stay locked.
-------------
Posted 03 May, 2021 09:49:14 Top
Andrei Smolin


Add-in Express team


Posts: 18019
Joined: 2006-05-11
Hello Fabrice,

Fabrice writes:
My test were not about doing nice or recommended code


I understand that you had to use these steps to test a way out of this situation. After testing your project I've found what causes this issue. Commenting out the lines below solves the issue for me.

public override bool ConnectTo(object olItem, bool eventClassReleasesComObject)
{
    //if (olItem == this.ItemObj && this.IsConnected)
    //{
    //    return true;
    //}

    this.RemoveConnection();
    return base.ConnectTo(olItem, eventClassReleasesComObject);
}


Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 04 May, 2021 03:46:08 Top
Fabrice




Posts: 158
Joined: 2010-12-13
Hello Andrei,

You're a genius !

What does it means ? I suppose this.ItemObj create a reference behind the scene ? An that was the reference I was looking to release.
Do you think this code is useful ? (= avoid to disconnect and reconnect if it's the same object). If yes I'll check to release reference.
-------------
Posted 04 May, 2021 04:23:09 Top
Andrei Smolin


Add-in Express team


Posts: 18019
Joined: 2006-05-11
Hello Fabrice,

That whole example demonstrates this approach: manage a single events class to handle events of the selected item or opened inspector. Note that in your logic there's a slip (I can't remember if such a slip originates from the example): you do not handle the Explorer.Activate event. Imagine switching between two explorer windows each having a different selection.

I'm sorry, my series of faults continues (bad month?). What I described as the cause of the issue was only the last step in making your project work. An essential part of the solution is this call:

public override void ProcessClose(ADXCancelEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("!!! ProcessClose");
    this.RemoveConnection();
}



ItemObj is a COM object representing the same email; you refer to that email via Inspector.CurrentItem. That COM object is managed by Add-in Express and you shouldn't release it. Add-in Express uses it to connect to events that you access via the events class (ADXOutlookItemEvents). When you call RemoveConnection, Add-in Express disconnects from the events. As you know, the RemoveConnection call also makes Add-in Express release the ItemObj COM object if that was specified by the eventClassReleasesComObject parameter of the ConnectTo() method.

To avoid other faults, I'll send you the corrected project in a couple of minutes.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 04 May, 2021 04:47:36 Top