Compartilhar via


VSTO based Custom Task Panes (CTP) may cause memory leak in Outlook

I have been wanting to post this for awhile but never got around to it. I have only seen two cases of this so I guess my procrastination is justified.  If you are using Visual Studio Tools for Office 3.0 you may experience a memory leak when using Custom Task Panes (CTP) within Outlook.  There are two issues here that I would like you to be aware of.  First, VSTO creates a COM Callable Wrapper (CCW) for the CTP created by Office.  To do this it calls the managed method System.Runtime.InteropServices.Marshal.GetIUnknownForObject() to get a System.IntPtr.  However, it never calls the required System.Runtime.InteropServices.Marshal.Release() when it's done with the object.  This causes a memory leak. To correct this, you can add the following code to around the time of CTP creation:

Visual Basic:

 Me.myTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(contactPane,
"TEST")
 Dim ptr As System.IntPtr =
System.Runtime.InteropServices.Marshal.GetIUnknownForObject(Me.myTaskPane.Control)
 Dim count As Integer = 0
 Do
   count = System.Runtime.InteropServices.Marshal.Release(ptr)
 Loop Until count = 0

 

C#:

       

 this.myTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(contactPane,
"TEST");
 System.IntPtr
ptr =
System.Runtime.InteropServices.Marshal.GetIUnknownForObject(this.myTaskPane.Control);
 count =
System.Runtime.InteropServices.Marshal.Release(ptr);
 while (count > 0)
 {
   count = System.Runtime.InteropServices.Marshal.Release(ptr);
 }

this will remove any dangling objects and thus remove the leak.  However, there is also another problem here.  If you pass a reference to a Window (such as an Inspector or Explorer) for the third argument of the Add method of the CustomTaskPaneCollection object this will introduce a leak as well.  This is because VSTO uses the same GetIUnknownForObject call for the Window and doesn't release the reference at the end.  The fix is to either not pass the reference to the Window or use the same code from above but this time against the Window reference.

I have confirmed that this issue is resolved in the VSTO 2010 runtime.

[Edit: 5/17/2013]

I recently got a case where the customer was using the VSTO 2010 runtime and still seeing this error. After investigating it I realized that this is only fixed in a specific version of the VSTO 2010 framework.  VST0 2010 and .NET 4.0 use a whole different set of supporting classes and one of those supporting classes has the fix in it.  VSTO 2010 and .NET 3.5 use the legacy supporting classes which do not have the fix.  Therefore, if you want to avoid using the workaround you must compile your solution to use the VSTO 2010 runtime along with the .NET 4.0 runtime.

I also noticed that if you are trying to release a reference to the Window object passed as the third parameter to the Add method, then you should not call Marshal.Release() in a tight loop.  This causes the Window to become "over released" or have a negative ref count and causes Outlook to crash. Instead just call Release twice, once to fix the issue, and once to release the pointer that was created when you called Marshal.GetIUnknownForObject().

I have confirmed that this issue is resolved in the VSTO 2010 runtime and .NET 4.0

Comments

  • Anonymous
    November 19, 2014
    Big thanks for creating this article.  We had been experiencing memory leaks in our word plugin for years.  I finally got around to digging into it with winDbg and saw that the control we were placing in the task pane was never being collected.  The gcroot info was minimal and confusing since it only listed ControlNativeWindow as the ref holder. I doubt i would have figured out the solution without your article.  Thanks!