Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I have been researching this question too, working on a COM/.Net-Interop-centric application, fighting leaks, hangs and crashes.</p> <p>Short answer: Every time the COM object is passed from COM environment to .NET.</p> <p>Long answer:</p> <ol> <li>For each COM object there is one RCW object [Test 1] [Ref 4]</li> <li>Reference count is incremented each time the object is requested from within COM object (calling property or method on COM object that return COM object, the returned COM object reference count will be incremented by one) [Test 1]</li> <li>Reference count is not incremented by casting to other COM interfaces of the object or moving the RCW reference around [Test 2]</li> <li>Reference count is incremented each time an object is passed as a parameter in event raised by COM [Ref 1]</li> </ol> <p>On a side note: You should <strong>ALWAYS</strong> release COM objects as soon as you are finished using them. Leaving this work to the GC can lead to leaks, unexpected behavior and event deadlocks. This is tenfold more important if you access object not on the STA thread it was created on. [Ref 2] [Ref 3] [Painful personal experience]</p> <p>I'm hope I have covered all cases, but COM is a tough cookie. Cheers.</p> <p><strong>Test 1 - reference count</strong></p> <pre><code>private void Test1( _Application outlookApp ) { var explorer1 = outlookApp.ActiveExplorer(); var count1 = Marshal.ReleaseComObject(explorer1); MessageBox.Show("Count 1:" + count1); var explorer2 = outlookApp.ActiveExplorer(); var explorer3 = outlookApp.ActiveExplorer(); var explorer4 = outlookApp.ActiveExplorer(); var equals = explorer2 == explorer3 &amp;&amp; ReferenceEquals(explorer2, explorer4); var count2 = Marshal.ReleaseComObject(explorer4); MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals); } Output: Count 1: 4 Count 2: 6, Equals: True </code></pre> <p><strong>Test 2 - reference count cont.</strong></p> <pre><code>private static void Test2(_Application outlookApp) { var explorer1 = outlookApp.ActiveExplorer(); var count1 = Marshal.ReleaseComObject(explorer1); MessageBox.Show("Count 1:" + count1); var explorer2 = outlookApp.ActiveExplorer(); var explorer3 = explorer2 as _Explorer; var explorer4 = (ExplorerEvents_10_Event)explorer2; var explorerObject = (object)explorer2; var explorer5 = (Explorer)explorerObject; var equals = explorer2 == explorer3 &amp;&amp; ReferenceEquals(explorer2, explorer5); var count2 = Marshal.ReleaseComObject(explorer4); MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals); } Output: Count 1: 4 Count 2: 4, Equals: True </code></pre> <p><strong>Sources I relay on in addition to my experience and testing:</strong></p> <p><a href="http://jpassing.com/2009/03/26/rcw-reference-counting-rules-com-reference-counting-rules/" rel="noreferrer">1. Johannes Passing's - RCW Reference Counting Rules != COM Reference Counting Rules</a></p> <p><a href="http://dotnetdebug.net/2005/09/10/runtime-callable-wrapper-internals-and-common-pitfalls/" rel="noreferrer">2. Eran Sandler - Runtime Callable Wrapper Internals and common pitfalls</a></p> <p><a href="http://dotnetdebug.net/2005/07/07/marshalreleasecomobject-and-cpu-spinning/" rel="noreferrer">3. Eran Sandler - Marshal.ReleaseComObject and CPU Spinning</a></p> <p><a href="http://msdn.microsoft.com/en-us/library/8bwh56xe.aspx" rel="noreferrer">4. MSDN - Runtime Callable Wrapper</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload