Perspective
This article is intended for
C++ developers, It is assumed that the reader of this article is familiar with object-oriented programming and design
.
Windows C++ developers working with COM may find this article helpful in leveraging their existing knowledge
of Windows with Linux.
Introduction
While COM is widely used in
Windows operating systems, rarely used with Linux, in this article I will demonstrate a simple and lightweight Linux
C++ implementation of the basic COM model.
This article is the first in a series of articles discussing object-oriented design using COM and C++, The article begins with a brief explanation of the basic ideas and follows a simple source code example.
The basics are simple and easy to implement on many platforms besides Windows, in its very basic form, COM solves two main problems,[1] Cross-module object runtime type information,[2] Object lifecycle management, these are fundamental concepts widely used in numerous projects, COM facilitates a simple yet flexible design pattern to solve these problems.
When to use and
when not to use
COM
was defined decades ago, Since then, new technologies have emerged that greatly reduce the cost of development compared to COM, However, while these technologies have proven to be effective, in most cases, there are cases where performance and resource consumption are critical, in these cases C++/COM are essential.
Web and big data applications (for example) have many highly optimized frameworks that allow implementation using a higher-level language such as C# or Java, however, for specialized applications where performance is critical, development must be done in C/C++, in these cases COM proves efficient, I have been using COM extensively while building media/streaming engines on Windows, Linux and mobile devices.
Fundamentals Object
lifecycle control: Reference counting is used to keep the object alive while it is being used, and therefore, each of the object consumers (class, method, …) increases its reference count while it is using the object (calling ‘
AddRef’) and, reduces the reference count when it has finished using the object (calling ‘Release’). Object runtime type information
: With COM, objects implement interfaces, each of these interfaces is associated with a unique identifier, this id is used by the object’s consumer (for example, calling method) to query the support of a specific interface, the method that implements this logic is called QueryInterface.
The most
fundamental COM construct is the IUnknown interface, this interface must be implemented by each COM object and interface, it defines methods for reference count control and querying runtime type information.
Object
lifecycle control is usually implemented using a class member variable for reference counting, calling AddRef to increase the reference count by one, while Release decreases the reference count, When the reference count reaches zero, the object is responsible for cleaning itself from memory.
The QueryInterface method is used to query the object for the support of a specific interface, the implementation of the
QueryInterface method involves iterating through the list of supported interface identifiers, if the queried interface is found to be compatible, the object will increase its reference count and return a pointer reference through ‘*ppvObject’, If the queried interface was not found, it is E_NOINTERFACE returned.
Implementation guidelines
Since COM objects
maintain their own lifespan by reference counting, controlling the lifetime of external objects should be avoided, for example, assigning a COM object to the stack will cause its allocated resources to be released upon completion of the stack frame, making the reference counting mechanism useless and misleading.
To ensure that the object maintains its own lifecycle, COM object builders and destructors are defined as protected, which prevents the object from being created directly on the stack.
The creation of
COM objects is implemented by a special static class method usually called CreateInstance, this method assigns the object, initializes the reference count and returns the default interface, that interface can be used later to query other interfaces.
The sample code
references
the
component object model, IUnknown