Since the advent of .NET, COM has been getting nothing but bad press, primarily regarding its lack of full-fidelity type information, and poor cross-language interoperability.
I agree that COM was broken because it lacked full-fidelity type information -- but its type-info woes would have been easy to solve. In fact, I often wonder why MS (or maybe even some 3rd party) never replaced IDL with an XML grammar to describe interfaces, their methods, and parameters... and replaced oleaut32.dll with a new universal marshalling engine based on that XML grammar. Heck, I almost did that myself, one rainy weekend...
(For the record, I think the problem was VB's inability to interoperate w/ COM's datatypes, not the other way around.)
MS didn't spend billions on .NET just to fix type-info, or to run Java out of business. .NET is here today because the opportunity existed to knock off many other COM/C++ problems with the same stone: a managed execution environment to avoid buffer overruns, a gc'd heap to avoid leaks, a loader to support sxs versioning, a virtualized instruction set to run code natively on Pentium/Itanium/Hammer/Transmeta/Whatever, a sandbox in which to run untrusted code, ... and last but not least, full-fidelity type info to facilitate communication across module, language, and security boundaries.