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.

1439 lines
36 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: MetaUtil object
  6. File: MUtilObj.cpp
  7. Owner: t-BrianM
  8. This file contains implementation of the main MetaUtil class.
  9. Except CheckSchema is in ChkSchm.cpp and CheckKey is in ChkKey.cpp
  10. ===================================================================*/
  11. #include "stdafx.h"
  12. #include "MetaUtil.h"
  13. #include "MUtilObj.h"
  14. #include "keycol.h"
  15. /*------------------------------------------------------------------
  16. * C M e t a U t i l (edit and general portions)
  17. */
  18. /*===================================================================
  19. CMetaUtil::CMetaUtil
  20. Constructor
  21. Parameters:
  22. None
  23. Returns:
  24. Nothing
  25. ===================================================================*/
  26. CMetaUtil::CMetaUtil() : m_dwMaxPropSize(10 * 1024), // 10k
  27. m_dwMaxKeySize(100 * 1024), // 100k
  28. m_dwMaxNumErrors(100)
  29. {
  30. }
  31. /*===================================================================
  32. CMetaUtil::FinalConstruct
  33. Constructor
  34. Parameters:
  35. None
  36. Returns:
  37. Nothing
  38. ===================================================================*/
  39. HRESULT CMetaUtil::FinalConstruct()
  40. {
  41. HRESULT hr;
  42. // Create the metabase admin base object
  43. hr = ::CoCreateInstance(CLSID_MSAdminBase,
  44. NULL,
  45. CLSCTX_ALL,
  46. IID_IMSAdminBase,
  47. (void **)&m_pIMeta);
  48. if (FAILED(hr)) {
  49. return ::ReportError(hr);
  50. }
  51. // Create a schema table
  52. m_pCSchemaTable = new CMetaSchemaTable;
  53. if (m_pCSchemaTable == NULL) {
  54. return ::ReportError(E_OUTOFMEMORY);
  55. }
  56. return S_OK;
  57. }
  58. /*===================================================================
  59. CMetaUtil::FinalRelease
  60. Destructor
  61. Parameters:
  62. None
  63. Returns:
  64. Nothing
  65. ===================================================================*/
  66. void CMetaUtil::FinalRelease()
  67. {
  68. m_pIMeta = NULL;
  69. if (m_pCSchemaTable != NULL)
  70. m_pCSchemaTable->Release();
  71. }
  72. /*===================================================================
  73. CMetaUtil::InterfaceSupportsErrorInfo
  74. Standard ATL implementation
  75. ===================================================================*/
  76. STDMETHODIMP CMetaUtil::InterfaceSupportsErrorInfo(REFIID riid)
  77. {
  78. static const IID* arr[] =
  79. {
  80. &IID_IMetaUtil,
  81. };
  82. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  83. {
  84. if (InlineIsEqualGUID(*arr[i],riid))
  85. return S_OK;
  86. }
  87. return S_FALSE;
  88. }
  89. /*===================================================================
  90. CMetaUtil::EnumKeys
  91. Do a flat (non-recursive) enumeration of subkeys
  92. Parameters:
  93. bstrBaseKey [in] Key to enumerate the subkeys of
  94. ppIReturn [out, retval] interface for the ouput key collection
  95. Returns:
  96. E_OUTOFMEMORY if allocation fails.
  97. E_INVALIDARG if ppIReturn == NULL
  98. S_OK on success
  99. ===================================================================*/
  100. STDMETHODIMP CMetaUtil::EnumKeys(BSTR bstrBaseKey,
  101. IKeyCollection ** ppIReturn)
  102. {
  103. TRACE0("MetaUtil: CMetaUtil::EnumKeys\n");
  104. ASSERT_NULL_OR_POINTER(bstrBaseKey, OLECHAR);
  105. ASSERT_NULL_OR_POINTER(ppIReturn, IKeyCollection *);
  106. if (ppIReturn == NULL) {
  107. return ::ReportError(E_INVALIDARG);
  108. }
  109. USES_CONVERSION;
  110. HRESULT hr;
  111. // Create the Flat Keys Collection
  112. CComObject<CFlatKeyCollection> *pObj = NULL;
  113. ATLTRY(pObj = new CComObject<CFlatKeyCollection>);
  114. if (pObj == NULL) {
  115. return ::ReportError(E_OUTOFMEMORY);
  116. }
  117. hr = pObj->Init(m_pIMeta, OLE2T(bstrBaseKey));
  118. if (FAILED(hr)) {
  119. return ::ReportError(hr);
  120. }
  121. // Set the interface to IKeyCollection
  122. hr = pObj->QueryInterface(IID_IKeyCollection, (void **) ppIReturn);
  123. if (FAILED(hr)) {
  124. return ::ReportError(hr);
  125. }
  126. ASSERT(ppIReturn != NULL);
  127. return S_OK;
  128. }
  129. /*===================================================================
  130. CMetaUtil::EnumAllKeys
  131. Do a deep (recursive) enumeration of subkeys
  132. Parameters:
  133. bstrBaseKey [in] Key to enumerate the subkeys of
  134. ppIReturn [out, retval] interface for the ouput key collection
  135. Returns:
  136. E_OUTOFMEMORY if allocation fails.
  137. E_INVALIDARG if ppIReturn == NULL
  138. S_OK on success
  139. ===================================================================*/
  140. STDMETHODIMP CMetaUtil::EnumAllKeys(BSTR bstrBaseKey,
  141. IKeyCollection ** ppIReturn)
  142. {
  143. TRACE0("MetaUtil: CMetaUtil::EnumAllKeys\n");
  144. ASSERT_NULL_OR_POINTER(bstrBaseKey, OLECHAR);
  145. ASSERT_NULL_OR_POINTER(ppIReturn, IKeyCollection *);
  146. if (ppIReturn == NULL) {
  147. return ::ReportError(E_INVALIDARG);
  148. }
  149. USES_CONVERSION;
  150. HRESULT hr;
  151. // Create the Flat Keys Collection
  152. CComObject<CDeepKeyCollection> *pObj = NULL;
  153. ATLTRY(pObj = new CComObject<CDeepKeyCollection>);
  154. if (pObj == NULL) {
  155. return ::ReportError(E_OUTOFMEMORY);
  156. }
  157. hr = pObj->Init(m_pIMeta, OLE2T(bstrBaseKey));
  158. if (FAILED(hr)) {
  159. return ::ReportError(hr);
  160. }
  161. // Set the interface to IKeyCollection
  162. hr = pObj->QueryInterface(IID_IKeyCollection, (void **) ppIReturn);
  163. if (FAILED(hr)) {
  164. return ::ReportError(hr);
  165. }
  166. ASSERT(ppIReturn != NULL);
  167. return S_OK;
  168. }
  169. /*===================================================================
  170. CMetaUtil::EnumProperties
  171. Do an enumeration of properties
  172. Parameters:
  173. bstrBaseKey [in] Key to enumerate the properties of
  174. ppIReturn [out, retval] interface for the ouput property collection
  175. Returns:
  176. E_OUTOFMEMORY if allocation fails.
  177. E_INVALIDARG if ppIReturn == NULL
  178. S_OK on success
  179. ===================================================================*/
  180. STDMETHODIMP CMetaUtil::EnumProperties(BSTR bstrKey,
  181. IPropertyCollection **ppIReturn)
  182. {
  183. TRACE0("MetaUtil: CMetaUtil::EnumProperties\n");
  184. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  185. ASSERT_NULL_OR_POINTER(ppIReturn, IKeyCollection *);
  186. if (ppIReturn == NULL) {
  187. return ::ReportError(E_INVALIDARG);
  188. }
  189. USES_CONVERSION;
  190. HRESULT hr;
  191. // Create the Flat Keys Collection
  192. CComObject<CPropertyCollection> *pObj = NULL;
  193. ATLTRY(pObj = new CComObject<CPropertyCollection>);
  194. if (pObj == NULL) {
  195. return ::ReportError(E_OUTOFMEMORY);
  196. }
  197. hr = pObj->Init(m_pIMeta, m_pCSchemaTable, OLE2T(bstrKey));
  198. if (FAILED(hr)) {
  199. return ::ReportError(hr);
  200. }
  201. // Set the interface to IPropertyCollection
  202. hr = pObj->QueryInterface(IID_IPropertyCollection, (void **) ppIReturn);
  203. if (FAILED(hr)) {
  204. return ::ReportError(hr);
  205. }
  206. ASSERT(ppIReturn != NULL);
  207. return S_OK;
  208. }
  209. /*===================================================================
  210. CMetaUtil::CreateKey
  211. Create a new key
  212. Parameters:
  213. bstrKey [in] Key to create
  214. Returns:
  215. E_INVALIDARG if bstrKey == NULL
  216. S_OK on success
  217. ===================================================================*/
  218. STDMETHODIMP CMetaUtil::CreateKey(BSTR bstrKey)
  219. {
  220. TRACE0("MetaUtil: CMetaUtil::CreateKey\n");
  221. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  222. if (bstrKey == NULL) {
  223. return ::ReportError(E_INVALIDARG);
  224. }
  225. USES_CONVERSION;
  226. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  227. _tcscpy(tszKey,OLE2T(bstrKey));
  228. CannonizeKey(tszKey);
  229. return ::CreateKey(m_pIMeta, tszKey);
  230. }
  231. /*===================================================================
  232. CMetaUtil::DeleteKey
  233. Delete a key
  234. Parameters:
  235. bstrKey [in] Key to delete
  236. Returns:
  237. E_INVALIDARG if bstrKey == NULL
  238. S_OK on success
  239. ===================================================================*/
  240. STDMETHODIMP CMetaUtil::DeleteKey(BSTR bstrKey)
  241. {
  242. TRACE0("MetaUtil: CMetaUtil::DeleteKey\n");
  243. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  244. if (bstrKey == NULL) {
  245. return ::ReportError(E_INVALIDARG);
  246. }
  247. USES_CONVERSION;
  248. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  249. _tcscpy(tszKey,OLE2T(bstrKey));
  250. CannonizeKey(tszKey);
  251. return ::DeleteKey(m_pIMeta, tszKey);
  252. }
  253. /*===================================================================
  254. CMetaUtil::RenameKey
  255. Rename a key
  256. Parameters:
  257. bstrOldName [in] Original Key Name
  258. bstrNewName [in] New key name
  259. Returns:
  260. E_INVALIDARG if bstrOldName == NULL OR bstrNewName == NULL
  261. S_OK on success
  262. ===================================================================*/
  263. STDMETHODIMP CMetaUtil::RenameKey(BSTR bstrOldName, BSTR bstrNewName)
  264. {
  265. TRACE0("MetaUtil: CMetaUtil::RenameKey\n");
  266. ASSERT_NULL_OR_POINTER(bstrOldName, OLECHAR);
  267. ASSERT_NULL_OR_POINTER(bstrNewName, OLECHAR);
  268. if ((bstrOldName == NULL) || (bstrNewName == NULL)) {
  269. return ::ReportError(E_INVALIDARG);
  270. }
  271. USES_CONVERSION;
  272. HRESULT hr;
  273. TCHAR tszOldName[ADMINDATA_MAX_NAME_LEN];
  274. TCHAR tszNewName[ADMINDATA_MAX_NAME_LEN];
  275. _tcscpy(tszOldName, OLE2T(bstrOldName));
  276. CannonizeKey(tszOldName);
  277. _tcscpy(tszNewName, OLE2T(bstrNewName));
  278. CannonizeKey(tszNewName);
  279. // Figure out the key's common root
  280. TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
  281. int i;
  282. i = 0;
  283. while ((tszOldName[i] != _T('\0')) && (tszNewName[i] != _T('\0')) &&
  284. (tszOldName[i] == tszNewName[i])) {
  285. tszParent[i] = tszOldName[i];
  286. i++;
  287. }
  288. if (i == 0) {
  289. // Nothing in common
  290. tszParent[i] = _T('\0');
  291. }
  292. else {
  293. // Back up to the first slash
  294. while ((i > 0) && (tszParent[i] != _T('/'))) {
  295. i--;
  296. }
  297. // Cut it off at the slash
  298. tszParent[i] = _T('\0');
  299. }
  300. int iParentKeyLen;
  301. iParentKeyLen = _tcslen(tszParent);
  302. LPTSTR tszRelOldName;
  303. LPTSTR tszRelNewName;
  304. // Figure out the relative new and old names
  305. tszRelOldName = tszOldName + iParentKeyLen;
  306. if (*tszRelOldName == _T('/')) {
  307. tszRelOldName++;
  308. }
  309. tszRelNewName = tszNewName + iParentKeyLen;
  310. if (*tszRelNewName == _T('/')) {
  311. tszRelNewName++;
  312. }
  313. // Open the parent
  314. METADATA_HANDLE hMDParentKey;
  315. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  316. T2W(tszParent),
  317. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  318. MUTIL_OPEN_KEY_TIMEOUT,
  319. &hMDParentKey);
  320. if (FAILED(hr)) {
  321. return ::ReportError(hr);
  322. }
  323. // Rename the key
  324. hr = m_pIMeta->RenameKey(hMDParentKey,
  325. T2W(tszRelOldName),
  326. T2W(tszRelNewName));
  327. if (FAILED(hr)) {
  328. m_pIMeta->CloseKey(hMDParentKey);
  329. return ::ReportError(hr);
  330. }
  331. // Close the parent
  332. m_pIMeta->CloseKey(hMDParentKey);
  333. return S_OK;
  334. }
  335. /*===================================================================
  336. CMetaUtil::CopyKey
  337. Copy a key
  338. Parameters:
  339. bstrSrcKey [in] Source Key Name
  340. bstrDestKey [in] Destination key name
  341. fOverwrite [in] If true then already existing properties
  342. at destination are overwritten.
  343. Returns:
  344. E_INVALIDARG if bstrSrcKey == NULL OR bstrDestKey == NULL
  345. S_OK on success
  346. ===================================================================*/
  347. STDMETHODIMP CMetaUtil::CopyKey(BSTR bstrSrcKey, BSTR bstrDestKey, BOOL fOverwrite)
  348. {
  349. TRACE0("MetaUtil: CMetaUtil::CopyKey\n");
  350. ASSERT_NULL_OR_POINTER(bstrSrcKey, OLECHAR);
  351. ASSERT_NULL_OR_POINTER(bstrDestKey, OLECHAR);
  352. if ((bstrSrcKey == NULL) || (bstrDestKey == NULL)) {
  353. return ::ReportError(E_INVALIDARG);
  354. }
  355. USES_CONVERSION;
  356. TCHAR tszSrcKey[ADMINDATA_MAX_NAME_LEN];
  357. TCHAR tszDestKey[ADMINDATA_MAX_NAME_LEN];
  358. _tcscpy(tszSrcKey, OLE2T(bstrSrcKey));
  359. CannonizeKey(tszSrcKey);
  360. _tcscpy(tszDestKey, OLE2T(bstrDestKey));
  361. CannonizeKey(tszDestKey);
  362. return ::CopyKey(m_pIMeta, tszSrcKey, tszDestKey, fOverwrite, TRUE);
  363. }
  364. /*===================================================================
  365. CMetaUtil::MoveKey
  366. Move a key
  367. Parameters:
  368. bstrSrcKey [in] Source Key Name
  369. bstrDestKey [in] Destination key name
  370. fOverwrite [in] If true then already existing properties
  371. at destination are overwritten.
  372. Returns:
  373. E_INVALIDARG if bstrSrcKey == NULL OR bstrDestKey == NULL
  374. S_OK on success
  375. ===================================================================*/
  376. STDMETHODIMP CMetaUtil::MoveKey(BSTR bstrSrcKey, BSTR bstrDestKey, BOOL fOverwrite)
  377. {
  378. TRACE0("MetaUtil: CMetaUtil::MoveKey\n");
  379. ASSERT_NULL_OR_POINTER(bstrSrcKey, OLECHAR);
  380. ASSERT_NULL_OR_POINTER(bstrDestKey, OLECHAR);
  381. if ((bstrSrcKey == NULL) || (bstrDestKey == NULL)) {
  382. return ::ReportError(E_INVALIDARG);
  383. }
  384. USES_CONVERSION;
  385. TCHAR tszSrcKey[ADMINDATA_MAX_NAME_LEN];
  386. TCHAR tszDestKey[ADMINDATA_MAX_NAME_LEN];
  387. _tcscpy(tszSrcKey, OLE2T(bstrSrcKey));
  388. CannonizeKey(tszSrcKey);
  389. _tcscpy(tszDestKey, OLE2T(bstrDestKey));
  390. CannonizeKey(tszDestKey);
  391. return ::CopyKey(m_pIMeta, tszSrcKey, tszDestKey, fOverwrite, FALSE);
  392. }
  393. /*===================================================================
  394. CMetaUtil::GetProperty
  395. Gets a property object from the metabase.
  396. Parameters:
  397. bstrKey [in] Key containing property to get
  398. varId [in] Identifier of property to get. Either the
  399. Id (number) or Name (string).
  400. ppIReturn [out, retval] Interface for retreived property.
  401. Returns:
  402. E_INVALIDARG if bstrKey == NULL or ppIReturn == NULL
  403. S_OK on success
  404. ===================================================================*/
  405. STDMETHODIMP CMetaUtil::GetProperty(BSTR bstrKey,
  406. VARIANT varId,
  407. IProperty **ppIReturn)
  408. {
  409. TRACE0("MetaUtil: CMetaUtil::GetProperty\n");
  410. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  411. ASSERT_NULL_OR_POINTER(ppIReturn, IProperty *);
  412. if ((bstrKey == NULL) || (ppIReturn == NULL)) {
  413. return ::ReportError(E_INVALIDARG);
  414. }
  415. USES_CONVERSION;
  416. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  417. _tcscpy(tszKey,OLE2T(bstrKey));
  418. CannonizeKey(tszKey);
  419. return ::GetProperty(m_pIMeta, m_pCSchemaTable, tszKey, varId, ppIReturn);
  420. }
  421. /*===================================================================
  422. CMetaUtil::CreateProperty
  423. Creates a property object that can be written to the Metbase or
  424. retreives the property if it already exists.
  425. Parameters:
  426. bstrKey [in] Key containing property to get
  427. varId [in] Identifier of property to get. Either the
  428. Id (number) or Name (string).
  429. ppIReturn [out, retval] Interface for retreived property.
  430. Returns:
  431. E_INVALIDARG if bstrKey == NULL or ppIReturn == NULL
  432. S_OK on success
  433. ===================================================================*/
  434. STDMETHODIMP CMetaUtil::CreateProperty(BSTR bstrKey,
  435. VARIANT varId,
  436. IProperty **ppIReturn)
  437. {
  438. TRACE0("MetaUtil: CMetaUtil::CreateProperty\n");
  439. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  440. ASSERT_NULL_OR_POINTER(ppIReturn, IProperty *);
  441. if ((bstrKey == NULL) || (ppIReturn == NULL)) {
  442. return ::ReportError(E_INVALIDARG);
  443. }
  444. USES_CONVERSION;
  445. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  446. _tcscpy(tszKey,OLE2T(bstrKey));
  447. CannonizeKey(tszKey);
  448. return ::CreateProperty(m_pIMeta, m_pCSchemaTable, tszKey, varId, ppIReturn);
  449. }
  450. /*===================================================================
  451. CMetaUtil::DeleteProperty
  452. Deletes a property from the metabase.
  453. Parameters:
  454. bstrKey [in] Key containing property to get
  455. varId [in] Identifier of property to get. Either the
  456. Id (number) or Name (string).
  457. Returns:
  458. E_INVALIDARG if bstrKey == NULL
  459. S_OK on success
  460. ===================================================================*/
  461. STDMETHODIMP CMetaUtil::DeleteProperty(BSTR bstrKey, VARIANT varId)
  462. {
  463. TRACE0("MetaUtil: CMetaUtil::DeleteProperty\n");
  464. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  465. if (bstrKey == NULL) {
  466. return ::ReportError(E_INVALIDARG);
  467. }
  468. USES_CONVERSION;
  469. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  470. _tcscpy(tszKey,OLE2T(bstrKey));
  471. CannonizeKey(tszKey);
  472. return ::DeleteProperty(m_pIMeta, m_pCSchemaTable, tszKey, varId);
  473. }
  474. /*===================================================================
  475. CMetaUtil::ExpandString
  476. Expands a string with environment variables. Maximum output is 1024
  477. bytes.
  478. Parameters:
  479. bstrIn [in] String to expand
  480. pbstrRet [out, retval] Expanded string
  481. Returns:
  482. E_INVALIDARG if bstrIn == NULL or pbstrRet == NULL
  483. S_OK on success
  484. ===================================================================*/
  485. STDMETHODIMP CMetaUtil::ExpandString(BSTR bstrIn, BSTR *pbstrRet)
  486. {
  487. ASSERT_POINTER(bstrIn, OLECHAR);
  488. ASSERT_NULL_OR_POINTER(pbstrRet, BSTR);
  489. if ((bstrIn == NULL) || (pbstrRet == NULL)) {
  490. return ::ReportError(E_INVALIDARG);
  491. }
  492. USES_CONVERSION;
  493. TCHAR tszRet[1024];
  494. int iRet;
  495. iRet = ExpandEnvironmentStrings(OLE2T(bstrIn), tszRet, 1024);
  496. if (iRet == 0) {
  497. ::ReportError(GetLastError());
  498. }
  499. *pbstrRet = T2BSTR(tszRet);
  500. return S_OK;
  501. }
  502. /*===================================================================
  503. MetaUtil::PropIdToName
  504. Converts a property Id to its name, as listed in
  505. _Machine_/Schema/Properties/Names
  506. Parameters:
  507. bstrKey [in] Approximate key where property is located,
  508. needed to determine what schema to use.
  509. lId [in] Id of property
  510. pbstrName [out, retval] Output name of property
  511. Returns:
  512. E_INVALIDARG if bstrKey == NULL or pbstrName == NULL
  513. S_OK on success
  514. ===================================================================*/
  515. STDMETHODIMP CMetaUtil::PropIdToName(BSTR bstrKey, long lId, BSTR *pbstrName)
  516. {
  517. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  518. ASSERT_NULL_OR_POINTER(pbstrName, BSTR);
  519. if ((bstrKey == NULL) || (pbstrName == NULL)) {
  520. return ::ReportError(E_INVALIDARG);
  521. }
  522. USES_CONVERSION;
  523. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  524. CPropInfo *pCPropInfo;
  525. // Convert the base key to cannonical form
  526. _tcscpy(tszKey, OLE2T(bstrKey));
  527. CannonizeKey(tszKey);
  528. // Get the property info from the Schema Table
  529. pCPropInfo = m_pCSchemaTable->GetPropInfo(tszKey, lId);
  530. // Did we find it? Is there a name entry?
  531. if ((pCPropInfo == NULL) || (pCPropInfo->GetName() == NULL)) {
  532. // No, return ""
  533. *pbstrName = T2BSTR(_T(""));
  534. }
  535. else {
  536. // Yes, return the name
  537. *pbstrName = T2BSTR(pCPropInfo->GetName());
  538. }
  539. return S_OK;
  540. }
  541. /*===================================================================
  542. MetaUtil::PropNameToId
  543. Converts a property name to its id, as listed in
  544. _Machine_/Schema/Properties/Names
  545. Parameters:
  546. bstrKey [in] Approximate key where property is located,
  547. needed to determine what schema to use.
  548. pbstrName [in] Name of property
  549. lId [out, retval] Output id of property
  550. Returns:
  551. E_INVALIDARG if bstrKey == NULL OR bstrName == NULL OR plId == NULL
  552. S_OK on success
  553. ===================================================================*/
  554. STDMETHODIMP CMetaUtil::PropNameToId(BSTR bstrKey, BSTR bstrName, long *plId)
  555. {
  556. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  557. ASSERT_NULL_OR_POINTER(bstrName, OLECHAR);
  558. ASSERT_NULL_OR_POINTER(plId, long);
  559. if ((bstrKey == NULL) || (bstrName == NULL) || (plId == NULL)) {
  560. return ::ReportError(E_INVALIDARG);
  561. }
  562. USES_CONVERSION;
  563. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  564. CPropInfo *pCPropInfo;
  565. // Convert the base key to cannonical form
  566. _tcscpy(tszKey, OLE2T(bstrKey));
  567. CannonizeKey(tszKey);
  568. // Get the property info from the Schema Table
  569. pCPropInfo = m_pCSchemaTable->GetPropInfo(tszKey, OLE2T(bstrName));
  570. // Did we find it?
  571. if (pCPropInfo == NULL) {
  572. // No, return 0
  573. *plId = 0;
  574. }
  575. else {
  576. // Yes, return the id
  577. *plId = pCPropInfo->GetId();
  578. }
  579. return S_OK;
  580. }
  581. /*===================================================================
  582. MetaUtil::get_Config
  583. Gets the value of a configuration setting.
  584. Valid Settings:
  585. MaxPropertySize
  586. MaxKeySize
  587. MaxNumberOfErrors
  588. Parameters:
  589. bstrSetting [in] Name of the setting
  590. pvarValue [out, retval] Value of the setting
  591. Returns:
  592. E_INVALIDARG if bstrSettting doesn't match any known settings
  593. S_OK on success
  594. ===================================================================*/
  595. STDMETHODIMP CMetaUtil::get_Config(BSTR bstrSetting, VARIANT *pvarValue)
  596. {
  597. ASSERT_POINTER(bstrSetting, OLECHAR);
  598. ASSERT_POINTER(pvarValue, VARIANT);
  599. USES_CONVERSION;
  600. LPTSTR tszSetting;
  601. if( !bstrSetting )
  602. {
  603. return ::ReportError(E_INVALIDARG);
  604. }
  605. VariantInit(pvarValue);
  606. tszSetting = OLE2T(bstrSetting);
  607. if (_tcsicmp(tszSetting, _T("MaxPropertySize")) == 0) {
  608. V_VT(pvarValue) = VT_I4;
  609. V_I4(pvarValue) = m_dwMaxPropSize;
  610. }
  611. else if (_tcsicmp(tszSetting, _T("MaxKeySize")) == 0) {
  612. V_VT(pvarValue) = VT_I4;
  613. V_I4(pvarValue) = m_dwMaxKeySize;
  614. }
  615. else if (_tcsicmp(tszSetting, _T("MaxNumberOfErrors")) == 0) {
  616. V_VT(pvarValue) = VT_I4;
  617. V_I4(pvarValue) = m_dwMaxNumErrors;
  618. }
  619. else {
  620. return ::ReportError(E_INVALIDARG);
  621. }
  622. return S_OK;
  623. }
  624. /*===================================================================
  625. MetaUtil::put_Config
  626. Sets the value of a configuration setting.
  627. Valid Settings:
  628. MaxPropertySize
  629. MaxKeySize
  630. MaxNumberOfErrors
  631. Parameters:
  632. bstrSetting [in] Name of the setting
  633. varValue [out, retval] New value of the setting
  634. Returns:
  635. E_INVALIDARG if bstrSettting doesn't match any known settings or
  636. if varValue is of an unexpected subtype.
  637. S_OK on success
  638. ===================================================================*/
  639. STDMETHODIMP CMetaUtil::put_Config(BSTR bstrSetting, VARIANT varValue)
  640. {
  641. ASSERT_POINTER(bstrSetting, OLECHAR);
  642. USES_CONVERSION;
  643. HRESULT hr;
  644. LPTSTR tszSetting;
  645. tszSetting = OLE2T(bstrSetting);
  646. // Cleanup any IDispatch or byref stuff
  647. CComVariant varValue2;
  648. hr = VariantResolveDispatch(&varValue, &varValue2);
  649. if (FAILED(hr)) {
  650. return hr;
  651. }
  652. if (_tcsicmp(tszSetting, _T("MaxPropertySize")) == 0) {
  653. // Set Maximum Property Size
  654. switch (V_VT(&varValue2)) {
  655. case VT_I1: case VT_I2: case VT_I4: case VT_I8:
  656. case VT_UI1: case VT_UI2: case VT_UI8:
  657. // Coerce all integral types to VT_UI4
  658. if (FAILED(hr = VariantChangeType(&varValue2, &varValue2, 0, VT_UI4))) {
  659. return ::ReportError(hr);
  660. }
  661. // fallthru to VT_UI4
  662. case VT_UI4:
  663. m_dwMaxPropSize = V_UI4(&varValue2);
  664. break;
  665. default:
  666. // Unexpected data type
  667. return ::ReportError(E_INVALIDARG);
  668. }
  669. }
  670. else if (_tcsicmp(tszSetting, _T("MaxKeySize")) == 0) {
  671. // Set Maximum Key Size
  672. switch (V_VT(&varValue2)) {
  673. case VT_I1: case VT_I2: case VT_I4: case VT_I8:
  674. case VT_UI1: case VT_UI2: case VT_UI8:
  675. // Coerce all integral types to VT_UI4
  676. if (FAILED(hr = VariantChangeType(&varValue2, &varValue2, 0, VT_UI4))) {
  677. return ::ReportError(hr);
  678. }
  679. // fallthru to VT_UI4
  680. case VT_UI4:
  681. m_dwMaxKeySize = V_UI4(&varValue2);
  682. break;
  683. default:
  684. // Unexpected data type
  685. return ::ReportError(E_INVALIDARG);
  686. }
  687. }
  688. else if (_tcsicmp(tszSetting, _T("MaxNumberOfErrors")) == 0) {
  689. // Set Maximum Number of Errors
  690. switch (V_VT(&varValue2)) {
  691. case VT_I1: case VT_I2: case VT_I4: case VT_I8:
  692. case VT_UI1: case VT_UI2: case VT_UI8:
  693. // Coerce all integral types to VT_UI4
  694. if (FAILED(hr = VariantChangeType(&varValue2, &varValue2, 0, VT_UI4))) {
  695. return ::ReportError(hr);
  696. }
  697. // fallthru to VT_UI4
  698. case VT_UI4:
  699. m_dwMaxNumErrors = V_UI4(&varValue2);
  700. break;
  701. default:
  702. // Unexpected data type
  703. return ::ReportError(E_INVALIDARG);
  704. }
  705. }
  706. else {
  707. return ::ReportError(E_INVALIDARG);
  708. }
  709. return S_OK;
  710. }
  711. /*------------------------------------------------------------------
  712. * Methods also supported by the collections
  713. *
  714. * Actual implementation here to avoid redundant code
  715. */
  716. /*===================================================================
  717. CreateKey
  718. Create a new key
  719. Parameters:
  720. pIMeta [in] Smart pointer to metabase, passed by reference
  721. to avoid the copy and unneeded AddRef/Release.
  722. Would have used const, however the '->' operator
  723. would not work.
  724. tszKey [in] Key to create
  725. Returns:
  726. E_INVALIDARG if bstrKey == NULL
  727. S_OK on success
  728. ===================================================================*/
  729. HRESULT CreateKey(CComPtr<IMSAdminBase> &pIMeta,
  730. LPCTSTR tszKey)
  731. {
  732. ASSERT(pIMeta.p != NULL);
  733. ASSERT_STRING(tszKey);
  734. USES_CONVERSION;
  735. HRESULT hr;
  736. TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
  737. TCHAR tszChild[ADMINDATA_MAX_NAME_LEN];
  738. ::SplitKey(tszKey, tszParent, tszChild);
  739. // Open the parent key
  740. METADATA_HANDLE hMDParent;
  741. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  742. T2W(tszParent),
  743. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  744. MUTIL_OPEN_KEY_TIMEOUT,
  745. &hMDParent);
  746. if (FAILED(hr)) {
  747. return ::ReportError(hr);
  748. }
  749. // Create the child
  750. hr = pIMeta->AddKey(hMDParent, T2W(tszChild));
  751. if (FAILED(hr)) {
  752. pIMeta->CloseKey(hMDParent);
  753. return ::ReportError(hr);
  754. }
  755. // Close the parent key
  756. pIMeta->CloseKey(hMDParent);
  757. return S_OK;
  758. }
  759. /*===================================================================
  760. DeleteKey
  761. Delete a key
  762. Parameters:
  763. pIMeta [in] Smart pointer to metabase, passed by reference
  764. to avoid the copy and unneeded AddRef/Release.
  765. Would have used const, however the '->' operator
  766. would not work.
  767. tszKey [in] Key to delete
  768. Returns:
  769. E_INVALIDARG if pbSuccess == NULL
  770. S_OK on success
  771. ===================================================================*/
  772. HRESULT DeleteKey(CComPtr<IMSAdminBase> &pIMeta,
  773. LPCTSTR tszKey)
  774. {
  775. ASSERT(pIMeta.p != NULL);
  776. ASSERT_STRING(tszKey);
  777. USES_CONVERSION;
  778. HRESULT hr;
  779. TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
  780. TCHAR tszChild[ADMINDATA_MAX_NAME_LEN];
  781. ::SplitKey(tszKey, tszParent, tszChild);
  782. // Open the parent key
  783. METADATA_HANDLE hMDParent;
  784. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  785. T2W(tszParent),
  786. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  787. MUTIL_OPEN_KEY_TIMEOUT,
  788. &hMDParent);
  789. if (FAILED(hr)) {
  790. return ::ReportError(hr);
  791. }
  792. // Delete the child
  793. hr = pIMeta->DeleteKey(hMDParent, T2W(tszChild));
  794. if (FAILED(hr)) {
  795. pIMeta->CloseKey(hMDParent);
  796. return ::ReportError(hr);
  797. }
  798. // Close the parent key
  799. pIMeta->CloseKey(hMDParent);
  800. return S_OK;
  801. }
  802. /*===================================================================
  803. CMetaUtil::CopyKey
  804. Copy or move a key
  805. Parameters:
  806. bstrSrcKey [in] Source Key Name
  807. bstrDestKey [in] Destination key name
  808. fOverwrite [in] If true then already existing properties
  809. at destination are overwritten.
  810. fCopy [in] If true than copy the key, else move it
  811. Returns:
  812. S_OK on success
  813. ===================================================================*/
  814. HRESULT CopyKey(CComPtr<IMSAdminBase> &pIMeta,
  815. LPTSTR tszSrcKey,
  816. LPTSTR tszDestKey,
  817. BOOL fOverwrite,
  818. BOOL fCopy)
  819. {
  820. ASSERT(pIMeta.p != NULL);
  821. ASSERT_STRING(tszSrcKey);
  822. ASSERT_STRING(tszDestKey);
  823. USES_CONVERSION;
  824. HRESULT hr;
  825. // Check for overlap
  826. TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
  827. int i;
  828. i = 0;
  829. while ((tszSrcKey[i] != _T('\0')) && (tszDestKey[i] != _T('\0')) &&
  830. (tszSrcKey[i] == tszDestKey[i])) {
  831. tszParent[i] = tszSrcKey[i];
  832. i++;
  833. }
  834. // Terminate tszParent
  835. tszParent[i] = _T('\0');
  836. if (i == 0) {
  837. // Nothing in common
  838. TCHAR tszSrcParent[ADMINDATA_MAX_NAME_LEN];
  839. TCHAR tszSrcChild[ADMINDATA_MAX_NAME_LEN];
  840. TCHAR tszDestParent[ADMINDATA_MAX_NAME_LEN];
  841. TCHAR tszDestChild[ADMINDATA_MAX_NAME_LEN];
  842. ::SplitKey(tszSrcKey, tszSrcParent, tszSrcChild);
  843. ::SplitKey(tszDestKey, tszDestParent, tszDestChild);
  844. // Open the parent source key
  845. METADATA_HANDLE hMDSrcParent;
  846. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  847. T2W(tszSrcParent),
  848. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  849. MUTIL_OPEN_KEY_TIMEOUT,
  850. &hMDSrcParent);
  851. if (FAILED(hr)) {
  852. return ::ReportError(hr);
  853. }
  854. // Open the parent dest key
  855. METADATA_HANDLE hMDDestParent;
  856. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  857. T2W(tszDestParent),
  858. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  859. MUTIL_OPEN_KEY_TIMEOUT,
  860. &hMDDestParent);
  861. if (FAILED(hr)) {
  862. return ::ReportError(hr);
  863. }
  864. // Copy the children
  865. hr = pIMeta->CopyKey(hMDSrcParent, T2W(tszSrcChild),
  866. hMDDestParent, T2W(tszDestChild),
  867. fOverwrite, fCopy);
  868. if (FAILED(hr)) {
  869. pIMeta->CloseKey(hMDSrcParent);
  870. pIMeta->CloseKey(hMDDestParent);
  871. return ::ReportError(hr);
  872. }
  873. // Close the parents
  874. pIMeta->CloseKey(hMDSrcParent);
  875. pIMeta->CloseKey(hMDDestParent);
  876. }
  877. else {
  878. // Something in common
  879. // Back up to the first slash
  880. while ((i > 0) && (tszParent[i] != _T('/'))) {
  881. i--;
  882. }
  883. // Cut it off at the slash
  884. tszParent[i] = _T('\0');
  885. int iParentKeyLen;
  886. iParentKeyLen = _tcslen(tszParent);
  887. LPTSTR tszSrcChild;
  888. LPTSTR tszDestChild;
  889. // Figure out the relative new and old names
  890. tszSrcChild = tszSrcKey + iParentKeyLen;
  891. if (*tszSrcChild == _T('/')) {
  892. tszSrcChild++;
  893. }
  894. tszDestChild = tszDestKey + iParentKeyLen;
  895. if (*tszDestChild == _T('/')) {
  896. tszDestChild++;
  897. }
  898. // Open the parent key
  899. METADATA_HANDLE hMDParent;
  900. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  901. T2W(tszParent),
  902. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  903. MUTIL_OPEN_KEY_TIMEOUT,
  904. &hMDParent);
  905. if (FAILED(hr)) {
  906. return ::ReportError(hr);
  907. }
  908. // Copy the children
  909. hr = pIMeta->CopyKey(hMDParent, T2W(tszSrcChild),
  910. hMDParent, T2W(tszDestChild),
  911. fOverwrite, fCopy);
  912. if (FAILED(hr)) {
  913. pIMeta->CloseKey(hMDParent);
  914. return ::ReportError(hr);
  915. }
  916. // Close the parent
  917. pIMeta->CloseKey(hMDParent);
  918. }
  919. return S_OK;
  920. }
  921. /*===================================================================
  922. GetProperty
  923. Gets a property object from the metabase.
  924. Parameters:
  925. pIMeta [in] Smart pointer to metabase, passed by
  926. reference to avoid the copy and unneeded
  927. AddRef/Release. Would have used const, however
  928. the '->' operator would not work.
  929. pCSchemaTable [in] Metabase schema table to use to look up
  930. property names
  931. tszKey [in] Key containing property to get
  932. varId [in] Identifier of property to get. Either the
  933. Id (number) or Name (string).
  934. ppIReturn [out, retval] Interface for retreived property.
  935. Returns:
  936. S_OK on success
  937. ===================================================================*/
  938. HRESULT GetProperty(CComPtr<IMSAdminBase> &pIMeta,
  939. CMetaSchemaTable *pCSchemaTable,
  940. LPCTSTR tszKey,
  941. VARIANT varId,
  942. IProperty **ppIReturn)
  943. {
  944. ASSERT(pIMeta != NULL);
  945. ASSERT_STRING(tszKey);
  946. ASSERT_POINTER(ppIReturn, IProperty *);
  947. HRESULT hr;
  948. DWORD dwId;
  949. // Figure out the property id
  950. hr = ::VarToMetaId(pCSchemaTable, tszKey, varId, &dwId);
  951. if (FAILED(hr)) {
  952. return ::ReportError(hr);
  953. }
  954. // Create the property object
  955. CComObject<CProperty> *pObj = NULL;
  956. ATLTRY(pObj = new CComObject<CProperty>);
  957. if (pObj == NULL) {
  958. return ::ReportError(E_OUTOFMEMORY);
  959. }
  960. hr = pObj->Init(pIMeta, pCSchemaTable, tszKey, dwId, FALSE);
  961. if (FAILED(hr)) {
  962. return ::ReportError(hr);
  963. }
  964. // Set the interface to IProperty
  965. hr = pObj->QueryInterface(IID_IProperty, (void **) ppIReturn);
  966. if (FAILED(hr)) {
  967. return ::ReportError(hr);
  968. }
  969. ASSERT(*ppIReturn != NULL);
  970. return S_OK;
  971. }
  972. /*===================================================================
  973. CreateProperty
  974. Creates a property object that can be written to the Metbase or
  975. retreives the property if it already exists.
  976. Parameters:
  977. pIMeta [in] Smart pointer to metabase, passed by
  978. reference to avoid the copy and unneeded
  979. AddRef/Release. Would have used const, however
  980. the '->' operator would not work.
  981. pCSchemaTable [in] Metabase schema table to use to look up
  982. property names
  983. tszKey [in] Key containing property to get
  984. varId [in] Identifier of property to get. Either the
  985. Id (number) or Name (string).
  986. ppIReturn [out, retval] Interface for retreived property.
  987. Returns:
  988. S_OK on success
  989. ===================================================================*/
  990. HRESULT CreateProperty(CComPtr<IMSAdminBase> &pIMeta,
  991. CMetaSchemaTable *pCSchemaTable,
  992. LPCTSTR tszKey,
  993. VARIANT varId,
  994. IProperty **ppIReturn)
  995. {
  996. ASSERT(pIMeta.p != NULL);
  997. ASSERT_STRING(tszKey);
  998. ASSERT_POINTER(ppIReturn, IProperty *);
  999. HRESULT hr;
  1000. DWORD dwId;
  1001. // Figure out the property id
  1002. hr = ::VarToMetaId(pCSchemaTable, tszKey, varId, &dwId);
  1003. if (FAILED(hr)) {
  1004. return ::ReportError(hr);
  1005. }
  1006. // Create the property object
  1007. CComObject<CProperty> *pObj = NULL;
  1008. ATLTRY(pObj = new CComObject<CProperty>);
  1009. if (pObj == NULL) {
  1010. return ::ReportError(E_OUTOFMEMORY);
  1011. }
  1012. hr = pObj->Init(pIMeta, pCSchemaTable, tszKey, dwId, TRUE);
  1013. if (FAILED(hr)) {
  1014. return ::ReportError(hr);
  1015. }
  1016. // Set the interface to IProperty
  1017. hr = pObj->QueryInterface(IID_IProperty, (void **) ppIReturn);
  1018. if (FAILED(hr)) {
  1019. return ::ReportError(hr);
  1020. }
  1021. ASSERT(*ppIReturn != NULL);
  1022. return S_OK;
  1023. }
  1024. /*===================================================================
  1025. DeleteProperty
  1026. Deletes a property from the metabase.
  1027. Parameters:
  1028. pIMeta [in] Smart pointer to metabase, passed by
  1029. reference to avoid the copy and unneeded
  1030. AddRef/Release. Would have used const, however
  1031. the '->' operator would not work.
  1032. pCSchemaTable [in] Metabase schema table to use to look up
  1033. property names
  1034. tszKey [in] Key containing property to get
  1035. varId [in] Identifier of property to get. Either the
  1036. Id (number) or Name (string).
  1037. Returns:
  1038. S_OK on success
  1039. ===================================================================*/
  1040. HRESULT DeleteProperty(CComPtr<IMSAdminBase> &pIMeta,
  1041. CMetaSchemaTable *pCSchemaTable,
  1042. LPTSTR tszKey,
  1043. VARIANT varId)
  1044. {
  1045. ASSERT(pIMeta.p != NULL);
  1046. ASSERT_STRING(tszKey);
  1047. USES_CONVERSION;
  1048. HRESULT hr;
  1049. DWORD dwId;
  1050. hr = ::VarToMetaId(pCSchemaTable, tszKey, varId, &dwId);
  1051. if (FAILED(hr)) {
  1052. return ::ReportError(hr);
  1053. }
  1054. // Open the key
  1055. METADATA_HANDLE hMDKey;
  1056. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1057. T2W(tszKey),
  1058. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1059. MUTIL_OPEN_KEY_TIMEOUT,
  1060. &hMDKey);
  1061. if (FAILED(hr)) {
  1062. return ::ReportError(hr);
  1063. }
  1064. // Delete the property
  1065. hr = pIMeta->DeleteData(hMDKey, NULL, dwId, ALL_METADATA);
  1066. if (FAILED(hr)) {
  1067. pIMeta->CloseKey(hMDKey);
  1068. return ::ReportError(hr);
  1069. }
  1070. // Close the key
  1071. pIMeta->CloseKey(hMDKey);
  1072. return S_OK;
  1073. }
  1074. /*===================================================================
  1075. VarToMetaId
  1076. Converts a variant to a metabase property id. IDispatch is resolved,
  1077. strings are looked up in the schema property list and integers are
  1078. converted to a DWORD.
  1079. Parameters:
  1080. pCSchemaTable [in] Metabase schema table to use to look up
  1081. property names
  1082. tszKey [in] Key the property is under (needed to get the
  1083. right schema)
  1084. varId [in] Variant to resolve
  1085. pdwId [out] Metabase property Id that varId resolved to
  1086. Returns:
  1087. E_INVALIDARG if varId subtype isn't an integer or string
  1088. ERROR_FILE_NOT_FOUND if varId is a BSTR that doesn't match any
  1089. property names.
  1090. S_OK on success
  1091. ===================================================================*/
  1092. HRESULT VarToMetaId(CMetaSchemaTable *pCSchemaTable,
  1093. LPCTSTR tszKey,
  1094. VARIANT varId,
  1095. DWORD *pdwId)
  1096. {
  1097. ASSERT_STRING(tszKey);
  1098. ASSERT_POINTER(pdwId, DWORD);
  1099. USES_CONVERSION;
  1100. HRESULT hr;
  1101. CComVariant varId2;
  1102. CPropInfo *pCPropInfo;
  1103. // VBScript can call us with a VARIANT that isn't a simple type,
  1104. // such as VT_VARIANT|VT_BYREF. This resolves it to a simple type.
  1105. if (FAILED(hr = VariantResolveDispatch(&varId, &varId2)))
  1106. return hr;
  1107. switch (V_VT(&varId2)) {
  1108. case VT_BSTR:
  1109. // Look up the property name
  1110. pCPropInfo = pCSchemaTable->GetPropInfo(tszKey, OLE2T(V_BSTR(&varId2)));
  1111. if (pCPropInfo == NULL) {
  1112. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1113. }
  1114. *pdwId = pCPropInfo->GetId();
  1115. return S_OK;
  1116. break;
  1117. case VT_I1: case VT_I2: case VT_I4: case VT_I8:
  1118. case VT_UI1: case VT_UI2: case VT_UI8:
  1119. // Coerce all integral types to VT_UI4, which is the same as REG_DWORD
  1120. if (FAILED(hr = VariantChangeType(&varId2, &varId2, 0, VT_UI4)))
  1121. return hr;
  1122. // fallthru to VT_UI4
  1123. case VT_UI4:
  1124. *pdwId = V_UI4(&varId2);
  1125. break;
  1126. default:
  1127. return E_INVALIDARG; // Cannot handle this data type
  1128. }
  1129. return S_OK;
  1130. }