views:

1061

answers:

3

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

A: 

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.

Lette
If we make this assumption, then goes the question about definition of "instance" - i.e. lets say every message is an object - does it mean that every adding creates/uses different COM (instance) to access the message, or there is one single COM object (instance) and all are accessing it?
Sunny
A Message object exposed by Outlook is probably shared - a single instance. However, every AppDomain has it's own pointer (RCW) to this instance, and maintains it's own internal reference count (if Mason is correct, and I believe he is).
Lette
Mason may be correct for the time of the article, as 1.1 docs do not say "process", but 2.0 and later frameworks' docs say "per process", not per AppDomain.
Sunny
+3  A: 

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

Ilya Ryzhenkov
+3  A: 

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...

Mike Rosenblum
Thanks for the answer. I'm using the shim solution. But I'm still confused because of the term "process" in RCW documentation (ver. 2.0 and up). And process is not app domain.
Sunny
Can you provide a doc, which confirms your (2) statement - "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."
Sunny
For this I would read the link that I posted, above, to the article "Isolating Microsoft Office Extensions with the COM Shim Wizard Version 2.3.1" found at http://msdn.microsoft.com/en-us/library/bb508939.aspx, especially the section titled "How the COM Shim Works".
Mike Rosenblum