Logo
Windows XP
Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
EPL Standings
 
 
Windows 7

Using COM to Develop UMDF Drivers : Basic Infrastructure Implementation

4/29/2013 4:07:15 PM
1. DllMain

A dynamic-link library (DLL) can contain any number of in-process COM objects, but it must have a single entry point that is named DllMain. Windows calls DllMain after the driver binary has been loaded into a host process and before it is unloaded. The function is also called when threads are created or destroyed. The dwReason parameter indicates why the function was called.

When a UMDF driver’s DllMain function is called for DLL loading or unloading, it should perform only simple module-wide initialization and termination tasks, such as initializing or freeing global variables and registering or unregistering Window Software Trace Preprocessor (WPP) tracing. There is a number of things DllMain should definitely not do, such as calling LoadLibrary.

When a UMDF driver’s DllMain function is called for thread creation or destruction, it can ignore the call. For more information, see the function’s reference page in the Platform Software Developers Kit (SDK). For a typical DllMain implementation, see the dllsup.cpp from the UMDF sample code.

2. DllGetClassObject

Because class factories aren’t exported by name, there is no direct way for a client to get access to them. Instead, the DLL exports the DllGetClassObject function by name, which allows it to be called by any client with access to the DLL. For many COM DLLs, including the UMDF samples, DllGetClassObject is the only function that is listed in the project’s .def file to be exported by name from the DLL.

When a client wants to create an instance of one of the COM objects in the DLL, it passes the CLSID of the desired class factory object to DllGetClassObject and the IID of the desired interface, usually IClassFactory. DllGetClassObject creates a new class factory object and returns a pointer to the appropriate interface on the object. The client can then use the IClassFactory::CreateInstance method to create an instance of the object. For a typical implementation of DllGetClassObject, see dllsup.cpp from the UMDF’s sample code in the book.

A standard COM server is also required to implement DllCanUnloadNow and, optionally, DllRegisterServer and DllUnregisterServer. These exports are not required for UMDF drivers.

3. Driver Object’s Class Factory

Some COM objects must be created by external clients. For UMDF drivers, there is usually only one such object: that is the driver callback object. A COM object that can be created by an external client must have a class factory. This is a small specialized COM object whose sole purpose is to create a new instance of its associated COM object and return a pointer to a specified interface. For a typical implementation of a class factory, see comsup.cpp from the UMDF’s sample code.

Class factories usually expose only one interface in addition to IUnknown, IClassFactory. The IClassFactory interface has two members:

  • CreateInstance creates an instance of the object and returns the requested interface pointer to the client.

  • LockServer can be used to keep the DLL in memory. UMDF class factories typically have only a token implementation because UMDF does not use LockServer.

Some recommendations for implementing CreateInstance are as follows.

  • Ignore the first parameter. Its purpose is to support COM aggregation, which is not used by UMDF.

  • Create a new driver callback object by whatever means is convenient. The sample code puts the object creation code in a static method on the class that implements the callback object.

  • Return the appropriate interface as an OUT parameter. At this point, the object should have a reference count of 1.

4. Implementing a UMDF Callback Object

A UMDF driver consists of a collection of COM callback objects. These objects respond to notification by the UMDF run time and allow the driver to process various events, such as read or write requests. All callback objects are in-process COM objects. This means that they are packaged in a DLL and run in the process context of a UMDF host.

The basic requirements for implementing UMDF callback objects are relatively simple and straightforward:

  • Implement the IUnknown methods to handle reference counting and provide pointers to the object’s interfaces.

  • Implement the methods of the UMDF callback interfaces that are to be exported by the object.

4.1. Implementing the UMDF Callback Class

UMDF callback objects are typically implemented as a C++ class that contains the code to support IUnknown plus any UMDF interfaces that the object exposes. The UMDF interfaces are declared in wudfdd.h. Following are some of the requirements:

  • The class must inherit from every interface that it exposes. However, it can do so indirectly, for example, by inheriting from a class that in turn inherits from one or more interfaces.

  • Interfaces are declared as abstract base classes, so the class must implement all the interface methods.

  • The class often inherits from a parent class in addition to interfaces. Many of the UMDF samples, for instance, inherit from a parent class, named CUnknown, that contains a base implementation of IUnknown.

  • The class can contain private data members, public methods that are not part of an interface, and so on. These are for internal use and are not visible to clients.

  • Constructors are optional. However, if a class has a constructor, it should contain no code in it that might fail. Put any code that can fail in a public initialization method that can be called after object creation.

