Home » Articles » COM »The Basics » P6COM Component Object Rules

P6COM Component Object Rules

By Jim Susoy - February 10, 2009 @ 4:57 pm


P6Platform and other planned products are and will be built on our light-weight component object framework implementation called P6COM. We chose the Component Object Model (COM) for our products because it provides many advantages (but that’s a whole other article), and in order to realize those advantages you have to follow the rules. There are lots of excellent references on COM (you can find some of my favorites at the end of this article) and you should read them. This article is not meant to replace those texts and is really here as a summary, or a kind of cheat sheet to help remember the rules.

It’s important to note when going through the rules below, that these rules are meant as a reference for our light-weight implementation of COM called P6COM, and so there are some notational differences with traditional COM. For example P6COM uses the p6ICom interface instead of the IUnknown interface used in traditional COM and P6COM use P6ERR instead of HRESULT for return values. They are however equivalent and the rules are the same.

Interface Rules

The motivation for COM to impose many of these rules is to ensure that interfaces provide binary compatibility between components and across languages (COM components can be implemented in different languages). This is important as it allows components compiled with one compiler to interface with programs and components compiled with a different compiler. This would not be possible if we were using ordinary C++ classes. The rules are also there to keep language features out and maintain cross language compatibility.

  • Interfaces must define a Unique Interface Identifier (IID).
  • Interfaces must directly inherit from p6ICom.
  • You always get the same p6ICom. An interface instance has one p6ICom. Whenever you query an instance of a component for p6ICom, you will always get the same pointer value.
  • The set of interfaces available for an instance of a component is static. The set of available interfaces is not allowed change, therefore if queryInterface() succeeds for a give IID, it must always succeed for that IID and if it fails, then it must always fail for that IID.
  • Interfaces that are available on a component via queryInterface() must be Reflexive, Symmetric and Transitive.
  • Reflexive or “You can always get back to where you started”. If you successfully query interface IX1 for interface IX2, then querying interface IX2 for interface IX1 must succeed.
  • Symmetric or “You can always get the interface you have”. Given an interface pSomeInterface, then pSomeInterface->queryInterface(IID_ISomeInterface,…) must succeed.
  • Transitive or “You can get there from anywhere if you can get there from somewhere”. Given a pointer (pX1) to the interface IX1, if pX1->queryInterface(IID_IX2,&pX2) succeeds and pX2->queryInterface(IID_IX3,&pX3) succeeds, then pX3->queryInterface(IID_IX1,…)
    must succeed.
  • Interfaces are immutable. Once the interface is published with an IID and made public, it can never change.

Interface Method Rules

  • All interface methods must return a value of type P6ERR (or HRESULT for MS COM). This becomes extremely important for support of remote interfaces and out of process servers. The reason for this is that the marshalling proxy code will return network and other errors via the HRESULT. P6COM however does not support remote interfaces or out of process servers. Never the less, to ensure future compatibility, methods must always return a P6ERR directly.
  • Interface methods are not allowed to use C++ overloading.
  • Interface methods are not allowed to use varargs. The calling conventions used on x86 platforms is __stdcall (aka pascal calling) where arguments are passed right to left and the called function pops its own arguments off of the stack. This is part of the COM specification to ensure that all interfaces use the same calling conventions to ensure binary compatibility.
  • Interface methods are not allowed to use default params. This another C++ language feature that is implemented differently by compilers. Default params are not COM compliant.
  • Interface methods are not allowed to throw exceptions. At the minimum, interfaces provide compiler independent access to a component object and therefore, components could very well be compiled using different compilers. Many compiler vendors implement language features (like exceptions) in a proprietary way. AS a result, a C++ exception thrown from a method compiled with one compiler can not reliably be caught by a client component compiled with a different C++ compiler.
  • Interface method arguments may only contain concrete types (like int, char, P6INT32, etc.) and interface pointers. Never pass C++ classes in arguments.

Reference Counting Rules

  1. Always addref() an interface pointer when you assign it to another interface pointer. By assigning the interface pointer to another interface pointer, you are creating another reference to it, and therefore need to addref() it so that the reference count matched the number of references.
  2. Always release() an interface pointer when you are done with it.
  3. NEVER reference an interface pointer once it has been released.
  4. Always call addref() before returning an interface pointer from a function or method. For example, p6CreateInstance() and queryInterface() both follow this rule by returning an addref()’d pointer to the requested interface.

Recommended Reading

If you are new to COM, then these books should be required reading. They have lots of valuable and practical information that will help you understand and easily master COM.

  • Inside COM (Microsoft Programming Series) by Dale Rogerson (Paperback – Feb 1997)
    This book is out of print but Amazon has them used. This is a great book on COM basics and will provide a good foundation if you are new to COM.
  • Essential COM (DevelopMentor Series) by Don Box (Paperback – Jan 1, 1998)
    This is also an excellent book on COM. It covers the basics as well as some more advanced topics.
  • The Component Object Specification (Version 0.9 October 24, 1995) There are still copies of this out there on the Internet, however I can’t seem to find it on Microsoft’s website anymore. There is a lot of great information in this document (it is “The” spec after all) and I strongly suggest that you search it out and read it. It will provide a lot of background as well as technical information that is very helpful.

"P6COM Component Object Rules" was published on February 10th, 2009 and is listed in COM, The Basics.

Follow comments via the RSS Feed | Leave a comment | Trackback URL

Leave Your Comment