This directory contains a sample PnP upper filter driver whose only
purpose is to provide WMI data blocks. Typically driver writers will copy the
sample code into their own driver and make any minor modifications so that the
WMI data blocks are always available when the driver is loaded. Alternatively
WmiSamp can be left as a filter driver if WMI data blocks should only be made
available when the filter driver is loaded. Drivers that link to classpnp.sys
should use a similar library that is part of classpnp.
WMI enabling a driver with the sample code consists of doing 5 things:
1. Determining what data needs to be provided and organize it into data blocks
that contain related data items. For example packets sent and bytes sent
could be part of a single data block while transmit errors could be part
of a data block that contains other error counts. Determine if the device
needs notifications of when to enable and disable collections in the case
of data blocks that impose a performance hit to collect.
2. Write a Managed Object Format (.mof) file that describes the data blocks.
In doing this the driver writer will need to run the guidgen tool to
create globally unique guids that are assigned to the data blocks. Guidgen
*MUST* be run so that no two data blocks will have the same guid. Reference
the .bmf file (.bmf files are created when mof files are compiled by the
mofcomp tool) in the driver's .rc file so that the .bmf file data is
included as a resource of the driver's .sys file. WmiLib hardcodes the
resource name as MofResourceName.
3. Build the GUIDREGINFO structure with the guids for the data blocks defined
in the .mof file. If the device wants to be notified of when to start and
stop collection of a data block the WMIREG_FLAG_EXPENSIVE flag should be
set for the data block in the GUIDREGINFO structure.
4. Implement the 6 WMI function callback routines and reference them in a
WMI_INFO structure.
The sample code supports does not support more than one instance of a
data block for each device, that is a single device object can only supply
one instance of a data block. Drivers that create multiple device objects
will supply multiple instances for a data block (ie, 1 data block per device
object).
The sample code does not support dynamic instance names. Instance names
are statically defined when device registers with WMI. The PQUERY_WMI_REGINFO
callback allows the device to specify a unique instance name for the device or
the PDO for the device. If the PDO is specified then WMI will translate it to
the device instance name and use that as the unique instance name.
All data blocks registered for a device will use the same instance name.
That is different data blocks for a device object cannot specify different
instance names.
The sample code can be extended to overcome these limitations if the need
arises, however this sample code should be sufficient for most applications.
All WMI callback functions that pass the irp as a parameter are
responsible to call WmiLibCompleteRequest when the request has been satisfied
so that the IRP can be completed. If the WMI callback function cannot
complete the request immediately it can mark the irp pending and return
STATUS_PENDING, but it must call WmiLibComnpleteRequest when the request
actually finishes.
The sample code uses a simple linear search to determine the guid index
for any guid passed. If a driver provides a long list of guids then
WmiLibFindGuid may need to be updated to use a better searching mechanism.
WmiLib counts on a number of fields being present in the device extension
in order for it to process the WMI requests. See Wmilib.h for their
description.
Finally the sample code uses a static global variable to store the
values for the data block. This is not quite correct since each device object
will typically have its own set of data that composes its instance of a
data block. Really the global variable should be part of the device extension,
however I did not want to confuse the device extension with extra stuff.