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