Logo
PREGNANCY
Windows XP
Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
 
 
Windows 7

Using COM to Develop UMDF Drivers : Using UMDF COM Objects

4/29/2013 4:06:20 PM

A process that uses a COM object is known as a COM client. Both UMDF drivers and the UMDF run-time function as COM clients. UMDF drivers interact with UMDF run time by using UMDF-provided COM objects. For example, the UMDF device object represents the device, and drivers can use the object for tasks such as setting or retrieving the device’s Plug and Play state.

The UMDF run time interacts with drivers through the drive-provided COM-based callback objects. For example, a driver can create one or more queue callback objects to handle I/O requests. The UMDF run time uses those objects to pass request to the driver.

After you get a pointer to an interface, you can call the interface methods by using the same syntax that is used for a pointer to a C++ method. For example, if pWdfRequest is a pointer to an IWDFloRequest interface, the following code is an example of how to invoke the interface’s Send method:

HRESULT hr;

hr = pWdfRequest- >Send( m_pIUsbTargetDevice,

                          WDR_REQUEST_SEND_OPTION_SYNCHRONOUS,

                             0);

The method’s return value is an HRESULT, a typical return type for COM methods. HRESULT is similar to the NTSTATUS type that Kernel Mode Drivers use as a return value and is used in much the same way. It is important not to think of HRESULT as error values. Methods sometimes have multiple return values for success as well as for failure. You can determine the result of calling a method by comparing the returned HRESULT to the list of possible values in the reference documentation. However, be aware that these lists are not always complete. Use the error-checking macros that are discussed shortly to ensure that you do not miss a possible return value.

You can also test an HRESULT for simple success or failure. COM provides two macros for that purpose that work much like the NT_SUCCESS macro. For an HRESULT return value of hr:

  • FAILED(hr) returns TRUE for failure and FALSE for success.

  • SUCCEEDED(hr) returns FALSE for failure and TRUE for success.

Although NTSTATUS and HRESULT are similar, they are not interchangeable. Occasionally, information in the form of an NTSTATUS value must be returned as an HRESULT. In that case, you can use the HRESULT_FROM_NT macro to convert the NTSTATUS into an equivalent HRESULT. Do not use this macro for an NTSTATUS value of STATUS_SUCCESS. In that case, return the S_OK HRESULT value.

1. Obtaining an Interface on a UMDF Object

You can obtain an interface on a UMDF object in one of three ways:

  • The UMDF run time passes an interface pointer in to one of the driver’s callback methods.

  • The driver creates a new WDF object by calling a UMDF object creation method.

  • The driver calls IUnknown::QueryInterface to request a new interface from an existing WDF object.

You can also receive an Interface through a Driver Method. The first case is the simplest. For example, when the UMDF run time calls a driver’s IDriverEntry::OnDeviceAdd method, it passes a pointer to the device object’s IWDFDriver interface.

The following example shows this activity:

HRESULT CMyDriver::OnDeviceAdd(
            __in IWDFDriver *FxWdfDriver,
            __in IWDFDeviceInitialize *FxDeviceInit
            )
{
   // Install the driver in the device stack
}

You can then use FxWdfDriver to access the methods on the driver object’s IWDFDriver interface. Do not release FxWdfDriver when you are finished with it. The caller ensures that the object remains valid during the scope of the method call.

Another way to create a WDF object is by calling the appropriate UMDF object creation method. For example, to create a request object, call the UMDF device object’s IWDFDevice::CreateRequest method. If you look at the UMDF reference in the Windows Driver Kit (WDK), you will find syntax like that for IWDFDevice::CreateRequest:

HRESULT CreateRequest(
           IN IUnknown*  pCallbackInterface,
           IN IWdfObject*  pParentObject,
           OUT IWDFIoRequest**  ppRequest
           );

ppRequest is an OUT parameter that provides an address at which the CreateRequest method can store a pointer to the newly created request object’s IWDFObject interface. The following procedure and sample show how to handle such parameters, by using a call to CreateRequest by the UMDF’s fx2_driver sample as an example.

We would declare a variable, pWdfRequest, to hold a pointer to IWDFloRequest.

Then we would pass a reference to pWdfRequest to CreateRequest as follows:

IWDFIoRequest *pWdfRequest = NULL;
...
hr = m_FxDevice- >CreateRequest ( NULL, NULL, &pWdfRequest);

When CreateRequest returns, pWdfRequest holds a pointer to an IWDFIoRequest interface. When the caller has finished with pWdfRequest, it should release the interface pointer by calling IUnknown::Release.

Another approach is to call QueryInterface to request a new interface. Objects can expose more than one interface. Sometimes, you have a pointer to one interface and need a pointer to another interface on the same object. In that case, call IUnknown::QueryInterface to request the desired pointer. Pass QueryInterface the IID of the desired interface and the address of the interface pointer, and QueryInterface returns the requested pointer. When the caller is finished with the interface pointer, the caller should release it. The following is an example:

VOID CMyDevice::StartTarget ( IWDFIoTarget * pTarget)
{
   IWDFIoTargetStateManagement * pStateMgmt = NULL;
   HRESULT hrQI  =
           pTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt));
   ...
}

