Developing Drivers with the Windows Driver Foundation (Pro Developer)

Drivers can use the registry to obtain information about their devices and to store information that must persist from one system reboot to the next. UMDF and KMDF provide the following ways for a driver to read and write the registry:

UMDF Device Property Store

The device property store is an area in the registry where a UMDF driver can maintain information about the characteristics of its device, such as time-out values or device configuration settings for a particular device-in short, any device-specific information that the driver stores for use each time the system or device starts.

Each property store has a name, which is the same as that of the registry key that maintains the information. By default, the key has the same name as the driver. A property store contains one or more named string, integer, or binary values. To read information from the property store, a UMDF driver must have both the name of the property store and the name of the value that contains the data.

The property store provides a secure way for UMDF driver to write data to the registry and insulates drivers from the actual location of the data. A UMDF driver should not try to read or write property store data by accessing a specific registry location, and conversely, a UMDF driver cannot use the property store methods to read or write data such as device parameters that are recorded in other parts of the registry. To obtain information from elsewhere in the registry, drivers should use the Windows Registry API or Setup API. However, a UMDF driver runs in the LocalService security context, which restricts the areas of the registry that the driver can read and write.

A UMDF driver can create a new device property store or retrieve an existing property store by calling the RetrieveDevicePropertyStore method on either of the following interfaces:

The RetrieveDevicePropertyStore method returns a pointer to an IWDFNamedPropertyStore helper interface through which the driver can set and get the values of device properties. This method has the following four parameters:

After the driver creates or retrieves the property store, it uses the IWDFNamedPropertyStore interface to get and set the values in the store. Table 12-3 summarizes the methods of the IWDFNamedPropertyStore interface.

Table 12-3: IWDFNamedPropertyStore Methods

Open table as spreadsheet

Method

Description

GetNameAt

Retrieves the name of a property, given the index of the property.

GetNameCount

Retrieves the number of properties in the property store.

GetNamedValue

Retrieves the value of a property given the name of the value.

SetNamedValue

Sets the value of a property.

The driver defines the format and contents of the property store. The property store persists in the registry until the device is uninstalled from the system. The framework saves the property store under the devnode, so the property store is deleted when the device is uninstalled. The device vendor is not required to supply an uninstall procedure. Listing 12-3 shows how a driver creates a named property store after it creates a device object. This example is excerpted from Sideshow\WSSDevice.cpp.

Listing 12-3: Creating a named property store

hr = m_pWdfDevice->RetrieveDevicePropertyStore(NULL, WdfPropertyStoreCreateIfMissing, &pStore, NULL); if (SUCCEEDED(hr)) { hr = m_pBasicDriver->Initialize(pStore); }

In the example, the m_pWdfDevice variable is a pointer to the IWDFDevice interface that the driver received when it created the framework device object. The driver passes NULL as the property store name and WdfPropertyStoreCreateIfMissing to request that the framework create a new property store with the default name. The driver also passes NULL for the pDisposition parameter because it does not require this information. The method returns a pointer to the IWDFNamedPropertyStore interface in pStore.

Listing 12-4 shows how the same sample driver gets a named value from the property store. This code is derived from Sideshow\BasicDDI.cpp.

Listing 12-4: Retrieving information from a property store

PROPVARIANT pvBlob = {0}; PropVariantInit(&pvBlob); hr = m_pPropertyStore->GetNamedValue(wszKey, &pvBlob); if (SUCCEEDED(hr) && VT_BLOB == pvBlob.vt && 0 == (pvBlob.blob.cbSize % sizeof(APPLICATION_ID))) { *pcAppIds = pvBlob.blob.cbSize / sizeof(APPLICATION_ID); *ppAppIds = (APPLICATION_ID*)pvBlob.blob.pBlobData; }

The sample code calls IWDFNamedPropertyStore::GetNamedValue to retrieve the value of the key that the wszKey string describes. The value is returned as a binary value of variant type VT_BLOB, which the driver then parses and evaluates. Note that PropVariantInit is a COM function that initializes a variant property structure.

 Tip  See "PropVariantInit" on MSDN for more information-online at http://go.microsoft.com/fwlink/?LinkId=79586.

Listing 12-5 shows how the Sideshow sample driver sets a named value in the property store. This code is also derived from Sideshow\BasicDDI.cpp.

Listing 12-5: Setting information in a property store

PROPVARIANT pvBlob = {0}; PropVariantInit(&pvBlob); pvBlob.vt = VT_BLOB; pvBlob.blob.cbSize = cApps * sizeof(APPLICATION_ID); pvBlob.blob.pBlobData = (BYTE*)pApps; hr = m_pPropertyStore->SetNamedValue(wszKey, &pvBlob);

In Listing 12-5, the sample driver writes an application ID to the property store as binary data. The sample fills a PROPVARIANT variable with a value of variant type VT_BLOB and then calls the IWDFNamedPropertyStore::SetNamedValue method to save the value in the key named by the wszKey string.

KMDF Registry Objects and Methods

KMDF includes numerous methods with which a driver can read and write the registry. These methods enable the driver to create, open, and close a registry key and to query, change, and delete the values of keys and individual data items within them.

A driver can access the registry entry for a driver or device either before or after creating the device object. If your driver requires information from the registry before it creates the device object, your driver can use the WdfFdoInitXxx methods to get the value of individual device properties or to retrieve the entire device hardware key or driver software key. After creating the device object, the driver uses WdfDeviceXxx methods. Table 12-4 summarizes the methods that query individual device properties and open registry keys.

Table 12-4: KMDF Methods to Query and Open Registry Keys

Open table as spreadsheet

Method

Description

WdfDeviceAllocAndQueryProperty

