The WMILIB_CONTEXT WmiLibInfo field also sets up several callback routines that we shall meet later. These are used to help the processing of the IRP_MJ_SYSTEM_CONTROL WMI IRP.
After calling IoWmiRegistrationControl , your driver will then be sent an IRP_MN_REGINFO System Control IRP to obtain the device's WMI MOF information, as described in the following.
Listing 12.3 RegisterWmi and DeregisterWMI code
const int GUID_COUNT = 3;
WMIGUIOREGINFO Wdm3GuidList[GUID_CЩUNT] = {
{ &WDM3_WMI_GUID, 1. 0 }, // Wdm3Information
{ &GUID_POWER_DEVICE_ENABLE, 1, 0}, // MSPower_DeviceEnable
{ &WDM3_WMI_EVENT_GUID, 1, 0}, // Wdm3Event
};
const ULONG WDM3_WMI_GUID_INDEX = 0;
const ULONG GUID_POWER_DEVICE_ENABLE_INDEX = 1;
const ULONG WDM3_WMI_EVENT_GUID_INDEX = 2;
void RegisterWmi(IN PDEVICE_OBJECT fdo) {
PWDM3_DEVICE_EXTENSION dx=(PWDM3_DEVICE_EXTENSION)fdo->DeviceExtension;
dx->WmiLibInfo.GuidCount = GUID_COUNT;
dx->WmiLibInfo.GuidList = Wdm3GuidList;
dx->WmiLibInfo.QueryWmiRegInfo = QueryWmiRegInfo;
dx->WmiLibInfo.QueryWmiDataBlock = QueryWmiDataBlock;
dx->WmiLibInfo.SetWmiDataBlock = SetWmiDataBlock;
dx->WmiLibInfo.SetWmiDataItem = SetWmiDataItem;
dx->WmiLibInfo.ExecuteWmiMethod = ExecuteWmiMethod;
dx->WmiLibInfo.WmiFunctionControl = WmiFunctionControl;
NTSTATUS status = IoWMIRegistrationControl(fdo, WMIREG_ACTION_REGISTER);
DebugPrint("RegisterWmi %x", status);
}
void DeregisterWmi( IN PDEVICE_OBJECT fdo) {
IoWMIRegistrationControl(fdo, WMIREG_ACTION_DEREGISTER);
DebugPrintMsg("DeregisterWmi");
}
Table 12.1 WMILIB_CONTEXT structure
GuidCount |
ULONG |
Required |
Count of WMI blocks |
GuidList |
|
Required |
Array with the GUIDs of the WMI blocks supported, etc. |
QueryWmiRegInfo |
|
Required |
Provide further information about the WMIblocks you are registering |
QueryWmiDataBlock |
Callback |
Required |
Return a single instance or all instances of adata block |
SetWmiDataBlock |
Callback |
Optional |
Set all data items in a single instance of adata block |
SetWmiDataItem |
Callback |
Optional |
Set a single data item in a single instance of a data block |
ExecuteWmiMethod |
Callback |
Optional |
Execute a method associated with a data block |
WmiFunctionControl |
Callback |
Optional |
Enable and disable event notification andexpensive data block collection |
Handling System Control IRPs
Your driver must then handle System Control IRPs in your SystemControl routine. Table 12.2 shows the various minor codes associated with this IRP.
Table 12.2 System control minor request codes
IRP_MN_REGINFO |
Query a driver's registration information |
IRP_MN_QUERY_ALL_DATA |
Get all instances in a given data block |
IRP_MN_QUERY_SINGLE_INSTANCE |
Get a single instance in a given data block |
IRP_MN_CHANGE_SINGLE_INSTANCE |
Change all data items in a given data block |
IRP_MN_CHANGE_SINGLE_ITEM |
Change a single data item in a given data block |
IRP_MN_ENABLE_EVENTS |
Enable event notification |
IRP_MN_DISABLE_EVENTS |
Disable event notification |
IRP_MN_ENABLE_COLLECTION |
Start collection of data that is expensive to collect |
IRP_MN_DISABLE_COLLECTION |
Stop collection of data that is expensive to collect |
IRP_MN_EXECUTE_METHOD |
Execute a method in a data block |
If you have dynamic instance names, you must process the IRP and call WmiCompleteRequest , or pass it onto the next driver if you do not recognize the GUID.
For static instances, as used by Wdm3, you simply have to call WmiSystemControl , passing a pointer to your WMILIBCONTEXT structure. WmiSystemControl processes the IRPs as much as possible. If the request is destined for your driver, it invokes the appropriate callback to let you process the IRP. On return, WmiSystemControl sets its IrpDisposition parameter to tell you how to continue processing the IRP, as shown in Table 12.3. For example, if the IRP was not destined for your driver, IrpDisposition is set to IrpForward and the IRP is sent down the stack.
Table 12.3 WmiSystemControl IrpDisposition handling
IrpProcessed |
Either call WmiCompleteRequest here or in your call-back routine. |
IrpNotComplete |
IRP processed but an error detected, so just call IoCompleteRequest . |
IrpNotWMI or IrpForward |
Forward to next driver: call IoSkipCurrentIrpStackLocation and IoCallDriver |
Listing 12.4 shows how the Wdm3SystemControl routine processes System Control IRPs. The main processing is carried out by the system function WmiSystemControl . Wdm3SystemControl acts on the IrpDisposition parameter in the recommended way.
Listing 12.4 Wdm3SystemControl routine
NTSTATUS Wdm3SystemControl (IN PDEVICE_OBJECT fdo, IN PIRP Irp) {
DebugPrintMsg("Wdm3SystemControl");
PWDM3_DEVICE_EXTENSION dx = (PWDM3_DEVICE_EXTENSION)fdo->DeviceExtension;
SYSCTL_IRP_DISPOSITION disposition;
NTSTATUS status = WmiSystemControl(&dx->WmiLibInfo, fdo, Irp, &disposition);
switch(disposition) {
case IrpProcessed:
// This irp has been processed and may be completed or pending.
break;
case IrpNotCompleted:
// This irp has not been completed, but has been fully processed.
// we will complete it now
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IrpForward: case IrpNotWmi:
// This irp is either not a WMI irp or is a WMI irp targetted
// at a device lower in the stack.
IoSkipCurrentIrpStacktocation(Irp);
status = IoCallDriver(dx->NextStackDevice, Irp);
break;
default:
DebugPrint("Wdm3SystemControl bad disposition %d",disposition);
// ASSERT(FALSE);
}
return status;
}
At a minimum, you should write QueryWmiRegInfo, QueryWmiDataBlock, SetWmiDataBlock , and SetWmiDataItem callbacks. Even though the last two callbacks are optional, it is best to implement them to ensure that WmiCompleteRequest is called with an appropriate error code.
QueryWmiRegInfo Handler
The Wdm3 QueryWmiRegInfo callback routine shown in Listing 12.5 provides further information about the WMI blocks you are registering, in addition to the GuidList provided in your WMILIB_CONTEXT.
Читать дальше