Leaked source code of windows server 2003
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.

5774 lines
168 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: wmiprop.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <windowsx.h>
  15. #include <tchar.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <prsht.h>
  19. #include <ole2.h>
  20. extern "C" {
  21. #include <commdlg.h>
  22. #include <cfgmgr32.h>
  23. #include <setupapi.h>
  24. #include <regstr.h>
  25. }
  26. #include <wbemidl.h>
  27. #include "wmiprop.h"
  28. #include "resource.h"
  29. HINSTANCE g_hInstance;
  30. #if DBG
  31. #define DEBUG_HEAP 1
  32. #define WmiAssert(x) if (! (x) ) { \
  33. DebugPrint((1, "WMI Assertion: "#x" at %s %d\n", __FILE__, __LINE__)); \
  34. DebugBreak(); }
  35. #else
  36. #define WmiAssert(x)
  37. #endif
  38. #if DEBUG_HEAP
  39. #undef LocalAlloc
  40. #undef LocalFree
  41. #define LocalAlloc(lptr, size) DebugAlloc(size)
  42. #define LocalFree(p) DebugFree(p)
  43. PVOID WmiPrivateHeap;
  44. PVOID DebugAlloc(ULONG size)
  45. {
  46. PVOID p = NULL;
  47. if (WmiPrivateHeap == NULL)
  48. {
  49. WmiPrivateHeap = RtlCreateHeap(HEAP_GROWABLE |
  50. HEAP_TAIL_CHECKING_ENABLED |
  51. HEAP_FREE_CHECKING_ENABLED |
  52. HEAP_DISABLE_COALESCE_ON_FREE,
  53. NULL,
  54. 0,
  55. 0,
  56. NULL,
  57. NULL);
  58. }
  59. if (WmiPrivateHeap != NULL)
  60. {
  61. p = RtlAllocateHeap(WmiPrivateHeap, 0, size);
  62. if (p != NULL)
  63. {
  64. memset(p, 0, size);
  65. }
  66. }
  67. return(p);
  68. }
  69. void DebugFree(PVOID p)
  70. {
  71. RtlFreeHeap(WmiPrivateHeap, 0, p);
  72. }
  73. #endif
  74. #if DBG
  75. PCHAR WmiGuidToString(
  76. PCHAR s,
  77. LPGUID piid
  78. )
  79. {
  80. GUID XGuid = *piid;
  81. sprintf(s, "%x-%x-%x-%x%x%x%x%x%x%x%x",
  82. XGuid.Data1, XGuid.Data2,
  83. XGuid.Data3,
  84. XGuid.Data4[0], XGuid.Data4[1],
  85. XGuid.Data4[2], XGuid.Data4[3],
  86. XGuid.Data4[4], XGuid.Data4[5],
  87. XGuid.Data4[6], XGuid.Data4[7]);
  88. return(s);
  89. }
  90. #endif
  91. TCHAR *WmiDuplicateString(
  92. TCHAR *String
  93. )
  94. {
  95. ULONG Len;
  96. PTCHAR Copy;
  97. Len = _tcslen(String);
  98. Copy = (PTCHAR)LocalAlloc(LPTR,
  99. (Len+1) * sizeof(TCHAR));
  100. if (Copy != NULL)
  101. {
  102. _tcscpy(Copy, String);
  103. }
  104. return(Copy);
  105. }
  106. BOOLEAN WmiGetDataBlockDesc(
  107. IN IWbemServices *pIWbemServices,
  108. IN IWbemClassObject *pIWbemClassObject,
  109. OUT PDATA_BLOCK_DESCRIPTION *DBD,
  110. IN PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc,
  111. IN BOOLEAN IsParentReadOnly
  112. );
  113. BOOLEAN WmiRefreshDataBlockFromWbem(
  114. IWbemClassObject *pIWbemClassObject,
  115. PDATA_BLOCK_DESCRIPTION DataBlockDesc
  116. );
  117. BOOLEAN WmiRefreshWbemFromDataBlock(
  118. IN IWbemServices *pIWbemServices,
  119. IN IWbemClassObject *pIWbemClassObject,
  120. IN PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  121. IN BOOLEAN IsEmbeddedClass
  122. );
  123. BOOLEAN WmiBstrToTchar(
  124. OUT PTCHAR *TString,
  125. IN BSTR BString
  126. )
  127. /*+++
  128. Routine Description:
  129. This routine will convert a BSTR into a TCHAR *
  130. Arguments:
  131. BString is the BSTR to convert from
  132. *TString returns with a pointer to a string containing the contents of
  133. the BSTR. It should be freed with LocalFree.
  134. Return Value:
  135. TRUE if successful else FALSE
  136. ---*/
  137. {
  138. ULONG SizeNeeded;
  139. BOOLEAN ReturnStatus;
  140. WmiAssert(BString != NULL);
  141. WmiAssert(TString != NULL);
  142. SizeNeeded = (SysStringLen(BString)+1) * sizeof(TCHAR);
  143. *TString = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
  144. if (*TString != NULL)
  145. {
  146. _tcscpy(*TString, BString);
  147. ReturnStatus = TRUE;
  148. } else {
  149. ReturnStatus = FALSE;
  150. }
  151. return(ReturnStatus);
  152. }
  153. BOOLEAN WmiBstrToUlong64(
  154. OUT PULONG64 Number,
  155. IN BSTR BString
  156. )
  157. /*+++
  158. Routine Description:
  159. This routine will convert a BSTR into a ULONG64 number
  160. Arguments:
  161. BString is the BSTR to convert from
  162. *Number returns with the value of the contents of BString converted to
  163. a number
  164. Return Value:
  165. TRUE if successful else FALSE
  166. ---*/
  167. {
  168. WmiAssert(BString != NULL);
  169. WmiAssert(Number != NULL);
  170. *Number = _ttoi64(BString);
  171. return(TRUE);
  172. }
  173. BOOLEAN WmiGetArraySize(
  174. IN SAFEARRAY *Array,
  175. OUT LONG *LBound,
  176. OUT LONG *UBound,
  177. OUT LONG *NumberElements
  178. )
  179. /*+++
  180. Routine Description:
  181. This routine will information about the size and bounds of a single
  182. dimensional safe array.
  183. Arguments:
  184. Array is the safe array
  185. *LBound returns with the lower bound of the array
  186. *UBound returns with the upper bound of the array
  187. *NumberElements returns with the number of elements in the array
  188. Return Value:
  189. TRUE if successful else FALSE
  190. ---*/
  191. {
  192. HRESULT hr;
  193. BOOLEAN ReturnStatus;
  194. WmiAssert(Array != NULL);
  195. WmiAssert(LBound != NULL);
  196. WmiAssert(UBound != NULL);
  197. WmiAssert(NumberElements != NULL);
  198. //
  199. // Only single dim arrays are supported
  200. //
  201. WmiAssert(SafeArrayGetDim(Array) == 1);
  202. hr = SafeArrayGetLBound(Array, 1, LBound);
  203. if (hr == WBEM_S_NO_ERROR)
  204. {
  205. hr = SafeArrayGetUBound(Array, 1, UBound);
  206. *NumberElements = (*UBound - *LBound) + 1;
  207. ReturnStatus = (hr == WBEM_S_NO_ERROR);
  208. } else {
  209. ReturnStatus = FALSE;
  210. }
  211. return(ReturnStatus);
  212. }
  213. BOOLEAN WmiConnectToWbem(
  214. PTCHAR MachineName,
  215. IWbemServices **pIWbemServices
  216. )
  217. /*+++
  218. Routine Description:
  219. This routine will establishes a connection to the WBEM service and
  220. saves the global IWbemServices interface
  221. Arguments:
  222. MachineName is the name of the remote machine we should connect to.
  223. If NULL then we connect to the local machine.
  224. Return Value:
  225. if this routine is successful then *pIWbemServices will have a valid
  226. IWbemServices pointer, if not then it is NULL.
  227. ---*/
  228. {
  229. #define Namespace TEXT("root\\wmi")
  230. IWbemLocator *pIWbemLocator;
  231. DWORD hr;
  232. SCODE sc;
  233. BSTR s;
  234. BOOLEAN ReturnStatus = FALSE;
  235. PTCHAR NamespacePath;
  236. WmiAssert(pIWbemServices != NULL);
  237. if (MachineName == NULL)
  238. {
  239. NamespacePath = Namespace;
  240. } else {
  241. NamespacePath = (PTCHAR)LocalAlloc(LPTR, (_tcslen(Namespace) +
  242. _tcslen(MachineName) +
  243. 2) * sizeof(TCHAR) );
  244. if (NamespacePath != NULL)
  245. {
  246. _tcscpy(NamespacePath, MachineName);
  247. _tcscat(NamespacePath, TEXT("\\"));
  248. _tcscat(NamespacePath, Namespace);
  249. } else {
  250. DebugPrint((1, "WMIPROP: Could not alloc memory for NamespacePath\n"));
  251. return(FALSE);
  252. }
  253. }
  254. hr = CoCreateInstance(CLSID_WbemLocator,
  255. NULL,
  256. CLSCTX_INPROC_SERVER,
  257. IID_IWbemLocator,
  258. (LPVOID *) &pIWbemLocator);
  259. if (hr == S_OK)
  260. {
  261. s = SysAllocString(NamespacePath);
  262. if (s != NULL)
  263. {
  264. *pIWbemServices = NULL;
  265. sc = pIWbemLocator->ConnectServer(s,
  266. NULL, // Userid
  267. NULL, // PW
  268. NULL, // Locale
  269. 0, // flags
  270. NULL, // Authority
  271. NULL, // Context
  272. pIWbemServices
  273. );
  274. SysFreeString(s);
  275. if (sc != WBEM_NO_ERROR)
  276. {
  277. *pIWbemServices = NULL;
  278. } else {
  279. //
  280. // Set security level to IMPERSONATE so that access
  281. // to wbem objects will be granted
  282. //
  283. sc = CoSetProxyBlanket( (IUnknown *)*pIWbemServices,
  284. RPC_C_AUTHN_WINNT,
  285. RPC_C_AUTHZ_NONE,
  286. NULL,
  287. RPC_C_AUTHN_LEVEL_CALL,
  288. RPC_C_IMP_LEVEL_IMPERSONATE,
  289. NULL,
  290. 0);
  291. if (sc == S_OK)
  292. {
  293. ReturnStatus = TRUE;
  294. } else {
  295. (*pIWbemServices)->Release();
  296. *pIWbemServices = NULL;
  297. }
  298. }
  299. pIWbemLocator->Release();
  300. } else {
  301. *pIWbemServices = NULL;
  302. }
  303. }
  304. if (MachineName != NULL)
  305. {
  306. LocalFree(NamespacePath);
  307. }
  308. return(ReturnStatus);
  309. }
  310. #define IsWhiteSpace(c) ( (c == TEXT(' ')) || (c == TEXT('\t')) )
  311. BOOLEAN WmiHexToUlong64(
  312. IN PTCHAR Text,
  313. OUT PULONG64 Number
  314. )
  315. /*+++
  316. Routine Description:
  317. This routine will convert a string with number in hex format into
  318. a ULONG64
  319. Arguments:
  320. Text is the string
  321. *Number returns with the hex value for string
  322. Return Value:
  323. TRUE if successful else FALSE
  324. ---*/
  325. {
  326. ULONG64 Value;
  327. ULONG Count;
  328. WmiAssert(Text != NULL);
  329. WmiAssert(Number != NULL);
  330. Value = 0;
  331. Count = 0;
  332. while ((*Text != 0) && (! IsWhiteSpace(*Text)))
  333. {
  334. if (Count == 16)
  335. {
  336. return(FALSE);
  337. }
  338. if (*Text >= '0' && *Text <= '9')
  339. Value = (Value << 4) + *Text - '0';
  340. else if (*Text >= 'A' && *Text <= 'F')
  341. Value = (Value << 4) + *Text - 'A' + 10;
  342. else if (*Text >= 'a' && *Text <= 'f')
  343. Value = (Value << 4) + *Text - 'a' + 10;
  344. else
  345. return(FALSE);
  346. Text++;
  347. }
  348. *Number = Value;
  349. return(TRUE);
  350. }
  351. BOOLEAN WmiValidateRange(
  352. IN struct _DATA_ITEM_DESCRIPTION *DataItemDesc,
  353. OUT PULONG64 Number,
  354. IN PTCHAR Text
  355. )
  356. /*+++
  357. Routine Description:
  358. This routine will validate that the value proposed for the property is
  359. correct. It checks that the value is a well formed number and within
  360. the appropriate range
  361. Arguments:
  362. DataItemDesc is the data item description for the property being validated
  363. *Number returns with the value as a ULONG64
  364. Text is the proposed value for the property. Note that hex values are
  365. required to be preceeded with 0x
  366. Return Value:
  367. TRUE if Value is appropriate for the property
  368. ---*/
  369. {
  370. #define HexMarkerText TEXT("0x")
  371. BOOLEAN ReturnStatus;
  372. PTCHAR s;
  373. PRANGELISTINFO RangeListInfo;
  374. PRANGEINFO RangeInfo;
  375. ULONG i;
  376. WmiAssert(DataItemDesc != NULL);
  377. WmiAssert(Number != NULL);
  378. WmiAssert(Text != NULL);
  379. //
  380. // Skip over any leading spaces
  381. //
  382. s = Text;
  383. while (IsWhiteSpace(*s) && (*s != 0))
  384. {
  385. s++;
  386. }
  387. if (*s != 0)
  388. {
  389. //
  390. // If this is not an empty string then go parse the number
  391. //
  392. if (_tcsnicmp(s,
  393. HexMarkerText,
  394. (sizeof(HexMarkerText) / sizeof(TCHAR))-1) == 0)
  395. {
  396. //
  397. // this is a hex number (starts with 0x), advance string ptr
  398. // and setup to use hex digit validation
  399. //
  400. s += (sizeof(HexMarkerText) / sizeof(TCHAR)) - 1;
  401. ReturnStatus = WmiHexToUlong64(s, Number);
  402. } else {
  403. *Number = _ttoi64(s);
  404. ReturnStatus = TRUE;
  405. while ((*s != 0) && ReturnStatus)
  406. {
  407. ReturnStatus = (_istdigit(*s) != 0);
  408. s++;
  409. }
  410. }
  411. //
  412. // Make sure that all characters are digits
  413. //
  414. if (ReturnStatus)
  415. {
  416. //
  417. // Now verify that the value is within the correct range
  418. //
  419. RangeListInfo = DataItemDesc->RangeListInfo;
  420. WmiAssert(RangeListInfo != NULL);
  421. ReturnStatus = FALSE;
  422. for (i = 0; (i < RangeListInfo->Count) && (! ReturnStatus); i++)
  423. {
  424. RangeInfo = &RangeListInfo->Ranges[i];
  425. ReturnStatus = ( (*Number >= RangeInfo->Minimum) &&
  426. (*Number <= RangeInfo->Maximum) );
  427. }
  428. }
  429. } else {
  430. ReturnStatus = FALSE;
  431. }
  432. return(ReturnStatus);
  433. }
  434. BOOLEAN WmiValidateDateTime(
  435. IN struct _DATA_ITEM_DESCRIPTION *DataItemDesc,
  436. IN PTCHAR Value
  437. )
  438. /*+++
  439. Routine Description:
  440. This routine will validate that the value proposed for the property is
  441. correct. It will make sure that it is in a valid format for a
  442. DATETIME with is of the form 19940525133015.000000-300
  443. Arguments:
  444. DataItemDesc is the data item description for the property being validated
  445. Value is the proposed value for the property
  446. Return Value:
  447. TRUE if Value is appropriate for the property
  448. ---*/
  449. {
  450. #define DATETIME_LENGTH 25
  451. ULONG Length;
  452. BOOLEAN ReturnStatus;
  453. ULONG i;
  454. WmiAssert(DataItemDesc != NULL);
  455. WmiAssert(Value != NULL);
  456. //
  457. // Validate that datetime is in correct format
  458. // TODO: Validate that the component parts of the DATETIME are correct,
  459. // for example that the month is between 1 and 12, the correct
  460. // month doesn't have too many days, The time is ok (not 30:11)
  461. //
  462. Length = _tcslen(Value);
  463. if (Length == DATETIME_LENGTH)
  464. {
  465. ReturnStatus = TRUE;
  466. for (i = 0; (i < 14) && ReturnStatus; i++)
  467. {
  468. ReturnStatus = (_istdigit(Value[i]) != 0);
  469. }
  470. if (ReturnStatus)
  471. {
  472. ReturnStatus = (Value[14] == TEXT('.')) &&
  473. ((Value[21] == TEXT('-')) ||
  474. (Value[21] == TEXT('+')) );
  475. if (ReturnStatus)
  476. {
  477. for (i = 22; (i < DATETIME_LENGTH) && ReturnStatus; i++)
  478. {
  479. ReturnStatus = (_istdigit(Value[i]) != 0);
  480. }
  481. }
  482. }
  483. } else {
  484. ReturnStatus = FALSE;
  485. }
  486. return(ReturnStatus);
  487. }
  488. BOOLEAN WmiGet8bitFromVariant(
  489. VARIANT *Value,
  490. PVOID Result
  491. )
  492. {
  493. BOOLEAN ReturnStatus;
  494. ReturnStatus = TRUE;
  495. //
  496. // 8 bit values can come back as signed or unsigned
  497. // or as 16 or 32 bit values
  498. //
  499. switch(Value->vt)
  500. {
  501. case VT_I1:
  502. {
  503. *((PCHAR)Result) = Value->cVal;
  504. break;
  505. }
  506. case VT_UI1:
  507. {
  508. *((PUCHAR)Result) = Value->bVal;
  509. break;
  510. }
  511. case VT_I2:
  512. {
  513. *((PCHAR)Result) = (CHAR)Value->iVal;
  514. break;
  515. }
  516. case VT_I4:
  517. {
  518. *((PCHAR)Result) = (CHAR)Value->lVal;
  519. break;
  520. }
  521. default:
  522. {
  523. ReturnStatus = FALSE;
  524. }
  525. }
  526. return(ReturnStatus);
  527. }
  528. BOOLEAN WmiGet16bitFromVariant(
  529. VARIANT *Value,
  530. PVOID Result
  531. )
  532. {
  533. BOOLEAN ReturnStatus;
  534. ReturnStatus = TRUE;
  535. //
  536. // 16 bit values can come back as signed or unsigned
  537. // or as 32 bit values
  538. //
  539. switch(Value->vt)
  540. {
  541. case VT_I2:
  542. {
  543. *((PSHORT)Result) = Value->iVal;
  544. break;
  545. }
  546. case VT_UI2:
  547. {
  548. *((PUSHORT)Result) = Value->uiVal;
  549. break;
  550. }
  551. case VT_I4:
  552. {
  553. *((PSHORT)Result) = (SHORT)Value->lVal;
  554. break;
  555. }
  556. default:
  557. {
  558. ReturnStatus = FALSE;
  559. }
  560. }
  561. return(ReturnStatus);
  562. }
  563. BOOLEAN WmiGet32bitFromVariant(
  564. VARIANT *Value,
  565. PVOID Result
  566. )
  567. {
  568. BOOLEAN ReturnStatus;
  569. ReturnStatus = TRUE;
  570. //
  571. // 32 bit values can come back as signed or unsigned
  572. //
  573. switch (Value->vt)
  574. {
  575. case VT_UI4:
  576. {
  577. *((PULONG)Result) = Value->ulVal;
  578. break;
  579. }
  580. case VT_I4:
  581. {
  582. *((PLONG)Result) = Value->lVal;
  583. break;
  584. }
  585. default:
  586. {
  587. ReturnStatus = FALSE;
  588. }
  589. }
  590. return(ReturnStatus);
  591. }
  592. BOOLEAN WmiGetSint64FromVariant(
  593. VARIANT *Value,
  594. PVOID Result
  595. )
  596. {
  597. BOOLEAN ReturnStatus;
  598. ReturnStatus = TRUE;
  599. //
  600. // 64 bit numbers are returned in a BSTR with the
  601. // number represented as a string. So we need to
  602. // convert back to a 64bit number.
  603. //
  604. WmiAssert(Value->vt == VT_BSTR);
  605. *((PLONGLONG)Result) = _ttoi64(Value->bstrVal);
  606. return(ReturnStatus);
  607. }
  608. BOOLEAN WmiGetUint64FromVariant(
  609. VARIANT *Value,
  610. PVOID Result
  611. )
  612. {
  613. BOOLEAN ReturnStatus;
  614. ReturnStatus = TRUE;
  615. //
  616. // 64 bit numbers are returned in a BSTR with the
  617. // number represented as a string. So we need to
  618. // convert back to a 64bit number.
  619. //
  620. WmiAssert(Value->vt == VT_BSTR);
  621. *((PULONGLONG)Result) = _ttoi64(Value->bstrVal);
  622. return(ReturnStatus);
  623. }
  624. BOOLEAN WmiGetBooleanFromVariant(
  625. VARIANT *Value,
  626. PVOID Result
  627. )
  628. {
  629. BOOLEAN ReturnStatus;
  630. ReturnStatus = TRUE;
  631. //
  632. // BOOLEAN values are true or false
  633. //
  634. WmiAssert(Value->vt == VT_BOOL);
  635. *((PBOOLEAN)Result) = (Value->boolVal != 0) ?
  636. 1 : 0;
  637. return(ReturnStatus);
  638. }
  639. BOOLEAN WmiGetStringFromVariant(
  640. VARIANT *Value,
  641. PVOID Result
  642. )
  643. {
  644. BOOLEAN ReturnStatus;
  645. WmiAssert( *((PTCHAR)Result) == NULL);
  646. ReturnStatus = WmiBstrToTchar((PTCHAR *)Result,
  647. Value->bstrVal);
  648. return(ReturnStatus);
  649. }
  650. BOOLEAN WmiGetObjectFromVariant(
  651. VARIANT *Value,
  652. PVOID Result
  653. )
  654. {
  655. IUnknown *punk;
  656. HRESULT hr;
  657. punk = Value->punkVal;
  658. hr = punk->QueryInterface(IID_IWbemClassObject,
  659. (PVOID *)Result);
  660. return(hr == WBEM_S_NO_ERROR);
  661. }
  662. ULONG WmiGetElementSize(
  663. CIMTYPE CimType
  664. )
  665. {
  666. ULONG Size;
  667. switch(CimType)
  668. {
  669. case CIM_UINT8:
  670. case CIM_SINT8:
  671. {
  672. Size = sizeof(CHAR);
  673. break;
  674. }
  675. case CIM_CHAR16:
  676. case CIM_UINT16:
  677. case CIM_SINT16:
  678. {
  679. Size = sizeof(SHORT);
  680. break;
  681. }
  682. case CIM_UINT32:
  683. case CIM_SINT32:
  684. {
  685. Size = sizeof(LONG);
  686. break;
  687. }
  688. case CIM_SINT64:
  689. {
  690. Size = sizeof(LONGLONG);
  691. break;
  692. }
  693. case CIM_UINT64:
  694. {
  695. Size = sizeof(ULONGLONG);
  696. break;
  697. }
  698. case CIM_BOOLEAN:
  699. {
  700. Size = sizeof(BOOLEAN);
  701. break;
  702. }
  703. case CIM_DATETIME:
  704. case CIM_STRING:
  705. {
  706. Size = sizeof(PTCHAR);
  707. break;
  708. }
  709. case CIM_OBJECT:
  710. {
  711. Size = sizeof(IWbemClassObject *);
  712. break;
  713. }
  714. //
  715. // Floating point values not supported
  716. //
  717. case CIM_REAL32:
  718. case CIM_REAL64:
  719. default:
  720. {
  721. Size = 0;
  722. break;
  723. }
  724. }
  725. return(Size);
  726. }
  727. typedef BOOLEAN (*GETVALUEFROMVARIANTFUNC)(
  728. VARIANT *Value,
  729. PVOID Result
  730. );
  731. BOOLEAN WmiGetValueFunc(
  732. CIMTYPE CimType,
  733. GETVALUEFROMVARIANTFUNC *GetValueFunc
  734. )
  735. {
  736. BOOLEAN ReturnStatus;
  737. ReturnStatus = TRUE;
  738. switch(CimType)
  739. {
  740. case CIM_UINT8:
  741. case CIM_SINT8:
  742. {
  743. *GetValueFunc = WmiGet8bitFromVariant;
  744. break;
  745. }
  746. case CIM_CHAR16:
  747. case CIM_UINT16:
  748. case CIM_SINT16:
  749. {
  750. *GetValueFunc = WmiGet16bitFromVariant;
  751. break;
  752. }
  753. case CIM_UINT32:
  754. case CIM_SINT32:
  755. {
  756. *GetValueFunc = WmiGet32bitFromVariant;
  757. break;
  758. }
  759. case CIM_SINT64:
  760. {
  761. *GetValueFunc = WmiGetSint64FromVariant;
  762. break;
  763. }
  764. case CIM_UINT64:
  765. {
  766. *GetValueFunc = WmiGetUint64FromVariant;
  767. break;
  768. }
  769. case CIM_BOOLEAN:
  770. {
  771. *GetValueFunc = WmiGetBooleanFromVariant;
  772. break;
  773. }
  774. case CIM_DATETIME:
  775. case CIM_STRING:
  776. {
  777. *GetValueFunc = WmiGetStringFromVariant;
  778. break;
  779. }
  780. case CIM_OBJECT:
  781. {
  782. *GetValueFunc = WmiGetObjectFromVariant;
  783. break;
  784. }
  785. //
  786. // Floating point values not supported
  787. //
  788. case CIM_REAL32:
  789. case CIM_REAL64:
  790. default:
  791. {
  792. *GetValueFunc = NULL;
  793. ReturnStatus = FALSE;
  794. break;
  795. }
  796. }
  797. return(ReturnStatus);
  798. }
  799. BOOLEAN WmiRefreshDataItemFromWbem(
  800. IN OUT PDATA_ITEM_DESCRIPTION DataItemDesc,
  801. IN IWbemClassObject *pIWbemClassObject
  802. )
  803. /*+++
  804. Routine Description:
  805. This routine will call WBEM to get the latest value for the property
  806. represented by the DataItemDesc
  807. Arguments:
  808. DataItemDesc is the data item description for the property
  809. pIWbemClassObject is the instance class object interface for the class
  810. Return Value:
  811. TRUE if successful
  812. ---*/
  813. {
  814. ULONG i;
  815. LONG i1;
  816. BSTR s;
  817. HRESULT hr;
  818. VARIANT Value;
  819. CIMTYPE ValueType;
  820. BOOLEAN ReturnStatus;
  821. ULONG ElementSize;
  822. GETVALUEFROMVARIANTFUNC GetValueFunc;
  823. WmiAssert(DataItemDesc != NULL);
  824. WmiAssert(pIWbemClassObject != NULL);
  825. DebugPrint((1,"WMI: Refreshing data item %ws\n", DataItemDesc->Name));
  826. ReturnStatus = FALSE;
  827. s = SysAllocString(DataItemDesc->Name);
  828. if (s != NULL)
  829. {
  830. hr = pIWbemClassObject->Get(s,
  831. 0,
  832. &Value,
  833. &ValueType,
  834. NULL);
  835. if (hr == WBEM_S_NO_ERROR)
  836. {
  837. DebugPrint((1, "WMIPROP: Got value for %ws as variant type 0x%x, cim type 0x%x at variant %p\n",
  838. s, Value.vt, ValueType, &Value));
  839. WmiAssert((ValueType & ~CIM_FLAG_ARRAY) == DataItemDesc->DataType);
  840. WmiCleanDataItemDescData(DataItemDesc);
  841. if ( (ValueType & CIM_FLAG_ARRAY) == 0)
  842. {
  843. //
  844. // Non Array value, just pull the value out of the variant
  845. // and stash into DataItemDesc
  846. //
  847. WmiAssert(DataItemDesc->IsVariableArray == 0);
  848. WmiAssert(DataItemDesc->IsFixedArray == 0);
  849. //
  850. // For all types we get the getvalue
  851. // function and the pull the value out of the
  852. // variant and into the DataItemDesc
  853. //
  854. if (WmiGetValueFunc(DataItemDesc->DataType,
  855. &GetValueFunc))
  856. {
  857. //
  858. // TODO: Keep track of data item position and
  859. // padding within data block
  860. //
  861. ReturnStatus = (*GetValueFunc)(
  862. &Value,
  863. (PVOID)&DataItemDesc->Data);
  864. #if DBG
  865. if (ReturnStatus == FALSE)
  866. {
  867. DebugPrint((1, "WMIPROP: Property %ws is type %d, but got type %d variant %p\n",
  868. DataItemDesc->Name,
  869. DataItemDesc->DataType,
  870. Value.vt, &Value));
  871. WmiAssert(FALSE);
  872. }
  873. #endif
  874. }
  875. } else {
  876. //
  877. // Get all of the data for an array
  878. //
  879. LONG LBound, UBound, NumberElements;
  880. PUCHAR Array;
  881. LONG Index;
  882. VARIANT Element;
  883. ULONG ElementSize;
  884. ULONG SizeNeeded;
  885. VARTYPE vt;
  886. WmiAssert((DataItemDesc->IsVariableArray != 0) ||
  887. (DataItemDesc->IsFixedArray != 0));
  888. WmiAssert(Value.vt & VT_ARRAY);
  889. if (WmiGetArraySize(Value.parray,
  890. &LBound,
  891. &UBound,
  892. &NumberElements))
  893. {
  894. if (WmiGetValueFunc(DataItemDesc->DataType,
  895. &GetValueFunc))
  896. {
  897. //
  898. // The size of each element is not allowed to
  899. // change, but the number of elements are
  900. //
  901. WmiAssert(DataItemDesc->ArrayPtr == NULL);
  902. ElementSize = DataItemDesc->DataSize;
  903. SizeNeeded = NumberElements * ElementSize;
  904. Array = (PUCHAR)LocalAlloc(LPTR, SizeNeeded);
  905. DataItemDesc->ArrayElementCount = NumberElements;
  906. DebugPrint((1,"WMIPROP: Alloc 0x%x bytes at %p\n", SizeNeeded, Array));
  907. memset(Array, 0, SizeNeeded);
  908. if (Array != NULL)
  909. {
  910. // CONSIDER: Use SafeArrayAccessData for number
  911. // types
  912. //
  913. // Now that we have memory for the array data
  914. // extract the data from the safe array and
  915. // store it in the C array
  916. //
  917. DataItemDesc->ArrayPtr = (PVOID)Array;
  918. hr = SafeArrayGetVartype(Value.parray,
  919. &vt);
  920. if (hr == WBEM_S_NO_ERROR)
  921. {
  922. ReturnStatus = TRUE;
  923. for (i1 = 0, Index = LBound;
  924. (i1 < NumberElements) && ReturnStatus;
  925. i1++, Index++)
  926. {
  927. VariantInit(&Element);
  928. Element.vt = vt;
  929. hr = SafeArrayGetElement(Value.parray,
  930. &Index,
  931. &Element.boolVal);
  932. if (hr == WBEM_S_NO_ERROR)
  933. {
  934. Element.vt = vt;
  935. DebugPrint((1, "WMIPROP: GetValueFunc at %p\n", Array));
  936. ReturnStatus = (*GetValueFunc)(
  937. &Element,
  938. (PVOID)Array);
  939. Array += ElementSize;
  940. } else {
  941. ReturnStatus = FALSE;
  942. }
  943. }
  944. }
  945. }
  946. } else {
  947. DebugPrint((1, "WMIPROP: Property %ws is array of type %d, but got type %d variant %p\n",
  948. DataItemDesc->Name,
  949. DataItemDesc->DataType,
  950. Value.vt, &Value));
  951. WmiAssert(FALSE);
  952. }
  953. }
  954. }
  955. VariantClear(&Value);
  956. }
  957. SysFreeString(s);
  958. }
  959. return(ReturnStatus);
  960. }
  961. BOOLEAN WmiRefreshDataBlockFromWbem(
  962. IN IWbemClassObject *pIWbemClassObject,
  963. IN OUT PDATA_BLOCK_DESCRIPTION DataBlockDesc
  964. )
  965. /*+++
  966. Routine Description:
  967. This routine will call WBEM to get the latest values for all property
  968. in data block represented by the DataBlockDesc
  969. Arguments:
  970. DataBlockDesc is the data item description for the class
  971. pIWbemClassObject is the instance class object interface for the class
  972. Return Value:
  973. TRUE if successful
  974. ---*/
  975. {
  976. PDATA_ITEM_DESCRIPTION DataItemDesc;
  977. BOOLEAN ReturnStatus;
  978. ULONG i;
  979. WmiAssert(DataBlockDesc != NULL);
  980. WmiAssert(pIWbemClassObject != NULL);
  981. ReturnStatus = TRUE;
  982. for (i = 0; (i < DataBlockDesc->DataItemCount) && ReturnStatus; i++)
  983. {
  984. DataItemDesc = &DataBlockDesc->DataItems[i];
  985. ReturnStatus = WmiRefreshDataItemFromWbem(DataItemDesc,
  986. pIWbemClassObject);
  987. }
  988. return(ReturnStatus);
  989. }
  990. VARTYPE WmiVarTypeForCimType(
  991. CIMTYPE CimType
  992. )
  993. {
  994. VARTYPE vt;
  995. //
  996. // Most things match their CIM types, except those below
  997. vt = (VARTYPE)CimType;
  998. switch(CimType)
  999. {
  1000. case CIM_UINT8:
  1001. case CIM_SINT8:
  1002. {
  1003. vt = VT_I4;
  1004. break;
  1005. }
  1006. case CIM_CHAR16:
  1007. case CIM_UINT16:
  1008. {
  1009. vt = VT_I2;
  1010. break;
  1011. }
  1012. case CIM_UINT32:
  1013. {
  1014. vt = VT_I4;
  1015. break;
  1016. }
  1017. case CIM_STRING:
  1018. case CIM_DATETIME:
  1019. case CIM_SINT64:
  1020. case CIM_UINT64:
  1021. {
  1022. vt = VT_BSTR;
  1023. break;
  1024. }
  1025. case CIM_OBJECT:
  1026. {
  1027. vt = VT_UNKNOWN;
  1028. break;
  1029. }
  1030. case CIM_BOOLEAN:
  1031. {
  1032. vt = VT_BOOL;
  1033. break;
  1034. }
  1035. }
  1036. return(vt);
  1037. }
  1038. typedef BOOLEAN (*SETVALUEFUNC)(
  1039. PVOID DataPtr,
  1040. PVOID DestPtr,
  1041. PVOID *SetPtr
  1042. );
  1043. BOOLEAN WmiSetBooleanValueFunc(
  1044. PVOID DataPtr,
  1045. PVOID DestPtr,
  1046. PVOID *SetPtr
  1047. )
  1048. {
  1049. BOOLEAN Value;
  1050. //
  1051. // A boolean needs to ve expressed as a VARIANT_TRUE or VARIANT_FALSE
  1052. //
  1053. Value = *((PBOOLEAN)DataPtr);
  1054. *((VARIANT_BOOL *)DestPtr) = Value ? VARIANT_TRUE : VARIANT_FALSE;
  1055. *SetPtr = (PVOID)DestPtr;
  1056. return(TRUE);
  1057. }
  1058. BOOLEAN WmiSetStringValueFunc(
  1059. PVOID DataPtr,
  1060. PVOID DestPtr,
  1061. PVOID *SetPtr
  1062. )
  1063. {
  1064. BSTR s;
  1065. PTCHAR String;
  1066. BOOLEAN ReturnStatus;
  1067. //
  1068. // Strings must be converted to BSTR
  1069. //
  1070. String = *((PTCHAR *)DataPtr);
  1071. WmiAssert(String != NULL);
  1072. s = SysAllocString(String);
  1073. if (s != NULL)
  1074. {
  1075. *((BSTR *)DestPtr) = s;
  1076. *SetPtr = (PVOID)s;
  1077. ReturnStatus = TRUE;
  1078. } else {
  1079. ReturnStatus = FALSE;
  1080. }
  1081. return(ReturnStatus);
  1082. }
  1083. BOOLEAN WmiSetEmbeddedValueFunc(
  1084. PVOID DataPtr,
  1085. PVOID DestPtr,
  1086. PVOID *SetPtr
  1087. )
  1088. {
  1089. IUnknown *pUnk;
  1090. IWbemClassObject *pIWbemClassObject;
  1091. HRESULT hr;
  1092. BOOLEAN ReturnStatus;
  1093. //
  1094. // QI for IUnknown since we are expected to put the IUnknown into
  1095. // the property.
  1096. //
  1097. pIWbemClassObject = *((IWbemClassObject **)DataPtr);
  1098. hr = pIWbemClassObject->QueryInterface(IID_IUnknown,
  1099. (PVOID *)&pUnk);
  1100. if (hr == WBEM_S_NO_ERROR)
  1101. {
  1102. *((IUnknown **)DestPtr) = pUnk;
  1103. *SetPtr = (PVOID)pUnk;
  1104. ReturnStatus = TRUE;
  1105. } else {
  1106. ReturnStatus = FALSE;
  1107. }
  1108. return(ReturnStatus);
  1109. }
  1110. BOOLEAN WmiSetSint8ValueFunc(
  1111. PVOID DataPtr,
  1112. PVOID DestPtr,
  1113. PVOID *SetPtr
  1114. )
  1115. {
  1116. //
  1117. // CHARs must be expressed as a LONG to keep WBEM happy
  1118. //
  1119. *((LONG *)DestPtr) = (LONG)(*((CHAR *)DataPtr));
  1120. *SetPtr = (PVOID)DestPtr;
  1121. return(TRUE);
  1122. }
  1123. BOOLEAN WmiSetUint8ValueFunc(
  1124. PVOID DataPtr,
  1125. PVOID DestPtr,
  1126. PVOID *SetPtr
  1127. )
  1128. {
  1129. //
  1130. // UCHARs must be expressed as a LONG to keep WBEM happy
  1131. //
  1132. *((LONG *)DestPtr) = (LONG)(*((UCHAR *)DataPtr));
  1133. *SetPtr = (PVOID)DestPtr;
  1134. return(TRUE);
  1135. }
  1136. BOOLEAN WmiSetSint16ValueFunc(
  1137. PVOID DataPtr,
  1138. PVOID DestPtr,
  1139. PVOID *SetPtr
  1140. )
  1141. {
  1142. //
  1143. // SHORTs must be expressed as a SHORT to keep WBEM happy
  1144. //
  1145. *((SHORT *)DestPtr) = (*((SHORT *)DataPtr));
  1146. *SetPtr = (PVOID)DestPtr;
  1147. return(TRUE);
  1148. }
  1149. BOOLEAN WmiSetUint16ValueFunc(
  1150. PVOID DataPtr,
  1151. PVOID DestPtr,
  1152. PVOID *SetPtr
  1153. )
  1154. {
  1155. //
  1156. // USHORTs must be expressed as a SHORT to keep WBEM happy
  1157. //
  1158. *((SHORT *)DestPtr) = (SHORT)(*((USHORT *)DataPtr));
  1159. *SetPtr = (PVOID)DestPtr;
  1160. return(TRUE);
  1161. }
  1162. BOOLEAN WmiSetSint32ValueFunc(
  1163. PVOID DataPtr,
  1164. PVOID DestPtr,
  1165. PVOID *SetPtr
  1166. )
  1167. {
  1168. //
  1169. // LONGs must be expressed as a LONG to keep WBEM happy
  1170. //
  1171. *((LONG *)DestPtr) = (*((LONG *)DataPtr));
  1172. *SetPtr = (PVOID)DestPtr;
  1173. return(TRUE);
  1174. }
  1175. BOOLEAN WmiSetUint32ValueFunc(
  1176. PVOID DataPtr,
  1177. PVOID DestPtr,
  1178. PVOID *SetPtr
  1179. )
  1180. {
  1181. //
  1182. // ULONGs must be expressed as a LONG to keep WBEM happy
  1183. //
  1184. *((LONG *)DestPtr) = (ULONG)(*((ULONG *)DataPtr));
  1185. *SetPtr = (PVOID)DestPtr;
  1186. return(TRUE);
  1187. }
  1188. BOOLEAN WmiSetSint64ValueFunc(
  1189. PVOID DataPtr,
  1190. PVOID DestPtr,
  1191. PVOID *SetPtr
  1192. )
  1193. {
  1194. TCHAR Text[MAX_PATH];
  1195. BSTR s;
  1196. BOOLEAN ReturnStatus;
  1197. //
  1198. // 64 bit values must be set via a BSTR
  1199. //
  1200. wsprintf(Text, TEXT("%I64d"), *((LONGLONG *)DataPtr));
  1201. s = SysAllocString(Text);
  1202. if (s != NULL)
  1203. {
  1204. *((BSTR *)DestPtr) = s;
  1205. *SetPtr = (PVOID)s;
  1206. ReturnStatus = TRUE;
  1207. } else {
  1208. ReturnStatus = FALSE;
  1209. }
  1210. return(ReturnStatus);
  1211. }
  1212. BOOLEAN WmiSetUint64ValueFunc(
  1213. PVOID DataPtr,
  1214. PVOID DestPtr,
  1215. PVOID *SetPtr
  1216. )
  1217. {
  1218. TCHAR Text[MAX_PATH];
  1219. BSTR s;
  1220. BOOLEAN ReturnStatus;
  1221. //
  1222. // 64 bit values must be set via a BSTR
  1223. //
  1224. wsprintf(Text, TEXT("%I64d"), *((ULONGLONG *)DataPtr));
  1225. s = SysAllocString(Text);
  1226. if (s != NULL)
  1227. {
  1228. *((BSTR *)DestPtr) = s;
  1229. *SetPtr = (PVOID)s;
  1230. ReturnStatus = TRUE;
  1231. } else {
  1232. ReturnStatus = FALSE;
  1233. }
  1234. return(ReturnStatus);
  1235. }
  1236. SETVALUEFUNC WmiGetSetValueFunc(
  1237. CIMTYPE CimType
  1238. )
  1239. {
  1240. SETVALUEFUNC SetValueFunc;
  1241. switch(CimType)
  1242. {
  1243. case CIM_SINT8:
  1244. {
  1245. SetValueFunc = WmiSetSint8ValueFunc;
  1246. break;
  1247. }
  1248. case CIM_UINT8:
  1249. {
  1250. SetValueFunc = WmiSetUint8ValueFunc;
  1251. break;
  1252. }
  1253. case CIM_CHAR16:
  1254. case CIM_SINT16:
  1255. {
  1256. SetValueFunc = WmiSetSint16ValueFunc;
  1257. break;
  1258. }
  1259. case CIM_UINT16:
  1260. {
  1261. SetValueFunc = WmiSetUint16ValueFunc;
  1262. break;
  1263. }
  1264. case CIM_SINT32:
  1265. {
  1266. SetValueFunc = WmiSetSint32ValueFunc;
  1267. break;
  1268. }
  1269. case CIM_UINT32:
  1270. {
  1271. SetValueFunc = WmiSetUint32ValueFunc;
  1272. break;
  1273. }
  1274. case CIM_SINT64:
  1275. {
  1276. SetValueFunc = WmiSetSint64ValueFunc;
  1277. break;
  1278. }
  1279. case CIM_UINT64:
  1280. {
  1281. SetValueFunc = WmiSetUint64ValueFunc;
  1282. break;
  1283. }
  1284. case CIM_BOOLEAN:
  1285. {
  1286. SetValueFunc = WmiSetBooleanValueFunc;
  1287. break;
  1288. }
  1289. case CIM_DATETIME:
  1290. case CIM_STRING:
  1291. {
  1292. SetValueFunc = WmiSetStringValueFunc;
  1293. break;
  1294. }
  1295. case CIM_OBJECT:
  1296. {
  1297. SetValueFunc = WmiSetEmbeddedValueFunc;
  1298. break;
  1299. }
  1300. default:
  1301. {
  1302. SetValueFunc = NULL;
  1303. break;
  1304. }
  1305. }
  1306. return(SetValueFunc);
  1307. }
  1308. BOOLEAN WmiAssignToVariantFromDataItem(
  1309. OUT VARIANT *NewValue,
  1310. IN PDATA_ITEM_DESCRIPTION DataItemDesc
  1311. )
  1312. /*+++
  1313. Routine Description:
  1314. This routine will assign the value for a property from the DataItemDesc
  1315. into an initied variant. It will figure out all of the strange rules
  1316. for what types of variants WBEM likes for different data types.
  1317. Arguments:
  1318. DataBlockDesc is the data item description for the class
  1319. pIWbemClassObject is the instance class object interface for the class
  1320. Return Value:
  1321. TRUE if successful
  1322. ---*/
  1323. {
  1324. BOOLEAN ReturnStatus;
  1325. BSTR s;
  1326. TCHAR Text[MAX_PATH];
  1327. SETVALUEFUNC SetValueFunc;
  1328. VARTYPE vt;
  1329. PVOID SetPtr;
  1330. WmiAssert(NewValue != NULL);
  1331. WmiAssert(DataItemDesc != NULL);
  1332. SetValueFunc = WmiGetSetValueFunc(DataItemDesc->DataType);
  1333. if (SetValueFunc != NULL)
  1334. {
  1335. ReturnStatus = TRUE;
  1336. vt = WmiVarTypeForCimType(DataItemDesc->DataType);
  1337. if ((DataItemDesc->IsFixedArray == 0) &&
  1338. (DataItemDesc->IsVariableArray == 0))
  1339. {
  1340. //
  1341. // This is a non array case
  1342. //
  1343. NewValue->vt = vt;
  1344. ReturnStatus = (*SetValueFunc)((PVOID)&DataItemDesc->Data,
  1345. &NewValue->lVal,
  1346. &SetPtr);
  1347. } else {
  1348. //
  1349. // This is an array, so we need to create a safe array in order to
  1350. // call WBEM.
  1351. //
  1352. SAFEARRAY *SafeArray;
  1353. PUCHAR DataArray;
  1354. PVOID DataPtr;
  1355. PVOID Temp;
  1356. HRESULT hr;
  1357. ULONG i;
  1358. //
  1359. // We do not support arrays of embedded classes
  1360. //
  1361. SafeArray = SafeArrayCreateVector(vt,
  1362. 0,
  1363. DataItemDesc->ArrayElementCount);
  1364. if (SafeArray != NULL)
  1365. {
  1366. DataArray = (PUCHAR)DataItemDesc->ArrayPtr;
  1367. WmiAssert(DataArray != NULL);
  1368. ReturnStatus = TRUE;
  1369. for (i = 0;
  1370. (i < DataItemDesc->ArrayElementCount) && ReturnStatus;
  1371. i++)
  1372. {
  1373. ReturnStatus = (*SetValueFunc)(DataArray, &Temp, &SetPtr);
  1374. if (ReturnStatus)
  1375. {
  1376. hr = SafeArrayPutElement(SafeArray,
  1377. (PLONG)&i,
  1378. SetPtr);
  1379. if (hr == WBEM_S_NO_ERROR)
  1380. {
  1381. DataArray += DataItemDesc->DataSize;
  1382. } else {
  1383. ReturnStatus = FALSE;
  1384. }
  1385. }
  1386. }
  1387. if (ReturnStatus == FALSE)
  1388. {
  1389. //
  1390. // if we failed to build the safearray we need to clean
  1391. // it up.
  1392. //
  1393. SafeArrayDestroy(SafeArray);
  1394. } else {
  1395. NewValue->vt = vt | VT_ARRAY;
  1396. NewValue->parray = SafeArray;
  1397. }
  1398. } else {
  1399. ReturnStatus = FALSE;
  1400. }
  1401. }
  1402. } else {
  1403. WmiAssert(FALSE);
  1404. ReturnStatus = FALSE;
  1405. }
  1406. return(ReturnStatus);
  1407. }
  1408. BOOLEAN WmiRefreshWbemFromDataItem(
  1409. IN IWbemServices *pIWbemServices,
  1410. IN IWbemClassObject *pIWbemClassObject,
  1411. IN PDATA_ITEM_DESCRIPTION DataItemDesc
  1412. )
  1413. /*+++
  1414. Routine Description:
  1415. This routine will update the WBEM property with the value specified in
  1416. the DataItemDesc.
  1417. Arguments:
  1418. DataItemDesc is the data item description for the property
  1419. pIWbemClassObject is the instance class object interface for the class
  1420. Return Value:
  1421. TRUE if successful
  1422. ---*/
  1423. {
  1424. VARIANT NewValue;
  1425. BOOLEAN ReturnStatus;
  1426. HRESULT hr;
  1427. BSTR s;
  1428. WmiAssert(pIWbemClassObject != NULL);
  1429. WmiAssert(DataItemDesc != NULL);
  1430. ReturnStatus = TRUE;
  1431. if (DataItemDesc->IsReadOnly == 0)
  1432. {
  1433. //
  1434. // Property is not read only so we want to try to update it
  1435. //
  1436. //
  1437. // Now build the value into a variant and call WBEM to get him
  1438. // to update it.
  1439. //
  1440. VariantInit(&NewValue);
  1441. ReturnStatus = WmiAssignToVariantFromDataItem(&NewValue,
  1442. DataItemDesc);
  1443. //
  1444. // if we need to update the value of the property do so and then
  1445. // free up the variant
  1446. //
  1447. if (ReturnStatus)
  1448. {
  1449. s = SysAllocString(DataItemDesc->Name);
  1450. if (s != NULL)
  1451. {
  1452. DebugPrint((1, "WMIPROP: Property %ws (%p) being updated to 0x%x (type 0x%x)\n",
  1453. DataItemDesc->Name,
  1454. DataItemDesc,
  1455. NewValue.ulVal,
  1456. NewValue.vt));
  1457. hr = pIWbemClassObject->Put(s,
  1458. 0,
  1459. &NewValue,
  1460. 0);
  1461. #if DBG
  1462. if (hr != WBEM_S_NO_ERROR)
  1463. {
  1464. DebugPrint((1, "WMIPROP: Property %ws (%p) Error %x from pIWbemClassObejct->Put\n",
  1465. DataItemDesc->Name,
  1466. DataItemDesc,
  1467. hr));
  1468. }
  1469. #endif
  1470. SysFreeString(s);
  1471. }
  1472. VariantClear(&NewValue);
  1473. }
  1474. }
  1475. return(ReturnStatus);
  1476. }
  1477. BOOLEAN WmiRefreshWbemFromDataBlock(
  1478. IN IWbemServices *pIWbemServices,
  1479. IN IWbemClassObject *pIWbemClassObject,
  1480. IN PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  1481. IN BOOLEAN IsEmbeddedClass
  1482. )
  1483. /*+++
  1484. Routine Description:
  1485. This routine will update the WBEM class with the values specified in
  1486. the DataBlockDesc. If the class is not an embedded (ie, top level) then
  1487. it will put the instance which will update the values in the schema and
  1488. call the provider (ie, device driver).
  1489. Arguments:
  1490. pIWbemServices is the Wbem Service interface
  1491. pIWbemClassObject is the instance class object interface for the class
  1492. DataBlockDesc is the data block description for the class
  1493. IsEmbeddedClass is TRUE if the class is an embedeed class.
  1494. Return Value:
  1495. TRUE if successful
  1496. ---*/
  1497. {
  1498. ULONG i;
  1499. PDATA_ITEM_DESCRIPTION DataItemDesc;
  1500. BOOLEAN ReturnStatus;
  1501. HRESULT hr;
  1502. WmiAssert(pIWbemServices != NULL);
  1503. WmiAssert(pIWbemClassObject != NULL);
  1504. WmiAssert(DataBlockDesc != NULL);
  1505. ReturnStatus = TRUE;
  1506. for (i = 0; (i < DataBlockDesc->DataItemCount) && ReturnStatus; i++)
  1507. {
  1508. DataItemDesc = &DataBlockDesc->DataItems[i];
  1509. ReturnStatus = WmiRefreshWbemFromDataItem(pIWbemServices,
  1510. pIWbemClassObject,
  1511. DataItemDesc);
  1512. }
  1513. if ((ReturnStatus) && (! IsEmbeddedClass))
  1514. {
  1515. //
  1516. // No need to do PutInsance on embedded classes, only top level ones
  1517. //
  1518. hr = pIWbemServices->PutInstance(pIWbemClassObject,
  1519. WBEM_FLAG_UPDATE_ONLY,
  1520. NULL,
  1521. NULL);
  1522. #if DBG
  1523. if (hr != WBEM_S_NO_ERROR)
  1524. {
  1525. DebugPrint((1, "WMIPROP: Error %x returned from PutInstance for %ws (%p)\n",
  1526. hr, DataBlockDesc->Name, DataBlockDesc));
  1527. }
  1528. #endif
  1529. ReturnStatus = (hr == WBEM_S_NO_ERROR);
  1530. }
  1531. return(ReturnStatus);
  1532. }
  1533. PTCHAR WmiGetDeviceInstanceId(
  1534. IN HDEVINFO deviceInfoSet,
  1535. IN PSP_DEVINFO_DATA deviceInfoData,
  1536. IN HANDLE MachineHandle
  1537. )
  1538. /*+++
  1539. Routine Description:
  1540. This routine will obtain the device instance id for the device that
  1541. we are working with.
  1542. Arguments:
  1543. deviceInfoSet
  1544. deviceInfoData
  1545. Return Value:
  1546. returns pointer to device instance id or NULL if unavailable
  1547. ---*/
  1548. {
  1549. ULONG Status;
  1550. PTCHAR Id;
  1551. ULONG SizeNeeded;
  1552. WmiAssert(deviceInfoSet != NULL);
  1553. WmiAssert(deviceInfoData != NULL);
  1554. SizeNeeded = (MAX_DEVICE_ID_LEN + 1) * sizeof(TCHAR);
  1555. Id = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
  1556. if (Id != NULL)
  1557. {
  1558. Status = CM_Get_Device_ID_Ex(deviceInfoData->DevInst,
  1559. Id,
  1560. SizeNeeded / sizeof(TCHAR),
  1561. 0,
  1562. MachineHandle);
  1563. if (Status != CR_SUCCESS)
  1564. {
  1565. DebugPrint((1, "WMIPROP: CM_Get_Device_ID_Ex returned %d\n",
  1566. Status));
  1567. LocalFree(Id);
  1568. Id = NULL;
  1569. }
  1570. } else {
  1571. DebugPrint((1, "WMIPROP: Could not alloc for device Id\n"));
  1572. }
  1573. return(Id);
  1574. }
  1575. PTCHAR WmiGetDeviceInstanceName(
  1576. IN HDEVINFO deviceInfoSet,
  1577. IN PSP_DEVINFO_DATA deviceInfoData,
  1578. IN HANDLE MachineHandle
  1579. )
  1580. /*+++
  1581. Routine Description:
  1582. This routine will obtain the WMI instance name id for the device that
  1583. we are working with.
  1584. Arguments:
  1585. deviceInfoSet
  1586. deviceInfoData
  1587. Return Value:
  1588. returns pointer to device instance name or NULL if unavailable
  1589. ---*/
  1590. {
  1591. #define InstanceNumberText TEXT("_0")
  1592. PTCHAR Id, in, s;
  1593. PTCHAR InstanceName;
  1594. ULONG SizeNeeded;
  1595. WmiAssert(deviceInfoSet != NULL);
  1596. WmiAssert(deviceInfoData != NULL);
  1597. InstanceName = NULL;
  1598. Id = WmiGetDeviceInstanceId(deviceInfoSet,
  1599. deviceInfoData,
  1600. MachineHandle);
  1601. if (Id != NULL)
  1602. {
  1603. //
  1604. // We need to play some games with the device id to make it into
  1605. // a WMI instance name.
  1606. //
  1607. // 1. We need to convert any "\\" in the instance name to "\\\\".
  1608. // For some reason wbem likes it this way.
  1609. // 2. We need to append a "_0" to the end to indicate the instance
  1610. // number we are dealing with.
  1611. s = Id;
  1612. SizeNeeded = (_tcslen(Id) * sizeof(TCHAR)) +
  1613. sizeof(InstanceNumberText);
  1614. while (*s != 0)
  1615. {
  1616. if (*s++ == TEXT('\\'))
  1617. {
  1618. SizeNeeded += sizeof(TCHAR);
  1619. }
  1620. }
  1621. InstanceName = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
  1622. if (InstanceName != NULL)
  1623. {
  1624. in = InstanceName;
  1625. s = Id;
  1626. while (*s != 0)
  1627. {
  1628. *in++ = *s;
  1629. if (*s++ == TEXT('\\'))
  1630. {
  1631. *in++ = TEXT('\\');
  1632. }
  1633. }
  1634. _tcscat(InstanceName, InstanceNumberText);
  1635. }
  1636. LocalFree(Id);
  1637. }
  1638. return(InstanceName);
  1639. }
  1640. BOOLEAN WmiGetQualifier(
  1641. IN IWbemQualifierSet *pIWbemQualifierSet,
  1642. IN PTCHAR QualifierName,
  1643. IN VARTYPE Type,
  1644. OUT VARIANT *Value
  1645. )
  1646. /*+++
  1647. Routine Description:
  1648. This routine will return the value for a specific qualifier
  1649. Arguments:
  1650. pIWbemQualifierSet is the qualifier set object
  1651. QualifierName is the name of the qualifier
  1652. Type is the type of qualifier expected
  1653. *Value returns with the value of the qualifier
  1654. Return Value:
  1655. returns pointer to device instance name or NULL if unavailable
  1656. ---*/
  1657. {
  1658. BSTR s;
  1659. HRESULT hr;
  1660. BOOLEAN ReturnStatus;
  1661. WmiAssert(pIWbemQualifierSet != NULL);
  1662. WmiAssert(QualifierName != NULL);
  1663. WmiAssert(Value != NULL);
  1664. s = SysAllocString(QualifierName);
  1665. if (s != NULL)
  1666. {
  1667. hr = pIWbemQualifierSet->Get(s,
  1668. 0,
  1669. Value,
  1670. NULL);
  1671. if (hr == WBEM_S_NO_ERROR)
  1672. {
  1673. ReturnStatus = ((Value->vt & ~CIM_FLAG_ARRAY) == Type);
  1674. } else {
  1675. ReturnStatus = FALSE;
  1676. }
  1677. SysFreeString(s);
  1678. } else {
  1679. ReturnStatus = FALSE;
  1680. }
  1681. return(ReturnStatus);
  1682. }
  1683. BOOLEAN WmiParseRange(
  1684. OUT PRANGEINFO RangeInfo,
  1685. IN BSTR Range
  1686. )
  1687. /*+++
  1688. Routine Description:
  1689. This routine will parse a range specified in the for x or x - y. The
  1690. former means the value x and the latter means from x to y.
  1691. Arguments:
  1692. *RangeInfo returns with the range specified
  1693. Range is the text representation of the range
  1694. Return Value:
  1695. TRUE if successful else FALSE
  1696. ---*/
  1697. {
  1698. #define RangeSeparator TEXT('-')
  1699. #define Space TEXT(' ')
  1700. #define MAX_RANGE_VALUE_LENGTH 64
  1701. LONG64 BeginValue, EndValue;
  1702. TCHAR *s;
  1703. TCHAR *d;
  1704. TCHAR ValueText[MAX_RANGE_VALUE_LENGTH];
  1705. ULONG i;
  1706. BOOLEAN ReturnStatus;
  1707. WmiAssert(RangeInfo != NULL);
  1708. WmiAssert(Range != NULL);
  1709. //
  1710. // Obtain the beginning value by copying up to the separator and
  1711. // then converting to a number
  1712. //
  1713. s = Range;
  1714. d = ValueText;
  1715. i = 0;
  1716. while ((*s != 0) && (*s != RangeSeparator) && (*s != Space) &&
  1717. (i < MAX_RANGE_VALUE_LENGTH))
  1718. {
  1719. *d++ = *s++;
  1720. i++;
  1721. }
  1722. *d = 0;
  1723. if (i < MAX_RANGE_VALUE_LENGTH)
  1724. {
  1725. BeginValue = _ttoi64(ValueText);
  1726. EndValue = BeginValue;
  1727. if (*s != 0)
  1728. {
  1729. //
  1730. // Skip to the beginning of the next number
  1731. //
  1732. while ( (*s != 0) &&
  1733. ((*s == RangeSeparator) || (*s == Space)) )
  1734. {
  1735. s++;
  1736. }
  1737. if (*s != 0)
  1738. {
  1739. //
  1740. // We do have a second number, copy it out
  1741. //
  1742. d = ValueText;
  1743. i = 0;
  1744. while ((*s != 0) && (*s != Space) &&
  1745. (i < MAX_RANGE_VALUE_LENGTH))
  1746. {
  1747. *d++ = *s++;
  1748. i++;
  1749. }
  1750. *d = 0;
  1751. if (*s == 0)
  1752. {
  1753. EndValue = _ttoi64(ValueText);
  1754. }
  1755. }
  1756. }
  1757. //
  1758. // Fill out the output RangeInfo making sure that the smaller value
  1759. // is placed in the miniumum and larger in the maximum.
  1760. //
  1761. if (BeginValue < EndValue)
  1762. {
  1763. RangeInfo->Minimum = BeginValue;
  1764. RangeInfo->Maximum = EndValue;
  1765. } else {
  1766. RangeInfo->Minimum = EndValue;
  1767. RangeInfo->Maximum = BeginValue;
  1768. }
  1769. ReturnStatus = TRUE;
  1770. } else {
  1771. //
  1772. // if range text is too long then give up
  1773. //
  1774. ReturnStatus = FALSE;
  1775. }
  1776. return(ReturnStatus);
  1777. }
  1778. BOOLEAN WmiRangeProperty(
  1779. IN IWbemQualifierSet *pIWbemQualifierSet,
  1780. OUT PDATA_ITEM_DESCRIPTION DataItemDesc
  1781. )
  1782. /*+++
  1783. Routine Description:
  1784. This routine will obtain information about the valid ranges of values
  1785. for the data item
  1786. Arguments:
  1787. pIWbemQualifierSet is the qualifier set object
  1788. DataItemDesc gets filled with info about ranges
  1789. Return Value:
  1790. TRUE if successful else FALSE
  1791. ---*/
  1792. {
  1793. #define RangeText TEXT("Range")
  1794. VARIANT Range;
  1795. BSTR RangeData;
  1796. LONG RangeLBound, RangeUBound, RangeElements;
  1797. LONG i, Index;
  1798. HRESULT hr;
  1799. ULONG SizeNeeded;
  1800. PRANGELISTINFO RangeListInfo;
  1801. BOOLEAN ReturnStatus;
  1802. WmiAssert(pIWbemQualifierSet != NULL);
  1803. WmiAssert(DataItemDesc != NULL);
  1804. if (WmiGetQualifier(pIWbemQualifierSet,
  1805. RangeText,
  1806. VT_BSTR, // array
  1807. &Range))
  1808. {
  1809. if (Range.vt & CIM_FLAG_ARRAY)
  1810. {
  1811. //
  1812. // Array of ranges
  1813. //
  1814. if (WmiGetArraySize(Range.parray,
  1815. &RangeLBound,
  1816. &RangeUBound,
  1817. &RangeElements))
  1818. {
  1819. SizeNeeded = sizeof(RANGELISTINFO) +
  1820. (RangeElements * sizeof(RANGEINFO));
  1821. RangeListInfo = (PRANGELISTINFO)LocalAlloc(LPTR, SizeNeeded);
  1822. if (RangeListInfo != NULL)
  1823. {
  1824. ReturnStatus = TRUE;
  1825. DataItemDesc->RangeListInfo = RangeListInfo;
  1826. RangeListInfo->Count = RangeElements;
  1827. for (i = 0; (i < RangeElements) && ReturnStatus; i++)
  1828. {
  1829. Index = i + RangeLBound;
  1830. hr = SafeArrayGetElement(Range.parray,
  1831. &Index,
  1832. &RangeData);
  1833. if (hr == WBEM_S_NO_ERROR)
  1834. {
  1835. ReturnStatus = WmiParseRange(
  1836. &RangeListInfo->Ranges[i],
  1837. RangeData);
  1838. #if DBG
  1839. if (ReturnStatus == FALSE)
  1840. {
  1841. DebugPrint((1, "WMIPROP: Error parsing range %ws\n",
  1842. RangeData));
  1843. }
  1844. #endif
  1845. } else {
  1846. ReturnStatus = FALSE;
  1847. }
  1848. }
  1849. } else {
  1850. ReturnStatus = FALSE;
  1851. }
  1852. } else {
  1853. ReturnStatus = FALSE;
  1854. }
  1855. } else {
  1856. //
  1857. // Single range
  1858. //
  1859. RangeListInfo = (PRANGELISTINFO)LocalAlloc(LPTR, sizeof(RANGELISTINFO));
  1860. if (RangeListInfo != NULL)
  1861. {
  1862. DataItemDesc->RangeListInfo = RangeListInfo;
  1863. RangeListInfo->Count = 1;
  1864. ReturnStatus = WmiParseRange(&RangeListInfo->Ranges[0],
  1865. Range.bstrVal);
  1866. } else {
  1867. ReturnStatus = FALSE;
  1868. }
  1869. }
  1870. VariantClear(&Range);
  1871. } else {
  1872. ReturnStatus = FALSE;
  1873. }
  1874. return(ReturnStatus);
  1875. }
  1876. BOOLEAN WmiValueMapProperty(
  1877. IN IWbemQualifierSet *pIWbemQualifierSet,
  1878. OUT PDATA_ITEM_DESCRIPTION DataItemDesc
  1879. )
  1880. /*+++
  1881. Routine Description:
  1882. This routine will obtain information about the enumeration values for
  1883. the data block
  1884. Arguments:
  1885. pIWbemQualifierSet is the qualifier set object
  1886. DataItemDesc gets filled with info about enumerations
  1887. Return Value:
  1888. TRUE if successful else FALSE
  1889. ---*/
  1890. {
  1891. #define ValueMapText TEXT("ValueMap")
  1892. #define ValuesText TEXT("Values")
  1893. VARIANT Values, ValueMap;
  1894. BSTR ValuesData, ValueMapData;
  1895. BOOLEAN ReturnStatus = FALSE;
  1896. VARTYPE ValuesType, ValueMapType;
  1897. LONG ValuesUBound, ValuesLBound, ValuesSize;
  1898. LONG ValueMapUBound, ValueMapLBound, ValueMapSize;
  1899. ULONG SizeNeeded;
  1900. PENUMERATIONINFO EnumerationInfo;
  1901. LONG i;
  1902. LONG Index;
  1903. HRESULT hr;
  1904. WmiAssert(pIWbemQualifierSet != NULL);
  1905. WmiAssert(DataItemDesc != NULL);
  1906. //
  1907. // Get the Values and ValueMap qualifier values. These can be single
  1908. // strings or arrays of strings.
  1909. //
  1910. if ((WmiGetQualifier(pIWbemQualifierSet,
  1911. ValuesText,
  1912. VT_BSTR, // array
  1913. &Values)) &&
  1914. (WmiGetQualifier(pIWbemQualifierSet,
  1915. ValueMapText,
  1916. VT_BSTR, // array
  1917. &ValueMap)))
  1918. {
  1919. //
  1920. // if we've got both qualifiers then we can do value map, make sure
  1921. // that both of them are strings and are either scalar or arrays with
  1922. // the same length.
  1923. //
  1924. ValuesType = Values.vt & ~CIM_FLAG_ARRAY;
  1925. ValueMapType = ValueMap.vt & ~CIM_FLAG_ARRAY;
  1926. if ((ValuesType == CIM_STRING) &&
  1927. (ValueMapType == CIM_STRING) &&
  1928. (Values.vt == ValueMap.vt))
  1929. {
  1930. if (Values.vt & CIM_FLAG_ARRAY)
  1931. {
  1932. //
  1933. // We have sets of arrays for the value map, make sure
  1934. // both arrays are the same size
  1935. //
  1936. SAFEARRAY *ValuesArray = Values.parray;
  1937. SAFEARRAY *ValueMapArray = ValueMap.parray;
  1938. if ((WmiGetArraySize(ValuesArray,
  1939. &ValuesLBound,
  1940. &ValuesUBound,
  1941. &ValuesSize)) &&
  1942. (WmiGetArraySize(ValueMapArray,
  1943. &ValueMapLBound,
  1944. &ValueMapUBound,
  1945. &ValueMapSize)) &&
  1946. (ValueMapSize == ValuesSize))
  1947. {
  1948. //
  1949. // Everything checks out with the arrays, just need to
  1950. // copy the values and valuemap into data item desc
  1951. //
  1952. SizeNeeded = sizeof(ENUMERATIONINFO) +
  1953. ValuesSize * sizeof(ENUMERATIONITEM);
  1954. EnumerationInfo = (PENUMERATIONINFO)LocalAlloc(LPTR,
  1955. SizeNeeded);
  1956. if (EnumerationInfo != NULL)
  1957. {
  1958. //
  1959. // We have memory to store the enumeration info
  1960. // loop over all enumations and record the info
  1961. //
  1962. ReturnStatus = TRUE;
  1963. DataItemDesc->EnumerationInfo = EnumerationInfo;
  1964. EnumerationInfo->Count = ValuesSize;
  1965. for (i = 0; (i < ValuesSize) && ReturnStatus; i++)
  1966. {
  1967. Index = i + ValuesLBound;
  1968. hr = SafeArrayGetElement(ValuesArray,
  1969. &Index,
  1970. &ValuesData);
  1971. if (hr == WBEM_S_NO_ERROR)
  1972. {
  1973. Index = i + ValueMapLBound;
  1974. hr = SafeArrayGetElement(ValueMapArray,
  1975. &Index,
  1976. &ValueMapData);
  1977. if (hr == WBEM_S_NO_ERROR)
  1978. {
  1979. ReturnStatus =
  1980. (WmiBstrToTchar(&EnumerationInfo->List[i].Text,
  1981. ValuesData)) &&
  1982. (WmiBstrToUlong64(&EnumerationInfo->List[i].Value,
  1983. ValueMapData));
  1984. }
  1985. } else {
  1986. ReturnStatus = FALSE;
  1987. }
  1988. }
  1989. }
  1990. }
  1991. } else {
  1992. //
  1993. // Single value in ValueMap
  1994. //
  1995. EnumerationInfo = (PENUMERATIONINFO)LocalAlloc(LPTR,
  1996. sizeof(ENUMERATIONINFO));
  1997. if (EnumerationInfo != NULL)
  1998. {
  1999. DataItemDesc->EnumerationInfo = EnumerationInfo;
  2000. EnumerationInfo->Count = 1;
  2001. ReturnStatus =
  2002. (WmiBstrToTchar(&EnumerationInfo->List[0].Text,
  2003. Values.bstrVal)) &&
  2004. (WmiBstrToUlong64(&EnumerationInfo->List[0].Value,
  2005. ValueMap.bstrVal));
  2006. } else {
  2007. ReturnStatus = FALSE;
  2008. }
  2009. }
  2010. }
  2011. }
  2012. VariantClear(&Values);
  2013. VariantClear(&ValueMap);
  2014. return(ReturnStatus);
  2015. }
  2016. BOOLEAN WmiGetEmbeddedDataItem(
  2017. IN IWbemServices *pIWbemServices,
  2018. IN IWbemQualifierSet *pIWbemQualifierSet,
  2019. IN PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  2020. IN OUT PDATA_ITEM_DESCRIPTION DataItemDesc
  2021. )
  2022. {
  2023. #define ObjectColonText TEXT("object:")
  2024. #define ObjectColonTextChars ((sizeof(ObjectColonText)/sizeof(TCHAR))-1)
  2025. #define CIMTYPEText TEXT("CIMTYPE")
  2026. IWbemClassObject *pIWbemClassObjectEmbedded;
  2027. VARIANT CimType;
  2028. BSTR s;
  2029. HRESULT hr;
  2030. BOOLEAN ReturnStatus;
  2031. //
  2032. // This is an embedded class, so we need to dig
  2033. // out the name of the embedded class from the CIMTYPE
  2034. // qualifier for the property and then go and get
  2035. // that class object (via IWbemServices) as if it
  2036. // were just another top level class.
  2037. //
  2038. ReturnStatus = FALSE;
  2039. if (WmiGetQualifier(pIWbemQualifierSet,
  2040. CIMTYPEText,
  2041. VT_BSTR,
  2042. &CimType))
  2043. {
  2044. //
  2045. // Make sure that CIMTYPE value starts with object:
  2046. //
  2047. if (_tcsnicmp(CimType.bstrVal,
  2048. ObjectColonText,
  2049. ObjectColonTextChars) == 0)
  2050. {
  2051. //
  2052. // and if so then the rest of the string is the embedded class
  2053. // name, so make that a bstr so we can get a class object to it.
  2054. //
  2055. s = SysAllocString(CimType.bstrVal + ObjectColonTextChars);
  2056. if (s != NULL)
  2057. {
  2058. pIWbemClassObjectEmbedded = NULL;
  2059. hr = pIWbemServices->GetObject(s,
  2060. WBEM_FLAG_USE_AMENDED_QUALIFIERS,
  2061. NULL,
  2062. &pIWbemClassObjectEmbedded,
  2063. NULL);
  2064. if (hr == WBEM_S_NO_ERROR)
  2065. {
  2066. DebugPrint((1, "WMIPROP: Parsing embedded class %ws for %ws \n",
  2067. s, DataItemDesc->Name));
  2068. ReturnStatus = WmiGetDataBlockDesc(
  2069. pIWbemServices,
  2070. pIWbemClassObjectEmbedded,
  2071. &DataItemDesc->DataBlockDesc,
  2072. DataBlockDesc,
  2073. (DataItemDesc->IsReadOnly == 1));
  2074. DebugPrint((1, "WMIPROP: Parsed embedded class %ws for %ws (%p) %ws\n",
  2075. s,
  2076. DataItemDesc->Name,
  2077. DataItemDesc->DataBlockDesc,
  2078. ReturnStatus ? L"ok" : L"failed"));
  2079. pIWbemClassObjectEmbedded->Release();
  2080. }
  2081. SysFreeString(s);
  2082. }
  2083. }
  2084. VariantClear(&CimType);
  2085. }
  2086. return(ReturnStatus);
  2087. }
  2088. BOOLEAN WmiGetDataItem(
  2089. IWbemServices *pIWbemServices,
  2090. IWbemClassObject *pIWbemClassObject,
  2091. BSTR PropertyName,
  2092. IWbemQualifierSet *pIWbemQualifierSet,
  2093. PDATA_ITEM_DESCRIPTION DataItemDesc,
  2094. PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  2095. BOOLEAN IsParentReadOnly
  2096. )
  2097. {
  2098. #define DescriptionText TEXT("Description")
  2099. #define MaxText TEXT("max")
  2100. #define WmiSizeIsText TEXT("WmiSizeIs")
  2101. #define WriteText TEXT("Write")
  2102. #define WmiDisplayInHexText TEXT("WmiDisplayInHex")
  2103. #define WmiDisplayNameText TEXT("DisplayName")
  2104. HRESULT hr;
  2105. CIMTYPE PropertyType;
  2106. LONG PropertyFlavor;
  2107. VARIANT WriteValue;
  2108. VARIANT DisplayHexValue;
  2109. VARIANT MaxValue;
  2110. VARIANT WmiSizeIsValue;
  2111. BOOLEAN ReturnStatus;
  2112. VARIANT Description;
  2113. VARIANT DisplayName;
  2114. PRANGELISTINFO RangeListInfo;
  2115. PRANGEINFO RangeInfo;
  2116. VARIANT PropertyValue;
  2117. WmiAssert(pIWbemServices != NULL);
  2118. WmiAssert(pIWbemClassObject != NULL);
  2119. WmiAssert(PropertyName != NULL);
  2120. WmiAssert(pIWbemQualifierSet != NULL);
  2121. WmiAssert(DataItemDesc != NULL);
  2122. hr = pIWbemClassObject->Get(PropertyName,
  2123. 0,
  2124. &PropertyValue,
  2125. &PropertyType,
  2126. &PropertyFlavor);
  2127. if (hr == WBEM_S_NO_ERROR)
  2128. {
  2129. DebugPrint((1, "Property %ws (%p) is Type %x\n",
  2130. PropertyName, DataItemDesc, PropertyType));
  2131. //
  2132. // Make sure this is not a system property
  2133. //
  2134. WmiAssert((PropertyFlavor & WBEM_FLAVOR_ORIGIN_SYSTEM) == 0);
  2135. //
  2136. // Gather up the important information about the data item and
  2137. // remember it
  2138. //
  2139. if (WmiBstrToTchar(&DataItemDesc->Name, PropertyName))
  2140. {
  2141. ReturnStatus = TRUE;
  2142. DataItemDesc->DataType = (PropertyType & ~CIM_FLAG_ARRAY);
  2143. //
  2144. // Get Description for data item
  2145. //
  2146. if (WmiGetQualifier(pIWbemQualifierSet,
  2147. DescriptionText,
  2148. VT_BSTR,
  2149. &Description))
  2150. {
  2151. WmiBstrToTchar(&DataItemDesc->Description,
  2152. Description.bstrVal);
  2153. DebugPrint((1, "Property %ws (%p) has description %ws\n",
  2154. PropertyName, DataItemDesc,
  2155. DataItemDesc->Description));
  2156. VariantClear(&Description);
  2157. }
  2158. //
  2159. // Get display name for data item
  2160. //
  2161. if (WmiGetQualifier(pIWbemQualifierSet,
  2162. WmiDisplayNameText,
  2163. VT_BSTR,
  2164. &DisplayName))
  2165. {
  2166. WmiBstrToTchar(&DataItemDesc->DisplayName,
  2167. DisplayName.bstrVal);
  2168. DebugPrint((1, "Property %ws (%p) has display name %ws\n",
  2169. PropertyName, DataItemDesc,
  2170. DataItemDesc->DisplayName));
  2171. VariantClear(&DisplayName);
  2172. }
  2173. //
  2174. // Lets see if this should be displayed in Hex
  2175. //
  2176. DataItemDesc->DisplayInHex = 0;
  2177. if (WmiGetQualifier(pIWbemQualifierSet,
  2178. WmiDisplayInHexText,
  2179. VT_BOOL,
  2180. &DisplayHexValue))
  2181. {
  2182. if (DisplayHexValue.boolVal != 0)
  2183. {
  2184. DataItemDesc->DisplayInHex = 1;
  2185. DebugPrint((1, "Property %ws (%p) is DisplayInHex\n",
  2186. DataItemDesc->Name, DataItemDesc));
  2187. }
  2188. VariantClear(&DisplayHexValue);
  2189. }
  2190. //
  2191. // Lets see if this is read only or not
  2192. //
  2193. DataItemDesc->IsReadOnly = 1;
  2194. if ( (IsParentReadOnly == FALSE) &&
  2195. (WmiGetQualifier(pIWbemQualifierSet,
  2196. WriteText,
  2197. VT_BOOL,
  2198. &WriteValue)) )
  2199. {
  2200. if (WriteValue.boolVal != 0)
  2201. {
  2202. DataItemDesc->IsReadOnly = 0;
  2203. DebugPrint((1, "Property %ws (%p) is Read/Write\n",
  2204. DataItemDesc->Name, DataItemDesc));
  2205. }
  2206. VariantClear(&WriteValue);
  2207. }
  2208. //
  2209. // See if this is an array and if so which kind
  2210. //
  2211. if (PropertyType & CIM_FLAG_ARRAY)
  2212. {
  2213. DataItemDesc->CurrentArrayIndex = 0;
  2214. if (WmiGetQualifier(pIWbemQualifierSet,
  2215. MaxText,
  2216. VT_I4,
  2217. &MaxValue))
  2218. {
  2219. //
  2220. // A fixed length array
  2221. //
  2222. DataItemDesc->IsFixedArray = 1;
  2223. DataItemDesc->ArrayElementCount = MaxValue.lVal;
  2224. } else if (WmiGetQualifier(pIWbemQualifierSet,
  2225. WmiSizeIsText,
  2226. VT_BSTR,
  2227. &WmiSizeIsValue)) {
  2228. //
  2229. // A VL arrays
  2230. //
  2231. DataItemDesc->IsVariableArray = 1;
  2232. } else {
  2233. //
  2234. // Arrays must be fixed or variable length
  2235. //
  2236. ReturnStatus = FALSE;
  2237. }
  2238. }
  2239. if (ReturnStatus)
  2240. {
  2241. //
  2242. // Now we know enough to assign the validation function
  2243. //
  2244. DataItemDesc->DataSize = WmiGetElementSize(DataItemDesc->DataType);
  2245. switch(DataItemDesc->DataType)
  2246. {
  2247. case CIM_SINT8:
  2248. case CIM_UINT8:
  2249. case CIM_SINT16:
  2250. case CIM_UINT16:
  2251. case CIM_SINT32:
  2252. case CIM_UINT32:
  2253. case CIM_SINT64:
  2254. case CIM_UINT64:
  2255. {
  2256. //
  2257. // Numbers can be validated by ranges or value maps
  2258. //
  2259. if (WmiValueMapProperty(pIWbemQualifierSet,
  2260. DataItemDesc))
  2261. {
  2262. //
  2263. // Validation is based upon value map
  2264. //
  2265. DataItemDesc->ValidationFunc = WmiValueMapValidation;
  2266. DebugPrint((1, "Property %ws (%p) is a ValueMap (%p)\n",
  2267. DataItemDesc->Name, DataItemDesc, DataItemDesc->EnumerationInfo));
  2268. } else if (WmiRangeProperty(pIWbemQualifierSet,
  2269. DataItemDesc)) {
  2270. //
  2271. // Validation is based upon ranges
  2272. //
  2273. DataItemDesc->ValidationFunc = WmiRangeValidation;
  2274. DebugPrint((1, "Property %ws (%p) is an explicit range (%p)\n",
  2275. DataItemDesc->Name, DataItemDesc, DataItemDesc->EnumerationInfo));
  2276. } else {
  2277. //
  2278. // No validation specified for number so create
  2279. // a range that corresponds to the minimum and
  2280. // maximum values for the data type
  2281. //
  2282. DataItemDesc->ValidationFunc = WmiRangeValidation;
  2283. RangeListInfo = (PRANGELISTINFO)LocalAlloc(LPTR,
  2284. sizeof(RANGELISTINFO));
  2285. if (RangeListInfo != NULL)
  2286. {
  2287. DebugPrint((1, "Property %ws (%p) is an implicit range (%p)\n",
  2288. DataItemDesc->Name, DataItemDesc, RangeListInfo));
  2289. DataItemDesc->RangeListInfo = RangeListInfo;
  2290. RangeListInfo->Count = 1;
  2291. RangeInfo = &RangeListInfo->Ranges[0];
  2292. RangeInfo->Minimum = 0;
  2293. DataItemDesc->IsSignedValue = 0;
  2294. switch(DataItemDesc->DataType)
  2295. {
  2296. case CIM_SINT8:
  2297. {
  2298. DataItemDesc->IsSignedValue = 1;
  2299. // Fall through
  2300. }
  2301. case CIM_UINT8:
  2302. {
  2303. RangeInfo->Maximum = 0xff;
  2304. break;
  2305. }
  2306. case CIM_SINT16:
  2307. {
  2308. DataItemDesc->IsSignedValue = 1;
  2309. // Fall through
  2310. }
  2311. case CIM_UINT16:
  2312. {
  2313. RangeInfo->Maximum = 0xffff;
  2314. break;
  2315. }
  2316. case CIM_SINT32:
  2317. {
  2318. DataItemDesc->IsSignedValue = 1;
  2319. // Fall through
  2320. }
  2321. case CIM_UINT32:
  2322. {
  2323. RangeInfo->Maximum = 0xffffffff;
  2324. break;
  2325. }
  2326. case CIM_SINT64:
  2327. {
  2328. DataItemDesc->IsSignedValue = 1;
  2329. // Fall through
  2330. }
  2331. case CIM_UINT64:
  2332. {
  2333. RangeInfo->Maximum = 0xffffffffffffffff;
  2334. break;
  2335. }
  2336. }
  2337. } else {
  2338. ReturnStatus = FALSE;
  2339. }
  2340. }
  2341. break;
  2342. }
  2343. case CIM_BOOLEAN:
  2344. {
  2345. ULONG SizeNeeded;
  2346. PENUMERATIONINFO EnumerationInfo;
  2347. //
  2348. // We create a Valuemap with TRUE being 1 and
  2349. // FALSE being 0
  2350. //
  2351. DebugPrint((1, "Property %ws (%p) uses boolean validation\n",
  2352. DataItemDesc->Name, DataItemDesc));
  2353. DataItemDesc->ValidationFunc = WmiValueMapValidation;
  2354. SizeNeeded = sizeof(ENUMERATIONINFO) +
  2355. 2 * sizeof(ENUMERATIONITEM);
  2356. EnumerationInfo = (PENUMERATIONINFO)LocalAlloc(LPTR,
  2357. SizeNeeded);
  2358. if (EnumerationInfo != NULL)
  2359. {
  2360. DataItemDesc->EnumerationInfo = EnumerationInfo;
  2361. EnumerationInfo->Count = 2;
  2362. EnumerationInfo->List[0].Value = 0;
  2363. EnumerationInfo->List[0].Text = WmiDuplicateString(TEXT("FALSE"));
  2364. EnumerationInfo->List[1].Value = 1;
  2365. EnumerationInfo->List[1].Text = WmiDuplicateString(TEXT("TRUE"));
  2366. }
  2367. break;
  2368. }
  2369. case CIM_STRING:
  2370. {
  2371. //
  2372. // String values are also validated simply
  2373. //
  2374. DebugPrint((1, "Property %ws (%p) uses string validation\n",
  2375. DataItemDesc->Name, DataItemDesc));
  2376. DataItemDesc->ValidationFunc = WmiStringValidation;
  2377. break;
  2378. }
  2379. case CIM_DATETIME:
  2380. {
  2381. //
  2382. // Date time values are also validated simply
  2383. //
  2384. DebugPrint((1, "Property %ws (%p) uses datetime validation\n",
  2385. DataItemDesc->Name, DataItemDesc));
  2386. DataItemDesc->ValidationFunc = WmiDateTimeValidation;
  2387. break;
  2388. }
  2389. case CIM_REAL32:
  2390. case CIM_REAL64:
  2391. {
  2392. //
  2393. // Floating point are not supported
  2394. //
  2395. DebugPrint((1, "Property %ws (%p) is floating point - not supported\n",
  2396. DataItemDesc->Name, DataItemDesc));
  2397. ReturnStatus = FALSE;
  2398. break;
  2399. }
  2400. case CIM_OBJECT:
  2401. {
  2402. if (WmiGetEmbeddedDataItem(pIWbemServices,
  2403. pIWbemQualifierSet,
  2404. DataBlockDesc,
  2405. DataItemDesc))
  2406. {
  2407. DataItemDesc->ValidationFunc = WmiEmbeddedValidation;
  2408. } else {
  2409. ReturnStatus = FALSE;
  2410. }
  2411. break;
  2412. }
  2413. default:
  2414. {
  2415. DebugPrint((1, "Property %ws (%p) is unknoen type %d\n",
  2416. DataItemDesc->Name, DataItemDesc,
  2417. DataItemDesc->DataType));
  2418. ReturnStatus = FALSE;
  2419. break;
  2420. }
  2421. }
  2422. }
  2423. } else {
  2424. ReturnStatus = FALSE;
  2425. }
  2426. VariantClear(&PropertyValue);
  2427. } else {
  2428. ReturnStatus = FALSE;
  2429. }
  2430. return(ReturnStatus);
  2431. }
  2432. #if DBG
  2433. void WmiDumpQualifiers(
  2434. IWbemQualifierSet *pIWbemQualiferSet
  2435. )
  2436. {
  2437. HRESULT hr;
  2438. LONG UBound, LBound, Count, i;
  2439. BSTR s;
  2440. SAFEARRAY *Quals = NULL;
  2441. WmiAssert(pIWbemQualiferSet != NULL);
  2442. hr = pIWbemQualiferSet->GetNames(0,
  2443. &Quals);
  2444. hr = SafeArrayGetLBound(Quals, 1, &LBound);
  2445. hr = SafeArrayGetUBound(Quals, 1, &UBound);
  2446. Count = UBound - LBound + 1;
  2447. for (i = LBound; i < Count; i++)
  2448. {
  2449. hr = SafeArrayGetElement(Quals,
  2450. &i,
  2451. &s);
  2452. DebugPrint((1, "qual - %ws\n", s));
  2453. }
  2454. SafeArrayDestroy(Quals);
  2455. }
  2456. #endif
  2457. BOOLEAN WmiGetAllDataItems(
  2458. IWbemServices *pIWbemServices,
  2459. IWbemClassObject *pIWbemClassObject,
  2460. SAFEARRAY *Names,
  2461. LONG LBound,
  2462. LONG Count,
  2463. PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  2464. BOOLEAN IsParentReadOnly
  2465. )
  2466. {
  2467. #define WmiDataIdText TEXT("WmiDataId")
  2468. BOOLEAN ReturnStatus = TRUE;
  2469. HRESULT hr;
  2470. BSTR s;
  2471. VARIANT DataIdIndex;
  2472. LONG Index;
  2473. LONG i;
  2474. BSTR PropertyName;
  2475. CIMTYPE PropertyType;
  2476. VARIANT PropertyValue;
  2477. LONG PropertyFlavor;
  2478. PDATA_ITEM_DESCRIPTION DataItemDesc;
  2479. IWbemQualifierSet *pIWbemQualifierSet;
  2480. WmiAssert(pIWbemServices != NULL);
  2481. WmiAssert(pIWbemClassObject != NULL);
  2482. WmiAssert(Names != NULL);
  2483. WmiAssert(DataBlockDesc != NULL);
  2484. //
  2485. // Loop over all of the WmiDataItem property
  2486. for (i = 0; (i < Count) && ReturnStatus; i++)
  2487. {
  2488. //
  2489. // Get the name of the first property
  2490. //
  2491. PropertyName = NULL;
  2492. Index = i + LBound;
  2493. hr = SafeArrayGetElement(Names,
  2494. &Index,
  2495. &PropertyName);
  2496. if (hr == WBEM_S_NO_ERROR)
  2497. {
  2498. //
  2499. // Now lets get the qualifier list so we can determine
  2500. // interesting things about the property
  2501. //
  2502. hr = pIWbemClassObject->GetPropertyQualifierSet(PropertyName,
  2503. &pIWbemQualifierSet);
  2504. if (hr == WBEM_S_NO_ERROR)
  2505. {
  2506. if (WmiGetQualifier(pIWbemQualifierSet,
  2507. WmiDataIdText,
  2508. VT_I4,
  2509. &DataIdIndex))
  2510. {
  2511. WmiAssert(DataIdIndex.vt == VT_I4);
  2512. Index = DataIdIndex.lVal - 1;
  2513. VariantClear(&DataIdIndex);
  2514. DataItemDesc = &DataBlockDesc->DataItems[Index];
  2515. DebugPrint((1, "Property %ws (%p) has WmiDataId %d\n",
  2516. PropertyName, DataItemDesc, Index));
  2517. ReturnStatus = WmiGetDataItem(pIWbemServices,
  2518. pIWbemClassObject,
  2519. PropertyName,
  2520. pIWbemQualifierSet,
  2521. DataItemDesc,
  2522. DataBlockDesc,
  2523. IsParentReadOnly);
  2524. #if DBG
  2525. if (! ReturnStatus)
  2526. {
  2527. DebugPrint((1, "Property %ws (%p) failed WmiGetDataItem\n",
  2528. PropertyName, DataItemDesc));
  2529. }
  2530. #endif
  2531. } else {
  2532. //
  2533. // Since our IWbemClassObject->GetNames call specified
  2534. // only retrieve those properties with WmiDataId qualifier
  2535. // we expect that it will be found
  2536. //
  2537. WmiAssert(FALSE);
  2538. }
  2539. pIWbemQualifierSet->Release();
  2540. } else {
  2541. ReturnStatus = FALSE;
  2542. }
  2543. } else {
  2544. ReturnStatus = FALSE;
  2545. }
  2546. SysFreeString(PropertyName);
  2547. }
  2548. return(ReturnStatus);
  2549. }
  2550. BOOLEAN WmiGetDataBlockDesc(
  2551. IN IWbemServices *pIWbemServices,
  2552. IN IWbemClassObject *pIWbemClassObject,
  2553. OUT PDATA_BLOCK_DESCRIPTION *DBD,
  2554. IN PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc,
  2555. IN BOOLEAN IsParentReadOnly
  2556. )
  2557. {
  2558. HRESULT hr;
  2559. BSTR s;
  2560. SAFEARRAY *Names = NULL;
  2561. BOOLEAN ReturnStatus = FALSE;
  2562. LONG LBound, UBound, Count;
  2563. PDATA_BLOCK_DESCRIPTION DataBlockDesc;
  2564. VARIANT DisplayName, Description;
  2565. IWbemQualifierSet *pIWbemQualifierSet;
  2566. ULONG SizeNeeded;
  2567. WmiAssert(pIWbemServices != NULL);
  2568. WmiAssert(pIWbemClassObject != NULL);
  2569. WmiAssert(DBD != NULL);
  2570. *DBD = NULL;
  2571. s = SysAllocString(WmiDataIdText);
  2572. if (s != NULL)
  2573. {
  2574. hr = pIWbemClassObject->GetNames(s,
  2575. WBEM_FLAG_ONLY_IF_TRUE | WBEM_FLAG_NONSYSTEM_ONLY,
  2576. NULL,
  2577. &Names);
  2578. if (hr == WBEM_S_NO_ERROR)
  2579. {
  2580. #if DBG
  2581. //
  2582. // Verify that the safe array of names has 1 dimension and is
  2583. // an array of BSTR.
  2584. //
  2585. {
  2586. HRESULT hr;
  2587. VARTYPE vt;
  2588. WmiAssert(SafeArrayGetDim(Names) == 1);
  2589. hr = SafeArrayGetVartype(Names, &vt);
  2590. WmiAssert( (hr == WBEM_S_NO_ERROR) &&
  2591. (vt == VT_BSTR) );
  2592. }
  2593. #endif
  2594. hr = SafeArrayGetLBound(Names, 1, &LBound);
  2595. if (hr == WBEM_S_NO_ERROR)
  2596. {
  2597. hr = SafeArrayGetUBound(Names, 1, &UBound);
  2598. if (hr == WBEM_S_NO_ERROR)
  2599. {
  2600. Count = (UBound - LBound) + 1;
  2601. DebugPrint((1, "WMIPROP: %d properties found for class\n",
  2602. Count));
  2603. if (Count > 0)
  2604. {
  2605. SizeNeeded = sizeof(DATA_BLOCK_DESCRIPTION) +
  2606. Count * sizeof(DATA_ITEM_DESCRIPTION);
  2607. DataBlockDesc = (PDATA_BLOCK_DESCRIPTION)LocalAlloc(LPTR,
  2608. SizeNeeded);
  2609. if (DataBlockDesc != NULL)
  2610. {
  2611. DataBlockDesc->ParentDataBlockDesc = ParentDataBlockDesc;
  2612. if (WmiGetAllDataItems(pIWbemServices,
  2613. pIWbemClassObject,
  2614. Names,
  2615. LBound,
  2616. Count,
  2617. DataBlockDesc,
  2618. IsParentReadOnly))
  2619. {
  2620. DataBlockDesc->DataItemCount = Count;
  2621. DataBlockDesc->CurrentDataItem = 0;
  2622. //
  2623. // Get display name and description for class
  2624. //
  2625. pIWbemQualifierSet = NULL;
  2626. hr = pIWbemClassObject->GetQualifierSet(
  2627. &pIWbemQualifierSet);
  2628. if (hr == WBEM_S_NO_ERROR)
  2629. {
  2630. if (WmiGetQualifier(pIWbemQualifierSet,
  2631. WmiDisplayNameText,
  2632. VT_BSTR,
  2633. &DisplayName))
  2634. {
  2635. WmiBstrToTchar(&DataBlockDesc->DisplayName,
  2636. DisplayName.bstrVal);
  2637. VariantClear(&DisplayName);
  2638. }
  2639. if (WmiGetQualifier(pIWbemQualifierSet,
  2640. DescriptionText,
  2641. VT_BSTR,
  2642. &Description))
  2643. {
  2644. WmiBstrToTchar(&DataBlockDesc->Description,
  2645. Description.bstrVal);
  2646. VariantClear(&Description);
  2647. }
  2648. pIWbemQualifierSet->Release();
  2649. } else {
  2650. DebugPrint((1, "WMIPROP: Error %x getting qualifier set from %ws\n",
  2651. hr, s));
  2652. }
  2653. *DBD = DataBlockDesc;
  2654. ReturnStatus = TRUE;
  2655. } else {
  2656. LocalFree(DataBlockDesc);
  2657. }
  2658. }
  2659. } else {
  2660. ReturnStatus = FALSE;
  2661. }
  2662. }
  2663. }
  2664. SafeArrayDestroy(Names);
  2665. }
  2666. SysFreeString(s);
  2667. }
  2668. return(ReturnStatus);
  2669. }
  2670. BOOLEAN WmiBuildConfigClass(
  2671. IN PTCHAR MachineName,
  2672. IN IWbemServices *pIWbemServices,
  2673. IN PTCHAR ClassName,
  2674. IN PTCHAR InstanceName,
  2675. OUT PCONFIGCLASS ConfigClass
  2676. )
  2677. /*+++
  2678. Routine Description:
  2679. This routine will try to get the wbem object corresponding to the
  2680. ClassName and InstanceName and then query the class to gather info
  2681. needed to fill the ConfigClass.
  2682. Arguments:
  2683. ClassName is the name of the class
  2684. InstanceName is the name of the instance
  2685. ConfigClass
  2686. Return Value:
  2687. TRUE if successful else FALSE
  2688. ---*/
  2689. {
  2690. #define RelPathText1 TEXT(".InstanceName=\"")
  2691. #define RelPathText2 TEXT("\"")
  2692. ULONG RelPathSize;
  2693. PTCHAR RelPath;
  2694. HRESULT hr;
  2695. IWbemClassObject *pIWbemClassObject, *pInstance;
  2696. ULONG SizeNeeded, i;
  2697. BOOLEAN ReturnStatus = FALSE;
  2698. BSTR sRelPath, sClassName;
  2699. WmiAssert(pIWbemServices != NULL);
  2700. WmiAssert(ClassName != NULL);
  2701. WmiAssert(InstanceName != NULL);
  2702. WmiAssert(ConfigClass != NULL);
  2703. if (MachineName != NULL)
  2704. {
  2705. RelPathSize = (_tcslen(MachineName) + 1) * sizeof(TCHAR);
  2706. ConfigClass->MachineName = (PTCHAR)LocalAlloc(LPTR, RelPathSize);
  2707. if (ConfigClass->MachineName != NULL)
  2708. {
  2709. _tcscpy(ConfigClass->MachineName, MachineName);
  2710. } else {
  2711. return(FALSE);
  2712. }
  2713. }
  2714. //
  2715. // Build up the relative path to the object
  2716. //
  2717. RelPathSize =
  2718. (_tcslen(ClassName) * sizeof(TCHAR)) +
  2719. sizeof(RelPathText1) +
  2720. (_tcslen(InstanceName) * sizeof(TCHAR)) +
  2721. sizeof(RelPathText2) +
  2722. sizeof(TCHAR);
  2723. RelPath = (PTCHAR)LocalAlloc(LPTR, RelPathSize);
  2724. if (RelPath != NULL)
  2725. {
  2726. _tcscpy(RelPath, ClassName);
  2727. _tcscat(RelPath, RelPathText1);
  2728. _tcscat(RelPath, InstanceName);
  2729. _tcscat(RelPath, RelPathText2);
  2730. ConfigClass->RelPath = RelPath;
  2731. //
  2732. // CONSIDER: Use semisynchronous call
  2733. //
  2734. sRelPath = SysAllocString(RelPath);
  2735. if (sRelPath != NULL)
  2736. {
  2737. pInstance = NULL;
  2738. hr = pIWbemServices->GetObject(sRelPath,
  2739. WBEM_FLAG_USE_AMENDED_QUALIFIERS,
  2740. NULL,
  2741. &pInstance,
  2742. NULL);
  2743. if (hr == WBEM_S_NO_ERROR)
  2744. {
  2745. //
  2746. // Now we know that the instance of the class exists so
  2747. // we need to get a class object for the class only. We
  2748. // need to do this since the instance class object does
  2749. // not have any of the qualifiers, but the class only
  2750. // class object does.
  2751. //
  2752. sClassName = SysAllocString(ClassName);
  2753. if (sClassName != NULL)
  2754. {
  2755. pIWbemClassObject= NULL;
  2756. hr = pIWbemServices->GetObject(sClassName,
  2757. WBEM_FLAG_USE_AMENDED_QUALIFIERS,
  2758. NULL,
  2759. &pIWbemClassObject,
  2760. NULL);
  2761. if (hr == WBEM_S_NO_ERROR)
  2762. {
  2763. //
  2764. // Go and get the data block description for
  2765. // the class. Note that if we are on a remote
  2766. // machine we force the entire data block to be
  2767. // read only so that it is consistent with the
  2768. // rest of device manager
  2769. //
  2770. if (WmiGetDataBlockDesc(pIWbemServices,
  2771. pIWbemClassObject,
  2772. &ConfigClass->DataBlockDesc,
  2773. NULL,
  2774. (MachineName != NULL) ?
  2775. TRUE :
  2776. FALSE))
  2777. {
  2778. WmiBstrToTchar(&ConfigClass->DataBlockDesc->Name,
  2779. sClassName);
  2780. ReturnStatus = TRUE;
  2781. }
  2782. pIWbemClassObject->Release();
  2783. } else {
  2784. DebugPrint((1, "WMIPROP: Error %x getting %ws class \n", hr, sClassName));
  2785. }
  2786. SysFreeString(sClassName);
  2787. }
  2788. //
  2789. // we have to release the class object to the instance of the
  2790. // class. We cannot hang onto the interface since it is
  2791. // only valid in this thread. We will again get a new
  2792. // instnace interface later in the window message thread
  2793. //
  2794. pInstance->Release();
  2795. } else {
  2796. DebugPrint((1, "WMIPROP: Error %x getting %ws class instance\n", hr, sRelPath));
  2797. }
  2798. }
  2799. SysFreeString(sRelPath);
  2800. }
  2801. return(ReturnStatus);
  2802. }
  2803. void WmiCleanDataItemDescData(
  2804. PDATA_ITEM_DESCRIPTION DataItemDesc
  2805. )
  2806. {
  2807. ULONG j;
  2808. if ((DataItemDesc->IsVariableArray == 1) ||
  2809. (DataItemDesc->IsFixedArray == 1))
  2810. {
  2811. if (DataItemDesc->ArrayPtr != NULL)
  2812. {
  2813. if ((DataItemDesc->DataType == CIM_STRING) ||
  2814. (DataItemDesc->DataType == CIM_DATETIME))
  2815. {
  2816. for (j = 0; j < DataItemDesc->ArrayElementCount; j++)
  2817. {
  2818. if (DataItemDesc->StringArray[j] != NULL)
  2819. {
  2820. LocalFree(DataItemDesc->StringArray[j]);
  2821. DataItemDesc->StringArray[j] = NULL;
  2822. }
  2823. }
  2824. } else if (DataItemDesc->DataType == CIM_OBJECT) {
  2825. for (j = 0; j < DataItemDesc->ArrayElementCount; j++)
  2826. {
  2827. if (DataItemDesc->StringArray[j] != NULL)
  2828. {
  2829. DataItemDesc->pIWbemClassObjectArray[j]->Release();
  2830. DataItemDesc->pIWbemClassObjectArray[j] = NULL;
  2831. }
  2832. }
  2833. }
  2834. LocalFree(DataItemDesc->ArrayPtr);
  2835. DataItemDesc->ArrayPtr = NULL;
  2836. }
  2837. } else {
  2838. if ((DataItemDesc->DataType == CIM_STRING) ||
  2839. (DataItemDesc->DataType == CIM_DATETIME))
  2840. {
  2841. LocalFree(DataItemDesc->String);
  2842. DataItemDesc->String = NULL;
  2843. }
  2844. if (DataItemDesc->DataType == CIM_OBJECT)
  2845. {
  2846. if (DataItemDesc->pIWbemClassObject != NULL)
  2847. {
  2848. DataItemDesc->pIWbemClassObject->Release();
  2849. DataItemDesc->pIWbemClassObject = NULL;
  2850. }
  2851. }
  2852. }
  2853. }
  2854. void WmiFreeDataBlockDesc(
  2855. PDATA_BLOCK_DESCRIPTION DataBlockDesc
  2856. )
  2857. /*+++
  2858. Routine Description:
  2859. This routine will free all resources used by a data block description
  2860. Arguments:
  2861. Return Value:
  2862. ---*/
  2863. {
  2864. ULONG i,j;
  2865. PDATA_ITEM_DESCRIPTION DataItemDesc;
  2866. PENUMERATIONINFO EnumerationInfo;
  2867. PRANGELISTINFO RangeListInfo;
  2868. if (DataBlockDesc != NULL)
  2869. {
  2870. //
  2871. // This is freed when walking the data item desc looking for
  2872. // embedded classes
  2873. //
  2874. DataBlockDesc->ParentDataBlockDesc = NULL;
  2875. if (DataBlockDesc->Name != NULL)
  2876. {
  2877. LocalFree(DataBlockDesc->Name);
  2878. DataBlockDesc->Name = NULL;
  2879. }
  2880. if (DataBlockDesc->DisplayName != NULL)
  2881. {
  2882. LocalFree(DataBlockDesc->DisplayName);
  2883. DataBlockDesc->DisplayName = NULL;
  2884. }
  2885. if (DataBlockDesc->Description != NULL)
  2886. {
  2887. LocalFree(DataBlockDesc->Description);
  2888. DataBlockDesc->Description = NULL;
  2889. }
  2890. if (DataBlockDesc->pInstance != NULL)
  2891. {
  2892. DataBlockDesc->pInstance->Release();
  2893. DataBlockDesc->pInstance = NULL;
  2894. }
  2895. for (i = 0; i < DataBlockDesc->DataItemCount; i++)
  2896. {
  2897. DataItemDesc = &DataBlockDesc->DataItems[i];
  2898. DebugPrint((1, "WMIPROP: Freeing %ws (%p) index %d\n",
  2899. DataItemDesc->Name,
  2900. DataItemDesc,
  2901. i));
  2902. WmiCleanDataItemDescData(DataItemDesc);
  2903. if (DataItemDesc->Name != NULL)
  2904. {
  2905. LocalFree(DataItemDesc->Name);
  2906. DataItemDesc->Name = NULL;
  2907. }
  2908. if (DataItemDesc->DisplayName != NULL)
  2909. {
  2910. LocalFree(DataItemDesc->DisplayName);
  2911. DataItemDesc->DisplayName = NULL;
  2912. }
  2913. if (DataItemDesc->Description != NULL)
  2914. {
  2915. LocalFree(DataItemDesc->Description);
  2916. DataItemDesc->Description = NULL;
  2917. }
  2918. if ((DataItemDesc->ValidationFunc == WmiValueMapValidation) &&
  2919. (DataItemDesc->EnumerationInfo))
  2920. {
  2921. EnumerationInfo = DataItemDesc->EnumerationInfo;
  2922. for (j = 0; j < EnumerationInfo->Count; j++)
  2923. {
  2924. if (EnumerationInfo->List[j].Text != NULL)
  2925. {
  2926. LocalFree(EnumerationInfo->List[j].Text);
  2927. EnumerationInfo->List[j].Text = NULL;
  2928. }
  2929. }
  2930. LocalFree(EnumerationInfo);
  2931. DataItemDesc->EnumerationInfo = NULL;
  2932. }
  2933. if ((DataItemDesc->ValidationFunc == WmiRangeValidation) &&
  2934. (DataItemDesc->RangeListInfo != NULL))
  2935. {
  2936. LocalFree(DataItemDesc->RangeListInfo);
  2937. DataItemDesc->RangeListInfo = NULL;
  2938. }
  2939. if (DataItemDesc->ValidationFunc == WmiEmbeddedValidation)
  2940. {
  2941. if (DataItemDesc->DataBlockDesc != NULL)
  2942. {
  2943. WmiFreeDataBlockDesc(DataItemDesc->DataBlockDesc);
  2944. DataItemDesc->DataBlockDesc = NULL;
  2945. }
  2946. }
  2947. }
  2948. LocalFree(DataBlockDesc);
  2949. }
  2950. }
  2951. void WmiFreePageInfo(
  2952. PPAGE_INFO PageInfo
  2953. )
  2954. /*+++
  2955. Routine Description:
  2956. This routine will free all resources used by a page info
  2957. Arguments:
  2958. Return Value:
  2959. ---*/
  2960. {
  2961. ULONG i;
  2962. PCONFIGCLASS ConfigClass;
  2963. WmiAssert(PageInfo != NULL);
  2964. if (PageInfo->hKeyDev != (HKEY) INVALID_HANDLE_VALUE)
  2965. {
  2966. RegCloseKey(PageInfo->hKeyDev);
  2967. PageInfo->hKeyDev = (HKEY) INVALID_HANDLE_VALUE;
  2968. }
  2969. ConfigClass = &PageInfo->ConfigClass;
  2970. if (ConfigClass->RelPath != NULL)
  2971. {
  2972. LocalFree(ConfigClass->RelPath);
  2973. ConfigClass->RelPath = NULL;
  2974. }
  2975. if (ConfigClass->pIWbemServices != NULL)
  2976. {
  2977. ConfigClass->pIWbemServices->Release();
  2978. ConfigClass->pIWbemServices = NULL;
  2979. }
  2980. if (ConfigClass->MachineName != NULL)
  2981. {
  2982. LocalFree(ConfigClass->MachineName);
  2983. ConfigClass->MachineName = NULL;
  2984. }
  2985. WmiFreeDataBlockDesc(ConfigClass->DataBlockDesc);
  2986. LocalFree(PageInfo);
  2987. }
  2988. PPAGE_INFO WmiCreatePageInfo(
  2989. IN PTCHAR MachineName,
  2990. IN IWbemServices *pIWbemServices,
  2991. IN PTCHAR ClassName,
  2992. IN PTCHAR InstanceName,
  2993. IN HDEVINFO deviceInfoSet,
  2994. IN PSP_DEVINFO_DATA deviceInfoData
  2995. )
  2996. /*+++
  2997. Routine Description:
  2998. This routine will create a PAGE_INFO structure that is used to describe
  2999. property pages.
  3000. Arguments:
  3001. Return Value:
  3002. ---*/
  3003. {
  3004. PPAGE_INFO PageInfo;
  3005. BOOLEAN ReturnStatus;
  3006. HKEY hKeyDev;
  3007. WmiAssert(pIWbemServices != NULL);
  3008. WmiAssert(ClassName != NULL);
  3009. WmiAssert(InstanceName != NULL);
  3010. WmiAssert(deviceInfoSet != NULL);
  3011. WmiAssert(deviceInfoData != NULL);
  3012. //
  3013. // Allocate room to store data for the property page
  3014. //
  3015. PageInfo = (PPAGE_INFO)LocalAlloc(LPTR, sizeof(PAGE_INFO));
  3016. if (PageInfo == NULL) {
  3017. return(NULL);
  3018. }
  3019. hKeyDev = SetupDiCreateDevRegKey(deviceInfoSet,
  3020. deviceInfoData,
  3021. DICS_FLAG_GLOBAL,
  3022. 0,
  3023. DIREG_DEV,
  3024. NULL,
  3025. NULL);
  3026. PageInfo->hKeyDev = hKeyDev;
  3027. PageInfo->deviceInfoSet = deviceInfoSet;
  3028. PageInfo->deviceInfoData = deviceInfoData;
  3029. ReturnStatus = WmiBuildConfigClass(MachineName,
  3030. pIWbemServices,
  3031. ClassName,
  3032. InstanceName,
  3033. &PageInfo->ConfigClass);
  3034. if (! ReturnStatus)
  3035. {
  3036. WmiFreePageInfo(PageInfo);
  3037. PageInfo = NULL;
  3038. }
  3039. return(PageInfo);
  3040. }
  3041. void
  3042. WmiDestroyPageInfo(PPAGE_INFO * ppPageInfo)
  3043. {
  3044. PPAGE_INFO ppi = *ppPageInfo;
  3045. WmiFreePageInfo(ppi);
  3046. *ppPageInfo = NULL;
  3047. }
  3048. HPROPSHEETPAGE
  3049. WmiCreatePropertyPage(PROPSHEETPAGE * ppsp,
  3050. PPAGE_INFO ppi,
  3051. PTCHAR ClassName)
  3052. {
  3053. WmiAssert(ppi != NULL);
  3054. WmiAssert(ppsp != NULL);
  3055. WmiAssert(ClassName != NULL);
  3056. //
  3057. // Add the Port Settings property page
  3058. //
  3059. ppsp->dwSize = sizeof(PROPSHEETPAGE);
  3060. ppsp->dwFlags = PSP_USECALLBACK | PSP_USETITLE; // | PSP_HASHELP;
  3061. ppsp->hInstance = g_hInstance;
  3062. ppsp->pszTemplate = MAKEINTRESOURCE(ID_WMI_PROPPAGE);
  3063. ppsp->pszTitle = ClassName;
  3064. //
  3065. // following points to the dlg window proc
  3066. //
  3067. ppsp->pfnDlgProc = WmiDlgProc;
  3068. ppsp->lParam = (LPARAM) ppi;
  3069. //
  3070. // Following points to the control callback of the dlg window proc.
  3071. // The callback gets called before creation/after destruction of the page
  3072. //
  3073. ppsp->pfnCallback = WmiDlgCallback;
  3074. //
  3075. // Allocate the actual page
  3076. //
  3077. return CreatePropertySheetPage(ppsp);
  3078. }
  3079. BOOLEAN WmiIsDuplicateClass(
  3080. PTCHAR ClassName,
  3081. PTCHAR ClassList,
  3082. PTCHAR ClassListEnd
  3083. )
  3084. {
  3085. BOOLEAN Found;
  3086. ULONG NameLen;
  3087. Found = FALSE;
  3088. NameLen = _tcslen(ClassName);
  3089. while (ClassList < ClassListEnd)
  3090. {
  3091. if (_tcsnicmp(ClassList, ClassName, NameLen) == 0)
  3092. {
  3093. //
  3094. // We found a duplicate name
  3095. //
  3096. return(TRUE);
  3097. }
  3098. while (*ClassList != ',')
  3099. {
  3100. if (ClassList >= ClassListEnd)
  3101. {
  3102. return(FALSE);
  3103. }
  3104. ClassList++;
  3105. }
  3106. ClassList++;
  3107. }
  3108. return(Found);
  3109. }
  3110. PTCHAR WmiGetNextClass(
  3111. PTCHAR *ClassList
  3112. )
  3113. {
  3114. PTCHAR s = *ClassList;
  3115. PTCHAR Class, ClassName;
  3116. ULONG Len;
  3117. //
  3118. // skip over any white space
  3119. //
  3120. while (IsWhiteSpace(*s) && (*s != 0))
  3121. {
  3122. s++;
  3123. }
  3124. //
  3125. // Search for separator or end of string
  3126. //
  3127. ClassName = s;
  3128. Len = 0;
  3129. while ((*s != TEXT(',')) && (*s != 0))
  3130. {
  3131. s++;
  3132. Len++;
  3133. }
  3134. if (*s != 0)
  3135. {
  3136. //
  3137. // If we have a string then alloc and copy it over
  3138. //
  3139. Class = (PTCHAR)LocalAlloc(LPTR, (Len+1)*sizeof(TCHAR));
  3140. if (Class != NULL)
  3141. {
  3142. _tcsncpy(Class, ClassName, Len);
  3143. DebugPrint((1,"WMIPROP: Class %ws is in list\n", Class));
  3144. }
  3145. s++;
  3146. } else {
  3147. //
  3148. // End of string, all done
  3149. //
  3150. Class = NULL;
  3151. }
  3152. *ClassList = s;
  3153. return(Class);
  3154. }
  3155. BOOL
  3156. WmiPropPageProvider(HDEVINFO deviceInfoSet,
  3157. PSP_DEVINFO_DATA deviceInfoData,
  3158. PSP_ADDPROPERTYPAGE_DATA AddPPageData,
  3159. PTCHAR MachineName,
  3160. HANDLE MachineHandle
  3161. )
  3162. {
  3163. #define WmiConfigClassesText TEXT("WmiConfigClasses")
  3164. PSP_PROPSHEETPAGE_REQUEST ppr;
  3165. PROPSHEETPAGE psp;
  3166. HPROPSHEETPAGE hpsp;
  3167. TCHAR ClassListStatic[MAX_PATH];
  3168. TCHAR *ClassList, *DeviceList;
  3169. ULONG Status, Size, ClassListSize, DeviceListSize;
  3170. ULONG RegType;
  3171. HKEY hKeyDev, hKeyClass;
  3172. BOOLEAN PageAdded;
  3173. PPAGE_INFO ppi;
  3174. TCHAR *s;
  3175. IWbemServices *pIWbemServices;
  3176. PTCHAR InstanceName;
  3177. PTCHAR ClassName;
  3178. ULONG PageIndex;
  3179. PUCHAR Ptr;
  3180. CHAR ss[MAX_PATH];
  3181. PTCHAR ClassListEnd;
  3182. DebugPrint((1, "WMI: Enter WmiPropPageProvider(%p, %p, %p) \n",
  3183. deviceInfoSet,
  3184. deviceInfoData,
  3185. AddPPageData));
  3186. WmiAssert(deviceInfoSet != NULL);
  3187. WmiAssert(deviceInfoData != NULL);
  3188. PageAdded = FALSE;
  3189. //
  3190. // Get List of classes from registry. It should be in the
  3191. // WmiConfigClasses value under class specific key
  3192. // HKLM\CurrentControlSet\Control\CLASS\<ClassGuid>
  3193. // key.
  3194. //
  3195. ClassList = ClassListStatic;
  3196. Size = sizeof(ClassListStatic);
  3197. *ClassList = 0;
  3198. hKeyClass = SetupDiOpenClassRegKeyEx(&deviceInfoData->ClassGuid,
  3199. KEY_READ,
  3200. DIOCR_INSTALLER,
  3201. MachineName,
  3202. NULL);
  3203. if (hKeyClass != NULL)
  3204. {
  3205. Status = RegQueryValueEx(hKeyClass,
  3206. WmiConfigClassesText,
  3207. NULL,
  3208. &RegType,
  3209. (PUCHAR)ClassList,
  3210. &Size);
  3211. if (Status == ERROR_MORE_DATA)
  3212. {
  3213. //
  3214. // The class list is bigger than we though so allocate room
  3215. // for the bigger class list and extra room for the device
  3216. // list
  3217. //
  3218. Size = 2*(Size + sizeof(WCHAR));
  3219. ClassList = (PTCHAR)LocalAlloc(LPTR, Size);
  3220. if (ClassList != NULL)
  3221. {
  3222. Status = RegQueryValueEx(hKeyClass,
  3223. WmiConfigClassesText,
  3224. NULL,
  3225. &RegType,
  3226. (PUCHAR)ClassList,
  3227. &Size);
  3228. } else {
  3229. //
  3230. // We couldn't alloc memory for the class list so we
  3231. // forget about it
  3232. //
  3233. Status = ERROR_NOT_ENOUGH_MEMORY;
  3234. ClassList = ClassListStatic;
  3235. Size = sizeof(ClassListStatic);
  3236. *ClassList = 0;
  3237. }
  3238. }
  3239. RegCloseKey(hKeyClass);
  3240. } else {
  3241. Status = ERROR_INVALID_PARAMETER;
  3242. DebugPrint((1, "WMIPROP: Could not open class key for %s --> %d\n",
  3243. WmiGuidToString(ss, &deviceInfoData->ClassGuid),
  3244. GetLastError()));
  3245. }
  3246. //
  3247. // Compute size and location of device list
  3248. //
  3249. if ((Status == ERROR_SUCCESS) && (RegType == REG_SZ))
  3250. {
  3251. if (*ClassList != 0)
  3252. {
  3253. //
  3254. // If there is a class be sure to add a , at the end to
  3255. // aid in parsing
  3256. //
  3257. _tcscat(ClassList, TEXT(","));
  3258. }
  3259. //
  3260. // Compute location to append the device class list
  3261. //
  3262. ClassListSize = _tcslen(ClassList) * sizeof(TCHAR);
  3263. DeviceList = (PTCHAR)((PUCHAR)ClassList + ClassListSize);
  3264. WmiAssert(*DeviceList == 0);
  3265. DeviceListSize = Size - ClassListSize;
  3266. } else {
  3267. ClassListSize = 0;
  3268. DeviceList = ClassList;
  3269. DeviceListSize = Size;
  3270. DebugPrint((1, "WMIPROP: Query for class list in class key %s failed %d\n",
  3271. WmiGuidToString(ss, &deviceInfoData->ClassGuid),
  3272. Status));
  3273. }
  3274. //
  3275. // Get List of classes from registry. It should be in the
  3276. // WmiConfigClasses value under device specific key
  3277. // HKLM\CurrentControlSet\Control\CLASS\<ClassGuid>\<inst id>
  3278. // key.
  3279. //
  3280. hKeyDev = SetupDiCreateDevRegKey(deviceInfoSet,
  3281. deviceInfoData,
  3282. DICS_FLAG_GLOBAL,
  3283. 0,
  3284. DIREG_DRV,
  3285. NULL,
  3286. NULL);
  3287. if (hKeyDev != (HKEY)INVALID_HANDLE_VALUE)
  3288. {
  3289. Size = DeviceListSize;
  3290. Status = RegQueryValueEx(hKeyDev,
  3291. WmiConfigClassesText,
  3292. NULL,
  3293. &RegType,
  3294. (PUCHAR)DeviceList,
  3295. &Size);
  3296. if (Status == ERROR_MORE_DATA)
  3297. {
  3298. //
  3299. // Not enough room for the device list so allocate enough
  3300. // memory for the class and device lists combined and copy
  3301. // the class list into the new buffer
  3302. //
  3303. Ptr = (PUCHAR)LocalAlloc(LPTR, Size+ClassListSize);
  3304. if (Ptr != NULL)
  3305. {
  3306. memcpy(Ptr, ClassList, ClassListSize);
  3307. if (ClassList != ClassListStatic)
  3308. {
  3309. LocalFree(ClassList);
  3310. }
  3311. ClassList = (PTCHAR)Ptr;
  3312. DeviceList = (PTCHAR)(Ptr + ClassListSize);
  3313. WmiAssert(*DeviceList == 0);
  3314. Status = RegQueryValueEx(hKeyDev,
  3315. WmiConfigClassesText,
  3316. NULL,
  3317. &RegType,
  3318. (PUCHAR)DeviceList,
  3319. &Size);
  3320. } else {
  3321. Status = ERROR_NOT_ENOUGH_MEMORY;
  3322. }
  3323. }
  3324. RegCloseKey(hKeyDev);
  3325. if ((Status != ERROR_SUCCESS) || (RegType != REG_SZ))
  3326. {
  3327. *DeviceList = 0;
  3328. DebugPrint((1, "WMIPROP: Query for class list in class key %s failed %d\n",
  3329. WmiGuidToString(ss, &deviceInfoData->ClassGuid),
  3330. Status));
  3331. }
  3332. }
  3333. if (*ClassList != 0)
  3334. {
  3335. //
  3336. // Establish connection to WBEM and obtain information
  3337. // about the class whose properties are being acted upon
  3338. //
  3339. if (WmiConnectToWbem(MachineName, &pIWbemServices))
  3340. {
  3341. WmiAssert(pIWbemServices != NULL);
  3342. //
  3343. // Get WMI InstanceName for device
  3344. //
  3345. InstanceName = WmiGetDeviceInstanceName(deviceInfoSet,
  3346. deviceInfoData,
  3347. MachineHandle);
  3348. if (InstanceName != NULL)
  3349. {
  3350. //
  3351. // Loop over all classes specified and create property
  3352. // page for each one
  3353. //
  3354. DebugPrint((1, "WMIPROP: Setup propsheets for %ws for classlist %ws\n",
  3355. InstanceName,
  3356. ClassList));
  3357. s = ClassList;
  3358. do
  3359. {
  3360. ClassListEnd = s;
  3361. ClassName = WmiGetNextClass(&s);
  3362. if (ClassName != NULL)
  3363. {
  3364. if (*ClassName != 0)
  3365. {
  3366. if (! WmiIsDuplicateClass(ClassName,
  3367. ClassList,
  3368. ClassListEnd))
  3369. {
  3370. //
  3371. // create property page data structure
  3372. // that corresponds to this class
  3373. //
  3374. DebugPrint((1, "WMIPROP: Parsing class %ws for instance %ws\n",
  3375. ClassName, InstanceName));
  3376. ppi = WmiCreatePageInfo(MachineName,
  3377. pIWbemServices,
  3378. ClassName,
  3379. InstanceName,
  3380. deviceInfoSet,
  3381. deviceInfoData);
  3382. if (ppi != NULL)
  3383. {
  3384. hpsp = WmiCreatePropertyPage(
  3385. &psp,
  3386. ppi,
  3387. ppi->ConfigClass.DataBlockDesc->DisplayName ?
  3388. ppi->ConfigClass.DataBlockDesc->DisplayName :
  3389. ClassName);
  3390. if (hpsp != NULL)
  3391. {
  3392. //
  3393. // Add the sheet into the list
  3394. //
  3395. PageIndex = AddPPageData->NumDynamicPages;
  3396. if (PageIndex < MAX_INSTALLWIZARD_DYNAPAGES)
  3397. {
  3398. AddPPageData->NumDynamicPages++;
  3399. AddPPageData->DynamicPages[PageIndex] = hpsp;
  3400. PageAdded = TRUE;
  3401. } else {
  3402. DebugPrint((1, "WMIPROP: Can add page, already %d pages",
  3403. PageIndex));
  3404. }
  3405. } else {
  3406. WmiFreePageInfo(ppi);
  3407. }
  3408. }
  3409. }
  3410. }
  3411. LocalFree(ClassName);
  3412. }
  3413. } while (ClassName != NULL);
  3414. LocalFree(InstanceName);
  3415. } else {
  3416. DebugPrint((1, "WMIPROP: Unable to get instance name\n"));
  3417. }
  3418. //
  3419. // We release the interface rather than holding it
  3420. // since it cannot be used in a different thread and
  3421. // we'll be running in a different thread later.
  3422. //
  3423. pIWbemServices->Release();
  3424. } else {
  3425. DebugPrint((1, "WMIPROP: Unable to connect to wbem\n"));
  3426. }
  3427. }
  3428. if (ClassList != ClassListStatic)
  3429. {
  3430. LocalFree(ClassList);
  3431. }
  3432. DebugPrint((1, "WMI: Leave %s WmiPropPageProvider(%p, %p, %p) \n",
  3433. PageAdded ? "TRUE" : "FALSE",
  3434. deviceInfoSet,
  3435. deviceInfoData,
  3436. AddPPageData));
  3437. return(PageAdded);
  3438. }
  3439. UINT CALLBACK
  3440. WmiDlgCallback(HWND hwnd,
  3441. UINT uMsg,
  3442. LPPROPSHEETPAGE ppsp)
  3443. {
  3444. PPAGE_INFO ppi;
  3445. DebugPrint((1, "WMI: Enter WniDlgCallback(%p, %d, 0x%x) \n",
  3446. hwnd, uMsg, ppsp));
  3447. switch (uMsg) {
  3448. case PSPCB_CREATE:
  3449. DebugPrint((1, "WMI: Leave TRUE WniDlgCallback(%p, %d, 0x%x) \n",
  3450. hwnd, uMsg, ppsp));
  3451. return TRUE; // return TRUE to continue with creation of page
  3452. case PSPCB_RELEASE:
  3453. ppi = (PPAGE_INFO) ppsp->lParam;
  3454. WmiDestroyPageInfo(&ppi);
  3455. DebugPrint((1, "WMI: Leave FALSE WniDlgCallback(%p, %d, 0x%x) \n",
  3456. hwnd, uMsg, ppsp));
  3457. return 0; // return value ignored
  3458. default:
  3459. break;
  3460. }
  3461. DebugPrint((1, "WMI: Leave TRUE WniDlgCallback(%p, %d, 0x%x) \n",
  3462. hwnd, uMsg, ppsp));
  3463. return TRUE;
  3464. }
  3465. BOOLEAN WmiGetDataItemValue(
  3466. IN PDATA_ITEM_DESCRIPTION DataItemDesc,
  3467. OUT ULONG64 *DataValue
  3468. )
  3469. {
  3470. ULONG64 ReturnValue;
  3471. BOOLEAN ReturnStatus = TRUE;
  3472. BOOLEAN IsArray;
  3473. ULONG Index;
  3474. IsArray = (DataItemDesc->IsVariableArray) || (DataItemDesc->IsFixedArray);
  3475. Index = DataItemDesc->CurrentArrayIndex;
  3476. switch(DataItemDesc->DataType)
  3477. {
  3478. case CIM_SINT8:
  3479. {
  3480. if (IsArray)
  3481. {
  3482. ReturnValue = DataItemDesc->sint8Array[Index];
  3483. } else {
  3484. ReturnValue = DataItemDesc->sint8;
  3485. }
  3486. break;
  3487. }
  3488. case CIM_UINT8:
  3489. {
  3490. if (IsArray)
  3491. {
  3492. ReturnValue = DataItemDesc->uint8Array[Index];
  3493. } else {
  3494. ReturnValue = DataItemDesc->uint8;
  3495. }
  3496. break;
  3497. }
  3498. case CIM_SINT16:
  3499. {
  3500. if (IsArray)
  3501. {
  3502. ReturnValue = DataItemDesc->sint16Array[Index];
  3503. } else {
  3504. ReturnValue = DataItemDesc->sint16;
  3505. }
  3506. break;
  3507. }
  3508. case CIM_UINT16:
  3509. {
  3510. if (IsArray)
  3511. {
  3512. ReturnValue = DataItemDesc->uint16Array[Index];
  3513. } else {
  3514. ReturnValue = DataItemDesc->uint16;
  3515. }
  3516. break;
  3517. }
  3518. case CIM_SINT32:
  3519. {
  3520. if (IsArray)
  3521. {
  3522. ReturnValue = DataItemDesc->sint32Array[Index];
  3523. } else {
  3524. ReturnValue = DataItemDesc->sint32;
  3525. }
  3526. break;
  3527. }
  3528. case CIM_UINT32:
  3529. {
  3530. if (IsArray)
  3531. {
  3532. ReturnValue = DataItemDesc->uint32Array[Index];
  3533. } else {
  3534. ReturnValue = DataItemDesc->uint32;
  3535. }
  3536. break;
  3537. }
  3538. case CIM_SINT64:
  3539. {
  3540. if (IsArray)
  3541. {
  3542. ReturnValue = DataItemDesc->sint64Array[Index];
  3543. } else {
  3544. ReturnValue = DataItemDesc->sint64;
  3545. }
  3546. break;
  3547. }
  3548. case CIM_UINT64:
  3549. {
  3550. if (IsArray)
  3551. {
  3552. ReturnValue = DataItemDesc->uint64Array[Index];
  3553. } else {
  3554. ReturnValue = DataItemDesc->uint64;
  3555. }
  3556. break;
  3557. }
  3558. case CIM_BOOLEAN:
  3559. {
  3560. if (IsArray)
  3561. {
  3562. ReturnValue = DataItemDesc->boolArray[Index] == 0 ? 0 : 1;
  3563. } else {
  3564. ReturnValue = DataItemDesc->boolval == 0 ? 0 : 1;
  3565. }
  3566. break;
  3567. }
  3568. case CIM_REAL32:
  3569. case CIM_REAL64:
  3570. default:
  3571. {
  3572. WmiAssert(FALSE);
  3573. ReturnStatus = FALSE;
  3574. ReturnValue = 0;
  3575. }
  3576. }
  3577. *DataValue = ReturnValue;
  3578. return(ReturnStatus);
  3579. }
  3580. BOOLEAN WmiSetDataItemValue(
  3581. IN PDATA_ITEM_DESCRIPTION DataItemDesc,
  3582. IN ULONG64 DataValue
  3583. )
  3584. {
  3585. BOOLEAN ReturnStatus = TRUE;
  3586. BOOLEAN IsArray;
  3587. ULONG Index;
  3588. WmiAssert(DataItemDesc != NULL);
  3589. IsArray = (DataItemDesc->IsVariableArray) || (DataItemDesc->IsFixedArray);
  3590. Index = DataItemDesc->CurrentArrayIndex;
  3591. switch(DataItemDesc->DataType)
  3592. {
  3593. case CIM_SINT8:
  3594. {
  3595. if (IsArray)
  3596. {
  3597. DataItemDesc->sint8Array[Index] = (CHAR)DataValue;
  3598. } else {
  3599. DataItemDesc->sint8 = (CHAR)DataValue;
  3600. }
  3601. break;
  3602. }
  3603. case CIM_UINT8:
  3604. {
  3605. if (IsArray)
  3606. {
  3607. DataItemDesc->uint8Array[Index] = (UCHAR)DataValue;
  3608. } else {
  3609. DataItemDesc->uint8 = (UCHAR)DataValue;
  3610. }
  3611. break;
  3612. }
  3613. case CIM_SINT16:
  3614. {
  3615. if (IsArray)
  3616. {
  3617. DataItemDesc->sint16Array[Index] = (SHORT)DataValue;
  3618. } else {
  3619. DataItemDesc->sint16 = (SHORT)DataValue;
  3620. }
  3621. break;
  3622. }
  3623. case CIM_UINT16:
  3624. {
  3625. if (IsArray)
  3626. {
  3627. DataItemDesc->uint16Array[Index] = (USHORT)DataValue;
  3628. } else {
  3629. DataItemDesc->uint16 = (USHORT)DataValue;
  3630. }
  3631. break;
  3632. }
  3633. case CIM_SINT32:
  3634. {
  3635. if (IsArray)
  3636. {
  3637. DataItemDesc->sint32Array[Index] = (LONG)DataValue;
  3638. } else {
  3639. DataItemDesc->sint32 = (LONG)DataValue;
  3640. }
  3641. break;
  3642. }
  3643. case CIM_UINT32:
  3644. {
  3645. if (IsArray)
  3646. {
  3647. DataItemDesc->uint32Array[Index] = (ULONG)DataValue;
  3648. } else {
  3649. DataItemDesc->uint32 = (ULONG)DataValue;
  3650. }
  3651. break;
  3652. }
  3653. case CIM_SINT64:
  3654. {
  3655. if (IsArray)
  3656. {
  3657. DataItemDesc->sint64Array[Index] = (LONG64)DataValue;
  3658. } else {
  3659. DataItemDesc->sint64 = (LONG64)DataValue;
  3660. }
  3661. break;
  3662. }
  3663. case CIM_UINT64:
  3664. {
  3665. if (IsArray)
  3666. {
  3667. DataItemDesc->uint64Array[Index] = DataValue;
  3668. } else {
  3669. DataItemDesc->uint64 = DataValue;
  3670. }
  3671. break;
  3672. }
  3673. case CIM_BOOLEAN:
  3674. {
  3675. if (IsArray)
  3676. {
  3677. DataItemDesc->boolArray[Index] = (DataValue == 0) ? 0 : 1;
  3678. } else {
  3679. DataItemDesc->boolval = (DataValue == 0) ? 0 : 1;
  3680. }
  3681. break;
  3682. }
  3683. case CIM_REAL32:
  3684. case CIM_REAL64:
  3685. default:
  3686. {
  3687. WmiAssert(FALSE);
  3688. ReturnStatus = FALSE;
  3689. }
  3690. }
  3691. return(ReturnStatus);
  3692. }
  3693. void WmiRefreshDataItemToControl(
  3694. HWND hDlg,
  3695. PDATA_ITEM_DESCRIPTION DataItemDesc,
  3696. BOOLEAN FullUpdate
  3697. )
  3698. {
  3699. HWND hWnd;
  3700. BOOLEAN IsReadOnly, IsArray;
  3701. PTCHAR v;
  3702. WmiAssert(hDlg != NULL);
  3703. WmiAssert(DataItemDesc != NULL);
  3704. IsArray = (DataItemDesc->IsVariableArray) || (DataItemDesc->IsFixedArray);
  3705. if (FullUpdate)
  3706. {
  3707. //
  3708. // This code is run when we switch from one property to another
  3709. // property
  3710. //
  3711. if (DataItemDesc->Description != NULL)
  3712. {
  3713. hWnd = GetDlgItem(hDlg, IDC_DESCRIPTION_TEXT);
  3714. if (hWnd != NULL)
  3715. {
  3716. SendMessage(hWnd,
  3717. WM_SETTEXT,
  3718. 0,
  3719. (LPARAM)DataItemDesc->Description);
  3720. ShowWindow(hWnd, SW_SHOW);
  3721. }
  3722. }
  3723. }
  3724. if ((DataItemDesc->ValidationFunc == WmiStringValidation) ||
  3725. (DataItemDesc->ValidationFunc == WmiDateTimeValidation) )
  3726. {
  3727. ULONG64 DataItemValue;
  3728. TCHAR s[MAX_PATH];
  3729. hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
  3730. ShowWindow(hWnd, SW_SHOW);
  3731. EnableWindow(hWnd, (DataItemDesc->IsReadOnly == 1) ? FALSE : TRUE);
  3732. if (IsArray)
  3733. {
  3734. v = DataItemDesc->StringArray[DataItemDesc->CurrentArrayIndex];
  3735. } else {
  3736. v = DataItemDesc->String;
  3737. }
  3738. if (hWnd != NULL)
  3739. {
  3740. WmiAssert(DataItemDesc->String != NULL);
  3741. SendMessage(hWnd,
  3742. WM_SETTEXT,
  3743. 0,
  3744. (LPARAM)v);
  3745. } else {
  3746. WmiAssert(FALSE);
  3747. }
  3748. } else if (DataItemDesc->ValidationFunc == WmiRangeValidation) {
  3749. ULONG64 DataItemValue;
  3750. TCHAR s[MAX_PATH];
  3751. PTCHAR FormatString;
  3752. ULONG FormatStringIndex;
  3753. static PTCHAR FormatStringList[8] = { TEXT("%lu"),
  3754. TEXT("%ld"),
  3755. TEXT("0x%lx"),
  3756. TEXT("0x%lx"),
  3757. TEXT("%I64u"),
  3758. TEXT("%I64d"),
  3759. TEXT("0x%I64x"),
  3760. TEXT("0x%I64x") };
  3761. hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
  3762. ShowWindow(hWnd, SW_SHOW);
  3763. EnableWindow(hWnd, (DataItemDesc->IsReadOnly == 1) ? FALSE : TRUE);
  3764. if (hWnd != NULL)
  3765. {
  3766. if (WmiGetDataItemValue(DataItemDesc, &DataItemValue))
  3767. {
  3768. FormatStringIndex = DataItemDesc->DisplayInHex * 2 +
  3769. DataItemDesc->IsSignedValue;
  3770. if ((DataItemDesc->DataType == CIM_SINT64) ||
  3771. (DataItemDesc->DataType == CIM_UINT64))
  3772. {
  3773. FormatStringIndex += 4;
  3774. }
  3775. FormatString = FormatStringList[FormatStringIndex];
  3776. wsprintf(s,
  3777. FormatString,
  3778. DataItemValue);
  3779. SendMessage(hWnd,
  3780. WM_SETTEXT,
  3781. 0,
  3782. (LPARAM)s);
  3783. }
  3784. } else {
  3785. WmiAssert(FALSE);
  3786. }
  3787. } else if (DataItemDesc->ValidationFunc == WmiValueMapValidation) {
  3788. PENUMERATIONINFO EnumerationInfo;
  3789. ULONG j;
  3790. ULONG64 DataItemValue;
  3791. hWnd = GetDlgItem(hDlg, IDC_DATA_COMBO);
  3792. if (hWnd != NULL)
  3793. {
  3794. EnumerationInfo = DataItemDesc->EnumerationInfo;
  3795. WmiAssert(EnumerationInfo != NULL);
  3796. SendMessage(hWnd,
  3797. CB_RESETCONTENT,
  3798. 0,
  3799. 0);
  3800. for (j = 0; j < EnumerationInfo->Count; j++)
  3801. {
  3802. WmiAssert(EnumerationInfo->List[j].Text != NULL);
  3803. SendMessage(hWnd,
  3804. CB_ADDSTRING,
  3805. 0,
  3806. (LPARAM)EnumerationInfo->List[j].Text);
  3807. }
  3808. ShowWindow(hWnd, SW_SHOW);
  3809. EnableWindow(hWnd, (DataItemDesc->IsReadOnly == 1) ?
  3810. FALSE : TRUE);
  3811. if (WmiGetDataItemValue(DataItemDesc, &DataItemValue))
  3812. {
  3813. for (j = 0; j < EnumerationInfo->Count; j++)
  3814. {
  3815. if (DataItemValue == EnumerationInfo->List[j].Value)
  3816. {
  3817. SendMessage(hWnd,
  3818. CB_SETCURSEL,
  3819. (WPARAM)j,
  3820. 0);
  3821. break;
  3822. }
  3823. }
  3824. }
  3825. } else {
  3826. WmiAssert(FALSE);
  3827. }
  3828. } else if (DataItemDesc->ValidationFunc == WmiEmbeddedValidation) {
  3829. hWnd = GetDlgItem(hDlg, IDC_DATA_BUTTON);
  3830. if (hWnd != NULL)
  3831. {
  3832. SendMessage(hWnd,
  3833. WM_SETTEXT,
  3834. 0,
  3835. (LPARAM) (DataItemDesc->DisplayName ?
  3836. DataItemDesc->DisplayName :
  3837. DataItemDesc->Name));
  3838. ShowWindow(hWnd, SW_SHOW);
  3839. EnableWindow(hWnd, TRUE);
  3840. } else {
  3841. WmiAssert(FALSE);
  3842. }
  3843. } else {
  3844. WmiAssert(FALSE);
  3845. }
  3846. if (FullUpdate)
  3847. {
  3848. if (IsArray)
  3849. {
  3850. TCHAR s[MAX_PATH];
  3851. hWnd = GetDlgItem(hDlg, IDC_ARRAY_SPIN);
  3852. if (hWnd != NULL)
  3853. {
  3854. SendMessage(hWnd,
  3855. UDM_SETRANGE32,
  3856. (WPARAM)1,
  3857. (LPARAM)DataItemDesc->ArrayElementCount);
  3858. DebugPrint((1, "WMIPROP: SetPos32 -> %d\n",
  3859. DataItemDesc->CurrentArrayIndex+1));
  3860. SendMessage(hWnd,
  3861. UDM_SETPOS32,
  3862. (WPARAM)0,
  3863. (LPARAM)DataItemDesc->CurrentArrayIndex+1);
  3864. ShowWindow(hWnd, SW_SHOW);
  3865. }
  3866. hWnd = GetDlgItem(hDlg, IDC_ARRAY_TEXT);
  3867. if (hWnd != NULL)
  3868. {
  3869. ShowWindow(hWnd, SW_SHOW);
  3870. }
  3871. hWnd = GetDlgItem(hDlg, IDC_ARRAY_STATIC);
  3872. if (hWnd != NULL)
  3873. {
  3874. ShowWindow(hWnd, SW_SHOW);
  3875. }
  3876. }
  3877. }
  3878. }
  3879. void
  3880. WmiRefreshDataBlockToControls(
  3881. HWND hDlg,
  3882. PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  3883. BOOLEAN FullUpdate
  3884. )
  3885. {
  3886. ULONG i;
  3887. WmiAssert(hDlg != NULL);
  3888. WmiAssert(DataBlockDesc != NULL);
  3889. WmiAssert(DataBlockDesc->CurrentDataItem < DataBlockDesc->DataItemCount);
  3890. WmiHideAllControls(hDlg, FALSE, FullUpdate);
  3891. WmiRefreshDataItemToControl(hDlg,
  3892. &DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem],
  3893. FullUpdate);
  3894. }
  3895. void
  3896. WmiInitializeControlsFromDataBlock(
  3897. HWND hDlg,
  3898. PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  3899. BOOLEAN IsEmbeddedClass
  3900. )
  3901. {
  3902. HWND hWnd, hWndBuddy;
  3903. PDATA_ITEM_DESCRIPTION DataItemDesc;
  3904. ULONG i;
  3905. BSTR s;
  3906. int ShowOrHide;
  3907. BOOLEAN IsReadOnly;
  3908. WmiAssert(hDlg != NULL);
  3909. WmiAssert(DataBlockDesc != NULL);
  3910. WmiHideAllControls(hDlg, TRUE, TRUE);
  3911. hWnd = GetDlgItem(hDlg, IDC_PROPERTY_LISTBOX);
  3912. if (hWnd != NULL)
  3913. {
  3914. SendMessage(hWnd,
  3915. LB_RESETCONTENT,
  3916. 0,
  3917. 0);
  3918. for (i = 0; i < DataBlockDesc->DataItemCount; i++)
  3919. {
  3920. DataItemDesc = &DataBlockDesc->DataItems[i];
  3921. SendMessage(hWnd,
  3922. LB_ADDSTRING,
  3923. 0,
  3924. (LPARAM) (DataItemDesc->DisplayName ?
  3925. DataItemDesc->DisplayName :
  3926. DataItemDesc->Name));
  3927. }
  3928. SendMessage(hWnd,
  3929. LB_SETCURSEL,
  3930. (WPARAM)DataBlockDesc->CurrentDataItem,
  3931. 0);
  3932. ShowWindow(hWnd, SW_SHOW);
  3933. EnableWindow(hWnd, TRUE);
  3934. //
  3935. // Refresh data from wbem and if successful update the controls
  3936. //
  3937. WmiRefreshDataBlockToControls(hDlg,
  3938. DataBlockDesc,
  3939. TRUE);
  3940. }
  3941. ShowOrHide = IsEmbeddedClass ? SW_SHOW : SW_HIDE;
  3942. hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_OK);
  3943. if (hWnd != NULL)
  3944. {
  3945. ShowWindow(hWnd, ShowOrHide);
  3946. }
  3947. hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_CANCEL);
  3948. if (hWnd != NULL)
  3949. {
  3950. ShowWindow(hWnd, ShowOrHide);
  3951. }
  3952. hWnd = GetDlgItem(hDlg, IDC_ARRAY_SPIN);
  3953. if (hWnd != NULL)
  3954. {
  3955. hWndBuddy = GetDlgItem(hDlg, IDC_ARRAY_TEXT);
  3956. SendMessage(hWnd,
  3957. UDM_SETBUDDY,
  3958. (WPARAM)hWndBuddy,
  3959. 0);
  3960. }
  3961. }
  3962. BOOLEAN WmiReconnectToWbem(
  3963. PCONFIGCLASS ConfigClass,
  3964. IWbemClassObject **pInstance
  3965. )
  3966. {
  3967. BOOLEAN ReturnStatus;
  3968. IWbemClassObject *pIWbemClassObject;
  3969. IWbemServices *pIWbemServices;
  3970. HRESULT hr;
  3971. BSTR s;
  3972. WmiAssert(ConfigClass != NULL);
  3973. //
  3974. // Reestablish our interfaces to WBEM now that we are on the
  3975. // window message thread
  3976. //
  3977. ReturnStatus = FALSE;
  3978. if (WmiConnectToWbem(ConfigClass->MachineName,
  3979. &pIWbemServices))
  3980. {
  3981. ConfigClass->pIWbemServices = pIWbemServices;
  3982. s = SysAllocString(ConfigClass->RelPath);
  3983. if (s != NULL)
  3984. {
  3985. pIWbemClassObject = NULL;
  3986. hr = pIWbemServices->GetObject(s,
  3987. WBEM_FLAG_USE_AMENDED_QUALIFIERS,
  3988. NULL,
  3989. &pIWbemClassObject,
  3990. NULL);
  3991. if (hr == WBEM_S_NO_ERROR)
  3992. {
  3993. *pInstance = pIWbemClassObject;
  3994. ReturnStatus = TRUE;
  3995. } else {
  3996. DebugPrint((1, "WMIPROP: Error %x reestablishing IWbemClassObject to instance for %ws\n",
  3997. hr, ConfigClass->RelPath));
  3998. }
  3999. SysFreeString(s);
  4000. }
  4001. }
  4002. return(ReturnStatus);
  4003. }
  4004. void WmiHideAllControls(
  4005. HWND hDlg,
  4006. BOOLEAN HideEmbeddedControls,
  4007. BOOLEAN HideArrayControls
  4008. )
  4009. {
  4010. HWND hWnd;
  4011. WmiAssert(hDlg != NULL);
  4012. hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
  4013. if (hWnd != NULL)
  4014. {
  4015. ShowWindow(hWnd, SW_HIDE);
  4016. }
  4017. hWnd = GetDlgItem(hDlg, IDC_DATA_COMBO);
  4018. if (hWnd != NULL)
  4019. {
  4020. ShowWindow(hWnd, SW_HIDE);
  4021. }
  4022. hWnd = GetDlgItem(hDlg, IDC_DATA_CHECK);
  4023. if (hWnd != NULL)
  4024. {
  4025. ShowWindow(hWnd, SW_HIDE);
  4026. }
  4027. hWnd = GetDlgItem(hDlg, IDC_DATA_BUTTON);
  4028. if (hWnd != NULL)
  4029. {
  4030. ShowWindow(hWnd, SW_HIDE);
  4031. }
  4032. hWnd = GetDlgItem(hDlg, IDC_ARRAY_EDIT);
  4033. if (hWnd != NULL)
  4034. {
  4035. ShowWindow(hWnd, SW_HIDE);
  4036. }
  4037. if (HideArrayControls)
  4038. {
  4039. hWnd = GetDlgItem(hDlg, IDC_ARRAY_SPIN);
  4040. if (hWnd != NULL)
  4041. {
  4042. ShowWindow(hWnd, SW_HIDE);
  4043. }
  4044. hWnd = GetDlgItem(hDlg, IDC_ARRAY_STATIC);
  4045. if (hWnd != NULL)
  4046. {
  4047. ShowWindow(hWnd, SW_HIDE);
  4048. }
  4049. hWnd = GetDlgItem(hDlg, IDC_ARRAY_TEXT);
  4050. if (hWnd != NULL)
  4051. {
  4052. ShowWindow(hWnd, SW_HIDE);
  4053. }
  4054. }
  4055. if (HideEmbeddedControls)
  4056. {
  4057. hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_OK);
  4058. if (hWnd != NULL)
  4059. {
  4060. ShowWindow(hWnd, SW_HIDE);
  4061. }
  4062. hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_CANCEL);
  4063. if (hWnd != NULL)
  4064. {
  4065. ShowWindow(hWnd, SW_HIDE);
  4066. }
  4067. }
  4068. }
  4069. void
  4070. WmiInitializeDialog(
  4071. PPAGE_INFO ppi,
  4072. HWND hDlg
  4073. )
  4074. {
  4075. PCONFIGCLASS ConfigClass;
  4076. HWND hWnd;
  4077. BOOLEAN ReturnStatus;
  4078. WmiAssert(ppi != NULL);
  4079. WmiAssert(hDlg != NULL);
  4080. ConfigClass = &ppi->ConfigClass;
  4081. ReturnStatus = FALSE;
  4082. if (WmiReconnectToWbem(ConfigClass,
  4083. &ConfigClass->DataBlockDesc->pInstance))
  4084. {
  4085. if (WmiRefreshDataBlockFromWbem( ConfigClass->DataBlockDesc->pInstance,
  4086. ConfigClass->DataBlockDesc))
  4087. {
  4088. WmiInitializeControlsFromDataBlock(hDlg,
  4089. ConfigClass->DataBlockDesc,
  4090. FALSE);
  4091. hWnd = GetDlgItem(hDlg, IDC_WMI_CONNECT_ERR);
  4092. if (hWnd != NULL)
  4093. {
  4094. ShowWindow(hWnd, SW_HIDE);
  4095. }
  4096. ReturnStatus = TRUE;
  4097. }
  4098. }
  4099. if (! ReturnStatus)
  4100. {
  4101. //
  4102. // Hide all controls except for a static string that says we cannot
  4103. // connect to wbem.
  4104. //
  4105. hWnd = GetDlgItem(hDlg, IDC_PROPERTY_LISTBOX);
  4106. if (hWnd != NULL)
  4107. {
  4108. ShowWindow(hWnd, SW_HIDE);
  4109. }
  4110. WmiHideAllControls(hDlg, TRUE, TRUE);
  4111. hWnd = GetDlgItem(hDlg, IDC_WMI_CONNECT_ERR);
  4112. if (hWnd != NULL)
  4113. {
  4114. ShowWindow(hWnd, SW_SHOW);
  4115. }
  4116. }
  4117. }
  4118. BOOLEAN WmiGetControlText(
  4119. HWND hWnd,
  4120. PTCHAR *Text
  4121. )
  4122. {
  4123. ULONG SizeNeeded;
  4124. BOOLEAN ReturnStatus = FALSE;
  4125. ULONG CharNeeded, CharCopied;
  4126. WmiAssert(hWnd != NULL);
  4127. WmiAssert(Text != NULL);
  4128. CharNeeded = (ULONG)SendMessage(hWnd,
  4129. WM_GETTEXTLENGTH,
  4130. 0,
  4131. 0);
  4132. if (CharNeeded > 0)
  4133. {
  4134. SizeNeeded = (++CharNeeded) * sizeof(TCHAR);
  4135. *Text = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
  4136. if (*Text != NULL)
  4137. {
  4138. CharCopied = (ULONG)SendMessage(hWnd,
  4139. WM_GETTEXT,
  4140. CharNeeded,
  4141. (LPARAM)*Text);
  4142. ReturnStatus = TRUE;
  4143. }
  4144. }
  4145. return(ReturnStatus);
  4146. }
  4147. void WmiValidationError(
  4148. HWND hWnd,
  4149. PDATA_ITEM_DESCRIPTION DataItemDesc
  4150. )
  4151. {
  4152. TCHAR buf[MAX_PATH];
  4153. TCHAR buf2[MAX_PATH];
  4154. ULONG Bytes;
  4155. //
  4156. // TODO: Do a better job of informing the user
  4157. //
  4158. //
  4159. // Get the string template for the error message
  4160. //
  4161. Bytes = LoadString(g_hInstance,
  4162. IDS_WMI_VALIDATION_ERROR,
  4163. buf,
  4164. MAX_PATH);
  4165. wsprintf(buf2, buf, DataItemDesc->Name);
  4166. MessageBox(hWnd, buf2, NULL, MB_ICONWARNING);
  4167. }
  4168. BOOLEAN WmiRefreshDataItemFromControl(
  4169. HWND hDlg,
  4170. PDATA_ITEM_DESCRIPTION DataItemDesc,
  4171. PBOOLEAN UpdateValues
  4172. )
  4173. {
  4174. HWND hWnd;
  4175. BOOLEAN ReturnStatus;
  4176. WmiAssert(hDlg != NULL);
  4177. WmiAssert(DataItemDesc != NULL);
  4178. WmiAssert(UpdateValues != NULL);
  4179. ReturnStatus = TRUE;
  4180. *UpdateValues = FALSE;
  4181. if (DataItemDesc->IsReadOnly == 0)
  4182. {
  4183. //
  4184. // Property is not read only so see what we need to update
  4185. //
  4186. if (DataItemDesc->ValidationFunc == WmiValueMapValidation)
  4187. {
  4188. //
  4189. // if a value map or enumeration then we get the current
  4190. // location and then lookup the corresponding value to
  4191. // set
  4192. //
  4193. ULONG CurSel;
  4194. ULONG64 EnumValue;
  4195. hWnd = GetDlgItem(hDlg, IDC_DATA_COMBO);
  4196. if (hWnd != NULL)
  4197. {
  4198. CurSel = (ULONG)SendMessage(hWnd,
  4199. CB_GETCURSEL,
  4200. 0,
  4201. 0);
  4202. if (CurSel != CB_ERR)
  4203. {
  4204. if (CurSel < DataItemDesc->EnumerationInfo->Count)
  4205. {
  4206. EnumValue = DataItemDesc->EnumerationInfo->List[CurSel].Value;
  4207. WmiSetDataItemValue(DataItemDesc,
  4208. EnumValue);
  4209. *UpdateValues = TRUE;
  4210. } else {
  4211. WmiAssert(FALSE);
  4212. }
  4213. }
  4214. } else {
  4215. WmiAssert(FALSE);
  4216. }
  4217. } else {
  4218. //
  4219. // All of the rest of the validation types are based
  4220. // upon the contents of the edit box, so get the value
  4221. // from there
  4222. //
  4223. PTCHAR Text;
  4224. ULONG64 Number;
  4225. hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
  4226. if (hWnd != NULL)
  4227. {
  4228. if (WmiGetControlText(hWnd,
  4229. &Text))
  4230. {
  4231. if (DataItemDesc->ValidationFunc == WmiRangeValidation) {
  4232. if (WmiValidateRange(DataItemDesc, &Number, Text))
  4233. {
  4234. WmiSetDataItemValue(DataItemDesc,
  4235. Number);
  4236. *UpdateValues = TRUE;
  4237. } else {
  4238. //
  4239. // Validation failed, go tell user
  4240. //
  4241. WmiValidationError(hDlg, DataItemDesc);
  4242. ReturnStatus = FALSE;
  4243. }
  4244. } else if (DataItemDesc->ValidationFunc == WmiDateTimeValidation) {
  4245. if (WmiValidateDateTime(DataItemDesc, Text))
  4246. {
  4247. DataItemDesc->DateTime = Text;
  4248. Text = NULL;
  4249. *UpdateValues = TRUE;
  4250. } else {
  4251. //
  4252. // Validation failed, go tell user
  4253. //
  4254. WmiValidationError(hDlg, DataItemDesc);
  4255. ReturnStatus = FALSE;
  4256. }
  4257. } else if (DataItemDesc->ValidationFunc == WmiStringValidation) {
  4258. DataItemDesc->String = Text;
  4259. Text = NULL;
  4260. *UpdateValues = TRUE;
  4261. }
  4262. if (Text != NULL)
  4263. {
  4264. LocalFree(Text);
  4265. }
  4266. }
  4267. } else {
  4268. WmiAssert(FALSE);
  4269. }
  4270. }
  4271. }
  4272. return(ReturnStatus);
  4273. }
  4274. BOOLEAN WmiRefreshDataBlockFromControls(
  4275. HWND hDlg,
  4276. PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  4277. PBOOLEAN UpdateValues
  4278. )
  4279. {
  4280. ULONG i;
  4281. PDATA_ITEM_DESCRIPTION DataItemDesc;
  4282. BOOLEAN UpdateItem, ReturnStatus;
  4283. WmiAssert(hDlg != NULL);
  4284. WmiAssert(DataBlockDesc != NULL);
  4285. WmiAssert(UpdateValues != NULL);
  4286. *UpdateValues = FALSE;
  4287. DataItemDesc = &DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem];
  4288. //
  4289. // We are not going to worry about failures from this function
  4290. // so we'll just use the previous values in the function
  4291. //
  4292. ReturnStatus = WmiRefreshDataItemFromControl(hDlg,
  4293. DataItemDesc,
  4294. &UpdateItem);
  4295. if (ReturnStatus && UpdateItem)
  4296. {
  4297. *UpdateValues = TRUE;
  4298. DataBlockDesc->UpdateClass = TRUE;
  4299. }
  4300. return(ReturnStatus);
  4301. }
  4302. void WmiPushIntoEmbeddedClass(
  4303. HWND hDlg,
  4304. PPAGE_INFO ppi,
  4305. PDATA_BLOCK_DESCRIPTION DataBlockDesc
  4306. )
  4307. {
  4308. ULONG i;
  4309. PDATA_ITEM_DESCRIPTION DataItemDesc;
  4310. WmiAssert(ppi != NULL);
  4311. WmiAssert(DataBlockDesc != NULL);
  4312. DataItemDesc = &DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem];
  4313. if (DataItemDesc->ValidationFunc == WmiEmbeddedValidation)
  4314. {
  4315. //
  4316. // The property is an embedded class so all we need to do
  4317. // is to change the controls to our embededded class
  4318. //
  4319. DataBlockDesc = DataItemDesc->DataBlockDesc;
  4320. WmiAssert(DataBlockDesc != NULL);
  4321. DataBlockDesc->UpdateClass = FALSE;
  4322. if ((DataItemDesc->IsVariableArray) ||
  4323. (DataItemDesc->IsFixedArray))
  4324. {
  4325. DataBlockDesc->pInstance = DataItemDesc->pIWbemClassObjectArray[DataItemDesc->CurrentArrayIndex];
  4326. } else {
  4327. DataBlockDesc->pInstance = DataItemDesc->pIWbemClassObject;
  4328. }
  4329. DataBlockDesc->pInstance->AddRef();
  4330. WmiRefreshDataBlockFromWbem(DataBlockDesc->pInstance,
  4331. DataBlockDesc);
  4332. ppi->ConfigClass.DataBlockDesc = DataBlockDesc;
  4333. } else {
  4334. WmiAssert(FALSE);
  4335. }
  4336. }
  4337. void WmiPopOutEmbeddedClass(
  4338. HWND hDlg,
  4339. PPAGE_INFO ppi,
  4340. PDATA_BLOCK_DESCRIPTION DataBlockDesc,
  4341. BOOLEAN SaveChanges
  4342. )
  4343. {
  4344. PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc;
  4345. ParentDataBlockDesc = DataBlockDesc->ParentDataBlockDesc;
  4346. WmiAssert(ParentDataBlockDesc != NULL);
  4347. if ((SaveChanges) && (DataBlockDesc->UpdateClass))
  4348. {
  4349. //
  4350. // Copy the properties for the data block back into WBEM
  4351. //
  4352. WmiRefreshWbemFromDataBlock(ppi->ConfigClass.pIWbemServices,
  4353. DataBlockDesc->pInstance,
  4354. DataBlockDesc,
  4355. TRUE);
  4356. ParentDataBlockDesc->UpdateClass = TRUE;
  4357. }
  4358. DataBlockDesc->pInstance->Release();
  4359. DataBlockDesc->pInstance = NULL;
  4360. ppi->ConfigClass.DataBlockDesc = ParentDataBlockDesc;
  4361. }
  4362. void WmiButtonSelected(
  4363. HWND hDlg,
  4364. PPAGE_INFO ppi,
  4365. ULONG ControlId
  4366. )
  4367. {
  4368. BOOLEAN UpdateValues, ReturnStatus;
  4369. PDATA_BLOCK_DESCRIPTION DataBlockDesc;
  4370. WmiAssert(ppi != NULL);
  4371. if (ControlId == IDC_DATA_BUTTON)
  4372. {
  4373. DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4374. WmiAssert(DataBlockDesc != NULL);
  4375. ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
  4376. DataBlockDesc,
  4377. &UpdateValues);
  4378. if (ReturnStatus)
  4379. {
  4380. WmiPushIntoEmbeddedClass(hDlg,
  4381. ppi,
  4382. DataBlockDesc);
  4383. WmiInitializeControlsFromDataBlock(hDlg,
  4384. ppi->ConfigClass.DataBlockDesc,
  4385. TRUE);
  4386. } else {
  4387. WmiRefreshDataBlockToControls(hDlg,
  4388. DataBlockDesc,
  4389. FALSE);
  4390. }
  4391. }
  4392. }
  4393. void WmiButtonEmbeddedOk(
  4394. HWND hDlg,
  4395. PPAGE_INFO ppi
  4396. )
  4397. {
  4398. PDATA_BLOCK_DESCRIPTION DataBlockDesc;
  4399. PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc;
  4400. BOOLEAN UpdateValues, ReturnStatus;
  4401. WmiAssert(ppi != NULL);
  4402. WmiAssert(hDlg != NULL);
  4403. DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4404. WmiAssert(DataBlockDesc != NULL);
  4405. ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
  4406. DataBlockDesc,
  4407. &UpdateValues);
  4408. if (ReturnStatus)
  4409. {
  4410. WmiPopOutEmbeddedClass(hDlg,
  4411. ppi,
  4412. DataBlockDesc,
  4413. TRUE);
  4414. ParentDataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4415. WmiAssert(ParentDataBlockDesc != NULL);
  4416. WmiInitializeControlsFromDataBlock(hDlg,
  4417. ParentDataBlockDesc,
  4418. (ParentDataBlockDesc->ParentDataBlockDesc != NULL));
  4419. } else {
  4420. WmiRefreshDataBlockToControls(hDlg,
  4421. DataBlockDesc,
  4422. FALSE);
  4423. }
  4424. }
  4425. void WmiButtonEmbeddedCancel(
  4426. HWND hDlg,
  4427. PPAGE_INFO ppi
  4428. )
  4429. {
  4430. PDATA_BLOCK_DESCRIPTION DataBlockDesc;
  4431. PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc;
  4432. BOOLEAN UpdateValues, ReturnStatus;
  4433. WmiAssert(ppi != NULL);
  4434. WmiAssert(hDlg != NULL);
  4435. DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4436. WmiAssert(DataBlockDesc != NULL);
  4437. WmiPopOutEmbeddedClass(hDlg,
  4438. ppi,
  4439. DataBlockDesc,
  4440. FALSE);
  4441. ParentDataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4442. WmiAssert(ParentDataBlockDesc != NULL);
  4443. WmiInitializeControlsFromDataBlock(hDlg,
  4444. ParentDataBlockDesc,
  4445. (ParentDataBlockDesc->ParentDataBlockDesc != NULL));
  4446. }
  4447. BOOLEAN
  4448. WmiApplyChanges(
  4449. PPAGE_INFO ppi,
  4450. HWND hDlg
  4451. )
  4452. {
  4453. PDATA_BLOCK_DESCRIPTION DataBlockDesc;
  4454. IWbemClassObject *pIWbemClassObject;
  4455. BOOLEAN UpdateClass, ReturnStatus;
  4456. IWbemServices *pIWbemServices;
  4457. WmiAssert(ppi != NULL);
  4458. WmiAssert(hDlg != NULL);
  4459. DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4460. pIWbemServices = ppi->ConfigClass.pIWbemServices;
  4461. ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
  4462. DataBlockDesc,
  4463. &UpdateClass);
  4464. if (ReturnStatus)
  4465. {
  4466. //
  4467. // Pop out of embedded classes to the root class
  4468. //
  4469. while (DataBlockDesc->ParentDataBlockDesc != NULL)
  4470. {
  4471. WmiPopOutEmbeddedClass(hDlg,
  4472. ppi,
  4473. DataBlockDesc,
  4474. TRUE);
  4475. DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4476. }
  4477. //
  4478. // Now we are at the root class so save that
  4479. //
  4480. if (DataBlockDesc->UpdateClass)
  4481. {
  4482. WmiRefreshWbemFromDataBlock(pIWbemServices,
  4483. DataBlockDesc->pInstance,
  4484. DataBlockDesc,
  4485. FALSE);
  4486. UpdateClass = TRUE;
  4487. }
  4488. DataBlockDesc->pInstance->Release();
  4489. DataBlockDesc->pInstance = NULL;
  4490. } else {
  4491. WmiRefreshDataBlockToControls(hDlg,
  4492. DataBlockDesc,
  4493. FALSE);
  4494. }
  4495. return(ReturnStatus);
  4496. }
  4497. INT_PTR WmipDataItemSelectionChange(
  4498. HWND hDlg,
  4499. PPAGE_INFO ppi
  4500. )
  4501. {
  4502. PDATA_BLOCK_DESCRIPTION DataBlockDesc;
  4503. HWND hWnd;
  4504. BOOLEAN UpdateClass, ReturnStatus;
  4505. WmiAssert(ppi != NULL);
  4506. WmiAssert(hDlg != NULL);
  4507. DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4508. WmiAssert(DataBlockDesc != NULL);
  4509. hWnd = GetDlgItem(hDlg, IDC_PROPERTY_LISTBOX);
  4510. if (hWnd != NULL)
  4511. {
  4512. ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
  4513. DataBlockDesc,
  4514. &UpdateClass);
  4515. if (UpdateClass)
  4516. {
  4517. DataBlockDesc->UpdateClass = TRUE;
  4518. }
  4519. //
  4520. // New value for data item is ok, refresh display with new
  4521. // data item
  4522. //
  4523. DataBlockDesc->CurrentDataItem = (ULONG)SendMessage(hWnd,
  4524. LB_GETCURSEL,
  4525. 0,
  4526. 0);
  4527. WmiRefreshDataBlockToControls(hDlg,
  4528. DataBlockDesc,
  4529. TRUE);
  4530. }
  4531. return(0);
  4532. }
  4533. void WmiSetArrayIndex(
  4534. HWND hDlg,
  4535. PPAGE_INFO ppi,
  4536. int NewIndex
  4537. )
  4538. {
  4539. PDATA_BLOCK_DESCRIPTION DataBlockDesc;
  4540. PDATA_ITEM_DESCRIPTION DataItemDesc;
  4541. HWND hWnd;
  4542. BOOLEAN UpdateClass, ReturnStatus;
  4543. WmiAssert(ppi != NULL);
  4544. WmiAssert(hDlg != NULL);
  4545. DebugPrint((1, "WMIPROP: Set index to %d\n", NewIndex));
  4546. DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
  4547. WmiAssert(DataBlockDesc != NULL);
  4548. DataItemDesc = &DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem];
  4549. if ((ULONG)NewIndex < DataItemDesc->ArrayElementCount)
  4550. {
  4551. ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
  4552. DataBlockDesc,
  4553. &UpdateClass);
  4554. if (UpdateClass)
  4555. {
  4556. DataBlockDesc->UpdateClass = TRUE;
  4557. }
  4558. DataItemDesc->CurrentArrayIndex = NewIndex;
  4559. WmiRefreshDataBlockToControls(hDlg,
  4560. DataBlockDesc,
  4561. FALSE);
  4562. }
  4563. }
  4564. INT_PTR WmiControlColorStatic(
  4565. HDC DC,
  4566. HWND HStatic
  4567. )
  4568. {
  4569. UINT id = GetDlgCtrlID(HStatic);
  4570. UINT ControlType;
  4571. //
  4572. // WM_CTLCOLORSTATIC is sent for the edit controls because they are read
  4573. // only
  4574. //
  4575. if ((id == IDC_DATA_CHECK) ||
  4576. (id == IDC_DATA_BUTTON))
  4577. {
  4578. SetBkColor(DC, GetSysColor(COLOR_WINDOW));
  4579. return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
  4580. }
  4581. return FALSE;
  4582. }
  4583. INT_PTR APIENTRY
  4584. WmiDlgProc(IN HWND hDlg,
  4585. IN UINT uMessage,
  4586. IN WPARAM wParam,
  4587. IN LPARAM lParam)
  4588. {
  4589. PPAGE_INFO ppi;
  4590. BOOLEAN ReturnStatus;
  4591. DebugPrint((7, "WMI: Enter WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
  4592. hDlg, uMessage, wParam, lParam));
  4593. ppi = (PPAGE_INFO) GetWindowLongPtr(hDlg, DWLP_USER);
  4594. switch (uMessage) {
  4595. case WM_INITDIALOG:
  4596. //
  4597. // on WM_INITDIALOG call, lParam points to the property
  4598. // sheet page.
  4599. //
  4600. // The lParam field in the property sheet page struct is set by the
  4601. // caller. When I created the property sheet, I passed in a pointer
  4602. // to a struct containing information about the device. Save this in
  4603. // the user window long so I can access it on later messages.
  4604. //
  4605. ppi = (PPAGE_INFO) ((LPPROPSHEETPAGE)lParam)->lParam;
  4606. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) ppi);
  4607. //
  4608. // Initialize dlg controls
  4609. //
  4610. WmiInitializeDialog(ppi,
  4611. hDlg);
  4612. //
  4613. // Didn't set the focus to a particular control. If we wanted to,
  4614. // then return FALSE
  4615. //
  4616. DebugPrint((7, "WMI: Leave TRUE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
  4617. hDlg, uMessage, wParam, lParam));
  4618. return TRUE;
  4619. case WM_COMMAND:
  4620. if (HIWORD(wParam) == LBN_SELCHANGE)
  4621. {
  4622. WmipDataItemSelectionChange(hDlg, ppi);
  4623. return(TRUE);
  4624. }
  4625. if (HIWORD(wParam) == CBN_SELCHANGE)
  4626. {
  4627. PropSheet_Changed(GetParent(hDlg), hDlg);
  4628. DebugPrint((7, "WMI: Leave TRUE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
  4629. hDlg, uMessage, wParam, lParam));
  4630. return TRUE;
  4631. }
  4632. switch (wParam)
  4633. {
  4634. case IDC_DATA_BUTTON:
  4635. {
  4636. WmiButtonSelected(hDlg, ppi, (ULONG)wParam);
  4637. break;
  4638. }
  4639. case IDC_WMI_EMBEDDED_OK:
  4640. {
  4641. WmiButtonEmbeddedOk(hDlg, ppi);
  4642. break;
  4643. }
  4644. case IDC_WMI_EMBEDDED_CANCEL:
  4645. {
  4646. WmiButtonEmbeddedCancel(hDlg, ppi);
  4647. break;
  4648. }
  4649. }
  4650. #if 0
  4651. //
  4652. // Add this code back in if we will need it
  4653. //
  4654. switch(LOWORD(wParam)) {
  4655. default:
  4656. break;
  4657. }
  4658. #endif
  4659. break;
  4660. case WM_CONTEXTMENU:
  4661. DebugPrint((7, "WMI: Leave ? WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
  4662. hDlg, uMessage, wParam, lParam));
  4663. return WmiContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  4664. case WM_HELP:
  4665. WmiHelp(hDlg, (LPHELPINFO) lParam);
  4666. break;
  4667. case WM_CTLCOLORSTATIC:
  4668. return WmiControlColorStatic((HDC)wParam, (HWND)lParam);
  4669. case WM_NOTIFY:
  4670. switch (((NMHDR *)lParam)->code) {
  4671. //
  4672. // Sent when the user clicks on Apply OR OK !!
  4673. //
  4674. case PSN_APPLY:
  4675. //
  4676. // Do what ever action is necessary
  4677. //
  4678. ReturnStatus = WmiApplyChanges(ppi,
  4679. hDlg);
  4680. if (ReturnStatus)
  4681. {
  4682. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  4683. DebugPrint((7, "WMI: Leave TRUE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
  4684. hDlg, uMessage, wParam, lParam));
  4685. }
  4686. SetWindowLong(hDlg,
  4687. DWLP_MSGRESULT, ReturnStatus ?
  4688. PSNRET_NOERROR : PSNRET_INVALID);
  4689. return(TRUE);
  4690. case UDN_DELTAPOS:
  4691. {
  4692. LPNMUPDOWN UpDown = (LPNMUPDOWN)lParam;
  4693. //
  4694. // Array spinner has changed. Note that it is biased +1 as
  4695. // compared with the array index
  4696. //
  4697. DebugPrint((1, "WMIPROP: iPos = %d, iDelta = %d\n",
  4698. UpDown->iPos, UpDown->iDelta));
  4699. WmiSetArrayIndex(hDlg,
  4700. ppi,
  4701. UpDown->iPos + UpDown->iDelta - 1);
  4702. return(TRUE);
  4703. }
  4704. default:
  4705. break;
  4706. }
  4707. break;
  4708. }
  4709. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  4710. DebugPrint((7, "WMI: Leave FALSE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
  4711. hDlg, uMessage, wParam, lParam));
  4712. return FALSE;
  4713. }
  4714. void
  4715. WmiUpdate (PPAGE_INFO ppi,
  4716. HWND hDlg)
  4717. {
  4718. }
  4719. BOOL
  4720. WmiContextMenu(
  4721. HWND HwndControl,
  4722. WORD Xpos,
  4723. WORD Ypos
  4724. )
  4725. {
  4726. return FALSE;
  4727. }
  4728. void
  4729. WmiHelp(
  4730. HWND ParentHwnd,
  4731. LPHELPINFO HelpInfo
  4732. )
  4733. {
  4734. }
  4735. //
  4736. // Debug support
  4737. //
  4738. #if DBG
  4739. #include <stdio.h> // for _vsnprintf
  4740. ULONG WmiDebug = 0;
  4741. CHAR WmiBuffer[DEBUG_BUFFER_LENGTH];
  4742. VOID
  4743. WmiDebugPrint(
  4744. ULONG DebugPrintLevel,
  4745. PCHAR DebugMessage,
  4746. ...
  4747. )
  4748. /*++
  4749. Routine Description:
  4750. Debug print for properties pages - stolen from classpnp\class.c
  4751. Arguments:
  4752. Debug print level between 0 and 3, with 3 being the most verbose.
  4753. Return Value:
  4754. None
  4755. --*/
  4756. {
  4757. va_list ap;
  4758. va_start(ap, DebugMessage);
  4759. if ((DebugPrintLevel <= (WmiDebug & 0x0000ffff)) ||
  4760. ((1 << (DebugPrintLevel + 15)) & WmiDebug)) {
  4761. _vsnprintf(WmiBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
  4762. OutputDebugStringA(WmiBuffer);
  4763. }
  4764. va_end(ap);
  4765. } // end WmiDebugPrint()
  4766. #else
  4767. //
  4768. // WmiDebugPrint stub
  4769. //
  4770. VOID
  4771. WmiDebugPrint(
  4772. ULONG DebugPrintLevel,
  4773. PCHAR DebugMessage,
  4774. ...
  4775. )
  4776. {
  4777. }
  4778. #endif // DBG
  4779. HRESULT DifAddPropertyPageAdvanced(
  4780. IN HDEVINFO DeviceInfoSet,
  4781. IN PSP_DEVINFO_DATA DeviceInfoData,
  4782. IN PTCHAR MachineName,
  4783. IN HANDLE MachineHandle
  4784. )
  4785. {
  4786. SP_ADDPROPERTYPAGE_DATA AddPropertyPageData;
  4787. BOOL b, PageAdded;
  4788. memset(&AddPropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
  4789. AddPropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  4790. b = SetupDiGetClassInstallParams(DeviceInfoSet, DeviceInfoData,
  4791. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  4792. sizeof(SP_ADDPROPERTYPAGE_DATA), NULL );
  4793. if (b)
  4794. {
  4795. if (AddPropertyPageData.NumDynamicPages < MAX_INSTALLWIZARD_DYNAPAGES)
  4796. {
  4797. PageAdded = WmiPropPageProvider(DeviceInfoSet,
  4798. DeviceInfoData,
  4799. &AddPropertyPageData,
  4800. MachineName,
  4801. MachineHandle);
  4802. if (PageAdded)
  4803. {
  4804. b = SetupDiSetClassInstallParams(
  4805. DeviceInfoSet,
  4806. DeviceInfoData,
  4807. (PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
  4808. sizeof(SP_ADDPROPERTYPAGE_DATA));
  4809. if (! b)
  4810. {
  4811. DebugPrint((1, "WMIPROP: SetupDiSetClassInstallParams(%p, %p) failed %d\n",
  4812. DeviceInfoSet, DeviceInfoData, GetLastError()));
  4813. }
  4814. }
  4815. } else {
  4816. DebugPrint((1, "WMIPROP: Already %d property sheets\n",
  4817. AddPropertyPageData.NumDynamicPages));
  4818. }
  4819. } else {
  4820. DebugPrint((1, "WMIPROP: SetupDiGetClassInstallParams(%p, %p) failed %d\n",
  4821. DeviceInfoSet, DeviceInfoData, GetLastError()));
  4822. }
  4823. return(NO_ERROR);
  4824. }
  4825. //+---------------------------------------------------------------------------
  4826. //
  4827. // Function: MyCoInstaller
  4828. //
  4829. // Purpose: Responds to co-installer messages
  4830. //
  4831. // Arguments:
  4832. // InstallFunction [in]
  4833. // DeviceInfoSet [in]
  4834. // DeviceInfoData [in]
  4835. // Context [inout]
  4836. //
  4837. // Returns: NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or an error code.
  4838. //
  4839. HRESULT
  4840. WmiPropCoInstaller (
  4841. IN DI_FUNCTION InstallFunction,
  4842. IN HDEVINFO DeviceInfoSet,
  4843. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4844. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  4845. )
  4846. {
  4847. if (DeviceInfoData != NULL)
  4848. {
  4849. //
  4850. // Only try to display property page for devices and not for
  4851. // the class
  4852. //
  4853. switch (InstallFunction)
  4854. {
  4855. case DIF_ADDPROPERTYPAGE_ADVANCED:
  4856. {
  4857. DifAddPropertyPageAdvanced(DeviceInfoSet,
  4858. DeviceInfoData,
  4859. NULL,
  4860. NULL);
  4861. break;
  4862. }
  4863. case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
  4864. {
  4865. SP_DEVINFO_LIST_DETAIL_DATA Detail;
  4866. Detail.cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA);
  4867. if (SetupDiGetDeviceInfoListDetail(DeviceInfoSet,
  4868. &Detail))
  4869. {
  4870. DebugPrint((1, "WMIPROP: Adding remote property pages for %ws\n",
  4871. Detail.RemoteMachineName));
  4872. DifAddPropertyPageAdvanced(DeviceInfoSet,
  4873. DeviceInfoData,
  4874. Detail.RemoteMachineName,
  4875. Detail.RemoteMachineHandle);
  4876. } else {
  4877. DebugPrint((1, "WMIPROP: SetupDiGetDeviceInfoListDetailA failed %d\n",
  4878. GetLastError()));
  4879. }
  4880. break;
  4881. }
  4882. default:
  4883. {
  4884. break;
  4885. }
  4886. }
  4887. }
  4888. return NO_ERROR;
  4889. }
  4890. BOOL WINAPI
  4891. DllMain(
  4892. HINSTANCE DllInstance,
  4893. DWORD Reason,
  4894. PVOID Reserved
  4895. )
  4896. {
  4897. switch(Reason) {
  4898. case DLL_PROCESS_ATTACH: {
  4899. g_hInstance = DllInstance;
  4900. DisableThreadLibraryCalls(DllInstance);
  4901. break;
  4902. }
  4903. case DLL_PROCESS_DETACH: {
  4904. g_hInstance = NULL;
  4905. break;
  4906. }
  4907. default: {
  4908. break;
  4909. }
  4910. }
  4911. return TRUE;
  4912. }