1

I know similar questions have been asked here, but I feel like I don't understand it correctly.

I have the following code for example:

Microsoft.Office.Interop.Outlook.Explorer expl = myOutlooApplication.ActiveExplorer();
if (expl.Selection.Count > 0)
{
    object selObject = expl.Selection[1];
    if (selObject is Microsoft.Office.Interop.Outlook.MailItem)
    {
        mailItem = (selObject as Microsoft.Office.Interop.Outlook.MailItem);
        this.myUserControl.MailItem = mailItem;
    }
}

As you can see, the MailItem gets passed to a property of myUserControl. MyUserControl will need to access this property later to extract some information from the MailItem.

Should I Marshal.ReleaseComObject() after passing the MailItem to myUserControl to reduce the reference counter of the RCW or is this too early?

EDIT: My problem is, that a .msg file will be opened from the file system. After closing the inspector, the user tries to open the file again, but it is locked and I am sure that the COM objects not being released properly is the cause for that.

cmos
  • 482
  • 4
  • 14
  • If you are going to manage memory by hand then you have to hit *all* of them. Missing just one is enough to completely fail to get the job done. You can't ignore the Explorer and Selection objects. And do it all over again in that UserControl. This is not practical of course, and very rarely needed in an Outlook add-in. You'd at best consider a GC.Collect() call in the FormClosed event of the form that hosts that UC. Only if needed, you have 99.9% odds that it isn't needed. – Hans Passant Feb 21 '19 at 09:20
  • @HansPassant My problem is, that a .msg file will be opened from the file system. After closing the inspector, the user tries to open the file again, but it is locked and I am sure that the COM objects not being released properly is the cause for that. I know it isn't practical, but I think I'll have to hit every COM object and release it manually. I tried the GC.Collect on FormClosed but it didn't help. – cmos Feb 21 '19 at 09:44
  • You asked the wrong question. – Hans Passant Feb 21 '19 at 09:51
  • I'll add my problem to the question then! – cmos Feb 21 '19 at 09:54

2 Answers2

3

Unless you have a documented memory leak linked to your COM objects, don't start messing with the Marshal COM methods. The RCW takes care of translating the garbage-collected world of .NET into the reference-counting world of COM, and generally does a good job of it.

You might consider forcing it out with Marshal.FinalReleaseComObject at a point where you're certain that no managed references to the object are going to be accessed and the COM object consumes considerable resources. You might want to consider an IDisposable wrapper to translate that into .NET terms. You're certainly not in that position in the code you've shown - you know you've just passed a managed reference to the RCW to myUserControl and you're presumably expecting it to access that reference.

.NET references to RCWs are not the type of references that COM counts.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • The problem I am facing right now is that when a .msg is opened from the file system, after closing the inspector window it can not be opened again because it is still in use. I am certain that this is because the COM objects are not released properly, so I thought I'd try to release them, if I'm certain they will not be used anymore. But I wasn't sure in the code of my question, so thanks for your answer and for clearing that up – cmos Feb 21 '19 at 09:13
  • If you want to understand "what's keeping these COM object references live", taking a memory dump of your process in that state and using WinDbg/SOS is more productive than *speculating* about what's holding the references and why. – Damien_The_Unbeliever Feb 21 '19 at 09:45
  • What is the RCW? – Enigmativity Feb 21 '19 at 10:00
  • 1
    @Enigmativity - [Runtime Callable Wrapper](https://learn.microsoft.com/en-us/dotnet/framework/interop/runtime-callable-wrapper). OP used it in their question so I asumed knowledge but I'll add a link from my first usage too. – Damien_The_Unbeliever Feb 21 '19 at 10:05
2

is operator creates an implicit variable, so you have a leak right there (GC will of course release it later).
Change your code to the following. It won't help you with an MSG file since it is never accessed through the explorer. this.myUserControl.MailItem must of course be also released as soon as you are done.

    object selObject = expl.Selection[1];
    MailItem mailItem =  selObject as MailItem;
    if (mailItem != null)
    {
        this.myUserControl.MailItem = mailItem;
    }
    Marshal.ReleaseComObject(mailItem);
Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78