Is COM Interop Fundamentally Flawed? IMHO, No.
Prefix: Sam Gentile posed the question Is COM Interop Fundamentally Flawed? to which this is a response.
First, I need to be completely honest. I've been down this road before. I've essentially been working with P/Invoke and COM interop, amongst other .NET concepts, since 1997. "How the heck is that possible?" I hear you ask. Well my friends, allow me to let you in on a little technology called Java, more specifically, Microsoft's implementation and extension of it known as J++. Most of you probably heard about the trial between Sun and MS, well these were the technologies at the very heart of the debate.
You see, the CLR and a majority of it's features stem from the MSJVM. Back then P/Invoke was called J/Direct and since there was no concrete concept of attributes, Microsoft invented a special commenting style that enabled similiar feature. They were lovingly referred to as "@dll" and "@com" directives. The @dll directives were used for mapping native methods to a Java signature, as well as mapping native structs to Java classes. The @com directives were used for mapping Java interfaces and classes to their respective COM interfaces and coclasses. The COM Interop portion of J++ took the nickname Java/COM. We had JCWs (Java callable wrappers) and CCWs (COM callable wrappers), .NET has RCWs (Runtime callable wrappers) and CCWs. Tools wise: Java/COM had JActiveX.exe, .NET has Tlbimp.exe. We had Javatlb.exe, .NET has Tlbexp.exe. We had delegates, .NET has delegates. We had the beginnings of a declaritive and programmable security model which was somewhat like .NET's System.Security.CodeAccessPermission and related classes. We had com.ms.wfc.ui *part of the Windows Foundation Classes libraries), .NET has System.Windows.Forms. Not many people bought into the marrige of Java and COM, but those of us that did loved it to death and had a very close relationship with the developers at Microsoft that were keeping the marrige alive. I've said it before and I still maintain that the Java/COM team was one of the best groups within Microsoft that I've ever worked with. Oh, and guess who some of the major players on that team were: Anders Hejlsberg who is primarily responsible for C# and Brad Merrill who is now Program Manager on the .NET Developer Platform team. So it really is no surprise that so much of the technology in .NET was inherited from J++, in fact check out this letter (dated 2001) where Anders says the technology started four years ago. Hmm... that would be 1997 when J++ was just going beta. Coincidence? I think not! ;)
So, what does all this have to do with Sam's question? Well, it's simple really, Sam's same question was at the center of many debates back in the Java/COM days as well[1]. The implementation was exactly the same. A JCW would go out of scope, but the underlying COM object would not be IUnknown::Release'd until the GC did it's duty and called the finalizer on the wrapper. To take better control of COM object lifetime we had a method just like System.Runtime.InteropServices.Marshal::ReleaseComObject, it was com.ms.com.ComLib::Release[2].
The fundamental problem with COM interop in both runtimes is that you're mixing garbage collection with deterministic finalization. For what COM interop is out of the box, I think it is good enough. For more complex scenarios where you need to control the lifetime of the underlying COM resources, both runtimes provide a releasing mechanism. Yes, you have to take a little bit more control in these scenarios. Yes you have to have use a try/finally pattern with a ReleaseComObject call to clean up your resource. It's not the end of the world. Everyone knows this now, it should be common knowledge learned easily by reading a chapter in a .NET book on COM interop or by searching through newsgroups and mailing lists and now by reading community weblogs.
Now as a final observation, I will say that we do have a new pattern in .NET that we did not have in Java/COM. That pattern is the IDisposable pattern. Early on when .NET was in it's beta2 days and IDispoable had just been defined I wondered why all RCWs didn't inherit from IDisposable where the Dispose implementation is provided by System.__ComObject and looked just like this:
<codeSnippet language="C#">
public void IDisposable.Dispose(){
System.Runtime.InteropServices.Marshal.ReleaseComObject(
this);}
</codeSnippet>
If this were the case, we could dispose of COM objects using a familiar .NET pattern taking advantage of whatever our chosen language provides for us to handle the pattern. In C#, a COM object could be used deterministically just by using the following syntax:
<codeSnippet language="C#">
using(MyComObject myVariable = new MyComObject()){
// use myVariable here
}
// C# ensures IDisposable::Dispose is called here exception or no exception</codeSnippet>
Maybe in v.Next of .NET we can hope such an adjustment is made.
[1] Search the Java/COM list archives for "(Release) or (COM Leak)" and you'll see what I mean. ;)
[2] Believe it or not, I could not find the documentation page for this online anywhere. You can still download the Microsoft Java SDK though.
(ed. note: All links for this article were found via Google and/or Microsoft's MSDN online)