Allocates a buffer and retrieves a device property from the registry, given a handle to a WDFDEVICE object.

WdfDeviceQueryProperty

Retrieves a device property from the registry, given a handle to a WDFDEVICE object.

WdfDeviceOpenRegistryKey

Opens the registry hardware key for a device or the software key for a driver and creates a framework registry-key object that represents the key.

WdfFdoInitAllocAndQueryProperty

Allocates a buffer and retrieves a device property from the registry, given a pointer to a WDFDEVICE_INIT structure.

WdfFdoInitOpenRegistryKey

Opens a device's hardware key or a driver's software key in the registry and creates a registry-key object that represents the registry key, given a pointer to a WDFDEVICE_INIT structure.

WdfFdoInitQueryProperty

Retrieves a device property from the registry, given a pointer to a WDFDEVICE_INIT structure.

To read the value of a registry key, a driver opens the registry key and then calls a method that queries the registry for data. The WdfFdoInitOpenRegistryKey and WdfRegistryOpenKey methods open a registry key. Both of these methods have the following five parameters:

To get or set the value of a single setting within the key, the driver must use one of the WdfRegistryXxx methods, which are listed in Table 12-5. When the driver has completed using the registry, the driver calls WdfRegistryClose to close and delete the key.

Table 12-5: KMDF Registry Key Methods

Open table as spreadsheet

Method

Description

WdfRegistryAssignMemory

Assigns data from a memory buffer to a value name in the registry.

WdfRegistryAssignMultiString

Assigns a set of strings from a collection of string objects to a value name in the registry.

WdfRegistryAssignString

Assigns a string from a string object to a value name in the registry.

WdfRegistryAssignULong

Assigns an unsigned long word value to a value name in the registry.

WdfRegistryAssignUnicodeString

Assigns a Unicode string to a value name in the registry.

WdfRegistryAssignValue

Assigns data to a value name in the registry.

WdfRegistryClose

Closes the registry key that is associated with a registry-key object and then deletes the registry-key object.

WdfRegistryCreateKey

Creates and opens a registry key, or just opens the key if it already exists, and creates a registry-key object that represents the registry key.

WdfRegistryOpenKey

Opens a registry key and creates a registry-key object that represents the registry key.

WdfRegistryQueryMemory

Retrieves the data that is currently assigned to a registry value, stores the data in a framework-allocated buffer, and creates a memory object to represent the buffer.

WdfRegistryQueryMultiString

Retrieves the strings that are currently assigned to a multistring registry value, creates a framework string object for each string, and adds each string object to a collection.

WdfRegistryQueryString

Retrieves the string data that is currently assigned to a registry string value and assigns the string to a string object.

WdfRegistryQueryULong

Retrieves the unsigned long word (REG_DWORD) data that is currently assigned to a registry value and copies the data to a driver-specified location.

WdfRegistryQueryUnicodeString

Retrieves the string data that is currently assigned to a registry string value and copies the string to a UNICODE_STRING structure.

WdfRegistryQueryValue

Retrieves the data that is currently assigned to a registry value.

WdfRegistryRemoveKey

Removes the registry key that is associated with a framework registry-key object and then deletes the registry-key object.

WdfRegistryRemoveValue

Removes a value and its data from a registry key.

WdfRegistryWdmGetHandle

Returns a WDM handle to the registry key that a framework registry-key object represents.

 Sample code to read and write the registry  In the Pcidrv.c source file, the PCIDRV sample provides functions that:

The PCIDRV sample driver's PciDrvReadFdoRegistryKeyValue function is called from the EvtDriverDeviceAdd callback before the driver creates the device object. It reads a key, which the driver's INF wrote at installation, that indicates whether the driver was installed as an NDIS upper-edge miniport driver. This information is important because it determines whether the driver registers certain power policy and I/O event callbacks. If the driver was installed as an upper-edge miniport driver, it is not the power policy manager for its device; instead, NDIS manages power policy. Listing 12-6 shows the source code for this function.

Listing 12-6: Reading a registry key during device object initialization

BOOLEAN PciDrvReadFdoRegistryKeyValue( __in PWDFDEVICE_INIT DeviceInit, __in PWCHAR Name, __out PULONG Value ) { WDFKEY hKey = NULL; NTSTATUS status; BOOLEAN retValue = FALSE; UNICODE_STRING valueName; PAGED_CODE(); *Value = 0; status = WdfFdoInitOpenRegistryKey(DeviceInit, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, WDF_NO_OBJECT_ATTRIBUTES, &hKey); if (NT_SUCCESS (status)) { RtlInitUnicodeString (&valueName,Name); status = WdfRegistryQueryULong (hKey, &valueName, Value); if (NT_SUCCESS (status)) { retValue = TRUE; } WdfRegistryClose(hKey); } return retValue; }

First, the driver initializes the Value parameter that will receive the requested key value. Next, it opens the registry key by calling WdfFdoInitOpenRegistryKey, passing the five previously described parameters, and receiving a handle to the returned WDFKEY object in hKey. The PLUGPLAY_REGKEY_DEVICE constant specifies the device's hardware key. Although the sample requests all access rights to the registry by specifying STANDARD_RIGHTS_ALL, the driver only reads the key and does not write it, so STANDARD_RIGHTS_READ would also work.

If the driver successfully opens the hardware key, it queries the key for the requested value. The name of the value is passed into the PciDrvReadFdoRegistryKeyValue function as a pointer to a string. However, the KMDF query method requires the name in a counted Unicode string. Therefore, before querying for the value, the driver calls RtlInitUnicodeString to copy the input string into a string of the correct format.

The driver then calls WdfRegistryQueryUlong, which returns the ULONG value of the key in the Value parameter. The driver closes the key by calling WdfRegistryClose and the function returns.

Категории