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.

737 lines
22 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1998.
  5. //
  6. // File: StdQSpec.cxx
  7. //
  8. // Contents: IQuery for file-based queries
  9. //
  10. // Classes: CQuerySpec
  11. //
  12. // History: 30 Jun 1995 AlanW Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. extern long gulcInstances;
  18. #include <cidbprop.hxx>
  19. #include <cmdprutl.hxx>
  20. #include <dbprputl.hxx>
  21. #include <datasrc.hxx>
  22. #include <session.hxx>
  23. #include <dsocf.hxx>
  24. #include <lgplist.hxx>
  25. #include <propglob.hxx>
  26. #include "stdqspec.hxx"
  27. //+-------------------------------------------------------------------------
  28. //
  29. // Member: CQuerySpec::QueryInternalQuery, protected
  30. //
  31. // Synopsis: Instantiates internal query, using current parameters.
  32. //
  33. // Returns: Pointer to internal query object.
  34. //
  35. // History: 03-Mar-1997 KyleP Created
  36. // 14-May-1997 mohamedn hidden core/fs property sets
  37. //
  38. //--------------------------------------------------------------------------
  39. PIInternalQuery * CQuerySpec::QueryInternalQuery()
  40. {
  41. //
  42. // get a pointer to the PIInternalQuery interface
  43. //
  44. XInterface<CDbProperties> xIDbProps(new CDbProperties);
  45. if ( xIDbProps.IsNull() )
  46. THROW( CException( E_OUTOFMEMORY ) );
  47. CGetCmdProps getCmdProps( (ICommand *)this);
  48. SCODE sc;
  49. PIInternalQuery * pQuery;
  50. ULONG cardinality = getCmdProps.GetCardinality();
  51. if ( cardinality <= 1 )
  52. {
  53. getCmdProps.PopulateDbProps( xIDbProps.GetPointer() );
  54. sc = EvalQuery( &pQuery,
  55. xIDbProps.GetReference(),
  56. _xDocStore.GetPointer());
  57. }
  58. else
  59. {
  60. Win4Assert( !_xDocStore.GetPointer() );
  61. sc = EvalDistributedQuery( &pQuery, getCmdProps );
  62. }
  63. if ( FAILED( sc ) )
  64. QUIETTHROW( CException( sc ) );
  65. Win4Assert( 0 != pQuery );
  66. return pQuery;
  67. } //QueryInternalQuery
  68. //+-------------------------------------------------------------------------
  69. //
  70. // Member: CQuerySpec::CQuerySpec, public
  71. //
  72. // Synopsis: Constructor of a CQuerySpec
  73. //
  74. // Arguments: [pOuterUnk] - Outer unknown
  75. // [ppMyUnk] - OUT: filled in with pointer to non-delegated
  76. // IUnknown on return
  77. // [pDocStore] - Known DocStore
  78. //
  79. // History: 22-Apr-97 KrishnaN Created
  80. //
  81. //--------------------------------------------------------------------------
  82. CQuerySpec::CQuerySpec ( IUnknown * pOuterUnk, IUnknown ** ppMyUnk, ICiCDocStore * pDocStore )
  83. : CRootQuerySpec(pOuterUnk, ppMyUnk)
  84. {
  85. //
  86. // Squirrel away DocStore.
  87. //
  88. pDocStore->AddRef();
  89. _xDocStore.Set(pDocStore);
  90. InitScopePropertySets();
  91. } //CQuerySpec
  92. //+-------------------------------------------------------------------------
  93. //
  94. // Member: CQuerySpec::InitScopePropertySets, private
  95. //
  96. // Synopsis: Initializes internal data structs
  97. //
  98. // Arguments: none
  99. //
  100. // History: 06-04-97 mohamedn Created
  101. //
  102. //--------------------------------------------------------------------------
  103. void CQuerySpec::InitScopePropertySets()
  104. {
  105. RtlZeroMemory( _aPropSet, sizeof (_aPropSet) );
  106. _aCoreProps.Init ( INITIAL_PROPERTIES_COUNT );
  107. _aFsClientProps.Init( INITIAL_PROPERTIES_COUNT );
  108. _aPropSet[0].guidPropertySet = DBPROPSET_CIFRMWRKCOREEXT;
  109. _aPropSet[0].rgProperties = _aCoreProps.GetPointer();
  110. _aPropSet[1].guidPropertySet = DBPROPSET_FSCIFRMWRKEXT;
  111. _aPropSet[1].rgProperties = _aFsClientProps.GetPointer();
  112. } //InitScopePropertySets
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Method: CQuerySpec::SetProperties, public
  116. //
  117. // Synopsis: Set rowset scope properties
  118. //
  119. // Arguments: [cPropertySets] - number of property sets
  120. // [rgPropertySets] - array of property sets
  121. //
  122. // Returns: SCODE - result code indicating error return status. One of
  123. // S_OK, DB_S_ERRORSOCCURRED or DB_E_ERRORSOCCURRED. Any
  124. // other errors are thrown.
  125. //
  126. // History: 01-Mar-97 KyleP Created
  127. // 14-May-97 mohamedn hidden core/fs property set details
  128. // 12-Dec-97 danleg ReleaseInternalQuery if setting scope props
  129. //
  130. //----------------------------------------------------------------------------
  131. SCODE STDMETHODCALLTYPE CQuerySpec::SetProperties( ULONG cPropertySets,
  132. DBPROPSET rgPropertySets[] )
  133. {
  134. _DBErrorObj.ClearErrorInfo();
  135. //
  136. // First, get parent properties.
  137. //
  138. SCODE scParent = CRootQuerySpec::SetProperties( cPropertySets, rgPropertySets );
  139. //
  140. // Any non-understood error is a bail. Return the error/successes from the parent.
  141. //
  142. if ( scParent != DB_S_ERRORSOCCURRED && scParent != DB_E_ERRORSOCCURRED )
  143. return scParent;
  144. BOOL fFoundErrors = FALSE;
  145. SCODE sc = S_OK;
  146. //
  147. // Set properties not handled by parent
  148. //
  149. TRANSLATE_EXCEPTIONS;
  150. TRY
  151. {
  152. DBPROPSET *pDbPropset = rgPropertySets;
  153. BOOL fScopeProps = FALSE;
  154. for ( unsigned i = 0; i < cPropertySets; i++, pDbPropset++ )
  155. {
  156. if ( DBPROPSET_FSCIFRMWRKEXT == pDbPropset->guidPropertySet ||
  157. DBPROPSET_CIFRMWRKCOREEXT == pDbPropset->guidPropertySet )
  158. {
  159. SetPropertyset( pDbPropset );
  160. fScopeProps = TRUE;
  161. }
  162. else
  163. {
  164. //
  165. // keep track of any errors occured in base class.
  166. //
  167. DBPROP * pProp = pDbPropset->rgProperties;
  168. ULONG cProps = pDbPropset->cProperties;
  169. for ( unsigned j = 0; j < cProps; j++ )
  170. {
  171. if ( DBPROPSTATUS_OK != pProp[j].dwStatus )
  172. fFoundErrors = TRUE;
  173. }
  174. }
  175. }
  176. //
  177. // If we found any scope properties, release the
  178. // internal query object.
  179. //
  180. if ( fScopeProps )
  181. {
  182. ReleaseInternalQuery();
  183. }
  184. }
  185. CATCH( CException, e )
  186. {
  187. scParent = GetOleError( e );
  188. fFoundErrors = TRUE;
  189. }
  190. END_CATCH;
  191. UNTRANSLATE_EXCEPTIONS;
  192. if ( fFoundErrors )
  193. {
  194. if ( S_OK != scParent )
  195. {
  196. _DBErrorObj.PostHResult( scParent, IID_ICommandProperties );
  197. return scParent;
  198. }
  199. else
  200. {
  201. _DBErrorObj.PostHResult( DB_S_ERRORSOCCURRED, IID_ICommandProperties );
  202. return DB_S_ERRORSOCCURRED;
  203. }
  204. }
  205. else
  206. return S_OK;
  207. } //SetProperties
  208. //+---------------------------------------------------------------------------
  209. //
  210. // Method: CQuerySpec::SetPropertyset, private
  211. //
  212. // Synopsis: Sets non-rowset properties
  213. //
  214. // Arguments: [pPropertyset] - pointer to property set (to be set).
  215. //
  216. // Returns: none - THROWS upon failure.
  217. //
  218. // History: 05-14-97 mohamedn created
  219. //
  220. //----------------------------------------------------------------------------
  221. void CQuerySpec::SetPropertyset( DBPROPSET *pPropertySet )
  222. {
  223. DBPROP * pProp = pPropertySet->rgProperties;
  224. ULONG cProps= pPropertySet->cProperties;
  225. //
  226. // un-error property dwStatus set by parent
  227. //
  228. for ( unsigned j = 0; j < cProps; j++ )
  229. {
  230. switch ( pProp[j].dwStatus )
  231. {
  232. case DBPROPSTATUS_NOTSUPPORTED:
  233. pProp[j].dwStatus = DBPROPSTATUS_OK;
  234. break;
  235. case DBPROPSTATUS_OK:
  236. break;
  237. default:
  238. vqDebugOut(( DEB_ERROR, "Unexpected pProp[j].dwStatus: j=%x, dwStatus=%x \n",j,pProp[j].dwStatus ));
  239. }
  240. }
  241. //
  242. // identify destination propset
  243. //
  244. for ( unsigned k = 0; k < SCOPE_PROPSET_COUNT; k++ )
  245. {
  246. if ( _aPropSet[k].guidPropertySet == pPropertySet->guidPropertySet )
  247. break;
  248. }
  249. if ( k == SCOPE_PROPSET_COUNT )
  250. {
  251. Win4Assert( !"Should never be hit" );
  252. THROW( CException(DB_E_ERRORSOCCURRED));
  253. }
  254. //
  255. // update property set
  256. //
  257. UpdatePropertySet( _aPropSet[k], *pPropertySet );
  258. } //SetPropertyset
  259. //+---------------------------------------------------------------------------
  260. //
  261. // Method: CQuerySpec::UpdatePropertySet, private
  262. //
  263. // Synopsis: Sets non-rowset properties
  264. //
  265. // Arguments: [destPropSet] - destination property set
  266. // [srcPropSet] - source property set
  267. //
  268. // Returns: none - THROWS upon failure.
  269. //
  270. // History: 06-04-97 mohamedn created
  271. //
  272. //----------------------------------------------------------------------------
  273. void CQuerySpec::UpdatePropertySet(DBPROPSET &destPropSet, DBPROPSET &srcPropSet )
  274. {
  275. CDbProp * pDestProp = (CDbProp *)destPropSet.rgProperties;
  276. CDbProp * pSrcProp = (CDbProp *)srcPropSet.rgProperties;
  277. ULONG cErrors = 0;
  278. for ( unsigned i = 0; i < srcPropSet.cProperties; i++ )
  279. {
  280. for ( unsigned j = 0; j < destPropSet.cProperties; j++ )
  281. {
  282. if ( pDestProp[j].dwPropertyID == pSrcProp[i].dwPropertyID )
  283. {
  284. if ( !pDestProp[j].Copy(pSrcProp[i]) )
  285. THROW( CException(E_OUTOFMEMORY) );
  286. break;
  287. }
  288. }
  289. if ( j == destPropSet.cProperties )
  290. {
  291. //
  292. // new PropID
  293. //
  294. if ( destPropSet.guidPropertySet == DBPROPSET_CIFRMWRKCOREEXT &&
  295. j >= _aCoreProps.Count() )
  296. {
  297. _aCoreProps.GrowToSize( srcPropSet.cProperties );
  298. _aPropSet[0].rgProperties = _aCoreProps.GetPointer();
  299. pDestProp = (CDbProp *)destPropSet.rgProperties;
  300. }
  301. else if ( destPropSet.guidPropertySet == DBPROPSET_FSCIFRMWRKEXT &&
  302. j >= _aFsClientProps.Count() )
  303. {
  304. _aFsClientProps.GrowToSize( srcPropSet.cProperties );
  305. _aPropSet[1].rgProperties = _aFsClientProps.GetPointer();
  306. pDestProp = (CDbProp *)destPropSet.rgProperties;
  307. }
  308. Win4Assert( pDestProp[j].dwPropertyID == 0 );
  309. Win4Assert( pDestProp[j].dwStatus == 0 );
  310. if ( !pDestProp[j].Copy(pSrcProp[i]) )
  311. THROW( CException(E_OUTOFMEMORY) );
  312. destPropSet.cProperties++;
  313. }
  314. }
  315. if ( cErrors == srcPropSet.cProperties )
  316. THROW (CException( DB_E_ERRORSOCCURRED ) );
  317. if ( cErrors > 0 )
  318. THROW (CException( DB_S_ERRORSOCCURRED ) );
  319. } //UpdatePropertySet
  320. //+---------------------------------------------------------------------------
  321. //
  322. // Method: CQuerySpec::GetProperties, public
  323. //
  324. // Synopsis: Get rowset properties
  325. //
  326. // Arguments: [cPropertySetIDs] - number of desired property set IDs or 0
  327. // [rgPropertySetIDs] - array of desired property set IDs or NULL
  328. // [pcPropertySets] - number of property sets returned
  329. // [prgPropertySets] - array of returned property sets
  330. //
  331. // Returns: SCODE - result code indicating error return status. One of
  332. // S_OK, DB_S_ERRORSOCCURRED or DB_E_ERRORSOCCURRED. Any
  333. // other errors are thrown.
  334. //
  335. // History: 01-Mar-97 KyleP Created
  336. // 14-May-97 mohamedn hidden core/fs property set details
  337. //
  338. //----------------------------------------------------------------------------
  339. SCODE STDMETHODCALLTYPE CQuerySpec::GetProperties(
  340. ULONG const cPropertySetIDs,
  341. DBPROPIDSET const rgPropertySetIDs[],
  342. ULONG * pcPropertySets,
  343. DBPROPSET ** prgPropertySets)
  344. {
  345. _DBErrorObj.ClearErrorInfo();
  346. BOOL fAddScopeProperties = FALSE;
  347. ULONG cPropSetIDs = cPropertySetIDs;
  348. XArray<CDbPropIDSet> aPropIDSets;
  349. CDbPropIDSet * pPropIDSet = (CDbPropIDSet *)rgPropertySetIDs;
  350. ULONG cAllocPropSets = cPropertySetIDs;
  351. //
  352. // Don't give back the scope properties for "all properties". If the
  353. // magic number 3141592653 is given in, all properties including the
  354. // scope properties are returned.
  355. //
  356. if ( 3141592653 == cPropertySetIDs )
  357. {
  358. fAddScopeProperties = TRUE;
  359. cPropSetIDs = 0;
  360. //
  361. // We want all properties, including scope properties. The base
  362. // implementation doesn't know about scope properties
  363. //
  364. SCODE sc = S_OK;
  365. TRY
  366. {
  367. aPropIDSets.Init( 5 );
  368. }
  369. CATCH( CException, e )
  370. {
  371. sc = e.GetErrorCode();
  372. }
  373. END_CATCH;
  374. if ( FAILED( sc ) )
  375. return sc;
  376. aPropIDSets[0].guidPropertySet = DBPROPSET_ROWSET;
  377. aPropIDSets[0].cPropertyIDs = 0;
  378. aPropIDSets[1].guidPropertySet = DBPROPSET_MSIDXS_ROWSET_EXT;
  379. aPropIDSets[1].cPropertyIDs = 0;
  380. aPropIDSets[2].guidPropertySet = DBPROPSET_QUERY_EXT;
  381. aPropIDSets[2].cPropertyIDs = 0;
  382. aPropIDSets[3].guidPropertySet = DBPROPSET_CIFRMWRKCOREEXT;
  383. aPropIDSets[3].cPropertyIDs = 0;
  384. aPropIDSets[4].guidPropertySet = DBPROPSET_FSCIFRMWRKEXT;
  385. aPropIDSets[4].cPropertyIDs = 0;
  386. cAllocPropSets = aPropIDSets.Count();
  387. pPropIDSet = aPropIDSets.GetPointer();
  388. }
  389. SCODE scParent = CRootQuerySpec::GetProperties( cAllocPropSets,
  390. pPropIDSet,
  391. pcPropertySets,
  392. prgPropertySets );
  393. //
  394. // Any non-understood error is a bail. S_OK here means all properties were
  395. // handled by parent. Just return unless *all* props were requested.
  396. //
  397. if ( scParent != DB_S_ERRORSOCCURRED && scParent != DB_E_ERRORSOCCURRED )
  398. {
  399. if ( scParent != S_OK || 0 != cPropSetIDs )
  400. return scParent;
  401. }
  402. SCODE sc = S_OK;
  403. BOOL fFoundErrors = FALSE;
  404. TRANSLATE_EXCEPTIONS;
  405. TRY
  406. {
  407. //
  408. // Find query properties.
  409. //
  410. if ( 0 == cPropSetIDs && fAddScopeProperties )
  411. {
  412. //
  413. // Case 1: All properties were requested. Append scope onto
  414. // appropriate property set.
  415. //
  416. for ( unsigned i = 0; i < SCOPE_PROPSET_COUNT; i++ )
  417. {
  418. DBPROPIDSET dbPropIdSet;
  419. ZeroMemory((void *) &dbPropIdSet, sizeof DBPROPIDSET );
  420. dbPropIdSet.guidPropertySet = _aPropSet[i].guidPropertySet;
  421. //
  422. // scan dest array of propsets (set by base) for matching guid.
  423. //
  424. for ( unsigned j = 0; j < *pcPropertySets; j++ )
  425. {
  426. if ( dbPropIdSet.guidPropertySet ==
  427. (*prgPropertySets)[j].guidPropertySet )
  428. {
  429. GetPropValues( dbPropIdSet,
  430. (*prgPropertySets)[j],
  431. fFoundErrors );
  432. break;
  433. }
  434. }
  435. //
  436. // PropSet not found
  437. //
  438. if ( j == *pcPropertySets )
  439. {
  440. fFoundErrors = TRUE;
  441. Win4Assert( !"CRowsetProperties doesn't support requested propset." );
  442. Win4Assert( !"base & derived classes are out of sync!");
  443. }
  444. }
  445. }
  446. else
  447. {
  448. //
  449. // Case 2: Specific properties were requested.
  450. //
  451. for ( unsigned i = 0; i < cPropSetIDs; i++ )
  452. {
  453. //
  454. // scan dest array of propsets (set by base) for matching guid.
  455. //
  456. for ( unsigned j = 0; j < *pcPropertySets; j++ )
  457. {
  458. if ( (*prgPropertySets)[j].guidPropertySet ==
  459. rgPropertySetIDs[i].guidPropertySet )
  460. {
  461. GetPropValues( rgPropertySetIDs[i],
  462. (*prgPropertySets)[j],
  463. fFoundErrors );
  464. break;
  465. }
  466. }
  467. //
  468. // PropSet not found
  469. //
  470. if ( j == *pcPropertySets )
  471. {
  472. fFoundErrors = TRUE;
  473. Win4Assert( !"Unexpected PropertySet requested" );
  474. }
  475. }
  476. }
  477. }
  478. CATCH( CException, e )
  479. {
  480. sc = e.GetErrorCode();
  481. }
  482. END_CATCH
  483. UNTRANSLATE_EXCEPTIONS;
  484. if ( FAILED(sc) && sc != DB_E_ERRORSOCCURRED )
  485. {
  486. for ( unsigned i = 0; i < *pcPropertySets; i++ )
  487. {
  488. DBPROP * rgProperties = (*prgPropertySets)[i].rgProperties;
  489. unsigned cProperties = (*prgPropertySets)[i].cProperties;
  490. for ( unsigned j = 0; j < cProperties; j++ )
  491. VariantClear( &(rgProperties[j].vValue) );
  492. CoTaskMemFree( rgProperties );
  493. }
  494. CoTaskMemFree( *prgPropertySets );
  495. *prgPropertySets = 0;
  496. }
  497. if ( fFoundErrors )
  498. {
  499. if ( scParent != S_OK )
  500. {
  501. _DBErrorObj.PostHResult( scParent, IID_ICommandProperties );
  502. return scParent;
  503. }
  504. else
  505. {
  506. _DBErrorObj.PostHResult( DB_S_ERRORSOCCURRED, IID_ICommandProperties );
  507. return DB_S_ERRORSOCCURRED;
  508. }
  509. }
  510. return sc;
  511. } //GetProperties
  512. //+-------------------------------------------------------------------------
  513. //
  514. // Member: CQuerySpec::GetPropValues, private
  515. //
  516. // Synopsis: Gets values of properties in a property set.
  517. //
  518. // Arguments: [rgPropertySetIDs] [in] - array of propIDs to get
  519. // [rgPropertySet] [out] - reference to property set to fill
  520. // [fFoundErrors] [out] - TRUE if any errors are found, but not thrown.
  521. //
  522. // Returns: Throws in case of failure
  523. //
  524. // History: 04-15-97 mohamedn created
  525. //
  526. //--------------------------------------------------------------------------
  527. void CQuerySpec::GetPropValues( DBPROPIDSET const & rgPropertySetIDs,
  528. DBPROPSET & rgPropertySet,
  529. BOOL & fFoundErrors)
  530. {
  531. Win4Assert( rgPropertySet.guidPropertySet == rgPropertySetIDs.guidPropertySet );
  532. //
  533. // Locate private property set source
  534. //
  535. for ( unsigned i = 0; i < SCOPE_PROPSET_COUNT; i++ )
  536. {
  537. if ( rgPropertySet.guidPropertySet == _aPropSet[i].guidPropertySet )
  538. {
  539. break; // found source property set
  540. }
  541. }
  542. //
  543. // If not one of the scope propsets, return
  544. //
  545. if ( SCOPE_PROPSET_COUNT == i )
  546. {
  547. fFoundErrors = TRUE;
  548. return;
  549. }
  550. DBPROPSET & srcPropSet = _aPropSet[i];
  551. DBPROP * psrcDbProp = srcPropSet.rgProperties;
  552. ULONG cPropsFound= 0;
  553. ULONG cDbProps = rgPropertySetIDs.cPropertyIDs ?
  554. rgPropertySetIDs.cPropertyIDs :
  555. srcPropSet.cProperties;
  556. XArrayOLEInPlace<CDbProp> aDbProps( cDbProps );
  557. //
  558. // scan private property set for reqeusted propId values
  559. //
  560. if ( 0 == rgPropertySetIDs.cPropertyIDs )
  561. {
  562. //
  563. // return all properties
  564. //
  565. for ( i = 0; i < srcPropSet.cProperties; i++ )
  566. {
  567. if ( !aDbProps[i].Copy( psrcDbProp[i] ) )
  568. THROW( CException(E_OUTOFMEMORY) );
  569. Win4Assert( aDbProps[i].dwStatus == DBPROPSTATUS_OK );
  570. }
  571. cPropsFound = i;
  572. }
  573. else
  574. {
  575. //
  576. // specific properties within this prop set are requested
  577. //
  578. for ( unsigned iPropsRequested = 0; iPropsRequested < rgPropertySetIDs.cPropertyIDs; iPropsRequested++ )
  579. {
  580. for ( unsigned iPropSrc = 0; iPropSrc < srcPropSet.cProperties; iPropSrc++ )
  581. {
  582. if ( rgPropertySetIDs.rgPropertyIDs[iPropsRequested] == psrcDbProp[iPropSrc].dwPropertyID )
  583. {
  584. if ( !aDbProps[iPropsRequested].Copy( psrcDbProp[iPropSrc] ) )
  585. THROW( CException(E_OUTOFMEMORY) );
  586. Win4Assert( aDbProps[iPropsRequested].dwStatus == DBPROPSTATUS_OK );
  587. break;
  588. }
  589. }
  590. //
  591. // if requested propID not found
  592. //
  593. if ( iPropSrc == srcPropSet.cProperties )
  594. {
  595. //
  596. // Property ID not set
  597. //
  598. aDbProps[iPropsRequested].dwPropertyID = rgPropertySetIDs.rgPropertyIDs[iPropsRequested];
  599. aDbProps[iPropsRequested].dwStatus = DBPROPSTATUS_NOTSET;
  600. fFoundErrors = TRUE;
  601. }
  602. }
  603. cPropsFound = iPropsRequested;
  604. }
  605. //
  606. // free rgProperties allocated by base class, assign new one.
  607. //
  608. CoTaskMemFree( rgPropertySet.rgProperties );
  609. rgPropertySet.rgProperties = aDbProps.Acquire();
  610. rgPropertySet.cProperties = cPropsFound;
  611. } //GetPropValues