ENTERPRISE

Windows 7 : Programming WMI Support (part 3) - Firing WMI Events

1/17/2014 2:47:48 AM

6. Firing WMI Events

In the Featured Toaster sample driver, the ToasterFireArrivalEvent function shows how to generate a WMI event that has a dynamic instance name. The WMI event contains the name of the device model, which WMI records to log the arrival of this device. The driver calls this function from its EvtDevicePrepareHardware callback to indicate that the device has been configured. Parts of this function are standard WMI tasks and have little to do with KMDF. This discussion focuses on the KMDF-specific code:

NTSTATUS
ToasterFireArrivalEvent(
IN WDFDEIVE Device
)
{
WDFMEMORY memory;
PWNODE_SINGLE_INSTANCE wnode;
ULONG wnodeSize;
ULONG wnodeDataBlockSize;
ULONG wnodeInstanceNameSize;
ULONG size;
ULONG length;
UNICODE_STRING deviceName;
UNICODE_STRING modelName;
NTSTATUS status;

//
// *NOTE*
// WdfWmiFireEvent only fires single instance events at
// the present, so continue to use this method of firing
// events
// *NOTE*
//

RtlInitUnicodeString(&modelName, L"Sonali\0\0");

//
// Get the device name.
//

status = GetDeviceFriendlyName(&Device, &memory);
if(!NT_SUCCESS(status)) {
return status;
}

RtlInitUnicodeString(&deviceName, (PWSTR)
WdfMemoryGetBuffer(memory, NULL));

//
//Determine the amount of wnode information we need.
//

wnodeSize = sizeof(WNODE_SINGLE_INSTANCE);
wnodeInstanceNameSize = deviceName.Length + sizeof(USHORT);
wnodeDataBlockSize = modelName.Length + sizeof(USHORT);

size = wnodeSize + wnodeInstanceNameSize +
wnodeDataBlockSize;


//
// Allocate memory for the WNODE from NonPagedPool
//

wnode = ExAllocatePoolWithTag(NoPagedPool, size,
TOASTER_POOL_TAG);

If(NULL != wnode) {
RtlZeroMemory(wnode, size);
wnode->WnodeHeader.BufferSize = size
wnode->WnodeHeader.ProviderId =
IoWMIDeviceObjectToProviderId(
WdfDeviceWdmGetDeviceObject(Device));
wnode->WnodeHeader.Version = 1;
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);

RtlCopyMemory(&wnode->WnodeHeader.Guid,
&TOASTER_NOTIFY_DEVICE_ARRIVAL_EVENT,
Sizeof(GUID));

//
// Set flags to indicate that you are creating dynamic
// instance names. This driver supports dynamic
// instances because it can fire the events at any time.
// If it used static instance names instead, it could only
// fire events after WMI queries for IRP_MN_REGINFO,
// which happens after the device has been started.
// Note also that if you are firing an event after the
// device is started, you should
// check whether the event is enabled, because that
// indicates that someone is interested in receiving the
// event. Why waste system resources by firing an event
// when nobody is interested?
//

wnode->WnodeHeader.Flags = WNODE_FLAG_EVENT_ITEM |
WNODE_FLAG_SINGLE_INSTANCE;

wnode->OffsetInstanceName = wnodeSize;
wnode->DataBlockOffset= wnodeSize + wnodeInstanceNameSize;
wnode->SizeDataBlock = wnodeDataBlockSize;

//
// Write the instance name.
//

size -= wnodeSize;
status = WDF_WMI_BUFFER_APPEND_STRING(
WDF_PTR_ADD_OFFSET(wnode, wnod->OffsetInstance),
size,
&deviceName,
&length
);

//
// Size was precomputed, so this should never fail.
//

ASSERT(NT_SUCCESS(status));


//
// Write the data, which is the model name as a
string.
//

size = -= wnodeInstanceNameSize;
WDF_WMI_BUFFER_APPEND_STRING(
WDF_PTR_ADD_OFFSET(wnode, wnode->DataBlockOffset),
size,
&modelName,
&length
);

//
// Size was precomputed, so this should never fail.
//

ASSERT(NT_SUCCESS(status));

//
// Indicate the event to WMI. WMI will take care of
// freeing the WMI struct back to pool.
//

status = IoWMIWriteEvent(wnode);

if(!NT_SUCCESS(status)) {
KdPrint(("IoWMIWriteEvent failed %x\n", status));
ExFreePool(wnode);
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}

//
// Free the memory allocated by GetDeviceFriendlyName
// function.
//

WdfObjectDelete(memory);
return status;
}


