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.

1974 lines
58 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: cumiprop.cxx
  7. //
  8. // Contents: Contains the property list implementation for UMI. This will
  9. // be used for both interface properties and object properties.
  10. //
  11. // History: 02-28-00 SivaramR Created.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "winnt.hxx"
  15. //----------------------------------------------------------------------------
  16. // Function: CUmiPropList
  17. //
  18. // Synopsis: Constructor. Stores off schema (list of available properties,
  19. // their types etc.) and the size of the schema.
  20. //
  21. // Arguments: Self explanatory
  22. //
  23. // Returns: Nothing
  24. //
  25. // Modifies: Nothing
  26. //
  27. //----------------------------------------------------------------------------
  28. CUmiPropList::CUmiPropList(PPROPERTYINFO pSchema, DWORD dwSchemaSize)
  29. {
  30. m_pSchema = pSchema;
  31. m_dwSchemaSize = dwSchemaSize;
  32. m_pPropCache = NULL;
  33. m_fIsIntfPropObj = TRUE;
  34. m_ulErrorStatus = 0;
  35. m_pszSchema = NULL;
  36. m_pClassInfo = NULL;
  37. m_fIsNamespaceObj = FALSE;
  38. m_fIsClassObj = FALSE;
  39. m_fDisableWrites = FALSE;
  40. m_ppszUnImpl = NULL;
  41. }
  42. //----------------------------------------------------------------------------
  43. // Function: CUmiPropList
  44. //
  45. // Synopsis: Constructor. Stores off schema (list of available properties,
  46. // their types etc.) and the size of the schema.
  47. //
  48. // Arguments: Self explanatory
  49. //
  50. // Returns: Nothing
  51. //
  52. // Modifies: Nothing
  53. //
  54. //----------------------------------------------------------------------------
  55. CUmiPropList::~CUmiPropList(void)
  56. {
  57. if( (m_pPropCache != NULL) && (TRUE == m_fIsIntfPropObj) )
  58. delete m_pPropCache;
  59. if(m_pszSchema != NULL)
  60. FreeADsStr(m_pszSchema);
  61. return;
  62. }
  63. //----------------------------------------------------------------------------
  64. // Function: QueryInterface
  65. //
  66. // Synopsis: Queries property list object for supported interfaces. Only
  67. // IUmiPropList is supported.
  68. //
  69. // Arguments:
  70. //
  71. // iid interface requested
  72. // ppInterface Returns pointer to interface requested. NULL if interface
  73. // is not supported.
  74. //
  75. // Returns: S_OK on success. Error code otherwise.
  76. //
  77. // Modifies: *ppInterface to return interface pointer
  78. //
  79. //----------------------------------------------------------------------------
  80. HRESULT CUmiPropList::QueryInterface(
  81. REFIID iid,
  82. LPVOID *ppInterface
  83. )
  84. {
  85. if(NULL == ppInterface)
  86. RRETURN(E_INVALIDARG);
  87. *ppInterface = NULL;
  88. if(IsEqualIID(iid, IID_IUnknown))
  89. *ppInterface = (IUmiPropList *) this;
  90. else if(IsEqualIID(iid, IID_IUmiPropList))
  91. *ppInterface = (IUmiPropList *) this;
  92. else
  93. RRETURN(E_NOINTERFACE);
  94. AddRef();
  95. RRETURN(S_OK);
  96. }
  97. //----------------------------------------------------------------------------
  98. // Function: FInit
  99. //
  100. // Synopsis: Initializes the property list object.
  101. //
  102. // Arguments:
  103. //
  104. // pPropCache Pointer to the property cache object. This argument will be
  105. // NULL if this object is for interface properties. In this case,
  106. // a new property cache is allocated by this function. If this
  107. // object is for object properties, then this argument points
  108. // to the property cache of the WinNT object.
  109. // ppszUnImpl Array of standard property names that are not implemented.
  110. // This is used on an interface property object to return E_NOTIMPL
  111. // as the error code.
  112. //
  113. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  114. //
  115. // Modifies: Nothing
  116. //
  117. //----------------------------------------------------------------------------
  118. HRESULT CUmiPropList::FInit(CPropertyCache *pPropCache, LPWSTR *ppszUnImpl)
  119. {
  120. HRESULT hr = UMI_S_NO_ERROR;
  121. if(NULL == pPropCache) {
  122. hr = CPropertyCache::createpropertycache(
  123. m_pSchema,
  124. m_dwSchemaSize,
  125. NULL, // this will ensure that the WinNT property cache
  126. // won't do implicit GetInfo for interface properties
  127. &m_pPropCache);
  128. BAIL_ON_FAILURE(hr);
  129. m_ppszUnImpl = ppszUnImpl;
  130. }
  131. else {
  132. m_fIsIntfPropObj = FALSE;
  133. m_pPropCache = pPropCache;
  134. }
  135. RRETURN(UMI_S_NO_ERROR);
  136. error:
  137. RRETURN(hr);
  138. }
  139. //----------------------------------------------------------------------------
  140. // Function: SetLastStatus
  141. //
  142. // Synopsis: Sets the status of the last operation.
  143. //
  144. // Arguments:
  145. //
  146. // ulStatus Status to be set
  147. //
  148. // Returns: Nothing
  149. //
  150. // Modifies: Nothing
  151. //
  152. //----------------------------------------------------------------------------
  153. void CUmiPropList::SetLastStatus(ULONG ulStatus)
  154. {
  155. m_ulErrorStatus = ulStatus;
  156. return;
  157. }
  158. //----------------------------------------------------------------------------
  159. // Function: GetLastStatus
  160. //
  161. // Synopsis: Returns status or error code from the last operation. Currently
  162. // only numeric status is returned i.e, no error objects are
  163. // returned.
  164. //
  165. // Arguments:
  166. //
  167. // uFlags Reserved. Must be 0 for now.
  168. // puSpecificStatus Returns status code
  169. // riid IID requested. Ignored currently.
  170. // pStatusObj Returns interface requested. Always returns NULL currently.
  171. //
  172. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  173. //
  174. // Modifies: *puSpecificStatus to return status code.
  175. //
  176. //----------------------------------------------------------------------------
  177. HRESULT CUmiPropList::GetLastStatus(
  178. ULONG uFlags,
  179. ULONG *puSpecificStatus,
  180. REFIID riid,
  181. LPVOID *pStatusObj
  182. )
  183. {
  184. if(pStatusObj != NULL)
  185. *pStatusObj = NULL;
  186. if(puSpecificStatus != NULL)
  187. *puSpecificStatus = 0;
  188. if(uFlags != 0)
  189. RRETURN(UMI_E_INVALID_FLAGS);
  190. if(NULL == puSpecificStatus)
  191. RRETURN(UMI_E_INVALIDARG);
  192. *puSpecificStatus = m_ulErrorStatus;
  193. RRETURN(UMI_S_NO_ERROR);
  194. }
  195. //----------------------------------------------------------------------------
  196. // Function: Put
  197. //
  198. // Synopsis: Implements IUmiPropList::Put. Writes a property into the cache.
  199. //
  200. // Arguments:
  201. //
  202. // pszName Name of the property
  203. // uFlags Flags for the Put operation. Unused currently.
  204. // pProp Pointer to the structure containing the value
  205. //
  206. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  207. //
  208. // Modifies: Nothing.
  209. //
  210. //----------------------------------------------------------------------------
  211. HRESULT CUmiPropList::Put(
  212. LPCWSTR pszName,
  213. ULONG uFlags,
  214. UMI_PROPERTY_VALUES *pProp
  215. )
  216. {
  217. HRESULT hr = UMI_S_NO_ERROR;
  218. DWORD dwSyntaxId = 0, dwIndex = 0;
  219. UMI_PROPERTY *pPropArray = NULL;
  220. LPNTOBJECT pNtObject = NULL;
  221. BOOL fMarkAsClean = FALSE;
  222. SetLastStatus(0);
  223. // fail if we have disabled writes
  224. if( (TRUE == m_fDisableWrites) && (TRUE == m_fIsIntfPropObj) )
  225. BAIL_ON_FAILURE(hr = UMI_E_READ_ONLY);
  226. // check args
  227. hr = ValidatePutArgs(
  228. pszName,
  229. uFlags,
  230. pProp
  231. );
  232. BAIL_ON_FAILURE(hr);
  233. // is this a standard interface property that's not implemented?
  234. if(m_ppszUnImpl != NULL) {
  235. while(m_ppszUnImpl[dwIndex] != NULL) {
  236. if(0 == _wcsicmp(m_ppszUnImpl[dwIndex], pszName)) {
  237. BAIL_ON_FAILURE(hr = UMI_E_NOTIMPL);
  238. }
  239. dwIndex++;
  240. }
  241. }
  242. // check if the property is in the schema
  243. hr = ValidatePropertyinSchemaClass(
  244. m_pSchema,
  245. m_dwSchemaSize,
  246. (LPWSTR) pszName,
  247. &dwSyntaxId
  248. );
  249. BAIL_ON_FAILURE(hr);
  250. // check if the property is writeable. Do this only if the flags are not
  251. // set to UMI_INTERNAL_FLAG_MARK_AS_CLEAN. Otherwise, the call is from
  252. // Clone() and we want read-only attributes to be succesfully copied
  253. // into the cloned object's cache. This requires that the check below
  254. // for writeable properties should be skipped.
  255. if(uFlags != UMI_INTERNAL_FLAG_MARK_AS_CLEAN) {
  256. hr = ValidateIfWriteableProperty(
  257. m_pSchema,
  258. m_dwSchemaSize,
  259. (LPWSTR) pszName
  260. );
  261. BAIL_ON_FAILURE(hr);
  262. }
  263. pPropArray = pProp->pPropArray;
  264. // convert UMI data into format that can be stored in the cache
  265. hr = UmiToWinNTType(
  266. dwSyntaxId,
  267. pPropArray,
  268. &pNtObject
  269. );
  270. BAIL_ON_FAILURE(hr);
  271. // Find the property in the cache. If it doesn't exist, add it.
  272. hr = m_pPropCache->findproperty((LPWSTR) pszName, &dwIndex);
  273. if(FAILED(hr))
  274. {
  275. hr = m_pPropCache->addproperty(
  276. (LPWSTR) pszName,
  277. dwSyntaxId,
  278. pPropArray->uCount,
  279. pNtObject
  280. );
  281. BAIL_ON_FAILURE(hr);
  282. }
  283. if(UMI_INTERNAL_FLAG_MARK_AS_CLEAN == uFlags)
  284. fMarkAsClean = TRUE;
  285. // Update property in cache
  286. hr = m_pPropCache->putproperty(
  287. (LPWSTR) pszName,
  288. dwSyntaxId,
  289. pPropArray->uCount,
  290. pNtObject,
  291. fMarkAsClean
  292. );
  293. BAIL_ON_FAILURE(hr);
  294. error:
  295. if(pNtObject)
  296. NTTypeFreeNTObjects(pNtObject, pPropArray->uCount);
  297. if(FAILED(hr))
  298. SetLastStatus(hr);
  299. RRETURN(MapHrToUmiError(hr));
  300. }
  301. //----------------------------------------------------------------------------
  302. // Function: ValidatePutArgs
  303. //
  304. // Synopsis: Checks if the arguments to Put() are well-formed.
  305. //
  306. // Arguments:
  307. //
  308. // pszName Name of the property
  309. // uFlags Flags for the Put operation. Unused currently.
  310. // pProp Pointer to the structure containing the value
  311. //
  312. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  313. //
  314. // Modifies: Nothing
  315. //
  316. //----------------------------------------------------------------------------
  317. HRESULT CUmiPropList::ValidatePutArgs(
  318. LPCWSTR pszName,
  319. ULONG uFlags,
  320. UMI_PROPERTY_VALUES *pProp
  321. )
  322. {
  323. UMI_PROPERTY *pPropArray = NULL;
  324. if( (NULL == pszName) || (NULL == pProp) )
  325. RRETURN(UMI_E_INVALIDARG);
  326. if( (uFlags != 0) && (uFlags != UMI_INTERNAL_FLAG_MARK_AS_CLEAN) )
  327. RRETURN(UMI_E_INVALID_FLAGS);
  328. if(pProp->uCount != 1) // cannot update multiple properties using Put()
  329. RRETURN(UMI_E_INVALIDARG);
  330. pPropArray = pProp->pPropArray;
  331. if(NULL == pPropArray)
  332. RRETURN(UMI_E_INVALIDARG);
  333. // WinNT provider supports only property update. Cannot append, clear etc.
  334. if(pPropArray->uOperationType != UMI_OPERATION_UPDATE)
  335. RRETURN(UMI_E_UNSUPPORTED_OPERATION);
  336. if(pPropArray->pszPropertyName &&
  337. _wcsicmp(pPropArray->pszPropertyName, pszName))
  338. RRETURN(UMI_E_INVALID_PROPERTY);
  339. if(NULL == pPropArray->pUmiValue)
  340. RRETURN(UMI_E_INVALIDARG);
  341. // all is well
  342. RRETURN(UMI_S_NO_ERROR);
  343. }
  344. //----------------------------------------------------------------------------
  345. // Function: Get
  346. //
  347. // Synopsis: Implements IUmiPropList::Get. Reads a property from the cache.
  348. // Since the WinNT provider does not support incremental updates
  349. // using PutEx, Get() will never return
  350. // UMI_E_SYNCHRONIZATION_REQUIRED. If a property is modified in
  351. // cache, Get() returns the modified value from the cache, without
  352. // any error.
  353. //
  354. // Arguments:
  355. //
  356. // pszName Name of the property
  357. // uFlags Flags for the Get operation. Unused currently.
  358. // ppProp Returns pointer to the structure containing the value
  359. //
  360. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  361. //
  362. // Modifies: *ppProp to return the address of UMI_PROPERT_VALUES structure.
  363. //
  364. //----------------------------------------------------------------------------
  365. HRESULT CUmiPropList::Get(
  366. LPCWSTR pszName,
  367. ULONG uFlags,
  368. UMI_PROPERTY_VALUES **ppProp
  369. )
  370. {
  371. RRETURN( GetHelper(
  372. pszName,
  373. uFlags,
  374. ppProp,
  375. UMI_TYPE_NULL, // no-op
  376. FALSE // not an internal call to GetHelper()
  377. ));
  378. }
  379. //----------------------------------------------------------------------------
  380. // Function: GetAs
  381. //
  382. // Synopsis: Implements IUmiPropList::GetAs. Reads a property from the cache.
  383. // The data is converted to the type requested by the caller.
  384. // Since the WinNT provider does not support incremental updates
  385. // using PutEx, GetAs() will never return
  386. // UMI_E_SYNCHRONIZATION_REQUIRED. If a property is modified in
  387. // cache, GetAs() returns the modified value from the cache, without
  388. // any error. This method is not supported for interface properties.
  389. //
  390. // Update: This method will not be supported on WinNT provider.
  391. //
  392. // Arguments:
  393. //
  394. // pszName Name of the property
  395. // uFlags Flags for the GetAs operation. Unused currently.
  396. // uCoercionType UMI type to convert the data to.
  397. // ppProp Returns pointer to the structure containing the value
  398. //
  399. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  400. //
  401. // Modifies: *ppProp to return the address of UMI_PROPERT_VALUES structure.
  402. //
  403. //----------------------------------------------------------------------------
  404. HRESULT CUmiPropList::GetAs(
  405. LPCWSTR pszName,
  406. ULONG uFlags,
  407. ULONG uCoercionType,
  408. UMI_PROPERTY_VALUES **ppProp
  409. )
  410. {
  411. SetLastStatus(UMI_E_NOTIMPL);
  412. RRETURN(UMI_E_NOTIMPL);
  413. SetLastStatus(0);
  414. if(TRUE == m_fIsIntfPropObj)
  415. // GetAs is only supported for object properties
  416. RRETURN(UMI_E_UNSUPPORTED_OPERATION);
  417. RRETURN( GetHelper(
  418. pszName,
  419. uFlags,
  420. ppProp,
  421. (UMI_TYPE) uCoercionType,
  422. FALSE, // not an internal call to GetHelper()
  423. TRUE
  424. ));
  425. }
  426. //----------------------------------------------------------------------------
  427. // Function: GetHelper
  428. //
  429. // Synopsis: Implements a helper function for Get() and GetAs().
  430. // Since the WinNT provider does not support incremental updates
  431. // using PutEx, Get()/GetAs() will never return
  432. // UMI_E_SYNCHRONIZATION_REQUIRED. If a property is modified in
  433. // cache, Get()/GetAs() returns the modified value from the cache,
  434. // wthout any error.
  435. //
  436. // Arguments:
  437. //
  438. // pszName Name of the property
  439. // uFlags Flags for the Get operation.
  440. // ppProp Returns pointer to the structure containing the value
  441. // UmiDstType UMI type to convert the NT value to. Used only by GetAs()
  442. // fInternal Flag to indicate if the call is through Get()/GetAs() or if it
  443. // is an internal call to this function from UMI. Difference is
  444. // that internal calls can read passwords from the cache.
  445. // fIsGetAs Flag to indicate if the caller is GetAs (in which case
  446. // UmiType is used). FALSE by default.
  447. //
  448. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  449. //
  450. // Modifies: *ppProp to return the address of UMI_PROPERT_VALUES structure.
  451. //
  452. //----------------------------------------------------------------------------
  453. HRESULT CUmiPropList::GetHelper(
  454. LPCWSTR pszName,
  455. ULONG uFlags,
  456. UMI_PROPERTY_VALUES **ppProp,
  457. UMI_TYPE UmiDstType,
  458. BOOL fInternal,
  459. BOOL fIsGetAs
  460. )
  461. {
  462. HRESULT hr = UMI_S_NO_ERROR;
  463. DWORD dwSyntaxId = 0, dwNumValues = 0, dwIndex = 0;
  464. LPNTOBJECT pNtObject = NULL;
  465. UMI_TYPE UmiType = UMI_TYPE_NULL;
  466. UMI_PROPERTY_VALUES *pProp = NULL;
  467. BOOL fModified = FALSE;
  468. SetLastStatus(0);
  469. hr = ValidateGetArgs(
  470. pszName,
  471. uFlags,
  472. ppProp
  473. );
  474. BAIL_ON_FAILURE(hr);
  475. if(UMI_FLAG_PROPERTY_ORIGIN == uFlags) {
  476. hr = GetPropertyOrigin(pszName, ppProp);
  477. if(FAILED(hr))
  478. goto error;
  479. else
  480. RRETURN(UMI_S_NO_ERROR);
  481. }
  482. // is this a standard interface property that's not implemented?
  483. if(m_ppszUnImpl != NULL) {
  484. while(m_ppszUnImpl[dwIndex] != NULL) {
  485. if(0 == _wcsicmp(m_ppszUnImpl[dwIndex], pszName)) {
  486. BAIL_ON_FAILURE(hr = UMI_E_NOTIMPL);
  487. }
  488. dwIndex++;
  489. }
  490. }
  491. *ppProp = NULL;
  492. // __SCHEMA should return a IUmiObject pointer. This property is treated as
  493. // a special case since it is not actually retrieved from the property
  494. // cache. This property will be requested only on an interface property
  495. // object.
  496. if( (TRUE == m_fIsIntfPropObj) &&
  497. (0 == _wcsicmp((LPWSTR) pszName, TEXT(UMIOBJ_INTF_PROP_SCHEMA))) ) {
  498. hr = GetSchemaObject((LPWSTR) pszName, ppProp);
  499. BAIL_ON_FAILURE(hr);
  500. RRETURN(hr);
  501. }
  502. // make sure that passwords cannot be read by a user
  503. if( (TRUE == m_fIsIntfPropObj) && (FALSE == fInternal) &&
  504. (0 == _wcsicmp((LPWSTR) pszName, TEXT(CONN_INTF_PROP_PASSWORD))) )
  505. BAIL_ON_FAILURE(hr = UMI_E_FAIL);
  506. // retrieve property from cache. This might result in an implicit GetInfo()
  507. // if this is for object properties. For, interface properties, there is
  508. // no implicit GetInfo().
  509. hr = m_pPropCache->getproperty(
  510. (LPWSTR) pszName,
  511. &dwSyntaxId,
  512. &dwNumValues,
  513. &pNtObject,
  514. &fModified
  515. );
  516. BAIL_ON_FAILURE(hr);
  517. // map the NT type to a UMI type
  518. if(dwSyntaxId >= g_dwNumNTTypes)
  519. BAIL_ON_FAILURE(hr = UMI_E_FAIL); // shouldn't happen
  520. if(FALSE == fIsGetAs)
  521. // get the UMI type corresponding to this NT type
  522. UmiType = g_mapNTTypeToUmiType[dwSyntaxId];
  523. else
  524. // try to convert to the type specified by the caller
  525. UmiType = UmiDstType;
  526. // allocate structure to return values
  527. pProp = (UMI_PROPERTY_VALUES *) AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
  528. if(NULL == pProp)
  529. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  530. memset(pProp, 0, sizeof(UMI_PROPERTY_VALUES));
  531. pProp->pPropArray = (UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
  532. if(NULL == pProp->pPropArray)
  533. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  534. memset(pProp->pPropArray, 0, sizeof(UMI_PROPERTY));
  535. hr = WinNTTypeToUmi(
  536. pNtObject,
  537. dwNumValues,
  538. pProp->pPropArray,
  539. NULL, // provider should allocate memory
  540. 0,
  541. UmiType
  542. );
  543. BAIL_ON_FAILURE(hr);
  544. // Get fetches only one property at a time
  545. pProp->uCount = 1;
  546. // Fill in remaining fields of UMI_PROPERTY
  547. if(TRUE == fModified) {
  548. // WinNT only allows updates
  549. if( (uFlags != UMI_FLAG_PROVIDER_CACHE) &&
  550. (FALSE == m_fIsIntfPropObj) ) {
  551. // need to return error since cache is dirty
  552. FreeMemory(0, pProp); // ignore error return
  553. pProp = NULL;
  554. BAIL_ON_FAILURE(hr = UMI_E_SYNCHRONIZATION_REQUIRED);
  555. }
  556. pProp->pPropArray->uOperationType = UMI_OPERATION_UPDATE;
  557. }
  558. else
  559. pProp->pPropArray->uOperationType = 0;
  560. // not critical if this memory allocation fails. Property name doesn't
  561. // have to be returned to the caller.
  562. pProp->pPropArray->pszPropertyName = AllocADsStr(pszName);
  563. *ppProp = pProp;
  564. error:
  565. if(pNtObject)
  566. NTTypeFreeNTObjects(pNtObject, dwNumValues);
  567. if(FAILED(hr)) {
  568. if(pProp != NULL) {
  569. if(pProp->pPropArray != NULL)
  570. FreeADsMem(pProp->pPropArray);
  571. FreeADsMem(pProp);
  572. }
  573. SetLastStatus(hr);
  574. }
  575. RRETURN(MapHrToUmiError(hr));
  576. }
  577. //----------------------------------------------------------------------------
  578. // Function: ValidateGetArgs
  579. //
  580. // Synopsis: Checks if the arguments to Get() are well-formed.
  581. //
  582. // Arguments:
  583. //
  584. // pszName Name of the property
  585. // uFlags Flags for the Put operation.
  586. // ppProp Returns pointer to the structure containing the value
  587. //
  588. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  589. //
  590. // Modifies: Nothing
  591. //
  592. //----------------------------------------------------------------------------
  593. HRESULT CUmiPropList::ValidateGetArgs(
  594. LPCWSTR pszName,
  595. ULONG uFlags,
  596. UMI_PROPERTY_VALUES **ppProp
  597. )
  598. {
  599. if( (NULL == pszName) || (NULL == ppProp) )
  600. RRETURN(UMI_E_INVALIDARG);
  601. // cannot combine UMI_FLAG_PROVIDER_CACHE and UMI_FLAG_PROPERTY_ORIGIN
  602. // since they are on the object property list and interface property list
  603. // respectively. So, don't need to AND with bitmasks to see if those flags
  604. // are set.
  605. if( (uFlags != 0) && (uFlags != UMI_FLAG_PROVIDER_CACHE) &&
  606. (uFlags != UMI_FLAG_PROPERTY_ORIGIN) )
  607. RRETURN(UMI_E_INVALID_FLAGS);
  608. if( (UMI_FLAG_PROVIDER_CACHE == uFlags) && (TRUE == m_fIsIntfPropObj) )
  609. RRETURN(UMI_E_INVALID_FLAGS);
  610. if(UMI_FLAG_PROPERTY_ORIGIN == uFlags) {
  611. // can set this flag only on the interface property object of a class
  612. // object.
  613. if( (FALSE == m_fIsIntfPropObj) || (NULL == m_pClassInfo) )
  614. RRETURN(UMI_E_INVALID_FLAGS);
  615. }
  616. // all is well
  617. RRETURN(UMI_S_NO_ERROR);
  618. }
  619. //----------------------------------------------------------------------------
  620. // Function: FreeMemory
  621. //
  622. // Synopsis: Implements IUmiPropList::FreeMemory. Frees a UMI_PROPERTY_VALUES
  623. // structure previously returned to the user.
  624. //
  625. // Arguments:
  626. //
  627. // uReserved Unused currently.
  628. // pMem Pointer to UMI_PROPERTY_VALUES structure to be freed.
  629. //
  630. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  631. //
  632. // Modifies: Nothing
  633. //
  634. //----------------------------------------------------------------------------
  635. HRESULT CUmiPropList::FreeMemory(
  636. ULONG uReserved,
  637. LPVOID pMem
  638. )
  639. {
  640. UMI_PROPERTY_VALUES *pUmiPropVal = NULL;
  641. UMI_PROPERTY *pPropArray = NULL;
  642. ULONG i;
  643. LPWSTR *pStrArray = NULL;
  644. UMI_OCTET_STRING *pOctetStrArray = NULL;
  645. PUMI_COM_OBJECT pUmiComObj = NULL;
  646. SetLastStatus(0);
  647. if( (NULL == pMem) || (uReserved != 0) ) {
  648. SetLastStatus(UMI_E_INVALIDARG);
  649. RRETURN(UMI_E_INVALIDARG);
  650. }
  651. // enclose in try/except to handle bad pointers sent in by caller
  652. __try {
  653. pUmiPropVal = (UMI_PROPERTY_VALUES *) pMem;
  654. for(i = 0; i < pUmiPropVal->uCount; i++) {
  655. pPropArray = pUmiPropVal->pPropArray + i;
  656. if(NULL == pPropArray)
  657. RRETURN(UMI_E_INVALID_POINTER);
  658. // GetProps returns a UMI_PROPERTY structure with just the
  659. // property name filled in and all other fields 0, when asked
  660. // for only property names.
  661. if(pPropArray->pszPropertyName != NULL)
  662. {
  663. FreeADsStr(pPropArray->pszPropertyName);
  664. pPropArray->pszPropertyName = NULL;
  665. }
  666. if(0 == pPropArray->uCount)
  667. continue;
  668. if(NULL == pPropArray->pUmiValue)
  669. RRETURN(UMI_E_INVALID_POINTER);
  670. // Free individual string values
  671. if(UMI_TYPE_LPWSTR == pPropArray->uType) {
  672. pStrArray = pPropArray->pUmiValue->pszStrValue;
  673. for(i = 0; i < pPropArray->uCount; i++) {
  674. if(pStrArray[i] != NULL) {
  675. FreeADsStr(pStrArray[i]);
  676. pStrArray[i] = NULL;
  677. }
  678. }
  679. }
  680. else if(UMI_TYPE_OCTETSTRING == pPropArray->uType) {
  681. pOctetStrArray = pPropArray->pUmiValue->octetStr;
  682. for(i = 0; i < pPropArray->uCount; i++) {
  683. if(pOctetStrArray[i].lpValue != NULL) {
  684. FreeADsMem(pOctetStrArray[i].lpValue);
  685. pOctetStrArray[i].lpValue = NULL;
  686. }
  687. }
  688. }
  689. else if(UMI_TYPE_IUNKNOWN == pPropArray->uType) {
  690. pUmiComObj = pPropArray->pUmiValue->comObject;
  691. for(i = 0; i < pPropArray->uCount; i++) {
  692. if(pUmiComObj[i].priid != NULL) {
  693. FreeADsMem(pUmiComObj[i].priid);
  694. pUmiComObj[i].priid = NULL;
  695. }
  696. if(pUmiComObj[i].pInterface != NULL){
  697. ((IUnknown *) pUmiComObj[i].pInterface)->Release();
  698. pUmiComObj[i].pInterface = NULL;
  699. }
  700. }
  701. }
  702. // Now free the UMI_VALUE structure
  703. FreeADsMem(pPropArray->pUmiValue);
  704. pPropArray->pUmiValue = NULL;
  705. } // for
  706. if(pUmiPropVal->pPropArray != NULL)
  707. FreeADsMem(pUmiPropVal->pPropArray);
  708. pUmiPropVal->pPropArray = NULL;
  709. FreeADsMem(pUmiPropVal);
  710. } __except( EXCEPTION_EXECUTE_HANDLER )
  711. {
  712. SetLastStatus(UMI_E_INTERNAL_EXCEPTION);
  713. RRETURN(UMI_E_INTERNAL_EXCEPTION);
  714. }
  715. RRETURN(UMI_S_NO_ERROR);
  716. }
  717. //----------------------------------------------------------------------------
  718. // Function: GetInterfacePropNames
  719. //
  720. // Synopsis: Returns the names of all interface properties supported.
  721. //
  722. // Arguments:
  723. //
  724. // pProps Returns the names of the properties, without any data
  725. //
  726. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  727. //
  728. // Modifies: *pProps to return the property names
  729. //
  730. //----------------------------------------------------------------------------
  731. HRESULT CUmiPropList::GetInterfacePropNames(
  732. UMI_PROPERTY_VALUES **pProps
  733. )
  734. {
  735. UMI_PROPERTY_VALUES *pUmiPropVals = NULL;
  736. UMI_PROPERTY *pUmiProps = NULL;
  737. HRESULT hr = UMI_S_NO_ERROR;
  738. ULONG ulIndex = 0, ulCount = 0;
  739. ADsAssert(pProps != NULL);
  740. ADsAssert(TRUE == m_fIsIntfPropObj);
  741. pUmiPropVals = (UMI_PROPERTY_VALUES *) AllocADsMem(
  742. sizeof(UMI_PROPERTY_VALUES));
  743. if(NULL == pUmiPropVals)
  744. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  745. memset(pUmiPropVals, 0, sizeof(UMI_PROPERTY_VALUES));
  746. if(0 == m_dwSchemaSize) {
  747. // no properties in cache
  748. *pProps = pUmiPropVals;
  749. RRETURN(UMI_S_NO_ERROR);
  750. }
  751. pUmiProps = (UMI_PROPERTY *) AllocADsMem(
  752. m_dwSchemaSize * sizeof(UMI_PROPERTY));
  753. if(NULL == pUmiProps)
  754. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  755. memset(pUmiProps, 0, m_dwSchemaSize * sizeof(UMI_PROPERTY));
  756. for(ulIndex = 0; ulIndex < m_dwSchemaSize; ulIndex++) {
  757. if( (0 == _wcsicmp((LPWSTR) m_pSchema[ulIndex].szPropertyName,
  758. TEXT(UMIOBJ_INTF_PROP_SCHEMA))) ||
  759. (0 == _wcsicmp((LPWSTR) m_pSchema[ulIndex].szPropertyName,
  760. TEXT(UMIOBJ_INTF_PROP_SCHEMAPATH))) ) {
  761. if(NULL == m_pszSchema)
  762. // must be a schema object, so don't return __SCHEMA and
  763. // __PADS_SCHEMA_CONTAINER_PATH.
  764. continue;
  765. }
  766. if(0 == _wcsicmp((LPWSTR) m_pSchema[ulIndex].szPropertyName,
  767. TEXT(UMIOBJ_INTF_PROP_SUPERCLASS))) {
  768. if(FALSE == m_fIsClassObj)
  769. // not a class object. Hence __SUPERCLASS is not exposed.
  770. continue;
  771. }
  772. if( (0 == _wcsicmp((LPWSTR) m_pSchema[ulIndex].szPropertyName,
  773. TEXT(UMIOBJ_INTF_PROP_KEY))) ||
  774. (0 == _wcsicmp((LPWSTR) m_pSchema[ulIndex].szPropertyName,
  775. TEXT(UMIOBJ_INTF_PROP_PARENT))) )
  776. if(TRUE == m_fIsNamespaceObj)
  777. // namespace objects have no key and parent
  778. continue;
  779. pUmiProps[ulCount].pszPropertyName =
  780. (LPWSTR) AllocADsStr(m_pSchema[ulIndex].szPropertyName);
  781. if(NULL == pUmiProps[ulCount].pszPropertyName)
  782. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  783. ulCount++;
  784. }
  785. pUmiPropVals->uCount = ulCount;
  786. pUmiPropVals->pPropArray = pUmiProps;
  787. *pProps = pUmiPropVals;
  788. RRETURN(UMI_S_NO_ERROR);
  789. error:
  790. if(pUmiProps != NULL) {
  791. for(ulIndex = 0; ulIndex < m_dwSchemaSize; ulIndex++)
  792. if(pUmiProps[ulIndex].pszPropertyName != NULL)
  793. FreeADsStr(pUmiProps[ulIndex].pszPropertyName);
  794. FreeADsMem(pUmiProps);
  795. }
  796. if(pUmiPropVals != NULL)
  797. FreeADsMem(pUmiPropVals);
  798. RRETURN(hr);
  799. }
  800. //----------------------------------------------------------------------------
  801. // Function: GetObjectPropNames
  802. //
  803. // Synopsis: Returns the names of all object properties in the cache.
  804. //
  805. // Arguments:
  806. //
  807. // pProps Returns the names of the properties, without any data
  808. //
  809. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  810. //
  811. // Modifies: *pProps to return the property names
  812. //
  813. //----------------------------------------------------------------------------
  814. HRESULT CUmiPropList::GetObjectPropNames(
  815. UMI_PROPERTY_VALUES **pProps
  816. )
  817. {
  818. ADsAssert(pProps != NULL);
  819. ADsAssert(FALSE == m_fIsIntfPropObj);
  820. RRETURN(m_pPropCache->GetPropNames(pProps));
  821. }
  822. //----------------------------------------------------------------------------
  823. // Function: GetProps
  824. //
  825. // Synopsis: Implements IUmiPropList::GetProps. Gets multiple properties.
  826. // This method will currently only support retrieving the names
  827. // of the properties supported. For interface property objects,
  828. // the names of all interface properties will be returned. For
  829. // object properties, the names of all properties in the cache will
  830. // be returned.
  831. // This method also supports retrieving class information if
  832. // the underlying object is a class object (in which case
  833. // m_pClassInfo will be non-NULL). This is supported only on an
  834. // interface property object.
  835. //
  836. // Arguments:
  837. //
  838. // pszNames Names of properties to retrieve. Should be NULL if only names
  839. // are requested.
  840. // uNameCount Number of properties in pszNames. Should be 0 if only names
  841. // are requested.
  842. // uFlags Should be UMI_FLAG_GETPROPS_NAMES to retrieve names of properties
  843. // and UMI_FLAG_GETPROPS_SCHEMA to get class information.
  844. // pProps Returns the names of the properties, without any data
  845. //
  846. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  847. //
  848. // Modifies: *pProps to return the property names
  849. //
  850. //----------------------------------------------------------------------------
  851. HRESULT CUmiPropList::GetProps(
  852. LPCWSTR *pszNames,
  853. ULONG uNameCount,
  854. ULONG uFlags,
  855. UMI_PROPERTY_VALUES **pProps
  856. )
  857. {
  858. HRESULT hr = UMI_S_NO_ERROR;
  859. SetLastStatus(0);
  860. if( (uFlags != ((ULONG) UMI_FLAG_GETPROPS_NAMES)) &&
  861. (uFlags != ((ULONG) UMI_FLAG_GETPROPS_SCHEMA)) )
  862. BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
  863. if( (pszNames != NULL) || (uNameCount != 0) || (NULL == pProps) )
  864. BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
  865. *pProps = NULL;
  866. if( ((ULONG) UMI_FLAG_GETPROPS_SCHEMA) == uFlags ) {
  867. if(NULL == m_pClassInfo) {
  868. // this is not a class object. This operation is not supported.
  869. BAIL_ON_FAILURE(hr = UMI_E_UNSUPPORTED_FLAGS);
  870. }
  871. else
  872. hr = GetClassInfo(pProps);
  873. }
  874. else {
  875. if(TRUE == m_fIsIntfPropObj)
  876. hr = GetInterfacePropNames(pProps);
  877. else
  878. hr = GetObjectPropNames(pProps);
  879. }
  880. error:
  881. if(FAILED(hr))
  882. SetLastStatus(hr);
  883. RRETURN(MapHrToUmiError(hr));
  884. }
  885. //---------------------------------------------------------------------------
  886. // Methods of IUmiPropList that are currently not implemented.
  887. //
  888. //---------------------------------------------------------------------------
  889. HRESULT CUmiPropList::GetAt(
  890. LPCWSTR pszName,
  891. ULONG uFlags,
  892. ULONG uBufferLength,
  893. LPVOID pExistingMem
  894. )
  895. {
  896. SetLastStatus(UMI_E_NOTIMPL);
  897. RRETURN(UMI_E_NOTIMPL);
  898. }
  899. HRESULT CUmiPropList::PutProps(
  900. LPCWSTR *pszNames,
  901. ULONG uNameCount,
  902. ULONG uFlags,
  903. UMI_PROPERTY_VALUES *pProps
  904. )
  905. {
  906. SetLastStatus(UMI_E_NOTIMPL);
  907. RRETURN(UMI_E_NOTIMPL);
  908. }
  909. HRESULT CUmiPropList::PutFrom(
  910. LPCWSTR pszName,
  911. ULONG uFlags,
  912. ULONG uBufferLength,
  913. LPVOID pExistingMem
  914. )
  915. {
  916. SetLastStatus(UMI_E_NOTIMPL);
  917. RRETURN(UMI_E_NOTIMPL);
  918. }
  919. HRESULT CUmiPropList::Delete(
  920. LPCWSTR pszName,
  921. ULONG uFlags
  922. )
  923. {
  924. SetLastStatus(UMI_E_NOTIMPL);
  925. RRETURN(UMI_E_NOTIMPL);
  926. }
  927. //----------------------------------------------------------------------------
  928. // Function: SetStandardProperties
  929. //
  930. // Synopsis: Sets standard interface properties supported by all UMI objects
  931. // in the cache.
  932. //
  933. // Arguments:
  934. //
  935. // pIADs Pointer to IADs interface on object
  936. // pCoreObj Pointer to core object for this WinNT object
  937. //
  938. // Returns: S_OK on success. Error code otherwise.
  939. //
  940. // Modifies: Nothing
  941. //
  942. //----------------------------------------------------------------------------
  943. HRESULT CUmiPropList::SetStandardProperties(
  944. IADs *pIADs,
  945. CCoreADsObject *pCoreObj
  946. )
  947. {
  948. HRESULT hr = S_OK;
  949. DWORD dwIndex = 0;
  950. IDispatch *pDispatch = NULL;
  951. DISPID DispId;
  952. DISPPARAMS DispParams = {NULL, NULL, 0, 0};
  953. VARIANT var;
  954. BSTR bstrADsPath = NULL, bstrClass = NULL;
  955. LPWSTR pFullUmiPath = NULL, pShortUmiPath = NULL, pRelUmiPath = NULL;
  956. LPWSTR pFullRelUmiPath = NULL, pFullParentPath = NULL;
  957. DWORD dwGenus = 0;
  958. BSTR bstrName = NULL, bstrParent = NULL;
  959. WCHAR *pSlash = NULL;
  960. LPWSTR Classes[] = {NULL, L"Schema"};
  961. LPWSTR pUmiSchemaPath = NULL;
  962. OBJECTINFO ObjectInfo;
  963. ADsAssert( (pIADs != NULL) && (TRUE == m_fIsIntfPropObj) );
  964. hr = pIADs->QueryInterface(
  965. IID_IDispatch,
  966. (void **) &pDispatch
  967. );
  968. BAIL_ON_FAILURE(hr);
  969. // First, set all properties supported on IADs. The names of these UMI
  970. // properties are not necessarily the same as the IADs properties, so
  971. // map the names appropriately.
  972. for(dwIndex = 0; dwIndex < g_dwIADsProperties; dwIndex++) {
  973. hr = pDispatch->GetIDsOfNames(
  974. IID_NULL,
  975. &g_IADsProps[dwIndex].IADsPropertyName,
  976. 1,
  977. LOCALE_SYSTEM_DEFAULT,
  978. &DispId
  979. );
  980. BAIL_ON_FAILURE(hr);
  981. hr = pDispatch->Invoke(
  982. DispId,
  983. IID_NULL,
  984. LOCALE_SYSTEM_DEFAULT,
  985. DISPATCH_PROPERTYGET,
  986. &DispParams,
  987. &var,
  988. NULL,
  989. NULL
  990. );
  991. if(0 == _wcsicmp(g_IADsProps[dwIndex].IADsPropertyName, L"Schema")) {
  992. if(FAILED(hr))
  993. // Not a catastrophic failure. Can't get this property from the
  994. // cache. Only scenario where this should happen is when calling
  995. // get_Schema on a schema/namespace object.
  996. continue;
  997. else {
  998. // store native path to schema in member variable
  999. m_pszSchema = AllocADsStr(V_BSTR(&var));
  1000. VariantClear(&var);
  1001. if(NULL == m_pszSchema)
  1002. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1003. // walk path backwards and get rid of last '/'
  1004. pSlash = wcsrchr(m_pszSchema, L'/');
  1005. if(NULL == pSlash)
  1006. // bad schema path
  1007. BAIL_ON_FAILURE(UMI_E_FAIL);
  1008. *pSlash = L'\0';
  1009. Classes[0] = pCoreObj->_CompClasses[0];
  1010. ObjectInfo.DisplayComponentArray[0] =
  1011. pCoreObj->_ObjectInfo.DisplayComponentArray[0];
  1012. ObjectInfo.DisplayComponentArray[1] = SCHEMA_NAME;
  1013. hr = ADsToUmiPath(
  1014. m_pszSchema,
  1015. &ObjectInfo,
  1016. Classes,
  1017. 2,
  1018. FULL_UMI_PATH,
  1019. &pUmiSchemaPath
  1020. );
  1021. *pSlash = L'/';
  1022. BAIL_ON_FAILURE(hr);
  1023. hr = SetLPTSTRPropertyInCache(
  1024. m_pPropCache,
  1025. TEXT(UMIOBJ_INTF_PROP_SCHEMAPATH),
  1026. pUmiSchemaPath,
  1027. TRUE
  1028. );
  1029. BAIL_ON_FAILURE(hr);
  1030. continue;
  1031. } // else
  1032. } // if(_wcsicmp...)
  1033. BAIL_ON_FAILURE(hr); // if Invoke failed
  1034. if(0 == _wcsicmp(g_IADsProps[dwIndex].IADsPropertyName, L"Parent")) {
  1035. // convert the parent to a full UMI path
  1036. if(0 == pCoreObj->_dwNumComponents) {
  1037. // namespace object has no parent
  1038. VariantClear(&var);
  1039. continue;
  1040. }
  1041. else {
  1042. bstrParent = V_BSTR(&var);
  1043. hr = ADsToUmiPath(
  1044. bstrParent,
  1045. pCoreObj->_pObjectInfo,
  1046. pCoreObj->_CompClasses,
  1047. pCoreObj->_dwNumComponents - 1,
  1048. FULL_UMI_PATH,
  1049. &pFullParentPath
  1050. );
  1051. VariantClear(&var);
  1052. BAIL_ON_FAILURE(hr);
  1053. hr = SetLPTSTRPropertyInCache(
  1054. m_pPropCache,
  1055. TEXT(UMIOBJ_INTF_PROP_PARENT),
  1056. pFullParentPath,
  1057. TRUE
  1058. );
  1059. BAIL_ON_FAILURE(hr);
  1060. continue;
  1061. } // else
  1062. } // if(0 ==
  1063. hr = GenericPutPropertyManager(
  1064. m_pPropCache,
  1065. m_pSchema,
  1066. m_dwSchemaSize,
  1067. g_IADsProps[dwIndex].UMIPropertyName,
  1068. var,
  1069. FALSE
  1070. );
  1071. VariantClear(&var);
  1072. BAIL_ON_FAILURE(hr);
  1073. }
  1074. // Now, set the remaining standard interface properties
  1075. hr = pIADs->get_ADsPath(&bstrADsPath);
  1076. BAIL_ON_FAILURE(hr);
  1077. hr = ADsToUmiPath(
  1078. bstrADsPath,
  1079. pCoreObj->_pObjectInfo,
  1080. pCoreObj->_CompClasses,
  1081. pCoreObj->_dwNumComponents,
  1082. FULL_UMI_PATH,
  1083. &pFullUmiPath
  1084. );
  1085. BAIL_ON_FAILURE(hr);
  1086. hr = ADsToUmiPath(
  1087. bstrADsPath,
  1088. pCoreObj->_pObjectInfo,
  1089. pCoreObj->_CompClasses,
  1090. pCoreObj->_dwNumComponents,
  1091. SHORT_UMI_PATH,
  1092. &pShortUmiPath
  1093. );
  1094. BAIL_ON_FAILURE(hr);
  1095. hr = ADsToUmiPath(
  1096. bstrADsPath,
  1097. pCoreObj->_pObjectInfo,
  1098. pCoreObj->_CompClasses,
  1099. pCoreObj->_dwNumComponents,
  1100. RELATIVE_UMI_PATH,
  1101. &pRelUmiPath
  1102. );
  1103. BAIL_ON_FAILURE(hr);
  1104. hr = ADsToUmiPath(
  1105. bstrADsPath,
  1106. pCoreObj->_pObjectInfo,
  1107. pCoreObj->_CompClasses,
  1108. pCoreObj->_dwNumComponents,
  1109. FULL_RELATIVE_UMI_PATH,
  1110. &pFullRelUmiPath
  1111. );
  1112. BAIL_ON_FAILURE(hr);
  1113. hr = SetLPTSTRPropertyInCache(
  1114. m_pPropCache,
  1115. TEXT(UMIOBJ_INTF_PROP_FULLURL),
  1116. pFullUmiPath,
  1117. TRUE
  1118. );
  1119. BAIL_ON_FAILURE(hr);
  1120. hr = SetLPTSTRPropertyInCache(
  1121. m_pPropCache,
  1122. TEXT(UMIOBJ_INTF_PROP_URL),
  1123. pShortUmiPath,
  1124. TRUE
  1125. );
  1126. BAIL_ON_FAILURE(hr);
  1127. hr = SetLPTSTRPropertyInCache(
  1128. m_pPropCache,
  1129. TEXT(UMIOBJ_INTF_PROP_RELURL),
  1130. pRelUmiPath,
  1131. TRUE
  1132. );
  1133. BAIL_ON_FAILURE(hr);
  1134. hr = SetLPTSTRPropertyInCache(
  1135. m_pPropCache,
  1136. TEXT(UMIOBJ_INTF_PROP_FULLRELURL),
  1137. pFullRelUmiPath,
  1138. TRUE
  1139. );
  1140. BAIL_ON_FAILURE(hr);
  1141. // Relpath is the same as the full relative URL
  1142. hr = SetLPTSTRPropertyInCache(
  1143. m_pPropCache,
  1144. TEXT(UMIOBJ_INTF_PROP_RELPATH),
  1145. pFullRelUmiPath,
  1146. TRUE
  1147. );
  1148. BAIL_ON_FAILURE(hr);
  1149. // set the genus based on the class of the object
  1150. hr = pIADs->get_Class(&bstrClass);
  1151. BAIL_ON_FAILURE(hr);
  1152. if(IsSchemaObject(bstrClass)) {
  1153. dwGenus = UMI_GENUS_CLASS;
  1154. // WMI requires that the value of __CLASS be the same on instances
  1155. // and classes. Thus, on class objects, the value of __CLASS should
  1156. // be "user" instead of "class". __SUPERCLASS is exposed only on
  1157. // class objects. Its value is always NULL in the WinNT provider
  1158. // since there is no class hierarchy.
  1159. if(IsClassObj(bstrClass)) {
  1160. hr = pIADs->get_Name(&bstrName);
  1161. BAIL_ON_FAILURE(hr);
  1162. // overwrite the value of __CLASS already stored in cache above
  1163. hr = SetLPTSTRPropertyInCache(
  1164. m_pPropCache,
  1165. TEXT(UMIOBJ_INTF_PROP_CLASS),
  1166. bstrName,
  1167. TRUE
  1168. );
  1169. BAIL_ON_FAILURE(hr);
  1170. hr = SetLPTSTRPropertyInCache(
  1171. m_pPropCache,
  1172. TEXT(UMIOBJ_INTF_PROP_SUPERCLASS),
  1173. NULL,
  1174. TRUE
  1175. );
  1176. m_fIsClassObj = TRUE;
  1177. BAIL_ON_FAILURE(hr);
  1178. } // if(IsClassObj...)
  1179. }
  1180. else
  1181. dwGenus = UMI_GENUS_INSTANCE;
  1182. hr = SetDWORDPropertyInCache(
  1183. m_pPropCache,
  1184. TEXT(UMIOBJ_INTF_PROP_GENUS),
  1185. dwGenus,
  1186. TRUE
  1187. );
  1188. BAIL_ON_FAILURE(hr);
  1189. // set the key property. For WinNT, it will always be "Name" except that
  1190. // namespace objects have no key (since the UMI path to a namespace object
  1191. // is just umi:///winnt - there is no component of the form class.key=val.
  1192. if(!IsNamespaceObj(bstrClass)) {
  1193. hr = SetLPTSTRPropertyInCache(
  1194. m_pPropCache,
  1195. TEXT(UMIOBJ_INTF_PROP_KEY),
  1196. WINNT_KEY_NAME,
  1197. TRUE
  1198. );
  1199. BAIL_ON_FAILURE(hr);
  1200. }
  1201. else {
  1202. m_fIsNamespaceObj = TRUE;
  1203. }
  1204. // Mark all properties as "not modified", since the client really hasn't
  1205. // updated the cache, though we have.
  1206. m_pPropCache->ClearModifiedFlags();
  1207. error:
  1208. if(pDispatch != NULL)
  1209. pDispatch->Release();
  1210. if(bstrADsPath != NULL)
  1211. SysFreeString(bstrADsPath);
  1212. if(bstrClass != NULL)
  1213. SysFreeString(bstrClass);
  1214. if(pFullUmiPath != NULL)
  1215. FreeADsStr(pFullUmiPath);
  1216. if(pRelUmiPath != NULL)
  1217. FreeADsStr(pRelUmiPath);
  1218. if(pFullRelUmiPath != NULL)
  1219. FreeADsStr(pFullRelUmiPath);
  1220. if(pShortUmiPath != NULL)
  1221. FreeADsStr(pShortUmiPath);
  1222. if(pFullParentPath != NULL)
  1223. FreeADsStr(pFullParentPath);
  1224. if(bstrName != NULL)
  1225. SysFreeString(bstrName);
  1226. if(pUmiSchemaPath != NULL)
  1227. FreeADsStr(pUmiSchemaPath);
  1228. RRETURN(hr);
  1229. }
  1230. //----------------------------------------------------------------------------
  1231. // Function: IsSchemaObject
  1232. //
  1233. // Synopsis: Returns whether an object of a specified class is a schema
  1234. // object or not.
  1235. //
  1236. // Arguments:
  1237. //
  1238. // bstrClass Class of object
  1239. //
  1240. // Returns: TRUE if it is a schema object. FALSE otherwise.
  1241. //
  1242. // Modifies: Nothing
  1243. //
  1244. //----------------------------------------------------------------------------
  1245. BOOL CUmiPropList::IsSchemaObject(
  1246. BSTR bstrClass
  1247. )
  1248. {
  1249. ADsAssert(bstrClass != NULL);
  1250. if( (!_wcsicmp(bstrClass, L"Schema")) ||
  1251. (!_wcsicmp(bstrClass, L"Class")) ||
  1252. (!_wcsicmp(bstrClass, L"Property")) ||
  1253. (!_wcsicmp(bstrClass, L"Syntax")) ||
  1254. (!_wcsicmp(bstrClass, L"Namespace")) )
  1255. RRETURN(TRUE);
  1256. RRETURN(FALSE);
  1257. }
  1258. //----------------------------------------------------------------------------
  1259. // Function: GetSchemaObject
  1260. //
  1261. // Synopsis: Returns a IUmiObject pointer pointing to the schema class object
  1262. // corresponding to this WinNT object. If there is no class object,
  1263. // returns error.
  1264. //
  1265. // Arguments:
  1266. //
  1267. // pszName Name of the schema property
  1268. // ppProp Returns pointer to the structure containing the IUmiObject
  1269. // pointer.
  1270. //
  1271. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  1272. //
  1273. // Modifies: *ppProp to return the address of UMI_PROPERTY_VALUES structure.
  1274. //
  1275. //----------------------------------------------------------------------------
  1276. HRESULT CUmiPropList::GetSchemaObject(
  1277. LPWSTR pszName,
  1278. UMI_PROPERTY_VALUES **ppProp
  1279. )
  1280. {
  1281. HRESULT hr = UMI_S_NO_ERROR;
  1282. IUnknown *pUnknown = NULL;
  1283. IUmiObject *pUmiObj = NULL;
  1284. UMI_PROPERTY_VALUES *pProp = NULL;
  1285. PUMI_COM_OBJECT pUmiComObj = NULL;
  1286. // use ADS_AUTH_RESERVED since the call is from UMI
  1287. CWinNTCredentials Credentials(NULL, NULL, ADS_AUTH_RESERVED);
  1288. ADsAssert( (ppProp != NULL) && (TRUE == m_fIsIntfPropObj) );
  1289. *ppProp = NULL;
  1290. if(NULL == m_pszSchema)
  1291. // schema objects don't support __SCHEMA
  1292. RRETURN(UMI_E_PROPERTY_NOT_FOUND);
  1293. hr = GetObject(
  1294. m_pszSchema,
  1295. (LPVOID *) &pUnknown,
  1296. Credentials
  1297. );
  1298. BAIL_ON_FAILURE(hr);
  1299. hr = pUnknown->QueryInterface(IID_IUmiObject, (LPVOID *) &pUmiObj);
  1300. BAIL_ON_FAILURE(hr);
  1301. pUmiComObj = (PUMI_COM_OBJECT) AllocADsMem(sizeof(UMI_COM_OBJECT));
  1302. if(NULL == pUmiComObj)
  1303. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1304. memset(pUmiComObj, 0, sizeof(UMI_COM_OBJECT));
  1305. pUmiComObj->priid = (IID *) AllocADsMem(sizeof(IID));
  1306. if(NULL == pUmiComObj->priid)
  1307. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1308. memcpy(pUmiComObj->priid, &IID_IUmiObject, sizeof(IID));
  1309. pUmiComObj->pInterface = (LPVOID) pUmiObj;
  1310. // allocate structure to return values
  1311. pProp = (UMI_PROPERTY_VALUES *) AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
  1312. if(NULL == pProp)
  1313. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1314. memset(pProp, 0, sizeof(UMI_PROPERTY_VALUES));
  1315. pProp->pPropArray = (UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
  1316. if(NULL == pProp->pPropArray)
  1317. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1318. memset(pProp->pPropArray, 0, sizeof(UMI_PROPERTY));
  1319. pProp->pPropArray->pUmiValue = (UMI_VALUE *) pUmiComObj;
  1320. // Get fetches only one property at a time
  1321. pProp->uCount = 1;
  1322. // Fill in remaining fields of UMI_PROPERTY
  1323. pProp->pPropArray->uOperationType = 0;
  1324. pProp->pPropArray->uType = UMI_TYPE_IUNKNOWN;
  1325. pProp->pPropArray->uCount = 1;
  1326. // not critical if this memory allocation fails. Property name doesn't
  1327. // have to be returned to the caller.
  1328. pProp->pPropArray->pszPropertyName = AllocADsStr(pszName);
  1329. *ppProp = pProp;
  1330. error:
  1331. if(pUnknown != NULL)
  1332. pUnknown->Release();
  1333. if(FAILED(hr)) {
  1334. if(pUmiObj != NULL)
  1335. pUmiObj->Release();
  1336. if(pUmiComObj != NULL) {
  1337. if(pUmiComObj->priid != NULL)
  1338. FreeADsMem(pUmiComObj->priid);
  1339. FreeADsMem(pUmiComObj);
  1340. }
  1341. if(pProp != NULL) {
  1342. if(pProp->pPropArray != NULL) {
  1343. if(pProp->pPropArray->pszPropertyName != NULL)
  1344. FreeADsStr(pProp->pPropArray->pszPropertyName);
  1345. FreeADsMem(pProp->pPropArray);
  1346. }
  1347. FreeADsMem(pProp);
  1348. }
  1349. } // if(FAILED(hr))
  1350. RRETURN(hr);
  1351. }
  1352. //----------------------------------------------------------------------------
  1353. // Function: SetClassInfo
  1354. //
  1355. // Synopsis: Initializes class info for this object. Class info will be
  1356. // stored only for class schema objects.
  1357. //
  1358. // Arguments:
  1359. //
  1360. // pClassInfo Class info for the object (NULL if not a class object)
  1361. //
  1362. // Returns: Nothing
  1363. //
  1364. // Modifies: Nothing
  1365. //
  1366. //----------------------------------------------------------------------------
  1367. void CUmiPropList::SetClassInfo(
  1368. CLASSINFO *pClassInfo
  1369. )
  1370. {
  1371. m_pClassInfo = pClassInfo;
  1372. return;
  1373. }
  1374. //----------------------------------------------------------------------------
  1375. // Function: GetClassInfo
  1376. //
  1377. // Synopsis: Returns the name and UMI type of all attributes in a given
  1378. // WinNT class. This method will only be called on the interface
  1379. // property object of a class object.
  1380. //
  1381. // Arguments:
  1382. //
  1383. // pProps Returns the names and types of the attributes, without any data
  1384. //
  1385. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  1386. //
  1387. // Modifies: *pProps to return the property names
  1388. //
  1389. //----------------------------------------------------------------------------
  1390. HRESULT CUmiPropList::GetClassInfo(
  1391. UMI_PROPERTY_VALUES **pProps
  1392. )
  1393. {
  1394. UMI_PROPERTY_VALUES *pUmiPropVals = NULL;
  1395. UMI_PROPERTY *pUmiProps = NULL;
  1396. HRESULT hr = UMI_S_NO_ERROR;
  1397. ULONG ulIndex = 0;
  1398. PPROPERTYINFO pClassSchema = NULL;
  1399. DWORD dwClassSchemaSize = 0;
  1400. ADsAssert(pProps != NULL);
  1401. ADsAssert(TRUE == m_fIsIntfPropObj);
  1402. ADsAssert(m_pClassInfo != NULL);
  1403. pUmiPropVals = (UMI_PROPERTY_VALUES *) AllocADsMem(
  1404. sizeof(UMI_PROPERTY_VALUES));
  1405. if(NULL == pUmiPropVals)
  1406. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1407. memset(pUmiPropVals, 0, sizeof(UMI_PROPERTY_VALUES));
  1408. pClassSchema = m_pClassInfo->aPropertyInfo;
  1409. dwClassSchemaSize = m_pClassInfo->cPropertyInfo;
  1410. if(0 == dwClassSchemaSize) {
  1411. // no properties in class
  1412. *pProps = pUmiPropVals;
  1413. RRETURN(UMI_S_NO_ERROR);
  1414. }
  1415. pUmiProps = (UMI_PROPERTY *) AllocADsMem(
  1416. dwClassSchemaSize * sizeof(UMI_PROPERTY));
  1417. if(NULL == pUmiProps)
  1418. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1419. memset(pUmiProps, 0, dwClassSchemaSize * sizeof(UMI_PROPERTY));
  1420. for(ulIndex = 0; ulIndex < dwClassSchemaSize; ulIndex++) {
  1421. pUmiProps[ulIndex].pszPropertyName =
  1422. (LPWSTR) AllocADsStr(pClassSchema[ulIndex].szPropertyName);
  1423. if(NULL == pUmiProps[ulIndex].pszPropertyName)
  1424. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1425. // map the NT type to a UMI type
  1426. if(pClassSchema[ulIndex].dwSyntaxId >= g_dwNumNTTypes)
  1427. BAIL_ON_FAILURE(hr = UMI_E_FAIL); // shouldn't happen
  1428. pUmiProps[ulIndex].uType =
  1429. g_mapNTTypeToUmiType[pClassSchema[ulIndex].dwSyntaxId];
  1430. }
  1431. pUmiPropVals->uCount = dwClassSchemaSize;
  1432. pUmiPropVals->pPropArray = pUmiProps;
  1433. *pProps = pUmiPropVals;
  1434. RRETURN(UMI_S_NO_ERROR);
  1435. error:
  1436. if(pUmiProps != NULL) {
  1437. for(ulIndex = 0; ulIndex < dwClassSchemaSize; ulIndex++)
  1438. if(pUmiProps[ulIndex].pszPropertyName != NULL)
  1439. FreeADsStr(pUmiProps[ulIndex].pszPropertyName);
  1440. FreeADsMem(pUmiProps);
  1441. }
  1442. if(pUmiPropVals != NULL)
  1443. FreeADsMem(pUmiPropVals);
  1444. RRETURN(hr);
  1445. }
  1446. //----------------------------------------------------------------------------
  1447. // Function: IsNamespaceObj
  1448. //
  1449. // Synopsis: Returns whether an object of a specified class is a namespace
  1450. // object or not.
  1451. //
  1452. // Arguments:
  1453. //
  1454. // bstrClass Class of object
  1455. //
  1456. // Returns: TRUE if it is a namespace object. FALSE otherwise.
  1457. //
  1458. // Modifies: Nothing
  1459. //
  1460. //----------------------------------------------------------------------------
  1461. BOOL CUmiPropList::IsNamespaceObj(
  1462. BSTR bstrClass
  1463. )
  1464. {
  1465. ADsAssert(bstrClass != NULL);
  1466. if(!_wcsicmp(bstrClass, L"Namespace"))
  1467. RRETURN(TRUE);
  1468. RRETURN(FALSE);
  1469. }
  1470. //----------------------------------------------------------------------------
  1471. // Function: IsClassObj
  1472. //
  1473. // Synopsis: Returns whether an object of a specified class is a class
  1474. // object or not.
  1475. //
  1476. // Arguments:
  1477. //
  1478. // bstrClass Class of object
  1479. //
  1480. // Returns: TRUE if it is a class object. FALSE otherwise.
  1481. //
  1482. // Modifies: Nothing
  1483. //
  1484. //----------------------------------------------------------------------------
  1485. BOOL CUmiPropList::IsClassObj(
  1486. BSTR bstrClass
  1487. )
  1488. {
  1489. ADsAssert(bstrClass != NULL);
  1490. if(!_wcsicmp(bstrClass, L"Class"))
  1491. RRETURN(TRUE);
  1492. RRETURN(FALSE);
  1493. }
  1494. //----------------------------------------------------------------------------
  1495. // Function: DisableWrites
  1496. //
  1497. // Synopsis: Disables writes on an interface property object. Used to disable
  1498. // modification of connection interface properties after the
  1499. // connection is opened.
  1500. //
  1501. // Arguments:
  1502. //
  1503. // None
  1504. //
  1505. // Returns: Nothing
  1506. //
  1507. // Modifies: Nothing
  1508. //
  1509. //----------------------------------------------------------------------------
  1510. void CUmiPropList::DisableWrites(void)
  1511. {
  1512. ADsAssert(TRUE == m_fIsIntfPropObj);
  1513. m_fDisableWrites = TRUE;
  1514. }
  1515. //----------------------------------------------------------------------------
  1516. // Function: SetDefaultConnProps
  1517. //
  1518. // Synopsis: Sets the default connection interface properties on the
  1519. // interface property object of a connection.
  1520. //
  1521. // Arguments:
  1522. //
  1523. // None
  1524. //
  1525. // Returns: S_OK on success. Error code otherwise.
  1526. //
  1527. // Modifies: Nothing
  1528. //
  1529. //----------------------------------------------------------------------------
  1530. HRESULT CUmiPropList::SetDefaultConnProps(void)
  1531. {
  1532. HRESULT hr = S_OK;
  1533. ADsAssert(TRUE == m_fIsIntfPropObj);
  1534. hr = SetLPTSTRPropertyInCache(
  1535. m_pPropCache,
  1536. TEXT(CONN_INTF_PROP_USERNAME),
  1537. CONN_INTF_PROP_DEFAULT_USERNAME,
  1538. TRUE
  1539. );
  1540. BAIL_ON_FAILURE(hr);
  1541. hr = SetLPTSTRPropertyInCache(
  1542. m_pPropCache,
  1543. TEXT(CONN_INTF_PROP_PASSWORD),
  1544. CONN_INTF_PROP_DEFAULT_PASSWORD,
  1545. TRUE
  1546. );
  1547. BAIL_ON_FAILURE(hr);
  1548. hr = SetBOOLPropertyInCache(
  1549. m_pPropCache,
  1550. TEXT(CONN_INTF_PROP_SECURE_AUTH),
  1551. CONN_INTF_PROP_DEFAULT_SECURE_AUTH,
  1552. TRUE
  1553. );
  1554. BAIL_ON_FAILURE(hr);
  1555. hr = SetBOOLPropertyInCache(
  1556. m_pPropCache,
  1557. TEXT(CONN_INTF_PROP_READONLY_SERVER),
  1558. CONN_INTF_PROP_DEFAULT_READONLY_SERVER,
  1559. TRUE
  1560. );
  1561. BAIL_ON_FAILURE(hr);
  1562. RRETURN(S_OK);
  1563. error:
  1564. RRETURN(hr);
  1565. }
  1566. //----------------------------------------------------------------------------
  1567. // Function: SetPropertyCount
  1568. //
  1569. // Synopsis: Sets the property count in the interface property object's
  1570. // cache. The property count is the number of properties in the
  1571. // schema class object. It is exposed on both schema objects and
  1572. // instances.
  1573. //
  1574. // Arguments:
  1575. //
  1576. // dwPropCount Property count
  1577. //
  1578. // Returns: S_OK on success. Error code otherwise.
  1579. //
  1580. // Modifies: Nothing
  1581. //
  1582. //----------------------------------------------------------------------------
  1583. HRESULT CUmiPropList::SetPropertyCount(DWORD dwPropCount)
  1584. {
  1585. HRESULT hr = S_OK;
  1586. hr = SetDWORDPropertyInCache(
  1587. m_pPropCache,
  1588. TEXT(UMIOBJ_INTF_PROP_PROPERTY_COUNT),
  1589. dwPropCount,
  1590. TRUE
  1591. );
  1592. BAIL_ON_FAILURE(hr);
  1593. error:
  1594. RRETURN(hr);
  1595. }
  1596. //----------------------------------------------------------------------------
  1597. // Function: GetPropertyOrigin
  1598. //
  1599. // Synopsis: Returns the class in the hierarchy that introduced a
  1600. // property. Since WinNT does not have a class hierarchy, this
  1601. // will always be the class on which this method is called. If
  1602. // the property is not in the class, an error is returned.
  1603. //
  1604. // Arguments:
  1605. //
  1606. // pszName Name of the schema property
  1607. // ppProp Returns pointer to the structure containing the class name
  1608. //
  1609. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  1610. //
  1611. // Modifies: *ppProp to return the address of UMI_PROPERTY_VALUES structure.
  1612. //
  1613. //----------------------------------------------------------------------------
  1614. HRESULT CUmiPropList::GetPropertyOrigin(
  1615. LPCWSTR pszName,
  1616. UMI_PROPERTY_VALUES **ppProp
  1617. )
  1618. {
  1619. HRESULT hr = UMI_S_NO_ERROR;
  1620. DWORD dwIndex = 0;
  1621. PPROPERTYINFO pClassSchema = NULL;
  1622. DWORD dwClassSchemaSize = 0;
  1623. UMI_PROPERTY_VALUES *pProp = NULL;
  1624. LPWSTR *ppszClassArray = NULL;
  1625. ADsAssert( (pszName != NULL) && (ppProp != NULL) &&
  1626. (TRUE == m_fIsIntfPropObj) && (m_pClassInfo != NULL) );
  1627. *ppProp = NULL;
  1628. pClassSchema = m_pClassInfo->aPropertyInfo;
  1629. dwClassSchemaSize = m_pClassInfo->cPropertyInfo;
  1630. if(0 == dwClassSchemaSize)
  1631. // no properties in class
  1632. BAIL_ON_FAILURE(hr = UMI_E_PROPERTY_NOT_FOUND);
  1633. for(dwIndex = 0; dwIndex < dwClassSchemaSize; dwIndex++) {
  1634. if(0 == _wcsicmp(pszName, pClassSchema[dwIndex].szPropertyName))
  1635. // found the property
  1636. break;
  1637. }
  1638. if(dwIndex == dwClassSchemaSize)
  1639. BAIL_ON_FAILURE(hr = UMI_E_PROPERTY_NOT_FOUND);
  1640. // allocate structure to return class name
  1641. pProp = (UMI_PROPERTY_VALUES *) AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
  1642. if(NULL == pProp)
  1643. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1644. memset(pProp, 0, sizeof(UMI_PROPERTY_VALUES));
  1645. pProp->pPropArray = (UMI_PROPERTY *) AllocADsMem(sizeof(UMI_PROPERTY));
  1646. if(NULL == pProp->pPropArray)
  1647. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1648. memset(pProp->pPropArray, 0, sizeof(UMI_PROPERTY));
  1649. ppszClassArray = (LPWSTR *) AllocADsMem(sizeof(LPWSTR *));
  1650. if(NULL == pProp->pPropArray)
  1651. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1652. memset(ppszClassArray, 0, sizeof(LPWSTR *));
  1653. ppszClassArray[0] = AllocADsStr(m_pClassInfo->bstrName);
  1654. if(NULL == ppszClassArray[0])
  1655. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  1656. pProp->pPropArray->pUmiValue = (UMI_VALUE *) ppszClassArray;
  1657. // Get fetches only one property at a time
  1658. pProp->uCount = 1;
  1659. // Fill in remaining fields of UMI_PROPERTY
  1660. pProp->pPropArray->uOperationType = 0;
  1661. pProp->pPropArray->uType = UMI_TYPE_LPWSTR;
  1662. pProp->pPropArray->uCount = 1;
  1663. // not critical if this memory allocation fails. Property name doesn't
  1664. // have to be returned to the caller.
  1665. pProp->pPropArray->pszPropertyName = AllocADsStr(pszName);
  1666. *ppProp = pProp;
  1667. error:
  1668. if(FAILED(hr)) {
  1669. if(pProp != NULL) {
  1670. if(pProp->pPropArray != NULL) {
  1671. if(pProp->pPropArray->pszPropertyName != NULL)
  1672. FreeADsStr(pProp->pPropArray->pszPropertyName);
  1673. FreeADsMem(pProp->pPropArray);
  1674. }
  1675. FreeADsMem(pProp);
  1676. }
  1677. if(ppszClassArray != NULL) {
  1678. if(ppszClassArray[0] != NULL)
  1679. FreeADsStr(ppszClassArray[0]);
  1680. FreeADsMem(ppszClassArray);
  1681. }
  1682. } // if(FAILED(hr))
  1683. RRETURN(hr);
  1684. }