As we mentioned, a UMDF callback object is typically implemented as a class that inherits from IUnknown and one or more object-specific interfaces. Listing 1 shows the full declaration of the CMyDriver class. The class inherits from a single UMDF interface IDriverEntry and inherits from IUnknown through the CUnknown parent class. For convenience, several of the simpler methods are implemented here, rather than in the associated .cpp file.

Listing 1. Declaration of a Driver’s Callback Object
Class CMyDriver : public Unknown, Public IDriveEntry
{
private:
   IDriverEntry * QueryIDriverEntry (VOID)
   {
      AddRef();
      return static_cast<IDriverEntry*>(this);
   }
   HRESULT initialize(VOID);
public:
   static HRESULT CreateInstance(__out PCMyDriver *Driver);
public:
   virtual HRESULT STDMETHODCALLTYPE OnInitialize(__in
          IWDFDriver *FxWdfDriver)
   {
      UNREFERENCED_PARAMETER (FxWdfDriver);
      return S_OK;
   }
   virtual HRESULT STDMETHODCALLTYPE OnDeviceAdd(
         __in IWDFDriver *FwWdfDriver,
         __in IWDFDeviceInitialize *FxDeviceInit);
   virtual VOID STDMETHODCALLTYPE OnDeinitialize(
         __in IWDFDriver *FxWdfDriver
         )
   {
      UNREFERENCED PARAMETER(FxWdfDriver);
      return;
   }
   virtual  ULONG STDMETHODCALLTYPE AddRef (VOID)
   {
      return __super::AddRef();
   }
   virtual ULONG STDMETHODCALLTYPE Release(VOID)
   {
      return __super::Release();
   }
   virtual HRESULT STDMETHODCALLTYPE QueryInterface(
      __in REFID InterfacedId,
      __deref_out PVOID *Object
      );
};

					  

IUnknown is the core COM interface; it is exposed by every COM object and is essential to the object’s operation. The approach that is used by the UMDF sample code is to have an IUnknown base class, called CUnknown, plus an implementation for each exposed interface that inherits from the base class.

4.2. Implementing AddRef and Release

Reference counting is arguably the key task of IUnknown. Normally, a single reference count is maintained for the object as a whole. The following are some recommendations for handling AddRef and Release:

  • Have the interface-specific implementations pass their calls to the base implementation and let it handle incrementing or decrementing the reference count for the object.

  • Use InterlockedIncrement and InterlockedDecrement to modify the reference count. This eliminates the possibility of a race condition.

  • After the Release method decrements the reference count, check to see whether the count has gone to zero. If so, there are no outstanding interface pointers and you can use delete to destroy the object.

  • Both AddRef and Release return the current reference count. Use this for debugging purposes.

5. Implementing QueryInterface

QueryInterface is the fundamental mechanism by which a COM object provides pointers to its interfaces. It responds to a client’s request by returning the specified interface pointer. The following are some recommendations for QueryInterface:

  • QueryInterface must check the incoming IID to see if the request is for a supported interface. IsEquallD is a utility function declared in guiddef.h that simplifies comparing IIDs.

  • If the object supports the requested interface, QueryInterface calls AddRef to increment the object’s reference count and returns the requested interface pointer. To return the pointer, QueryInterface casts a this pointer to the requested interface type. This cast is required because of the way in which C++ handles multiple inheritances.

  • When a client queries for IUnknown, an object must always return the same IUnknown pointer regardless of which interface QueryInterface is called from.

The basic process of implementing UMDF callback interfaces is similar to IUnknown. Most of the implementation details are governed by the requirements of the individual methods.

