A couple of days ago, David Candy asked (in a comment on a previous COM related post) what exactly was COM.
Mike Dimmick gave an excellent answer to the question, and I'd like to riff on his answer a bit.
COM is just one of three associated technologies: RPC, COM and OLE (really OLE Automation).
Taken in turn:
RPC, or Remote Proceedure Call, is actually the first of the "Cairo" features to debut in Windows (what, you didn't know that there were parts of Cairo already in Windows? Yup, actually, almost all of what was called "Cairo" is currently in windows).
RPC provides a set of services to enable inter-procedure and inter-machine procedure calls. The RPC technology is actually an implementation of the DCE RPC specification (the DCE APIs are renamed to be more windows-like), and is on-the-wire interoperable with 3rd party DCE implementations. RPC deals with two types of entities, client's and servers. The client makes requests, and the server responds to those requests. You tell RPC about the semantics of the procedures you're calling with an IDL file (IDL stands for "Interface Definition Language" - It defines the interface between client and server). IDL files are turned into C files by MIDL, the "Microsoft IDL compiler".
When RPC needs to make a call from one process to another, it "marshalls" the parameters to the function call. Marshalling is essentially the process of flattening the data structures (using the information in the IDL file), copying the data to the destination and then unpacking the flattened data into a format that the receiver can use.
RPC provides an extraordinarily rich set of services - it's essentially trivial to write an application that says "I want to talk to someone on my local network segment who's providing this service, but I don't care who they are - find out who's offering this service and let me talk to them" and RPC will do the hard work.
The next technology, COM, is built on RPC. COM stands for "Component Object Model". COM is many, many, things - it's a design pattern, it's a mechanism to hide implementation of functionality, it's an inter-process communication mechanism, it's the kitchen sink.
At it's heart, COM's all about a design pattern that's based around "Interfaces". Just as RPC defines an interface as the contract between a client and a server, COM defines an interface as a contract between a client of a set of functionality and the implementor of that functionality. All COM interfaces are built around a single "base" interface called IUnknown, which provides reference count semantics, and the ability to query to see if a particular object implements a specific interface. In addition, COM provides a standardized activation pattern (CoCreateInstance) that allows the implementation of the object to be isolated from the client of the object.
Because the implementation of the COM object is hidden from the client of the object, and the implementation may exist in another process (or on another machine in the case of DCOM), COM also defines its interfaces in an IDL file. When the MIDL compiler is compiling an IDL file for COM, it emits some additional information including a C++ class definitions (and C surrogates for those definitions). It will also optionally emit a typelib for the interfaces.
The typelib is essentially a partially compiled version of the information in the IDL - it contains enough information to allow someone to know how to marshall the data. For instance, you can take the information in a typelib and generate enough information to allow managed code to interoperate with the COM object - the typelib file contains enough information for the CLR to know how to convert the unmanaged data into its managed equivilant (and vice versa).
The third technology is OLE Automation (Object Linking and Embedding Automation). OLE Automation is an extension of COM that allows COM to be used by languages that aren't C/C++. Essentially OLE Automation is built around the IDispatch interface. IDispatch can be though of as "varargs.h-on-steroids" - it provides a abstraction for the process of passing parameters too and from functions, thus allowing an application to accept method semantics that are radically different from the semantics provided by the language (for instance, VB allows parameters to functions to be absent, which is not allowed for C functions - IDispatch allows a VB client to call into an object implemented in C).
Anyway that's a REALLY brief discussion, there are MANY, MANY books written about this subject. Mike referenced Dale Rogerson's "Inside COM", I've not read that one, but he says it's good :)