ToasterfireArrivalEvent first defines a model name for its device and then retrieves the friendly name for the device by calling the internal routine GetDeviceFriendlyName. GetDeviceFriendlyName takes a handle to the device object and returns a handle to a WDFMEMORY object that contains a buffer that holds the name.

The driver passes the returned WDFMEMORY object handle to WdfGetMemoryBuffer to retrieve a pointer to the buffer itself and calls RtlUnicodeString to copy the contents of the buffer into the Unicode string variable deviceName, as follows:

RtlInitUnicodeString(&deviceName,
(PWSTR)WdfMemoryGetBuffer(memory, NULL));

The driver now constructs the WMI event by using standard WMI structures and routines (defined in wmistr.h) along with standard Windows device driver interfaces (DDIs), which are defined in wdm.h and ntddk.h. The driver allocates memory from the nonpaged pool for the WNODE_SINGLE_INSTANCE structure (wnode) by calling ExAllocatePoolWithTag. If memory allocation succeeds, the driver zero-initializes the wnode structure and then fills it in the usual way for WMI. To supply the WMI provider ID, the driver calls IoWmiDeviceObjectToProviderId, passing as a parameter the WDM device object returned by WdfDeviceWdmGetDeviceObject.

After the wnode structure is filled, the driver calls the WDF_WMI_BUFFER_APPEND_STRING function once to append the instance name to the WNODE_SINGLE_INSTANCE structure and a second time to append the model name.

Finally, the driver fires the event by calling IoWMIWriteEvent. WMI records the data and frees the memory allocated for the WNODE_SINGLE_INSTANCE structure.

Other  
  •  Parallel Programming with Microsoft Visual Studio 2010 : PLINQ Operators and Methods (part 2)
  •  Parallel Programming with Microsoft Visual Studio 2010 : PLINQ Operators and Methods (part 1)
  •  Parallel Programming with Microsoft Visual Studio 2010 : Introduction to LINQ (part 2) - PLINQ
  •  Parallel Programming with Microsoft Visual Studio 2010 : Introduction to LINQ (part 1) - Execute a LINQ query and then iterate and display the results
  •  LINQ to Objects : How to Join with Data in Another Sequence (part 7)
  •  LINQ to Objects : How to Join with Data in Another Sequence (part 6) - One-to-Many Joins - The join Operator
  •  LINQ to Objects : How to Join with Data in Another Sequence (part 5) - One-to-One Join Performance Comparisons
  •  LINQ to Objects : How to Join with Data in Another Sequence (part 4)
  •  LINQ to Objects : How to Join with Data in Another Sequence (part 3)
  •  LINQ to Objects : How to Join with Data in Another Sequence (part 2) - One-to-One Joins - The join Operator
  •  
    Video
    Top 10
    SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
    The latest Audi TT : New angles for TT
    Era of million-dollar luxury cars
    Game Review : Hearthstone - Blackrock Mountain
    Game Review : Battlefield Hardline
    Google Chromecast
    Keyboards for Apple iPad Air 2 (part 3) - Logitech Ultrathin Keyboard Cover for iPad Air 2
    Keyboards for Apple iPad Air 2 (part 2) - Zagg Slim Book for iPad Air 2
    Keyboards for Apple iPad Air 2 (part 1) - Belkin Qode Ultimate Pro Keyboard Case for iPad Air 2
    Michael Kors Designs Stylish Tech Products for Women
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    Popular Tags
    Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone