1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4 
5 Module Name:
6 
7     classwmi.c
8 
9 Abstract:
10 
11     SCSI class driver routines
12 
13 Environment:
14 
15     kernel mode only
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 #include "classp.h"
25 
26 #include <wmistr.h>
27 
28 NTSTATUS
29 NTAPI
30 ClassSystemControl(
31     IN PDEVICE_OBJECT DeviceObject,
32     IN PIRP Irp
33     );
34 
35 BOOLEAN
36 ClassFindGuid(
37     PGUIDREGINFO GuidList,
38     ULONG GuidCount,
39     LPGUID Guid,
40     PULONG GuidIndex
41     );
42 
43 //
44 // This is the name for the MOF resource that must be part of all drivers that
45 // register via this interface.
46 #define MOFRESOURCENAME L"MofResourceName"
47 
48 //
49 // What can be paged ???
50 #ifdef ALLOC_PRAGMA
51 #pragma alloc_text(PAGE, ClassSystemControl)
52 #pragma alloc_text(PAGE, ClassFindGuid)
53 #endif
54 
55 
56 /*++////////////////////////////////////////////////////////////////////////////
57 
58 ClassFindGuid()
59 
60 Routine Description:
61 
62     This routine will search the list of guids registered and return
63     the index for the one that was registered.
64 
65 Arguments:
66 
67     GuidList is the list of guids to search
68 
69     GuidCount is the count of guids in the list
70 
71     Guid is the guid being searched for
72 
73     *GuidIndex returns the index to the guid
74 
75 Return Value:
76 
77     TRUE if guid is found else FALSE
78 
79 --*/
80 BOOLEAN
81 ClassFindGuid(
82     PGUIDREGINFO GuidList,
83     ULONG GuidCount,
84     LPGUID Guid,
85     PULONG GuidIndex
86     )
87 {
88     ULONG i;
89 
90     PAGED_CODE();
91 
92     for (i = 0; i < GuidCount; i++)
93     {
94         if (IsEqualGUID(Guid, &GuidList[i].Guid))
95         {
96             *GuidIndex = i;
97             return(TRUE);
98         }
99     }
100 
101     return(FALSE);
102 } // end ClassFindGuid()
103 
104 /*++////////////////////////////////////////////////////////////////////////////
105 
106 ClassSystemControl()
107 
108 Routine Description:
109 
110     Dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine will process
111     all wmi requests received, forwarding them if they are not for this
112     driver or determining if the guid is valid and if so passing it to
113     the driver specific function for handing wmi requests.
114 
115 Arguments:
116 
117     DeviceObject - Supplies a pointer to the device object for this request.
118 
119     Irp - Supplies the Irp making the request.
120 
121 Return Value:
122 
123     status
124 
125 --*/
126 NTSTATUS
127 NTAPI
128 ClassSystemControl(
129     IN PDEVICE_OBJECT DeviceObject,
130     IN PIRP Irp
131     )
132 {
133     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
134     PCLASS_DRIVER_EXTENSION driverExtension;
135     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
136     ULONG isRemoved;
137     ULONG bufferSize;
138     PUCHAR buffer;
139     NTSTATUS status;
140     UCHAR minorFunction;
141     ULONG guidIndex;
142     PCLASS_WMI_INFO classWmiInfo;
143 
144     PAGED_CODE();
145 
146     //
147     // Make sure device has not been removed
148     isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
149     if(isRemoved)
150     {
151         Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
152         ClassReleaseRemoveLock(DeviceObject, Irp);
153         ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
154         return STATUS_DEVICE_DOES_NOT_EXIST;
155     }
156 
157     //
158     // If the irp is not a WMI irp or it is not targeted at this device
159     // or this device has not registered with WMI then just forward it on.
160     minorFunction = irpStack->MinorFunction;
161     if ((minorFunction > IRP_MN_EXECUTE_METHOD) ||
162         (irpStack->Parameters.WMI.ProviderId != (ULONG_PTR)DeviceObject) ||
163         ((minorFunction != IRP_MN_REGINFO) &&
164          (commonExtension->GuidRegInfo == NULL)))
165     {
166         //
167         // CONSIDER: Do I need to hang onto lock until IoCallDriver returns ?
168         IoSkipCurrentIrpStackLocation(Irp);
169         ClassReleaseRemoveLock(DeviceObject, Irp);
170         return(IoCallDriver(commonExtension->LowerDeviceObject, Irp));
171     }
172 
173     buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
174     bufferSize = irpStack->Parameters.WMI.BufferSize;
175 
176     if (minorFunction != IRP_MN_REGINFO)
177     {
178         //
179         // For all requests other than query registration info we are passed
180         // a guid. Determine if the guid is one that is supported by the
181         // device.
182         if (ClassFindGuid(commonExtension->GuidRegInfo,
183                             commonExtension->GuidCount,
184                             (LPGUID)irpStack->Parameters.WMI.DataPath,
185                             &guidIndex))
186         {
187             status = STATUS_SUCCESS;
188         } else {
189             status = STATUS_WMI_GUID_NOT_FOUND;
190         }
191 
192         if (NT_SUCCESS(status) &&
193             ((minorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
194              (minorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
195              (minorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
196              (minorFunction == IRP_MN_EXECUTE_METHOD)))
197         {
198             if ( (((PWNODE_HEADER)buffer)->Flags) &
199                                           WNODE_FLAG_STATIC_INSTANCE_NAMES)
200             {
201                 if ( ((PWNODE_SINGLE_INSTANCE)buffer)->InstanceIndex != 0 )
202                 {
203                     status = STATUS_WMI_INSTANCE_NOT_FOUND;
204                 }
205             } else {
206                 status = STATUS_WMI_INSTANCE_NOT_FOUND;
207             }
208         }
209 
210         if (! NT_SUCCESS(status))
211         {
212             Irp->IoStatus.Status = status;
213             ClassReleaseRemoveLock(DeviceObject, Irp);
214             ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
215             return(status);
216         }
217     }
218 
219     driverExtension = commonExtension->DriverExtension;
220 
221     classWmiInfo = commonExtension->IsFdo ?
222                            &driverExtension->InitData.FdoData.ClassWmiInfo :
223                            &driverExtension->InitData.PdoData.ClassWmiInfo;
224     switch(minorFunction)
225     {
226         case IRP_MN_REGINFO:
227         {
228             ULONG guidCount;
229             PGUIDREGINFO guidList;
230             PWMIREGINFOW wmiRegInfo;
231             PWMIREGGUIDW wmiRegGuid;
232             //PDEVICE_OBJECT pdo;
233             PUNICODE_STRING regPath;
234             PWCHAR stringPtr;
235             ULONG retSize;
236             ULONG registryPathOffset;
237             ULONG mofResourceOffset;
238             ULONG bufferNeeded;
239             ULONG i;
240             ULONG_PTR nameInfo;
241             ULONG nameSize, nameOffset, nameFlags;
242             UNICODE_STRING name, mofName;
243             PCLASS_QUERY_WMI_REGINFO_EX ClassQueryWmiRegInfoEx;
244 
245             name.Buffer = NULL;
246             name.Length = 0;
247             name.MaximumLength = 0;
248             nameFlags = 0;
249 
250             ClassQueryWmiRegInfoEx = commonExtension->IsFdo ?
251                                driverExtension->ClassFdoQueryWmiRegInfoEx :
252                                driverExtension->ClassPdoQueryWmiRegInfoEx;
253 
254             if (ClassQueryWmiRegInfoEx == NULL)
255             {
256                 status = classWmiInfo->ClassQueryWmiRegInfo(
257                                                         DeviceObject,
258                                                         &nameFlags,
259                                                         &name);
260 
261                 RtlInitUnicodeString(&mofName, MOFRESOURCENAME);
262             } else {
263                 RtlInitUnicodeString(&mofName, L"");
264                 status = (*ClassQueryWmiRegInfoEx)(
265                                                     DeviceObject,
266                                                     &nameFlags,
267                                                     &name,
268                                                     &mofName);
269             }
270 
271             if (NT_SUCCESS(status) &&
272                 (! (nameFlags &  WMIREG_FLAG_INSTANCE_PDO) &&
273                 (name.Buffer == NULL)))
274             {
275                 //
276                 // if PDO flag not specified then an instance name must be
277                 status = STATUS_INVALID_DEVICE_REQUEST;
278             }
279 
280             if (NT_SUCCESS(status))
281             {
282                 guidList = classWmiInfo->GuidRegInfo;
283                 guidCount = classWmiInfo->GuidCount;
284 
285                 nameOffset = sizeof(WMIREGINFO) +
286                                       guidCount * sizeof(WMIREGGUIDW);
287 
288                 if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
289                 {
290                     nameSize = 0;
291                     nameInfo = commonExtension->IsFdo ?
292                                    (ULONG_PTR)((PFUNCTIONAL_DEVICE_EXTENSION)commonExtension)->LowerPdo :
293                                    (ULONG_PTR)DeviceObject;
294                 } else {
295                     nameFlags |= WMIREG_FLAG_INSTANCE_LIST;
296                     nameSize = name.Length + sizeof(USHORT);
297                     nameInfo = nameOffset;
298                 }
299 
300                 mofResourceOffset = nameOffset + nameSize;
301 
302                 registryPathOffset = mofResourceOffset +
303                                   mofName.Length + sizeof(USHORT);
304 
305                 regPath = &driverExtension->RegistryPath;
306                 bufferNeeded = registryPathOffset +
307                 regPath->Length + sizeof(USHORT);
308 
309                 if (bufferNeeded <= bufferSize)
310                 {
311                     retSize = bufferNeeded;
312 
313                     commonExtension->GuidCount = guidCount;
314                     commonExtension->GuidRegInfo = guidList;
315 
316                     wmiRegInfo = (PWMIREGINFO)buffer;
317                     wmiRegInfo->BufferSize = bufferNeeded;
318                     wmiRegInfo->NextWmiRegInfo = 0;
319                     wmiRegInfo->MofResourceName = mofResourceOffset;
320                     wmiRegInfo->RegistryPath = registryPathOffset;
321                     wmiRegInfo->GuidCount = guidCount;
322 
323                     for (i = 0; i < guidCount; i++)
324                     {
325                         wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
326                         wmiRegGuid->Guid = guidList[i].Guid;
327                         wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
328                         wmiRegGuid->InstanceInfo = nameInfo;
329                         wmiRegGuid->InstanceCount = 1;
330                     }
331 
332                     if ( nameFlags &  WMIREG_FLAG_INSTANCE_LIST)
333                     {
334                         stringPtr = (PWCHAR)((PUCHAR)buffer + nameOffset);
335                         *stringPtr++ = name.Length;
336                         RtlCopyMemory(stringPtr,
337                                   name.Buffer,
338                                   name.Length);
339                     }
340 
341                     stringPtr = (PWCHAR)((PUCHAR)buffer + mofResourceOffset);
342                     *stringPtr++ = mofName.Length;
343                     RtlCopyMemory(stringPtr,
344                                   mofName.Buffer,
345                                   mofName.Length);
346 
347                     stringPtr = (PWCHAR)((PUCHAR)buffer + registryPathOffset);
348                     *stringPtr++ = regPath->Length;
349                     RtlCopyMemory(stringPtr,
350                               regPath->Buffer,
351                               regPath->Length);
352                 } else {
353                     *((PULONG)buffer) = bufferNeeded;
354                     retSize = sizeof(ULONG);
355                 }
356             } else {
357                 retSize = 0;
358             }
359 
360             if (name.Buffer != NULL)
361             {
362                 ExFreePool(name.Buffer);
363             }
364 
365             Irp->IoStatus.Status = status;
366             Irp->IoStatus.Information = retSize;
367             ClassReleaseRemoveLock(DeviceObject, Irp);
368             ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
369             return(status);
370         }
371 
372         case IRP_MN_QUERY_ALL_DATA:
373         {
374             PWNODE_ALL_DATA wnode;
375             ULONG bufferAvail;
376 
377             wnode = (PWNODE_ALL_DATA)buffer;
378 
379             if (bufferSize < sizeof(WNODE_ALL_DATA))
380             {
381                 bufferAvail = 0;
382             } else {
383                 bufferAvail = bufferSize - sizeof(WNODE_ALL_DATA);
384             }
385 
386             wnode->DataBlockOffset = sizeof(WNODE_ALL_DATA);
387 
388             status = classWmiInfo->ClassQueryWmiDataBlock(
389                                              DeviceObject,
390                                              Irp,
391                                              guidIndex,
392                                              bufferAvail,
393                                              buffer + sizeof(WNODE_ALL_DATA));
394 
395             break;
396         }
397 
398         case IRP_MN_QUERY_SINGLE_INSTANCE:
399         {
400             PWNODE_SINGLE_INSTANCE wnode;
401             ULONG dataBlockOffset;
402 
403             wnode = (PWNODE_SINGLE_INSTANCE)buffer;
404 
405             dataBlockOffset = wnode->DataBlockOffset;
406 
407             status = classWmiInfo->ClassQueryWmiDataBlock(
408                                           DeviceObject,
409                                           Irp,
410                                           guidIndex,
411                                           bufferSize - dataBlockOffset,
412                                           (PUCHAR)wnode + dataBlockOffset);
413 
414             break;
415         }
416 
417         case IRP_MN_CHANGE_SINGLE_INSTANCE:
418         {
419             PWNODE_SINGLE_INSTANCE wnode;
420 
421             wnode = (PWNODE_SINGLE_INSTANCE)buffer;
422 
423             status = classWmiInfo->ClassSetWmiDataBlock(
424                                      DeviceObject,
425                                      Irp,
426                                      guidIndex,
427                                      wnode->SizeDataBlock,
428                                      (PUCHAR)wnode + wnode->DataBlockOffset);
429 
430             break;
431         }
432 
433         case IRP_MN_CHANGE_SINGLE_ITEM:
434         {
435             PWNODE_SINGLE_ITEM wnode;
436 
437             wnode = (PWNODE_SINGLE_ITEM)buffer;
438 
439             status = classWmiInfo->ClassSetWmiDataItem(
440                                      DeviceObject,
441                                      Irp,
442                                      guidIndex,
443                                      wnode->ItemId,
444                                      wnode->SizeDataItem,
445                                      (PUCHAR)wnode + wnode->DataBlockOffset);
446 
447             break;
448         }
449 
450         case IRP_MN_EXECUTE_METHOD:
451         {
452             PWNODE_METHOD_ITEM wnode;
453 
454             wnode = (PWNODE_METHOD_ITEM)buffer;
455 
456             status = classWmiInfo->ClassExecuteWmiMethod(
457                                          DeviceObject,
458                                          Irp,
459                                          guidIndex,
460                                          wnode->MethodId,
461                                          wnode->SizeDataBlock,
462                                          bufferSize - wnode->DataBlockOffset,
463                                          buffer + wnode->DataBlockOffset);
464 
465 
466             break;
467         }
468 
469         case IRP_MN_ENABLE_EVENTS:
470         {
471             status = classWmiInfo->ClassWmiFunctionControl(
472                                                            DeviceObject,
473                                                            Irp,
474                                                            guidIndex,
475                                                            EventGeneration,
476                                                            TRUE);
477             break;
478         }
479 
480         case IRP_MN_DISABLE_EVENTS:
481         {
482             status = classWmiInfo->ClassWmiFunctionControl(
483                                                            DeviceObject,
484                                                            Irp,
485                                                            guidIndex,
486                                                            EventGeneration,
487                                                            FALSE);
488             break;
489         }
490 
491         case IRP_MN_ENABLE_COLLECTION:
492         {
493             status = classWmiInfo->ClassWmiFunctionControl(
494                                                          DeviceObject,
495                                                          Irp,
496                                                          guidIndex,
497                                                          DataBlockCollection,
498                                                          TRUE);
499             break;
500         }
501 
502         case IRP_MN_DISABLE_COLLECTION:
503         {
504             status = classWmiInfo->ClassWmiFunctionControl(
505                                                          DeviceObject,
506                                                          Irp,
507                                                          guidIndex,
508                                                          DataBlockCollection,
509                                                          FALSE);
510             break;
511         }
512 
513         default:
514         {
515             status = STATUS_INVALID_DEVICE_REQUEST;
516             break;
517         }
518 
519     }
520 
521     return(status);
522 } // end ClassSystemControl()
523 
524 /*++////////////////////////////////////////////////////////////////////////////
525 
526 ClassWmiCompleteRequest()
527 
528 Routine Description:
529 
530 
531     This routine will do the work of completing a WMI irp. Depending upon the
532     the WMI request this routine will fixup the returned WNODE appropriately.
533 
534     NOTE: This routine assumes that the ClassRemoveLock is held and it will
535           release it.
536 
537 Arguments:
538 
539     DeviceObject - Supplies a pointer to the device object for this request.
540 
541     Irp - Supplies the Irp making the request.
542 
543     Status - Status to complete the irp with.  STATUS_BUFFER_TOO_SMALL is used
544         to indicate that more buffer is required for the data requested.
545 
546     BufferUsed - number of bytes of actual data to return (not including WMI
547         specific structures)
548 
549     PriorityBoost - priority boost to pass to ClassCompleteRequest
550 
551 Return Value:
552 
553     status
554 
555 --*/
556 SCSIPORTAPI
557 NTSTATUS
558 NTAPI
559 ClassWmiCompleteRequest(
560     IN PDEVICE_OBJECT DeviceObject,
561     IN PIRP Irp,
562     IN NTSTATUS Status,
563     IN ULONG BufferUsed,
564     IN CCHAR PriorityBoost
565     )
566 {
567     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
568     //UCHAR MinorFunction;
569     PUCHAR buffer;
570     ULONG retSize;
571     UCHAR minorFunction;
572 
573     minorFunction = irpStack->MinorFunction;
574     buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
575 
576     switch(minorFunction)
577     {
578         case IRP_MN_QUERY_ALL_DATA:
579         {
580             PWNODE_ALL_DATA wnode;
581             PWNODE_TOO_SMALL wnodeTooSmall;
582             ULONG bufferNeeded;
583 
584             wnode = (PWNODE_ALL_DATA)buffer;
585 
586             bufferNeeded = sizeof(WNODE_ALL_DATA) + BufferUsed;
587 
588             if (NT_SUCCESS(Status))
589             {
590                 retSize = bufferNeeded;
591                 wnode->WnodeHeader.BufferSize = bufferNeeded;
592                 KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
593                 wnode->WnodeHeader.Flags |= WNODE_FLAG_FIXED_INSTANCE_SIZE;
594                 wnode->FixedInstanceSize = BufferUsed;
595                 wnode->InstanceCount = 1;
596 
597             } else if (Status == STATUS_BUFFER_TOO_SMALL) {
598                 wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
599 
600                 wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
601                 wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
602                 wnodeTooSmall->SizeNeeded = sizeof(WNODE_ALL_DATA) + BufferUsed;
603                 retSize = sizeof(WNODE_TOO_SMALL);
604                 Status = STATUS_SUCCESS;
605             } else {
606                 retSize = 0;
607             }
608             break;
609         }
610 
611         case IRP_MN_QUERY_SINGLE_INSTANCE:
612         {
613             PWNODE_SINGLE_INSTANCE wnode;
614             PWNODE_TOO_SMALL wnodeTooSmall;
615             ULONG bufferNeeded;
616 
617             wnode = (PWNODE_SINGLE_INSTANCE)buffer;
618 
619             bufferNeeded = wnode->DataBlockOffset + BufferUsed;
620 
621             if (NT_SUCCESS(Status))
622             {
623                 retSize = bufferNeeded;
624                 wnode->WnodeHeader.BufferSize = bufferNeeded;
625                 KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
626                 wnode->SizeDataBlock = BufferUsed;
627 
628             } else if (Status == STATUS_BUFFER_TOO_SMALL) {
629                 wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
630 
631                 wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
632                 wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
633                 wnodeTooSmall->SizeNeeded = bufferNeeded;
634                 retSize = sizeof(WNODE_TOO_SMALL);
635                 Status = STATUS_SUCCESS;
636             } else {
637                 retSize = 0;
638             }
639             break;
640         }
641 
642         case IRP_MN_EXECUTE_METHOD:
643         {
644             PWNODE_METHOD_ITEM wnode;
645             PWNODE_TOO_SMALL wnodeTooSmall;
646             ULONG bufferNeeded;
647 
648             wnode = (PWNODE_METHOD_ITEM)buffer;
649 
650             bufferNeeded = wnode->DataBlockOffset + BufferUsed;
651 
652             if (NT_SUCCESS(Status))
653             {
654                 retSize = bufferNeeded;
655                 wnode->WnodeHeader.BufferSize = bufferNeeded;
656                 KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
657                 wnode->SizeDataBlock = BufferUsed;
658 
659             } else if (Status == STATUS_BUFFER_TOO_SMALL) {
660                 wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
661 
662                 wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
663                 wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
664                 wnodeTooSmall->SizeNeeded = bufferNeeded;
665                 retSize = sizeof(WNODE_TOO_SMALL);
666                 Status = STATUS_SUCCESS;
667             } else {
668                 retSize = 0;
669             }
670             break;
671         }
672 
673         default:
674         {
675             //
676             // All other requests don't return any data
677             retSize = 0;
678             break;
679         }
680 
681     }
682 
683     Irp->IoStatus.Status = Status;
684     Irp->IoStatus.Information = retSize;
685     ClassReleaseRemoveLock(DeviceObject, Irp);
686     ClassCompleteRequest(DeviceObject, Irp, PriorityBoost);
687     return(Status);
688 } // end ClassWmiCompleteRequest()
689 
690 /*++////////////////////////////////////////////////////////////////////////////
691 
692 ClassWmiFireEvent()
693 
694 Routine Description:
695 
696     This routine will fire a WMI event using the data buffer passed. This
697     routine may be called at or below DPC level
698 
699 Arguments:
700 
701     DeviceObject - Supplies a pointer to the device object for this event
702 
703     Guid is pointer to the GUID that represents the event
704 
705     InstanceIndex is the index of the instance of the event
706 
707     EventDataSize is the number of bytes of data that is being fired with
708        with the event
709 
710     EventData is the data that is fired with the events. This may be NULL
711         if there is no data associated with the event
712 
713 
714 Return Value:
715 
716     status
717 
718 --*/
719 NTSTATUS
720 NTAPI
721 ClassWmiFireEvent(
722     IN PDEVICE_OBJECT DeviceObject,
723     IN LPGUID Guid,
724     IN ULONG InstanceIndex,
725     IN ULONG EventDataSize,
726     IN PVOID EventData
727     )
728 {
729 
730     ULONG sizeNeeded;
731     PWNODE_SINGLE_INSTANCE event;
732     NTSTATUS status;
733 
734     if (EventData == NULL)
735     {
736         EventDataSize = 0;
737     }
738 
739     sizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) + EventDataSize;
740 
741     event = ExAllocatePoolWithTag(NonPagedPool, sizeNeeded, CLASS_TAG_WMI);
742     if (event != NULL)
743     {
744         event->WnodeHeader.Guid = *Guid;
745         event->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(DeviceObject);
746         event->WnodeHeader.BufferSize = sizeNeeded;
747         event->WnodeHeader.Flags =  WNODE_FLAG_SINGLE_INSTANCE |
748                                     WNODE_FLAG_EVENT_ITEM |
749                                     WNODE_FLAG_STATIC_INSTANCE_NAMES;
750         KeQuerySystemTime(&event->WnodeHeader.TimeStamp);
751 
752         event->InstanceIndex = InstanceIndex;
753         event->SizeDataBlock = EventDataSize;
754         event->DataBlockOffset = sizeof(WNODE_SINGLE_INSTANCE);
755         if (EventData != NULL)
756         {
757             RtlCopyMemory( &event->VariableData, EventData, EventDataSize);
758         }
759 
760         status = IoWMIWriteEvent(event);
761         if (! NT_SUCCESS(status))
762         {
763             ExFreePool(event);
764         }
765     } else {
766         status = STATUS_INSUFFICIENT_RESOURCES;
767     }
768 
769     return(status);
770 } // end ClassWmiFireEvent()
771 
772