Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

777 lines
24 KiB

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