Sam Gentile's Radio Weblog : Partying with .NET

 

Click to see the XML version of this web page.

Click here to send an email to the editor of this weblog.

 
 

Is COM interop Fundamentally Flawed?

Of course, .NET COM interop has this fascinating simple story. We'll give you these wonderfull wrapper objects, that will give COM the illusion that they are interacting with other COM objects and give .NET objects the illusion that they're interacting with other .NET objects. The story is that you supply your COM Type Libraryto tlbimp.exe and it spits out this wonderfull Runtime Callable Wrapper (RCW). The counterpart on the otherside is COM-callable wrapper.

Its a good story in theory. The wrappers handle all the transitions between managed and unmanaged code and all the issues between the world of COM and the world of .NET like data marshalling, exception handling, object lifetime. The issue is that to play in the .NET world, the RCW's lifetime is controlled by the CLR's garbage collector. Each RCW caches its interface pointers for the  COM object that it wraps, and internally performs reference counting on these interface pointers. When an RCW is collected, it's  finalizer calls IUnknown.Release on all its cached interface pointers. Thus, a COM object is guaranteed to be alive as long as its RCW is alive.

Herein lies the problem for non-trivial COM components and large interacting COM components in a large COM infrastructure. The release calls are non-determinstic in the sense that they will happen when the GC gets around to killing off the RCW. Most particuarly,this plays havoc witth COM architectures that reley on Callbacks happening between COM components with their own sense of when they want to be released. The wrapped COM object doesn't get released until the RCW is collected. Oh sure, Interop has a way for you to "insist", again in theory. You can call the Marshal::ReleaseComObject method in the System::Runtime::InteropServices namespace. And you can call raw release calls that are provided. The point is that in a non-trivial COM architecture with callabacks and such, this becomes a mess and is quite problematic. In my work in this area for a certain company, we have had over a month's worth of problems with crashes and leaks and having to do countless "Tweaks" to call ReleaseComObject and raw releases. It comes down to this: It shouldn't be this dran hard! The COM Interop layer should be handling all of this INSIDEits wrapper in a determinstic way. I'm beginning to wonder if its design is flawed.

Peter picks up on the discussion:

Sam Gentile: "Is .NET COM Interop fundamentally flawed?" Not sure I agree that it's fundamentally flawed, but it's definitely substantially more complex than the commonly cited "just use TlbImp.exe" story. After all, how simple can it be if there's a 900 page book on the topic? Sam's been doing a lot more COM Interop work than I have, so I'm inclined to listen to him in this regard.

[Peter Drayton's Radio Weblog]

Ahh, but it's not a 900 page book, it's a 1608 page book-))) But that really isn't the main point I am trying to make. Certainly, one of the points to be made is that it is "definitely substantially more complex than the commonly cited "just use TlbImp.exe" story." I think we can all agree on that, right? But that is not the main point I am making. The main point is that  the world of COM is determinstic, right? Interface pointers must be released at the right times or you will get memory leaks (at the least) and crashes (at the worst and more likely). My main point is all of this cruft should have been totally hidden by the tlbimp.exe/RCW/CCW mechanism and it isn't. We have had 3 very smart engineers (COM experts) on these problems for 2 months and we are facing things that Microsoft even has no idea on (i.e. things that are not even in that 1608 page book!. This leads me to think that COM Interop was designed for the "textbook" COM case and if you are doing anything else or non-trivial, you will have big, big problems. Microsoft says "You should never need to explicitly release anything unless keeping it alive would cause some sort of issue. Eventually the GC will collect the RCW and the underlying COM object will be released at that point." Wrong, oh so wrong. Major COM architectures don't work that way. There are custom marshalling schemes. There are callbacks and connection points. And on and on. By forcing us to do tons of Marshal.ReleaseComObject calls and UCOM calls, it goes away from what we think the Interop should be an do. I (and we) subscribe to this view that the RCW should do all of this. By making it act non-determinstically, it doesn't play well with others (in the COM world).



© Copyright 2002 Sam Gentile.
Last update: 6/26/2002; 8:56:21 AM.

Click here to visit the Radio UserLand website.