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