Other -----------------
- Using COM to Develop UMDF Drivers : Using UMDF COM Objects
- Using COM to Develop UMDF Drivers : Getting Started - COM Fundamentals, HRESULT
- Repairing and Removing Programs : Removing Programs, Returning to a Previous Version, Turning Windows Features On and Off
- Repairing and Removing Programs : Changing and Repairing Programs
- Windows 7 Mobility Features : Power Management (part 2) - Power Options Control Panel
- Windows 7 Mobility Features : Power Management (part 1) - Battery Meter, Power Plans
- Windows 7 Mobility Features : Working with the Windows 7 User Interface
- Microsoft Access 2010 : Viewing the Design of a Report
- Microsoft Access 2010 : The AutoReport Feature and the Report Wizard
- Microsoft PowerPoint 2010 : Finalizing Your Slide Show - Setting Up a Slide Show
- Microsoft PowerPoint 2010 : Finalizing Your Slide Show - Reviewing Your Presentation
- Evaluating Applications for Windows 7 Compatibility : Application Compatibility
- Using Wireless Bluetooth Devices : Adding Bluetooth-Enabled Devices
- Using Wireless Bluetooth Devices : Configuring Your Bluetooth Adapter
- Deploying Applications Using Group Policy and SCCM 2007 : Deploying Applications Using SCCM 2007 (part 2)
- Deploying Applications Using Group Policy and SCCM 2007 : Deploying Applications Using SCCM 2007 (part 1)
- Deploying Applications Using Group Policy and SCCM 2007 : Creating Software Installation Policies
- Deploying Applications Using Group Policy and SCCM 2007 : Deploying Applications Using Group Policy
- Programming Drivers for the User Mode Driver Framework : Using the Skeleton Driver as a Basis for Development
- Programming Drivers for the User Mode Driver Framework : Functions for COM Support
 
 
Most view of day
- Troubleshooting Hardware, Driver, and Disk Issues : How to Use Built-In Diagnostics (part 5)
- Microsoft Dynamic AX 2009 : .NET Business Connector - Usage Scenarios for .NET Business Connector
- System Center Configuration Manager 2007 : Network Design - Network Discovery
- Sharing Your Computer with Others : Create a User Account, Switch Between Accounts
- Using Microsoft SharePoint with Microsoft Dynamics CRM Functions (part 2) - Displaying Data Using BDC in Microsoft Office SharePoint Server
- Windows Server 2012 : File Services and Storage - Configuring iSCSI storage (part 5) - Using iSCSI Initiator - Discovering targets
- Understanding Network Services and Active Directory Domain Controller Placement for Exchange Server 2007 : Configuring DNS to Support Exchange Servers, Troubleshooting DNS Problems
- Using OneNote with Other Programs : OneNote Integration with Outlook (part 2)
- Microsoft Visio 2010 : Introducing Data Graphics (part 1) - What Is a Data Graphic?
- Creating a Home Network : Creating a Wired LAN, Creating a Wireless LAN
Top 10
- Windows Server 2012 : DHCP,IPv6 and IPAM - Exploring DHCP (part 3) - Creating IPv4 DHCP Scopes
- Windows Server 2012 : DHCP,IPv6 and IPAM - Exploring DHCP (part 2) - Installing DHCP Server and Server Tools
- Windows Server 2012 : DHCP,IPv6 and IPAM - Exploring DHCP (part 1)
- Windows Server 2012 : DHCP,IPv6 and IPAM - Understanding the Components of an Enterprise Network
- Microsoft OneNote 2010 : Using the Research and Translate Tools (part 3) - Translating Text with the Mini Translator
- Microsoft OneNote 2010 : Using the Research and Translate Tools (part 2) - Translating a Word or Phrase with the Research Pane
- Microsoft OneNote 2010 : Using the Research and Translate Tools (part 1) - Setting Options for the Research Task Pane, Searching with the Research Task Pane
- Microsoft OneNote 2010 : Doing Research with Linked Notes (part 2) - Ending a Linked Notes Session, Viewing Linked Notes
- Microsoft OneNote 2010 : Doing Research with Linked Notes (part 1) - Beginning a Linked Notes Session
- Microsoft OneNote 2010 : Doing Research with Side Notes (part 3) - Moving Side Notes to Your Existing Notes
 
 
Windows XP
Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
2015 Camaro