This example requests an IWDFIoTargetStateManagement interface pointer from the UMDF’s I/O target object. It uses the IID_PPV_ARGS macro—declared in objbase.h—which takes an interface pointer and produces the correct arguments for QueryInterface.

QueryInterface belongs to the IUnknown interface. However, as shown earlier, there is no need to have an explicit pointer to an object’s IUnknown interface to call QueryInterface. All interfaces inherit from IUnknown, so you can use any interface to call QueryInterface.

2. Reference Counting

Unlike C++ objects, a client does not directly manage the lifetime of a COM object. Instead, a COM object maintains a reference count on itself. When a client creates a new object with an object-creation method, the object has a reference count of 1. Each time the client requests an additional interface on the object, the object increments the reference count. When a client is finished with an interface, it releases the interface pointer, which decrements the reference count. When all the interface pointers on the object have been released, the reference count is zero and the object destroys itself.

You must be extremely careful about handling reference counts when you use or implement COM objects. Although clients do not explicitly destroy COM objects, there is no garbage collection to take care of the problem automatically as there is with managed code. A common mistake is to fail to release an interface. In that case, the reference count never goes to zero and the object remains in memory indefinitely. Conversely, releasing the interface pointer too many times causes the object to be destroyed prematurely, which can cause a crash. Failure to correctly manage reference counts is a common cause of memory leaks in COM-based applications, along with a variety of other problems. Even worse, bugs that are caused by mismanaged reference counts can be very difficult to locate.

The following are some basic rules for reference counting:

  • Release any interface pointer that is passed to you as an OUT parameter when you are finished with it by calling IUnknown::Release. Do not release pointers that are passed as IN parameters. A common practice to ensure that all interface pointers are properly released is to initialize all pointers to NULL. Then set them to NULL again when they are released. That convention allows you to test all the interface pointers in your cleanup code; any non-NULL pointers are still valid and should be released.

  • The reference count is usually incremented for you. The main exception is when you make a copy of an interface pointer. In that case, call IUnknown::AddRef to explicitly increment the object’s reference count. You must then release the pointer when you are finished.

  • When you discover that the driver has reference counting problems, do not attempt to fix them by simply adding calls to AddRef or Release. Make sure that the driver is acquiring and releasing references according to the rules. Otherwise, you may find, for example, that the Release calls that you added to solve a memory leak occasionally deletes the object prematurely and instead causes a crash.

As with QueryInterface, you do not need a pointer to the object’s IUnknown interface to call AddRef or Release. You can call these methods from any of the object’s interfaces.

Other -----------------
- 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
- Customizing Windows 7 : Customize the Taskbar
 
 
Most view of day
- Microsoft Exchange Server 2010 : Managing Transport and Journaling Rules - Setting Up Message Classifications (part 2)
- Microsoft Exchange Server 2013 : Mailbox management - Setting mailbox permissions (part 1) - Mailbox delegation
- Using Micrsosft Outlook 2010 with SharePoint and OCS : Using SharePoint Document Libraries in Outlook
- Backup and Restore of Microsoft Lync Server 2010 : Restore Processes
- Tracking Change in Vista : Turning on the audit policy, Exploring the Vista Event Log
- Zero Touch Installations : Creating and Capturing a Reference Image (part 2) - Install Packages on the Distribution Points, Create a Collection and a Computer Association
- Multi-Tenancy in SharePoint 2013 (part 2) - Multi-Tenant Use Cases, Partitioning in the Enterprise
- Windows Server 2008 R2 high-availability and recovery features : Installing and Administering Failover Clustering (part 4) - Verifying cluster configuration using the Cluster Validation Wizard
- Exchange Server 2007 : Using OWA Mail Features (part 2)
- Sharepoint 2013 : The Office JavaScript Object Model (part 1) - Document-based Apps
Top 10
- Managing Windows Server 2012 Systems : Configuring Roles, Role Services, and Features (part 6) - Tracking installed roles, role services, and features
- Managing Windows Server 2012 Systems : Configuring Roles, Role Services, and Features (part 5) - Installing components at the prompt
- Managing Windows Server 2012 Systems : Configuring Roles, Role Services, and Features (part 4) - Managing server binaries
- Managing Windows Server 2012 Systems : Configuring Roles, Role Services, and Features (part 3) - Adding server roles and features
- Managing Windows Server 2012 Systems : Configuring Roles, Role Services, and Features (part 2) - Installing components with Server Manager - Viewing configured roles and role services
- Managing Windows Server 2012 Systems : Configuring Roles, Role Services, and Features (part 1) - Using roles, role services, and features
- Windows Server 2012 : Configuring IPsec (part 7) - Configuring connection security rules - Monitoring IPsec
- Windows Server 2012 : Configuring IPsec (part 6) - Configuring connection security rules - Creating a custom rule, Configuring authenticated bypass
- Windows Server 2012 : Configuring IPsec (part 5) - Configuring connection security rules - Creating an authentication exemption rule, Creating a server-to-server rule, Creating a tunnel rule
- Windows Server 2012 : Configuring IPsec (part 4) - Configuring connection security rules - Types of connection security rules, Creating an isolation rule
 
 
Windows XP
Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
2015 Camaro