What is the scope of Runtime Callable Wrapper (RCW), when referencing unmanaged COM objects? According to the docs:
The runtime creates exactly one RCW
for each COM object, regardless of the
number of references that exist on
that object.
If I had to "guess" - this explanation should mean "one per process", but is it really? Any additional documentation will be very welcome.
My application runs in its own application domain (it is Outlook addin), and I would like to know what happens if I use Marshal.ReleaseComObject(x) in a loop until it's count reaches 0 (as recommended). Will it release references from other addins (running in other application domain in the same Outlook process)?
EDIT: Perfect - now the confusion is even bigger. Based on the 2 answers (from Lette and Ilya) we have 2 different answers. The official MSDN doc says per process (for ver. 2.0+), but it is missing this sentence for ver. 1.1 of the doc.
In the same time, in Mason Bendixen's article, it says it's per appdomain.
As his article is old (April 2007), I have send him an email asking for clarification, but if someone else has to add something, please do.
Thanks
In managed, we have a per app domain
cache
mapping canonical IUnknowns back to
RCWs. When an IUnknown enters the
system (through a marshal call,
through activation, as a return
parameter from a method call, etc.),
we check the cache to see if an RCW
already exists for the COM object. If
a mapping exists, a reference to the
existing RCW is returned. Otherwise a
new RCW is created and a cache mapping
is added.
from Mason's Blog
The Mason Bendixen blog article that Ilya cites is correct: the RCW is scoped to the AppDomain, not to the process. I can only guess that the Runtime Callable Wrapper (MSDN 2.0) article was speaking "casually". That article is not necessarily incorrect in the general sense, because it is most typical to execute using only a single AppDomain, but that sentence is not technically accurate.
As to your specific question:
"I would like to know what happens if I
use Marshal.ReleaseComObject(x) in a
loop until it's count reaches 0 (as
recommended). Will it release
references from other addins
(running in other application domain
in the same Outlook process)??"
The answer to this depends on how you set up your add-in. In general, if you do not take precautions, then the answer is yes, it would impact the references in other add-ins operating from within the same AppDomain. But since you state that you are running from a separate AppDomain, then, no, it would not.
There is a COM Shim Wizard Version 2.3.1 that you can use to isolate your add-in. The documentation for the COM Shim Wizard can be found here: Isolating Microsoft Office Extensions with the COM Shim Wizard Version 2.3.1.
The COM Shim Wizard uses reflection to build a customized COM front-end loader that loads your add-in assembly within a separate AppDomain. This creates safety in two respects:
(1) By using a separate, customized COM entry point, your add-in is correctly identified separately by Microsoft Office from all other add-ins. Otherwise, by default, all add-ins share the same default mscoree.dll loader. The problem with sharing the same loader is that if any add-in has a crash, then mscoree.dll will be identified by Microsoft Office as the source of the problem and will not load it automatically the next time. You can turn it on again manually, but your add-in would not load automatically the next time due to a problem in someone else's add-in!
(2) By loading your assembly within a separate AppDomain, the runtime callable wrappers (RCWs) are isolated from the other add-ins that are loaded into the same process. In this case, if you call Marshal.ReleaseComObject(object) or Marshal.FinalReleaseComObject(object) then you would not be impacting anyone else's add-ins. More importantly, if any of those other add-ins make such calls, then your add-in would be protected from being corrupted. :-)
The downside to using the COM Shim Wizard is that by operating out of a separate AppDomain there is extra marshalling overhead. I don't believe that this should be noticeable for a Microsoft Outlook add-in. It can be a factor, however, for some intensive routines that have lots of calls to the object model, such as can sometimes be the case for a Microsoft Excel add-in.
You stated that you are already running your add-in from a separate AppDomain. If this is true, then you are already isolated from Marshal.ReleaseComObject(object) and Marshal.FinalReleaseComObject(object) calls with respect to other AppDomains. (I am curious as to how you are doing this, by the way... Are you explicitly creating your own AppDomain? The default add-in template in Visual Studio does not run in separate AppDomain and loads using the mscoree.dll.)
If you are creating your own AppDomain, your code is isolated, but its identity might not be separate from other add-ins, however, as your add-in would still be sharing the default mscoree.dll loader, unless you utilized some other means to address this.
I hope this helps...
According to the same docs:
The runtime maintains a single RCW per process for each object.
I think we can safely assume that object = instance, so if the addins/AppDomains doesn't hold references to the same instance, the call to ReleaseComObject
won't release references to instances created elsewhere.
Edit: The wording of the docs may be wrong, as stated elsewhere. If so, since your add-in is running in a separate AppDomain, you're in luck. Even if the different add-ins reference the same instance (e.g. a Message object in Outlook), ReleaseComObject
called in your AppDomain will not cause RCWs in other AppDomains to lose the reference to that instance.