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

2183 lines
50 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: MetaUtil object
  6. File: MetaSchm.cpp
  7. Owner: t-BrianM
  8. This file contains implementation of the CMetaSchemaTable object and
  9. other schema related objects.
  10. The CMetaSchemaTable object has COM style reference counting so it
  11. can service objects created by CMetaUtil. I didn't make it a full
  12. blown COM object because all of the class stuff would be a pain to
  13. export.
  14. To reduce the overhead of maintaining this object (which may or
  15. may not be used), all information is loaded on demand, then set
  16. dirty or unloaded when portions of the metabase associated with it
  17. are modified.
  18. ===================================================================*/
  19. #include "stdafx.h"
  20. #include "MetaUtil.h"
  21. #include "MUtilObj.h"
  22. #include "MetaSchm.h"
  23. /*------------------------------------------------------------------
  24. * C P r o p I n f o
  25. */
  26. /*===================================================================
  27. CPropInfo::Init
  28. Constructor
  29. Parameters:
  30. dwId Id of property
  31. Returns:
  32. S_OK on success
  33. ===================================================================*/
  34. HRESULT CPropInfo::Init(DWORD dwId)
  35. {
  36. m_dwId = dwId;
  37. return S_OK;
  38. }
  39. /*===================================================================
  40. CPropInfo::SetName
  41. Sets the property name.
  42. Parameters:
  43. tszName Name of property
  44. Returns:
  45. E_OUTOFMEMORY if allocation fails
  46. S_OK on success
  47. ===================================================================*/
  48. HRESULT CPropInfo::SetName(LPCTSTR tszName)
  49. {
  50. ASSERT_STRING(tszName);
  51. ASSERT(m_tszName == NULL); // m_tszName not yet set
  52. m_tszName = new TCHAR[_tcslen(tszName) + 1];
  53. if (m_tszName == NULL) {
  54. return E_OUTOFMEMORY;
  55. }
  56. _tcscpy(m_tszName, tszName);
  57. return S_OK;
  58. }
  59. /*===================================================================
  60. CPropInfo::SetTypeInfo
  61. Sets the property name.
  62. Parameters:
  63. pType PropValue structure containing type information.
  64. Returns:
  65. E_OUTOFMEMORY if allocation fails
  66. S_OK on success
  67. ===================================================================*/
  68. HRESULT CPropInfo::SetTypeInfo(PropValue *pType)
  69. {
  70. ASSERT_POINTER(pType, PropValue);
  71. ASSERT(m_pType == NULL); // m_pType not yet set
  72. m_pType = new PropValue;
  73. if (m_pType == NULL) {
  74. return E_OUTOFMEMORY;
  75. }
  76. memcpy(m_pType, pType, sizeof(PropValue));
  77. return S_OK;
  78. }
  79. /*------------------------------------------------------------------
  80. * C P r o p I n f o T a b l e
  81. */
  82. /*===================================================================
  83. CPropInfoTable::CPropInfoTable
  84. Constructor
  85. Parameters:
  86. None
  87. Returns:
  88. Nothing
  89. ===================================================================*/
  90. CPropInfoTable::CPropInfoTable() : m_fLoaded(FALSE)
  91. {
  92. // Clear the hash tables
  93. memset(m_rgCPropIdTable, 0, PROPERTY_HASH_SIZE * sizeof(CPropInfo *));
  94. memset(m_rgCPropNameTable, 0, PROPERTY_HASH_SIZE * sizeof(CPropInfo *));
  95. }
  96. /*===================================================================
  97. CPropInfoTable::~CPropInfoTable
  98. Destructor
  99. Parameters:
  100. None
  101. Returns:
  102. Nothing
  103. ===================================================================*/
  104. CPropInfoTable::~CPropInfoTable()
  105. {
  106. if (m_fLoaded) {
  107. Unload();
  108. }
  109. }
  110. /*===================================================================
  111. CPropInfoTable::Load
  112. Loads properties from the "_Machine_/Schema/Properties" key into the
  113. property information table. On failure, recovers by unloading
  114. everything.
  115. Parameters:
  116. pIMeta ATL Smart pointer to the metabase
  117. hMDComp Open metabase handle to "_Machine_" key
  118. Returns:
  119. E_OUTOFMEMORY on allocation failure
  120. S_OK on success
  121. ===================================================================*/
  122. HRESULT CPropInfoTable::Load(CComPtr<IMSAdminBase> &pIMeta,
  123. METADATA_HANDLE hMDComp)
  124. {
  125. //If it's already loaded, unload then reload
  126. if (m_fLoaded) {
  127. Unload();
  128. }
  129. USES_CONVERSION;
  130. HRESULT hr;
  131. int iDataIndex;
  132. METADATA_RECORD mdrDataRec;
  133. DWORD dwReqDataLen;
  134. DWORD dwReturnBufLen;
  135. UCHAR *lpReturnBuf = NULL;
  136. unsigned int uiLoc;
  137. CPropInfo *pCNewProp;
  138. METADATA_HANDLE hMDNames = NULL;
  139. METADATA_HANDLE hMDTypes = NULL;
  140. //Setup the return buffer
  141. dwReturnBufLen = 1024;
  142. lpReturnBuf = new UCHAR[dwReturnBufLen];
  143. if (lpReturnBuf == NULL)
  144. return E_OUTOFMEMORY;
  145. // Open the Schema/Properties/Names subkey
  146. hr = pIMeta->OpenKey(hMDComp,
  147. L"Schema/Properties/Names",
  148. METADATA_PERMISSION_READ,
  149. MUTIL_OPEN_KEY_TIMEOUT,
  150. &hMDNames);
  151. if (FAILED(hr)) {
  152. delete lpReturnBuf;
  153. return hr;
  154. };
  155. // For each name
  156. iDataIndex = 0;
  157. mdrDataRec.dwMDIdentifier = 0;
  158. mdrDataRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  159. mdrDataRec.dwMDUserType = ALL_METADATA;
  160. mdrDataRec.dwMDDataType = ALL_METADATA;
  161. mdrDataRec.dwMDDataLen = dwReturnBufLen;
  162. mdrDataRec.pbMDData = (PBYTE) lpReturnBuf;
  163. mdrDataRec.dwMDDataTag = 0;
  164. hr = pIMeta->EnumData(hMDNames,
  165. NULL,
  166. &mdrDataRec,
  167. iDataIndex,
  168. &dwReqDataLen);
  169. while (SUCCEEDED(hr)) {
  170. // Make sure we got a string
  171. if (mdrDataRec.dwMDDataType != STRING_METADATA) {
  172. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  173. goto LError;
  174. }
  175. // Create the property object
  176. pCNewProp = new CPropInfo;
  177. if (pCNewProp == NULL) {
  178. hr = E_OUTOFMEMORY;
  179. goto LError;
  180. }
  181. hr = pCNewProp->Init(mdrDataRec.dwMDIdentifier);
  182. if (FAILED(hr)) {
  183. delete pCNewProp;
  184. goto LError;
  185. }
  186. hr = pCNewProp->SetName(W2T(reinterpret_cast<LPWSTR> (lpReturnBuf)));
  187. if (FAILED(hr)) {
  188. delete pCNewProp;
  189. goto LError;
  190. }
  191. // Add it to the Id hash table
  192. uiLoc = IdHash(mdrDataRec.dwMDIdentifier);
  193. pCNewProp->m_pCIdHashNext = m_rgCPropIdTable[uiLoc];
  194. m_rgCPropIdTable[uiLoc] = pCNewProp;
  195. // Add it to the Name hash table
  196. uiLoc = NameHash(pCNewProp->m_tszName);
  197. pCNewProp->m_pCNameHashNext = m_rgCPropNameTable[uiLoc];
  198. m_rgCPropNameTable[uiLoc] = pCNewProp;
  199. iDataIndex++;
  200. mdrDataRec.dwMDIdentifier = 0;
  201. mdrDataRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  202. mdrDataRec.dwMDUserType = ALL_METADATA;
  203. mdrDataRec.dwMDDataType = ALL_METADATA;
  204. mdrDataRec.dwMDDataLen = dwReturnBufLen;
  205. mdrDataRec.pbMDData = (PBYTE) lpReturnBuf;
  206. mdrDataRec.dwMDDataTag = 0;
  207. hr = pIMeta->EnumData(hMDNames,
  208. NULL,
  209. &mdrDataRec,
  210. iDataIndex,
  211. &dwReqDataLen);
  212. }
  213. // Make sure we ran out of items
  214. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  215. goto LError;
  216. }
  217. // Close the Schema/Properties/Names sub-key
  218. pIMeta->CloseKey(hMDNames);
  219. hMDNames = NULL;
  220. // Open the Schema/Properties/Types sub-key
  221. hr = pIMeta->OpenKey(hMDComp,
  222. L"Schema/Properties/Types",
  223. METADATA_PERMISSION_READ,
  224. MUTIL_OPEN_KEY_TIMEOUT,
  225. &hMDTypes);
  226. if (FAILED(hr)) {
  227. goto LError;
  228. };
  229. // For each type
  230. iDataIndex = 0;
  231. mdrDataRec.dwMDIdentifier = 0;
  232. mdrDataRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  233. mdrDataRec.dwMDUserType = ALL_METADATA;
  234. mdrDataRec.dwMDDataType = ALL_METADATA;
  235. mdrDataRec.dwMDDataLen = dwReturnBufLen;
  236. mdrDataRec.pbMDData = (PBYTE) lpReturnBuf;
  237. mdrDataRec.dwMDDataTag = 0;
  238. hr = pIMeta->EnumData(hMDTypes,
  239. NULL,
  240. &mdrDataRec,
  241. iDataIndex,
  242. &dwReqDataLen);
  243. while (SUCCEEDED(hr)) {
  244. // Make sure we got binary data
  245. if (mdrDataRec.dwMDDataType != BINARY_METADATA) {
  246. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  247. goto LError;
  248. }
  249. // Look for an existing property object for this Id
  250. pCNewProp = GetPropInfo(mdrDataRec.dwMDIdentifier);
  251. if (pCNewProp == NULL) {
  252. // Create the property object
  253. pCNewProp = new CPropInfo;
  254. if (pCNewProp == NULL) {
  255. hr = E_OUTOFMEMORY;
  256. goto LError;
  257. }
  258. hr = pCNewProp->Init(mdrDataRec.dwMDIdentifier);
  259. if (FAILED(hr)) {
  260. delete pCNewProp;
  261. goto LError;
  262. }
  263. // Add it to the Id hash table
  264. uiLoc = IdHash(mdrDataRec.dwMDIdentifier);
  265. pCNewProp->m_pCIdHashNext = m_rgCPropIdTable[uiLoc];
  266. m_rgCPropIdTable[uiLoc] = pCNewProp;
  267. }
  268. // Add type information to the property object
  269. pCNewProp->SetTypeInfo(reinterpret_cast<PropValue *> (lpReturnBuf));
  270. iDataIndex++;
  271. mdrDataRec.dwMDIdentifier = 0;
  272. mdrDataRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  273. mdrDataRec.dwMDUserType = ALL_METADATA;
  274. mdrDataRec.dwMDDataType = ALL_METADATA;
  275. mdrDataRec.dwMDDataLen = dwReturnBufLen;
  276. mdrDataRec.pbMDData = (PBYTE) lpReturnBuf;
  277. mdrDataRec.dwMDDataTag = 0;
  278. hr = pIMeta->EnumData(hMDTypes,
  279. NULL,
  280. &mdrDataRec,
  281. iDataIndex,
  282. &dwReqDataLen);
  283. }
  284. // Make sure we ran out of items
  285. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  286. goto LError;
  287. }
  288. // Close the Schema/Properties/Types sub-key
  289. pIMeta->CloseKey(hMDTypes);
  290. hMDTypes = NULL;
  291. delete lpReturnBuf;
  292. m_fLoaded = TRUE;
  293. return S_OK;
  294. LError:
  295. if (hMDNames != NULL) {
  296. pIMeta->CloseKey(hMDNames);
  297. }
  298. if (hMDTypes != NULL) {
  299. pIMeta->CloseKey(hMDTypes);
  300. }
  301. if (lpReturnBuf != NULL) {
  302. delete lpReturnBuf;
  303. }
  304. // Cleanup the entries we loaded
  305. Unload();
  306. return hr;
  307. }
  308. /*===================================================================
  309. CPropInfoTable::Unload
  310. Unloads the property information table.
  311. Parameters:
  312. None
  313. Returns:
  314. Nothing
  315. ===================================================================*/
  316. void CPropInfoTable::Unload()
  317. {
  318. int iIndex;
  319. CPropInfo *pCDeleteProp;
  320. //Clear the Name table
  321. memset(m_rgCPropNameTable, 0, PROPERTY_HASH_SIZE * sizeof(CPropInfo *));
  322. // For each Id hash table entry
  323. for (iIndex =0; iIndex < PROPERTY_HASH_SIZE; iIndex++) {
  324. // While the entry is not empty
  325. while (m_rgCPropIdTable[iIndex] != NULL) {
  326. // Nuke the first table entry
  327. pCDeleteProp = m_rgCPropIdTable[iIndex];
  328. m_rgCPropIdTable[iIndex] = pCDeleteProp->m_pCIdHashNext;
  329. delete pCDeleteProp;
  330. }
  331. }
  332. m_fLoaded = FALSE;
  333. }
  334. /*===================================================================
  335. CPropInfoTable::GetPropInfo
  336. Gets property information from the table based on property id
  337. Parameters:
  338. dwId Id of property to get
  339. Returns:
  340. NULL if property not found or error
  341. Pointer to CPropInfo class on success
  342. ===================================================================*/
  343. CPropInfo *CPropInfoTable::GetPropInfo(DWORD dwId)
  344. {
  345. CPropInfo *pCCurProp;
  346. // Go to the table location
  347. pCCurProp = m_rgCPropIdTable[IdHash(dwId)];
  348. // Look at all of the entries
  349. while ((pCCurProp != NULL) && (pCCurProp->m_dwId != dwId)) {
  350. pCCurProp = pCCurProp->m_pCIdHashNext;
  351. }
  352. return pCCurProp; // Will be NULL if not found
  353. }
  354. /*===================================================================
  355. CPropInfoTable::GetPropInfo
  356. Gets property information from the table based on property name.
  357. Case insensitive.
  358. Parameters:
  359. tszName Name of property to get
  360. Returns:
  361. NULL if property not found or error
  362. Pointer to CPropInfo class on success
  363. ===================================================================*/
  364. CPropInfo *CPropInfoTable::GetPropInfo(LPCTSTR tszName)
  365. {
  366. CPropInfo *pCCurProp;
  367. // Go to the table location
  368. pCCurProp = m_rgCPropNameTable[NameHash(tszName)];
  369. // Look at all of the entries
  370. while ((pCCurProp != NULL) &&
  371. (_tcsicmp(pCCurProp->m_tszName, tszName) != 0)) {
  372. pCCurProp = pCCurProp->m_pCNameHashNext;
  373. }
  374. return pCCurProp; // Will be NULL if not found
  375. }
  376. /*===================================================================
  377. CPropInfoTable::NameHash
  378. Private function to get a hash value from a property name for the
  379. name table. Case insensitive.
  380. Parameters:
  381. tszName Name to hash
  382. Returns:
  383. Hash value of name
  384. ===================================================================*/
  385. unsigned int CPropInfoTable::NameHash(LPCTSTR tszName)
  386. {
  387. ASSERT_STRING(tszName);
  388. unsigned int uiSum;
  389. unsigned int uiIndex;
  390. uiSum = 0;
  391. for (uiIndex=0; uiIndex < _tcslen(tszName); uiIndex++) {
  392. uiSum += _totlower(tszName[uiIndex]);
  393. }
  394. return (uiSum % PROPERTY_HASH_SIZE);
  395. }
  396. /*------------------------------------------------------------------
  397. * C C l a s s P r o p I n f o
  398. */
  399. // Everything is inline
  400. /*------------------------------------------------------------------
  401. * C C l a s s I n f o
  402. */
  403. /*===================================================================
  404. CClassInfo::CClassInfo
  405. Constructor
  406. Parameters:
  407. None
  408. Returns:
  409. Nothing
  410. ===================================================================*/
  411. CClassInfo::CClassInfo() : m_tszName(NULL),
  412. m_pCHashNext(NULL),
  413. m_fLoaded(FALSE),
  414. m_pCOptionalPropList(NULL),
  415. m_pCMandatoryPropList(NULL)
  416. {
  417. // Clear the hash table
  418. memset(m_rgCPropTable, 0, CLASS_PROPERTY_HASH_SIZE * sizeof(CClassPropInfo *));
  419. }
  420. /*===================================================================
  421. CClassInfo::Init
  422. Constructor
  423. Parameters:
  424. tszName Name of the class
  425. Returns:
  426. E_OUTOFMEMORY on allocation failure
  427. S_OK on success
  428. ===================================================================*/
  429. HRESULT CClassInfo::Init(LPCTSTR tszName)
  430. {
  431. ASSERT_STRING(tszName);
  432. m_tszName = new TCHAR[_tcslen(tszName) + 1];
  433. if (m_tszName == NULL) {
  434. return E_OUTOFMEMORY;
  435. }
  436. _tcscpy(m_tszName, tszName);
  437. return S_OK;
  438. }
  439. /*===================================================================
  440. CClassInfo::~CClassInfo
  441. Destructor
  442. Parameters:
  443. None
  444. Returns:
  445. Nothing
  446. ===================================================================*/
  447. CClassInfo::~CClassInfo()
  448. {
  449. Unload();
  450. if (m_tszName != NULL) {
  451. delete m_tszName;
  452. }
  453. }
  454. /*===================================================================
  455. CClassInfo::Load
  456. Loads class properties from the "_Machine_/Schema/Classes/_Class_/Mandatory"
  457. and "_Machine_/Schema/Classes/_Class_/Optional" keys into the class
  458. property information table, mandatory list and optional list. On
  459. failure, recovers by unloading everything.
  460. Parameters:
  461. pIMeta ATL Smart pointer to the metabase
  462. hMDClasses Open metabase handle to "_Machine_/Schema/Classes" key
  463. Returns:
  464. E_OUTOFMEMORY on allocation failure
  465. S_OK on success
  466. ===================================================================*/
  467. HRESULT CClassInfo::Load(CComPtr<IMSAdminBase> &pIMeta,
  468. METADATA_HANDLE hMDClasses)
  469. {
  470. USES_CONVERSION;
  471. HRESULT hr;
  472. //If it's already loaded, unload then reload
  473. if (m_fLoaded) {
  474. Unload();
  475. }
  476. // Open the class key
  477. METADATA_HANDLE hMDClass = NULL;
  478. hr = pIMeta->OpenKey(hMDClasses,
  479. T2W(m_tszName),
  480. METADATA_PERMISSION_READ,
  481. 1000,
  482. &hMDClass);
  483. if (FAILED(hr)) {
  484. return hr;
  485. }
  486. // Load the class properties
  487. METADATA_HANDLE hMDClassProp = NULL;
  488. int iDataIndex;
  489. METADATA_RECORD mdr;
  490. DWORD dwReqDataLen;
  491. DWORD dwReturnBufLen;
  492. UCHAR *lpReturnBuf = NULL;
  493. unsigned int uiLoc;
  494. CClassPropInfo *pCNewClassProp;
  495. //Setup the return buffer
  496. dwReturnBufLen = 1024;
  497. lpReturnBuf = new UCHAR[dwReturnBufLen];
  498. if (lpReturnBuf == NULL) {
  499. hr = E_OUTOFMEMORY;
  500. goto LError;
  501. }
  502. // Load the mandatory class properties
  503. // Open the Mandatory key
  504. hr = pIMeta->OpenKey(hMDClass,
  505. L"Mandatory",
  506. METADATA_PERMISSION_READ,
  507. 1000,
  508. &hMDClassProp);
  509. if (FAILED(hr)) {
  510. goto LError;
  511. }
  512. // For each Mandatory property
  513. iDataIndex = 0;
  514. mdr.dwMDIdentifier = 0;
  515. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  516. mdr.dwMDUserType = ALL_METADATA;
  517. mdr.dwMDDataType = ALL_METADATA;
  518. mdr.dwMDDataLen = dwReturnBufLen;
  519. mdr.pbMDData = (PBYTE) lpReturnBuf;
  520. mdr.dwMDDataTag = 0;
  521. hr = pIMeta->EnumData(hMDClassProp,
  522. NULL,
  523. &mdr,
  524. iDataIndex,
  525. &dwReqDataLen);
  526. while (SUCCEEDED(hr)|| (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
  527. // Handle insufficent buffer errors
  528. if ((HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
  529. // Allocate more memory
  530. delete lpReturnBuf;
  531. dwReturnBufLen = dwReqDataLen;
  532. lpReturnBuf = new UCHAR[dwReturnBufLen];
  533. if (lpReturnBuf == NULL) {
  534. hr = E_OUTOFMEMORY;
  535. goto LError;
  536. }
  537. // Loop again
  538. hr = S_OK;
  539. }
  540. else { //Buffer is big enough, proceed to add the class property
  541. // Create the Class Property object
  542. pCNewClassProp = new CClassPropInfo;
  543. if (pCNewClassProp == NULL) {
  544. hr = E_OUTOFMEMORY;
  545. goto LError;
  546. }
  547. hr = pCNewClassProp->Init(mdr.dwMDIdentifier, TRUE);
  548. if (FAILED(hr)) {
  549. delete pCNewClassProp;
  550. goto LError;
  551. }
  552. //Add it to the mandatory list
  553. pCNewClassProp->m_pCListNext = m_pCMandatoryPropList;
  554. m_pCMandatoryPropList = pCNewClassProp;
  555. //Add it to the hash table
  556. uiLoc = Hash(mdr.dwMDIdentifier);
  557. pCNewClassProp->m_pCHashNext = m_rgCPropTable[uiLoc];
  558. m_rgCPropTable[uiLoc] = pCNewClassProp;
  559. iDataIndex++;
  560. }
  561. mdr.dwMDIdentifier = 0;
  562. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  563. mdr.dwMDUserType = ALL_METADATA;
  564. mdr.dwMDDataType = ALL_METADATA;
  565. mdr.dwMDDataLen = dwReturnBufLen;
  566. mdr.pbMDData = (PBYTE) lpReturnBuf;
  567. mdr.dwMDDataTag = 0;
  568. hr = pIMeta->EnumData(hMDClassProp,
  569. NULL,
  570. &mdr,
  571. iDataIndex,
  572. &dwReqDataLen);
  573. }
  574. // Make sure we ran out of items
  575. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  576. goto LError;
  577. }
  578. // Close the Mandatory key
  579. pIMeta->CloseKey(hMDClassProp);
  580. hMDClassProp = NULL;
  581. // Load the optional class properties
  582. // Open the Optional key
  583. hr = pIMeta->OpenKey(hMDClass,
  584. L"Optional",
  585. METADATA_PERMISSION_READ,
  586. 1000,
  587. &hMDClassProp);
  588. if (FAILED(hr)) {
  589. goto LError;
  590. }
  591. // For each Optional property
  592. iDataIndex = 0;
  593. mdr.dwMDIdentifier = 0;
  594. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  595. mdr.dwMDUserType = ALL_METADATA;
  596. mdr.dwMDDataType = ALL_METADATA;
  597. mdr.dwMDDataLen = dwReturnBufLen;
  598. mdr.pbMDData = (PBYTE) lpReturnBuf;
  599. mdr.dwMDDataTag = 0;
  600. hr = pIMeta->EnumData(hMDClassProp,
  601. NULL,
  602. &mdr,
  603. iDataIndex,
  604. &dwReqDataLen);
  605. while (SUCCEEDED(hr)|| (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
  606. // Handle insufficent buffer errors
  607. if ((HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
  608. // Allocate more memory
  609. delete lpReturnBuf;
  610. dwReturnBufLen = dwReqDataLen;
  611. lpReturnBuf = new UCHAR[dwReturnBufLen];
  612. if (lpReturnBuf == NULL) {
  613. hr = E_OUTOFMEMORY;
  614. goto LError;
  615. }
  616. // Loop again
  617. hr = S_OK;
  618. }
  619. else { //Buffer is big enough, proceed to add the class property
  620. // Create the Class Property object
  621. pCNewClassProp = new CClassPropInfo;
  622. if (pCNewClassProp == NULL) {
  623. hr = E_OUTOFMEMORY;
  624. goto LError;
  625. }
  626. hr = pCNewClassProp->Init(mdr.dwMDIdentifier, FALSE);
  627. if (FAILED(hr)) {
  628. delete pCNewClassProp;
  629. goto LError;
  630. }
  631. //Add it to the optional list
  632. pCNewClassProp->m_pCListNext = m_pCOptionalPropList;
  633. m_pCOptionalPropList = pCNewClassProp;
  634. //Add it to the hash table
  635. uiLoc = Hash(mdr.dwMDIdentifier);
  636. pCNewClassProp->m_pCHashNext = m_rgCPropTable[uiLoc];
  637. m_rgCPropTable[uiLoc] = pCNewClassProp;
  638. iDataIndex++;
  639. }
  640. mdr.dwMDIdentifier = 0;
  641. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  642. mdr.dwMDUserType = ALL_METADATA;
  643. mdr.dwMDDataType = ALL_METADATA;
  644. mdr.dwMDDataLen = dwReturnBufLen;
  645. mdr.pbMDData = (PBYTE) lpReturnBuf;
  646. mdr.dwMDDataTag = 0;
  647. hr = pIMeta->EnumData(hMDClassProp,
  648. NULL,
  649. &mdr,
  650. iDataIndex,
  651. &dwReqDataLen);
  652. }
  653. // Make sure we ran out of items
  654. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  655. goto LError;
  656. }
  657. // Close the Optional key
  658. pIMeta->CloseKey(hMDClassProp);
  659. delete lpReturnBuf;
  660. // Close the Class key
  661. pIMeta->CloseKey(hMDClass);
  662. m_fLoaded = TRUE;
  663. return S_OK;
  664. //Error durring loading, back out
  665. LError:
  666. if (hMDClassProp != NULL) {
  667. pIMeta->CloseKey(hMDClassProp);
  668. }
  669. if (hMDClass != NULL) {
  670. pIMeta->CloseKey(hMDClass);
  671. }
  672. if (lpReturnBuf != NULL) {
  673. delete lpReturnBuf;
  674. }
  675. Unload();
  676. return hr;
  677. }
  678. /*===================================================================
  679. CClassInfo::Unload
  680. Unloads the class property information table.
  681. Parameters:
  682. None
  683. Returns:
  684. Nothing
  685. ===================================================================*/
  686. void CClassInfo::Unload()
  687. {
  688. int iIndex;
  689. CClassPropInfo *pCDeleteProp;
  690. // Clear the lists
  691. m_pCOptionalPropList = NULL;
  692. m_pCMandatoryPropList = NULL;
  693. // For each hash table entry
  694. for (iIndex =0; iIndex < CLASS_PROPERTY_HASH_SIZE; iIndex++) {
  695. // While the entry is not empty
  696. while (m_rgCPropTable[iIndex] != NULL) {
  697. // Nuke the first table entry
  698. pCDeleteProp = m_rgCPropTable[iIndex];
  699. m_rgCPropTable[iIndex] = pCDeleteProp->m_pCHashNext;
  700. delete pCDeleteProp;
  701. }
  702. }
  703. m_fLoaded = FALSE;
  704. }
  705. /*===================================================================
  706. CClassInfo::GetProperty
  707. Get the CClassPropInfo (class property info) object from the hash
  708. table given the property id.
  709. Parameters:
  710. dwId Identifier of the property to get
  711. Returns:
  712. NULL on failure
  713. Pointer to the CClassPropInfo object on success
  714. ===================================================================*/
  715. CClassPropInfo *CClassInfo::GetProperty(DWORD dwId) {
  716. CClassPropInfo *pCCurProp;
  717. // Go to the table location
  718. pCCurProp = m_rgCPropTable[Hash(dwId)];
  719. // Look at all of the entries
  720. while ((pCCurProp != NULL) && (pCCurProp->m_dwId != dwId)) {
  721. pCCurProp = pCCurProp->m_pCHashNext;
  722. }
  723. return pCCurProp; // Will be NULL if not found
  724. }
  725. /*------------------------------------------------------------------
  726. * C C l a s s I n f o T a b l e
  727. */
  728. /*===================================================================
  729. CClassInfoTable::CClassInfoTable
  730. Constructor
  731. Parameters:
  732. None
  733. Returns:
  734. Nothing
  735. ===================================================================*/
  736. CClassInfoTable::CClassInfoTable() : m_fLoaded(FALSE)
  737. {
  738. // Clear the hash table
  739. memset(m_rgCClassTable, 0, CLASS_HASH_SIZE * sizeof(CClassInfo *));
  740. }
  741. /*===================================================================
  742. CClassInfoTable::~CClassInfoTable
  743. Destructor
  744. Parameters:
  745. None
  746. Returns:
  747. Nothing
  748. ===================================================================*/
  749. CClassInfoTable::~CClassInfoTable()
  750. {
  751. if (m_fLoaded) {
  752. Unload();
  753. }
  754. }
  755. /*===================================================================
  756. CClassInfoTable::Load
  757. Loads classes from the "_Machine_/Schema/Classes" key into the class
  758. information table. On failure, recovers by unloading everything.
  759. Parameters:
  760. pIMeta ATL Smart pointer to the metabase
  761. hMDComp Open metabase handle to "_Machine_" key
  762. Returns:
  763. E_OUTOFMEMORY on allocation failure
  764. S_OK on success
  765. ===================================================================*/
  766. HRESULT CClassInfoTable::Load(CComPtr<IMSAdminBase> &pIMeta,
  767. METADATA_HANDLE hMDComp)
  768. {
  769. ASSERT(pIMeta.p != NULL);
  770. USES_CONVERSION;
  771. HRESULT hr;
  772. //If it's already loaded, unload then reload
  773. if (m_fLoaded) {
  774. Unload();
  775. }
  776. int iKeyIndex;
  777. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  778. LPTSTR tszSubKey;
  779. int iLoc;
  780. CClassInfo *pCNewClass;
  781. //Load the classes
  782. METADATA_HANDLE hMDClasses = NULL;
  783. // Open the Schema/Classes subkey
  784. hr = pIMeta->OpenKey(hMDComp,
  785. L"Schema/Classes",
  786. METADATA_PERMISSION_READ,
  787. 1000,
  788. &hMDClasses);
  789. if (FAILED(hr)) {
  790. return hr;
  791. };
  792. // For each subkey
  793. iKeyIndex = 0;
  794. hr = pIMeta->EnumKeys(hMDClasses,
  795. NULL,
  796. wszSubKey,
  797. iKeyIndex);
  798. while (SUCCEEDED(hr)) {
  799. tszSubKey = W2T(wszSubKey);
  800. // Create the new class
  801. pCNewClass = new CClassInfo;
  802. if (pCNewClass == NULL) {
  803. hr = E_OUTOFMEMORY;
  804. goto LError;
  805. }
  806. hr = pCNewClass->Init(tszSubKey);
  807. if (FAILED(hr)) {
  808. delete pCNewClass;
  809. goto LError;
  810. }
  811. // Load the class properties
  812. hr = pCNewClass->Load(pIMeta, hMDClasses);
  813. if (FAILED(hr)) {
  814. delete pCNewClass;
  815. goto LError;
  816. }
  817. // Add it to the hash table
  818. iLoc = Hash(tszSubKey);
  819. pCNewClass->m_pCHashNext = m_rgCClassTable[iLoc];
  820. m_rgCClassTable[iLoc] = pCNewClass;
  821. iKeyIndex++;
  822. hr = pIMeta->EnumKeys(hMDClasses,
  823. NULL,
  824. wszSubKey,
  825. iKeyIndex);
  826. }
  827. //Make sure we ran out of items
  828. if (!(HRESULT_CODE(hr) == ERROR_NO_MORE_ITEMS)) {
  829. goto LError;
  830. }
  831. // Close the schema properties key
  832. pIMeta->CloseKey(hMDClasses);
  833. m_fLoaded = TRUE;
  834. return S_OK;
  835. LError:
  836. if (hMDClasses != NULL) {
  837. pIMeta->CloseKey(hMDClasses);
  838. }
  839. // Cleanup the entries we loaded
  840. Unload();
  841. return hr;
  842. }
  843. /*===================================================================
  844. CClassInfo::Unload
  845. Unloads the class information table.
  846. Parameters:
  847. None
  848. Returns:
  849. Nothing
  850. ===================================================================*/
  851. void CClassInfoTable::Unload()
  852. {
  853. int iIndex;
  854. CClassInfo *pCDeleteClass;
  855. // For each hash table entry
  856. for (iIndex =0; iIndex < CLASS_HASH_SIZE; iIndex++) {
  857. // While the entry is not empty
  858. while (m_rgCClassTable[iIndex] != NULL) {
  859. // Nuke the first table entry
  860. pCDeleteClass = m_rgCClassTable[iIndex];
  861. m_rgCClassTable[iIndex] = pCDeleteClass->m_pCHashNext;
  862. delete pCDeleteClass;
  863. }
  864. }
  865. m_fLoaded = FALSE;
  866. }
  867. /*===================================================================
  868. CCClasssInfoTable::GetClassInfo
  869. Get the CClassInfo (class info) object from the hash table given
  870. the class name
  871. Parameters:
  872. tszClassName Name of the class to get info for
  873. Returns:
  874. NULL on failure
  875. Pointer to the CClassInfo object on success
  876. ===================================================================*/
  877. CClassInfo *CClassInfoTable::GetClassInfo(LPCTSTR tszName)
  878. {
  879. ASSERT_STRING(tszName);
  880. CClassInfo *pCCurClass;
  881. // Go to the table location
  882. pCCurClass = m_rgCClassTable[Hash(tszName)];
  883. // Look at all of the entries
  884. while ((pCCurClass != NULL) &&
  885. (_tcscmp(pCCurClass->m_tszName, tszName) != 0)) {
  886. pCCurClass = pCCurClass->m_pCHashNext;
  887. }
  888. return pCCurClass; // Will be NULL if not found
  889. }
  890. /*===================================================================
  891. CClassInfoTable::Hash
  892. Private function to get a hash value from a class name for the
  893. class table.
  894. Parameters:
  895. tszName Name to hash
  896. Returns:
  897. Hash value of name
  898. ===================================================================*/
  899. unsigned int CClassInfoTable::Hash(LPCTSTR tszName)
  900. {
  901. ASSERT_STRING(tszName);
  902. unsigned int uiSum;
  903. unsigned int uiIndex;
  904. uiSum = 0;
  905. for (uiIndex=0; uiIndex < _tcslen(tszName); uiIndex++) {
  906. uiSum += tszName[uiIndex];
  907. }
  908. return (uiSum % CLASS_HASH_SIZE);
  909. }
  910. /*------------------------------------------------------------------
  911. * C M e t a S c h e m a
  912. */
  913. /*===================================================================
  914. CMetaSchema::Init
  915. Constructor
  916. Parameters:
  917. pIMeta ATL Smart pointer to the metabase
  918. tszMachineName Name of machine the schema is for
  919. Returns:
  920. E_OUTOFMEMORY if allocation fails
  921. S_OK on success
  922. ===================================================================*/
  923. HRESULT CMetaSchema::Init(const CComPtr<IMSAdminBase> &pIMeta,
  924. LPCTSTR tszMachineName)
  925. {
  926. ASSERT(pIMeta.p != NULL);
  927. ASSERT_STRING(tszMachineName);
  928. m_pIMeta = pIMeta;
  929. m_tszMachineName = new TCHAR[_tcslen(tszMachineName) + 1];
  930. if (m_tszMachineName == NULL)
  931. return E_OUTOFMEMORY;
  932. _tcscpy(m_tszMachineName, tszMachineName);
  933. return S_OK;
  934. }
  935. /*===================================================================
  936. CMetaSchema::GetPropInfo
  937. Get the CPropInfo (property info) object for a given id
  938. Parameters:
  939. dwId Id of property to get info for
  940. Returns:
  941. NULL on failure
  942. Pointer to the CPropInfo object on success
  943. ===================================================================*/
  944. CPropInfo *CMetaSchema::GetPropInfo(DWORD dwId)
  945. {
  946. // Make sure the property table is up to date
  947. if (m_fPropTableDirty) {
  948. HRESULT hr;
  949. hr = LoadPropTable();
  950. if (FAILED(hr)) {
  951. return NULL;
  952. }
  953. }
  954. // Pass on the call
  955. return m_CPropInfoTable.GetPropInfo(dwId);
  956. }
  957. /*===================================================================
  958. CMetaSchema::GetPropInfo
  959. Get the CPropInfo (property info) object for a given name
  960. Parameters:
  961. tszName Name of property to get info for
  962. Returns:
  963. NULL on failure
  964. Pointer to the CPropInfo object on success
  965. ===================================================================*/
  966. CPropInfo *CMetaSchema::GetPropInfo(LPCTSTR tszName)
  967. {
  968. ASSERT_STRING(tszName);
  969. // Make sure the property table is up to date
  970. if (m_fPropTableDirty) {
  971. HRESULT hr;
  972. hr = LoadPropTable();
  973. if (FAILED(hr)) {
  974. return NULL;
  975. }
  976. }
  977. // Pass on the call
  978. return m_CPropInfoTable.GetPropInfo(tszName);
  979. }
  980. /*===================================================================
  981. CMetaSchema::GetClassInfo
  982. Get the CClassInfo (class info) object for a given class name
  983. Parameters:
  984. tszClassName Name of the class to get info for
  985. Returns:
  986. NULL on failure
  987. Pointer to the CClassInfo object on success
  988. ===================================================================*/
  989. CClassInfo *CMetaSchema::GetClassInfo(LPCTSTR tszClassName) {
  990. ASSERT_STRING(tszClassName);
  991. // Make sure the class table is up to date
  992. if (m_fClassTableDirty) {
  993. HRESULT hr;
  994. hr = LoadClassTable();
  995. if (FAILED(hr)) {
  996. return NULL;
  997. }
  998. }
  999. // Pass on the call
  1000. return m_CClassInfoTable.GetClassInfo(tszClassName);
  1001. }
  1002. /*===================================================================
  1003. CMetaSchema:::GetClassPropInfo
  1004. Get the CClassPropInfo (class property info) object for a given
  1005. class name and property id.
  1006. Parameters:
  1007. tszClassName Name of the class get property from
  1008. dwPropId Id of property to get info for
  1009. Returns:
  1010. NULL on failure
  1011. Pointer to the CClassPropInfo object on success
  1012. ===================================================================*/
  1013. CClassPropInfo *CMetaSchema::GetClassPropInfo(LPCTSTR tszClassName,
  1014. DWORD dwPropId)
  1015. {
  1016. // Make sure the class table is up to date
  1017. if (m_fClassTableDirty) {
  1018. HRESULT hr;
  1019. hr = LoadClassTable();
  1020. if (FAILED(hr)) {
  1021. return NULL;
  1022. }
  1023. }
  1024. // Get the class
  1025. CClassInfo *pCClassInfo;
  1026. pCClassInfo = m_CClassInfoTable.GetClassInfo(tszClassName);
  1027. if (pCClassInfo == NULL) {
  1028. return NULL;
  1029. }
  1030. else {
  1031. // Pass on the call
  1032. return pCClassInfo->GetProperty(dwPropId);
  1033. }
  1034. }
  1035. /*===================================================================
  1036. CMetaSchema::GetMandatoryClassPropList
  1037. Get the list of optional class properties for a class name.
  1038. Parameters:
  1039. tszClassName Name of the class get the properties from
  1040. Returns:
  1041. NULL on failure
  1042. Pointer to the first optional CClassPropInfo object on success
  1043. ===================================================================*/
  1044. CClassPropInfo *CMetaSchema::GetMandatoryClassPropList(LPCTSTR tszClassName)
  1045. {
  1046. // Make sure the class table is up to date
  1047. if (m_fClassTableDirty) {
  1048. HRESULT hr;
  1049. hr = LoadClassTable();
  1050. if (FAILED(hr)) {
  1051. return NULL;
  1052. }
  1053. }
  1054. // Get the class
  1055. CClassInfo *pCClassInfo;
  1056. pCClassInfo = m_CClassInfoTable.GetClassInfo(tszClassName);
  1057. if (pCClassInfo == NULL) {
  1058. return NULL;
  1059. }
  1060. else {
  1061. // Pass on the call
  1062. return pCClassInfo->GetMandatoryPropList();
  1063. }
  1064. }
  1065. /*===================================================================
  1066. CMetaSchema::GetOptionalClassPropList
  1067. Get the list of optional class properties for a class name.
  1068. Parameters:
  1069. tszClassName Name of the class get the properties from
  1070. Returns:
  1071. NULL on failure
  1072. Pointer to the first optional CClassPropInfo object on success
  1073. ===================================================================*/
  1074. CClassPropInfo *CMetaSchema::GetOptionalClassPropList(LPCTSTR tszClassName)
  1075. {
  1076. // Make sure the class table is up to date
  1077. if (m_fClassTableDirty) {
  1078. HRESULT hr;
  1079. hr = LoadClassTable();
  1080. if (FAILED(hr)) {
  1081. return NULL;
  1082. }
  1083. }
  1084. // Get the class
  1085. CClassInfo *pCClassInfo;
  1086. pCClassInfo = m_CClassInfoTable.GetClassInfo(tszClassName);
  1087. if (pCClassInfo == NULL) {
  1088. return NULL;
  1089. }
  1090. else {
  1091. // Pass on the call
  1092. return pCClassInfo->GetOptionalPropList();
  1093. }
  1094. }
  1095. /*===================================================================
  1096. CMetaSchema::ChangeNotification
  1097. Processes change events effecting the machine where the schema is
  1098. located. If the dirty flag for the property and class tables is not
  1099. already set a call to Unload() is made to free up memory no longer
  1100. needed.
  1101. Parameters:
  1102. tszChangedKey Cannonized key where change took place
  1103. pcoChangeObject Pointer to the change event information
  1104. Returns:
  1105. Nothing
  1106. ===================================================================*/
  1107. void CMetaSchema::ChangeNotification(LPTSTR tszKey,
  1108. MD_CHANGE_OBJECT *pcoChangeObject)
  1109. {
  1110. ASSERT_POINTER(pcoChangeObject, MD_CHANGE_OBJECT);
  1111. USES_CONVERSION;
  1112. LPTSTR tszChangedKey;
  1113. tszChangedKey = tszKey;
  1114. // Skip the slash
  1115. if (*tszChangedKey != _T('\0') && *tszChangedKey == _T('/')) {
  1116. tszChangedKey++;
  1117. }
  1118. if (_tcsnicmp(tszChangedKey, _T("schema/"), 7) == 0) {
  1119. // It effects a "Schema" subkey
  1120. if ((_tcsnicmp(tszChangedKey, _T("schema/properties/"), 18) == 0) ||
  1121. (_tcsicmp(tszChangedKey, _T("schema/properties")) == 0)) {
  1122. // It effects "Schema/Properties"
  1123. if (!m_fPropTableDirty) {
  1124. // Unload the prop table
  1125. m_CPropInfoTable.Unload();
  1126. }
  1127. m_fPropTableDirty = TRUE;
  1128. }
  1129. else if ((_tcsnicmp(tszChangedKey, _T("schema/classes/"), 15) == 0) ||
  1130. (_tcsicmp(tszChangedKey, _T("schema/classes")) == 0)) {
  1131. // It effects "Schema/Classes"
  1132. if (!m_fClassTableDirty) {
  1133. // Unload the class table
  1134. m_CClassInfoTable.Unload();
  1135. }
  1136. m_fClassTableDirty = TRUE;
  1137. }
  1138. }
  1139. else if (_tcsicmp(tszChangedKey, _T("schema")) == 0) {
  1140. // Just the "Schema" key was changed
  1141. if (!m_fPropTableDirty) {
  1142. // Unload the prop table
  1143. m_CPropInfoTable.Unload();
  1144. }
  1145. m_fPropTableDirty = TRUE;
  1146. if (!m_fClassTableDirty) {
  1147. // Unload the class table
  1148. m_CClassInfoTable.Unload();
  1149. }
  1150. m_fClassTableDirty = TRUE;
  1151. }
  1152. }
  1153. /*===================================================================
  1154. CMetaSchema::LoadPropTable
  1155. (Re)loads a dirty property table
  1156. Parameters:
  1157. None
  1158. Returns:
  1159. S_OK on success
  1160. ===================================================================*/
  1161. HRESULT CMetaSchema::LoadPropTable()
  1162. {
  1163. USES_CONVERSION;
  1164. HRESULT hr;
  1165. // Open the Machine key
  1166. METADATA_HANDLE hMDKey;
  1167. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1168. L"", // schema path moved to /schema
  1169. METADATA_PERMISSION_READ,
  1170. MUTIL_OPEN_KEY_TIMEOUT,
  1171. &hMDKey);
  1172. if (FAILED(hr)) {
  1173. return hr;
  1174. }
  1175. // Load the properties
  1176. hr = m_CPropInfoTable.Load(m_pIMeta, hMDKey);
  1177. if (FAILED(hr)) {
  1178. return hr;
  1179. }
  1180. // Close the Machine key
  1181. m_pIMeta->CloseKey(hMDKey);
  1182. m_fPropTableDirty = FALSE;
  1183. return S_OK;
  1184. }
  1185. /*===================================================================
  1186. CMetaSchema::LoadClassTable
  1187. (Re)loads a dirty class table
  1188. Parameters:
  1189. None
  1190. Returns:
  1191. S_OK on success
  1192. ===================================================================*/
  1193. HRESULT CMetaSchema::LoadClassTable()
  1194. {
  1195. USES_CONVERSION;
  1196. HRESULT hr;
  1197. // Open the Machine key
  1198. METADATA_HANDLE hMDKey;
  1199. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1200. L"", // schema path moved to /schema
  1201. METADATA_PERMISSION_READ,
  1202. MUTIL_OPEN_KEY_TIMEOUT,
  1203. &hMDKey);
  1204. if (FAILED(hr)) {
  1205. return hr;
  1206. }
  1207. // Load the properties
  1208. hr = m_CClassInfoTable.Load(m_pIMeta, hMDKey);
  1209. if (FAILED(hr)) {
  1210. return hr;
  1211. }
  1212. // Close the Machine key
  1213. m_pIMeta->CloseKey(hMDKey);
  1214. m_fClassTableDirty = FALSE;
  1215. return S_OK;
  1216. }
  1217. /*------------------------------------------------------------------
  1218. * C M e t a S c h e m a T a b l e
  1219. */
  1220. /*===================================================================
  1221. CMetaSchemaTable::CMetaSchemaTable
  1222. Constructor
  1223. Parameters:
  1224. None
  1225. Returns:
  1226. Nothing
  1227. ===================================================================*/
  1228. CMetaSchemaTable::CMetaSchemaTable() : m_dwNumRef(1),
  1229. m_fLoaded(FALSE)
  1230. {
  1231. m_CMSAdminBaseSink = new CComObject<CMSAdminBaseSink>;
  1232. m_CMSAdminBaseSink->AddRef();
  1233. // Clear the hash table
  1234. memset(m_rgCSchemaTable, 0, SCHEMA_HASH_SIZE * sizeof(CMetaSchema *));
  1235. }
  1236. /*===================================================================
  1237. CMetaSchemaTable::~CMetaSchemaTable
  1238. Destructor
  1239. Parameters:
  1240. None
  1241. Returns:
  1242. Nothing
  1243. ===================================================================*/
  1244. CMetaSchemaTable::~CMetaSchemaTable()
  1245. {
  1246. TRACE0("MetaUtil: CMetaSchemaTable::~CMetaSchemaTable\n");
  1247. if (m_fLoaded) {
  1248. Unload();
  1249. }
  1250. DWORD dwTemp;
  1251. if (m_CMSAdminBaseSink != NULL) {
  1252. dwTemp = m_CMSAdminBaseSink->Release();
  1253. TRACE1("MetaUtil: CMetaSchemaTable::~CMetaSchemaTable Release Sink %i\n", dwTemp);
  1254. }
  1255. }
  1256. /*===================================================================
  1257. CMetaSchemaTable::Load
  1258. Loads/Creates the schema information for all of the machines
  1259. Parameters:
  1260. None
  1261. Returns:
  1262. Nothing
  1263. ===================================================================*/
  1264. void CMetaSchemaTable::Load()
  1265. {
  1266. USES_CONVERSION;
  1267. HRESULT hr;
  1268. if (m_fLoaded) {
  1269. Unload();
  1270. }
  1271. // Create an instance of the Metabase Admin Base Object
  1272. // Need a seperate instance so we pick up changes made
  1273. // by our "parent" MetaUtil object family.
  1274. hr = ::CoCreateInstance(CLSID_MSAdminBase,
  1275. NULL,
  1276. CLSCTX_ALL,
  1277. IID_IMSAdminBase,
  1278. (void **)&m_pIMeta);
  1279. if (FAILED(hr)) {
  1280. m_pIMeta = NULL;
  1281. return;
  1282. }
  1283. // Build the schema list
  1284. int iKeyIndex;
  1285. wchar_t wszMDSubKey[ADMINDATA_MAX_NAME_LEN];
  1286. CMetaSchema *pCNewSchema;
  1287. int iLoc;
  1288. // For each subkey of root
  1289. iKeyIndex = 0;
  1290. hr = m_pIMeta->EnumKeys(METADATA_MASTER_ROOT_HANDLE,
  1291. NULL,
  1292. wszMDSubKey,
  1293. iKeyIndex);
  1294. while (SUCCEEDED(hr)) {
  1295. // Create the new schema
  1296. pCNewSchema = new CMetaSchema;
  1297. if (pCNewSchema == NULL) {
  1298. goto LError;
  1299. }
  1300. hr = pCNewSchema->Init(m_pIMeta, W2T(wszMDSubKey));
  1301. if (FAILED(hr)) {
  1302. delete pCNewSchema;
  1303. goto LError;
  1304. }
  1305. // Add it to the hash table
  1306. iLoc = Hash(W2T(wszMDSubKey));
  1307. pCNewSchema->m_pCNextSchema = m_rgCSchemaTable[iLoc];
  1308. m_rgCSchemaTable[iLoc] = pCNewSchema;
  1309. // Next
  1310. iKeyIndex++;
  1311. hr = m_pIMeta->EnumKeys(METADATA_MASTER_ROOT_HANDLE,
  1312. NULL,
  1313. wszMDSubKey,
  1314. iKeyIndex);
  1315. }
  1316. // Make sure we ran out of items
  1317. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  1318. goto LError;
  1319. }
  1320. // Setup notification
  1321. if (m_CMSAdminBaseSink != NULL) {
  1322. m_CMSAdminBaseSink->Connect(m_pIMeta, this);
  1323. }
  1324. m_fLoaded = TRUE;
  1325. return;
  1326. LError:
  1327. // Back out of the load
  1328. Unload();
  1329. }
  1330. /*===================================================================
  1331. CMetaSchemaTable::Unload
  1332. Unloads the schema table.
  1333. Parameters:
  1334. None
  1335. Returns:
  1336. Nothing
  1337. ===================================================================*/
  1338. void CMetaSchemaTable::Unload() {
  1339. int iIndex;
  1340. CMetaSchema *pCDelete;
  1341. // Stop notification
  1342. if (m_CMSAdminBaseSink != NULL) {
  1343. m_CMSAdminBaseSink->Disconnect();
  1344. }
  1345. m_pIMeta = NULL;
  1346. // For each hash table entry
  1347. for (iIndex =0; iIndex < SCHEMA_HASH_SIZE; iIndex++) {
  1348. // While the entry is not empty
  1349. while (m_rgCSchemaTable[iIndex] != NULL) {
  1350. // Nuke the first table entry
  1351. pCDelete = m_rgCSchemaTable[iIndex];
  1352. m_rgCSchemaTable[iIndex] = pCDelete->m_pCNextSchema;
  1353. delete pCDelete;
  1354. }
  1355. }
  1356. m_fLoaded = FALSE;
  1357. }
  1358. /*===================================================================
  1359. CMetaSchemaTable::GetPropInfo
  1360. Get the CPropInfo (property info) object for a given key and id
  1361. Parameters:
  1362. tszKey Key the property is located under
  1363. dwPropId Id of the property to get info for
  1364. Returns:
  1365. NULL on failure
  1366. Pointer to the CPropInfo object on success
  1367. ===================================================================*/
  1368. CPropInfo *CMetaSchemaTable::GetPropInfo(LPCTSTR tszKey,
  1369. DWORD dwPropId)
  1370. {
  1371. ASSERT_STRING(tszKey);
  1372. if (!m_fLoaded) {
  1373. Load();
  1374. }
  1375. CMetaSchema *pCSchema;
  1376. pCSchema = GetSchema(tszKey);
  1377. // If found then pass the call on
  1378. if (pCSchema != NULL) {
  1379. return pCSchema->GetPropInfo(dwPropId);
  1380. }
  1381. else {
  1382. return NULL;
  1383. }
  1384. }
  1385. /*===================================================================
  1386. CMetaSchemaTable::GetPropInfo
  1387. Get the CPropInfo (property info) object for a given key and name
  1388. Parameters:
  1389. tszKey Key the property is located under
  1390. tszPropName Name of the property to get info for
  1391. Returns:
  1392. NULL on failure
  1393. Pointer to the CPropInfo object on success
  1394. ===================================================================*/
  1395. CPropInfo *CMetaSchemaTable::GetPropInfo(LPCTSTR tszKey,
  1396. LPCTSTR tszPropName)
  1397. {
  1398. ASSERT_STRING(tszKey);
  1399. ASSERT_STRING(tszPropName);
  1400. if (!m_fLoaded) {
  1401. Load();
  1402. }
  1403. CMetaSchema *pCSchema;
  1404. pCSchema = GetSchema(tszKey);
  1405. // If found then pass the call on
  1406. if (pCSchema != NULL) {
  1407. return pCSchema->GetPropInfo(tszPropName);
  1408. }
  1409. else {
  1410. return NULL;
  1411. }
  1412. }
  1413. /*===================================================================
  1414. CMetaSchemaTable::GetClassInfo
  1415. Get the CClassInfo (class info) object for a given key and class name
  1416. Parameters:
  1417. tszKey Approxiamte key the class is located under. Used
  1418. to get the machine name.
  1419. tszClassName Name of the class to get info for
  1420. Returns:
  1421. NULL on failure
  1422. Pointer to the CClassInfo object on success
  1423. ===================================================================*/
  1424. CClassInfo *CMetaSchemaTable::GetClassInfo(LPCTSTR tszKey,
  1425. LPCTSTR tszClassName)
  1426. {
  1427. ASSERT_STRING(tszKey);
  1428. ASSERT_STRING(tszClassName);
  1429. if (!m_fLoaded) {
  1430. Load();
  1431. }
  1432. CMetaSchema *pCSchema;
  1433. pCSchema = GetSchema(tszKey);
  1434. // If found then pass the call on
  1435. if (pCSchema != NULL) {
  1436. return pCSchema->GetClassInfo(tszClassName);
  1437. }
  1438. else {
  1439. return NULL;
  1440. }
  1441. }
  1442. /*===================================================================
  1443. CMetaSchemaTable::GetClassPropInfo
  1444. Get the CClassPropInfo (class property info) object for a given
  1445. key, class name and property id.
  1446. Parameters:
  1447. tszKey Approxiamte key the class is located under. Used
  1448. to get the machine name.
  1449. tszClassName Name of the class get property from
  1450. dwPropId Id of property to get info for
  1451. Returns:
  1452. NULL on failure
  1453. Pointer to the CClassPropInfo object on success
  1454. ===================================================================*/
  1455. CClassPropInfo *CMetaSchemaTable::GetClassPropInfo(LPCTSTR tszKey,
  1456. LPCTSTR tszClassName,
  1457. DWORD dwPropId)
  1458. {
  1459. ASSERT_STRING(tszKey);
  1460. ASSERT_STRING(tszClassName);
  1461. if (!m_fLoaded) {
  1462. Load();
  1463. }
  1464. CMetaSchema *pCSchema;
  1465. pCSchema = GetSchema(tszKey);
  1466. // If found then pass the call on
  1467. if (pCSchema != NULL) {
  1468. return pCSchema->GetClassPropInfo(tszClassName, dwPropId);
  1469. }
  1470. else {
  1471. return NULL;
  1472. }
  1473. }
  1474. /*===================================================================
  1475. CMetaSchemaTable::GetMandatoryClassPropList
  1476. Get the list of mandatory class properties for a given key and class
  1477. name.
  1478. Parameters:
  1479. tszKey Approxiamte key the class is located under. Used
  1480. to get the machine name.
  1481. tszClassName Name of the class get the properties from
  1482. Returns:
  1483. NULL on failure
  1484. Pointer to the first mandatory CClassPropInfo object on success
  1485. ===================================================================*/
  1486. CClassPropInfo *CMetaSchemaTable::GetMandatoryClassPropList(LPCTSTR tszKey,
  1487. LPCTSTR tszClassName)
  1488. {
  1489. ASSERT_STRING(tszKey);
  1490. ASSERT_STRING(tszClassName);
  1491. if (!m_fLoaded) {
  1492. Load();
  1493. }
  1494. CMetaSchema *pCSchema;
  1495. pCSchema = GetSchema(tszKey);
  1496. // If found then pass the call on
  1497. if (pCSchema != NULL) {
  1498. return pCSchema->GetMandatoryClassPropList(tszClassName);
  1499. }
  1500. else {
  1501. return NULL;
  1502. }
  1503. }
  1504. /*===================================================================
  1505. CMetaSchemaTable::GetOptionalClassPropList
  1506. Get the list of optional class properties for a given key and class
  1507. name.
  1508. Parameters:
  1509. tszKey Approxiamte key the class is located under. Used
  1510. to get the machine name.
  1511. tszClassName Name of the class get the properties from
  1512. Returns:
  1513. NULL on failure
  1514. Pointer to the first optional CClassPropInfo object on success
  1515. ===================================================================*/
  1516. CClassPropInfo *CMetaSchemaTable::GetOptionalClassPropList(LPCTSTR tszKey,
  1517. LPCTSTR tszClassName)
  1518. {
  1519. ASSERT_STRING(tszKey);
  1520. ASSERT_STRING(tszClassName);
  1521. if (!m_fLoaded) {
  1522. Load();
  1523. }
  1524. CMetaSchema *pCSchema;
  1525. pCSchema = GetSchema(tszKey);
  1526. // If found then pass the call on
  1527. if (pCSchema != NULL) {
  1528. return pCSchema->GetOptionalClassPropList(tszClassName);
  1529. }
  1530. else {
  1531. return NULL;
  1532. }
  1533. }
  1534. /*===================================================================
  1535. CMetaSchemaTable::SinkNotify
  1536. Metabase change notification callback from CMSAdminBaseSink. Either
  1537. determines a need to reload all of the schema information or sends
  1538. the message on to the appropriate CMetaSchema object.
  1539. Parameters:
  1540. dwMDNumElements Number of change events
  1541. pcoChangeObject Array of change events
  1542. Returns:
  1543. S_OK always
  1544. ===================================================================*/
  1545. HRESULT CMetaSchemaTable::SinkNotify(DWORD dwMDNumElements,
  1546. MD_CHANGE_OBJECT pcoChangeObject[])
  1547. {
  1548. ASSERT(IsValidAddress(pcoChangeObject, dwMDNumElements * sizeof(MD_CHANGE_OBJECT), FALSE));
  1549. USES_CONVERSION;
  1550. DWORD dwIndex;
  1551. CMetaSchema *pCMetaSchema;
  1552. // For each event
  1553. for (dwIndex = 0; dwIndex < dwMDNumElements; dwIndex++) {
  1554. // Figure out what machine it's for
  1555. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  1556. _tcscpy(tszKey, W2T(pcoChangeObject[dwIndex].pszMDPath));
  1557. CannonizeKey(tszKey);
  1558. pCMetaSchema = GetSchema(tszKey);
  1559. // If the machine is not found
  1560. if (pCMetaSchema == NULL) {
  1561. // Reload the schema table
  1562. Load();
  1563. }
  1564. else {
  1565. // Send it to the appropriate machine
  1566. pCMetaSchema->ChangeNotification(tszKey, &(pcoChangeObject[dwIndex]));
  1567. }
  1568. }
  1569. return S_OK;
  1570. }
  1571. /*===================================================================
  1572. CMetaSchemaTable::GetSchema
  1573. Get the schema object that contains information on the given key.
  1574. Parameters:
  1575. tszKey Approxiamte key to get schema information for.
  1576. Returns:
  1577. NULL on failure
  1578. Pointer to the CMetaSchema object on success
  1579. ===================================================================*/
  1580. CMetaSchema *CMetaSchemaTable::GetSchema(LPCTSTR tszKey) {
  1581. // Extract the machine name
  1582. TCHAR tszMachineName[ADMINDATA_MAX_NAME_LEN];
  1583. ::GetMachineFromKey(tszKey, tszMachineName);
  1584. // Find the right schema
  1585. CMetaSchema *pCCurSchema;
  1586. pCCurSchema =m_rgCSchemaTable[Hash(tszMachineName)];
  1587. while ((pCCurSchema != NULL) &&
  1588. (_tcsicmp(pCCurSchema->m_tszMachineName, tszMachineName) != 0)) {
  1589. pCCurSchema = pCCurSchema->m_pCNextSchema;
  1590. }
  1591. return pCCurSchema; // Will be NULL if not found
  1592. }
  1593. /*===================================================================
  1594. CMetaSchemaTable::Hash
  1595. Private function to get a hash value from a machine name for the
  1596. schema table.
  1597. Parameters:
  1598. tszName Machinea name to hash
  1599. Returns:
  1600. Hash value of name
  1601. ===================================================================*/
  1602. unsigned int CMetaSchemaTable::Hash(LPCTSTR tszName) {
  1603. ASSERT_STRING(tszName);
  1604. unsigned int uiSum;
  1605. unsigned int uiIndex;
  1606. uiSum = 0;
  1607. for (uiIndex=0; uiIndex < _tcslen(tszName); uiIndex++) {
  1608. uiSum += _totlower(tszName[uiIndex]);
  1609. }
  1610. return (uiSum % SCHEMA_HASH_SIZE);
  1611. }
  1612. /*------------------------------------------------------------------
  1613. * C M S A d m i n B a s e S i n k
  1614. */
  1615. /*===================================================================
  1616. CMSAdminBaseSink::CMSAdminBaseSink
  1617. Constructor
  1618. Parameters:
  1619. None
  1620. Returns:
  1621. Nothing
  1622. ===================================================================*/
  1623. CMSAdminBaseSink::CMSAdminBaseSink() : m_fConnected(FALSE),
  1624. m_dwCookie(0),
  1625. m_pCMetaSchemaTable(NULL)
  1626. {
  1627. }
  1628. /*===================================================================
  1629. CMSAdminBaseSink::~CMSAdminBaseSink
  1630. Destructor
  1631. Parameters:
  1632. None
  1633. Returns:
  1634. Nothing
  1635. ===================================================================*/
  1636. CMSAdminBaseSink::~CMSAdminBaseSink()
  1637. {
  1638. TRACE0("MetaUtil: CMSAdminBaseSink::~CMSAdminBaseSink !!!!!!!!!!!\n");
  1639. // Make sure we disconnected
  1640. if (m_fConnected) {
  1641. Disconnect();
  1642. }
  1643. }
  1644. /*===================================================================
  1645. CMSAdminBaseSink::SinkNotify
  1646. Entry point for notification events from the metabase admin base
  1647. object.
  1648. Parameters:
  1649. dwMDNumElements Number of change events
  1650. pcoChangeObject Array of change events
  1651. Returns:
  1652. E_FAIL if m_pCMetaSchemaTable == NULL
  1653. S_OK on success
  1654. ===================================================================*/
  1655. STDMETHODIMP CMSAdminBaseSink::SinkNotify(DWORD dwMDNumElements,
  1656. MD_CHANGE_OBJECT pcoChangeObject[])
  1657. {
  1658. TRACE0("MetaUtil: CMSAdminBaseSink::SinkNotify\n");
  1659. ASSERT(IsValidAddress(pcoChangeObject, dwMDNumElements * sizeof(MD_CHANGE_OBJECT), FALSE));
  1660. if (m_pCMetaSchemaTable == NULL) {
  1661. return E_FAIL;
  1662. }
  1663. // Pass on the notification
  1664. return m_pCMetaSchemaTable->SinkNotify(dwMDNumElements, pcoChangeObject);
  1665. }
  1666. /*===================================================================
  1667. CMSAdminBaseSink::ShutdownNotify
  1668. Entry point for the shutdown notification event from the metabase
  1669. admin base object.
  1670. Parameters:
  1671. None
  1672. Returns:
  1673. ERROR_NOT_SUPPORTE always
  1674. ===================================================================*/
  1675. STDMETHODIMP CMSAdminBaseSink::ShutdownNotify() {
  1676. return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  1677. }
  1678. /*===================================================================
  1679. CMSAdminBaseSink::Connect
  1680. Begins notification of change events. Connects to the metabase admin
  1681. base object.
  1682. Parameters:
  1683. pIMeta Pointer to the metabase admin base object
  1684. pCMetaSchemaTable Pointer to the schema table so that events
  1685. can be sent back to it.
  1686. Returns:
  1687. E_NOINTERFACE if can not convert IMSAdminBase to
  1688. IConnectionPointContainer.
  1689. S_OK on success
  1690. ===================================================================*/
  1691. HRESULT CMSAdminBaseSink::Connect(CComPtr<IMSAdminBase> &pIMeta,
  1692. CMetaSchemaTable *pCMetaSchemaTable)
  1693. {
  1694. ASSERT(pIMeta.p != NULL);
  1695. ASSERT_POINTER(pCMetaSchemaTable, CMetaSchemaTable);
  1696. HRESULT hr;
  1697. if (m_fConnected) {
  1698. Disconnect();
  1699. }
  1700. m_pCMetaSchemaTable = pCMetaSchemaTable;
  1701. // Get the connection container
  1702. CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pIMetaConnContainer;
  1703. pIMetaConnContainer = pIMeta;
  1704. if (pIMetaConnContainer == NULL) {
  1705. // Failure to change interfaces
  1706. return E_NOINTERFACE;
  1707. }
  1708. // Get the connection point
  1709. hr = pIMetaConnContainer->FindConnectionPoint(IID_IMSAdminBaseSink, &m_pIMetaConn);
  1710. if (FAILED(hr)) {
  1711. return hr;
  1712. }
  1713. // Advise (connect)
  1714. AddRef();
  1715. m_pIMetaConn->Advise((IMSAdminBaseSink *) this, &m_dwCookie);
  1716. m_fConnected = TRUE;
  1717. return S_OK;
  1718. }
  1719. /*===================================================================
  1720. CMSAdminBaseSink::Disconnect
  1721. Stops notification of change events. Disconnects from the metabase
  1722. admin base object.
  1723. Parameters:
  1724. None
  1725. Returns:
  1726. Nothing
  1727. ===================================================================*/
  1728. void CMSAdminBaseSink::Disconnect()
  1729. {
  1730. if (!m_fConnected) {
  1731. // Not connected
  1732. return;
  1733. }
  1734. // Stop notification
  1735. m_pIMetaConn->Unadvise(m_dwCookie);
  1736. // No longer needed
  1737. m_pIMetaConn = NULL;
  1738. m_pCMetaSchemaTable = NULL;
  1739. m_fConnected = FALSE;
  1740. }