Using COM to Develop UMDF Drivers, Part 1
- Using COM to Develop UMDF Drivers (Part 1 of 2)
- Returns from a COM Method (<tt>HRESULT</tt> Type)/Using UMDF COM Objects
- Obtaining an Interface on a UMDF Object
In previous articles we looked at the architecture of the Windows 7 User Mode Driver Framework (UMDF), the programming approach for developing UMDF drivers, and specifically in the previous article how to program drivers for the UMDF. In this article, we'll examine the Component Object Model (COM), and its use in creating user mode drivers. COM is a specification for a way of building applications based on using components. In the traditional sense, applications were divided into files, modules, or classes; then they were linked to form a monolithic application. By contrast, a component is like a small application that comes packaged as a binary piece of code that is compiled, linked, and ready to use. This piece of code then links with other components at runtime to form an application. One of the great features of this approach is that you can change or enhance the application by replacing one of the components.
This article introduces COM and its use in creating UMDF drivers. For our work in UMDF driver development, we must use COM objects that are part of the Windows Driver Foundation (WDF) framework. We need to create a number of UMDF driver callback objects, based on COM-based callback objects. In the UMDF driver development, we won't use the COM runtime, which contains a good deal of complexity, but we will use the essential core of the COM programming model. This keeps the UMDF driver fairly lightweight and thus relatively easy to implement.
In general, UMDF drivers are programmed using C++, and COM objects are developed and also written in C++. It's good to have an understanding of class structure, such as the struct and class keywords, public and private members, static methods, constructors, destructors, and pure abstract classes. Also, you should understand object creation, which includes base and derived classes, multiple inheritance, and pure virtual methods. Paul Deitel and Harvey M. Deitel's book C++ How to Program, Seventh Edition is a good reference to review to help you get an understanding of these basic concepts. In UMDF drivers, the operator overloading or templates are not necessary. The UMDF drivers can use-but are not required to use-the C++ standard template libraries.
Let's start by looking at some of the fundamental aspects of COM:
- IUnknown is the core COM interface, from which all other COM interfaces derive. Every COM object exposes this interface, and it's essential to the object's operation.
- One significant difference between objects in COM and other object-oriented programming (OOP) models is that COM has no fundamental object pointers. COM exposes interfaces that are groups of related methods. Objects typically expose at least two and sometimes many interfaces. Thus, when you obtain a COM object, you're given a pointer to one of the object's interfaces-not to the object itself.
Globally unique identifiers (GUIDs) are used by COM to identify unique COM interfaces. COM uses GUIDs for two primary purposes:
- Interface ID (IID). An IID is a GUID that uniquely identifies a particular COM interface. The interface always has the same IID, regardless of which object exposes it.
Class ID (CLSID). A CLSID is a GUID that identifies a particular COM object. CLSIDs are required for COM objects that are created by a class factory, but optional for objects that are created in other ways. With UMDF, only the driver callback object has a class factory or a CLSID.
Some COM objects have GUID identifiers, in which case they're referred to as CLSIDs. GUIDs are referred to as IIDs when you request an interface pointer by using these IIDs.
To simplify using GUIDs, an associated header file usually defines friendly names that conventionally have a prefix of either IID_ or CLSID_ followed by the description name. For example, the friendly name for the GUID associated with IDriverEntry is IID_IDriveEntry. For convenience, the UMDF documentation usually refers to interfaces by the name used in their implementation, such as IDriverEntry, rather than the IID.
- Any of the methods on an interface can be used with an interface pointer. If you want access to a method on another interface, you must obtain another interface pointer by using the IUnknown::QueryInterface method.
- There is no public data member's exposure in COM objects. Public data is exposed through methods called accessors. In UMDF, you use a Get/Retrieve or Set/Assign prefix for its read and write accessors, respectively. Figure 1 shows the logical relationship between an object and its contents.
Figure 1 COM object, interfaces, and methods.
All access to COM objects is through a virtual function table—commonly called a VTable—that defines the physical memory structure of the interface. The VTable is an array of pointers to the implementation of each of the methods that the interface exposes. When a client gets a pointer to an interface, it's actually a pointer to the VTable pointer, which in turn points to the method pointer. For example, Figure 2 shows the memory structure of the VTable for IWDFloRequest.
Figure 2 VTable and interface pointers.
The VTable is exactly the memory structure that many C++ compilers create for a pure abstract base class. This is one of the main reasons that COM objects are normally implemented in C++, with interfaces declared as pure abstract base classes. You can then use C++ inheritance to implement the interfaces in your objects, and the VTable is created for you by the compiler.