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.

805 lines
19 KiB

  1. #include "StdAfx.h"
  2. #include "ACShim.h"
  3. #include <secconlib.h>
  4. #include <shlwapi.h>
  5. #include "reg.hxx"
  6. // Undef PathAppend, or TSTR::PathAppend will not work
  7. #undef PathAppend
  8. // ProcessIISShims
  9. //
  10. // Open the app compat database and process all the IIS
  11. // entries
  12. //
  13. BOOL
  14. ProcessIISShims()
  15. {
  16. PDB hCompatDB = NULL;
  17. BOOL bRet = TRUE;
  18. TSTR_PATH strCompatDB;
  19. iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Processeing AppCompat DB.\n") ) );
  20. if ( !strCompatDB.RetrieveWindowsDir() ||
  21. !strCompatDB.PathAppend( APPCOMPAT_DBNAME ) )
  22. {
  23. // Failed to create path
  24. return FALSE;
  25. }
  26. hCompatDB = SdbOpenDatabase( strCompatDB.QueryStr(), DOS_PATH );
  27. if ( hCompatDB == NULL )
  28. {
  29. // Failed to open DB
  30. return FALSE;
  31. }
  32. bRet = ProcessAppCompatDB( hCompatDB );
  33. SdbCloseDatabase( hCompatDB );
  34. return bRet;
  35. }
  36. // ProcessAppCompatDB
  37. //
  38. // Loop through all of the App Compat entries, and process
  39. // the ones that are IIS's
  40. //
  41. BOOL
  42. ProcessAppCompatDB( PDB hCompatDB )
  43. {
  44. TAGID tagDB;
  45. TAGID tagExe;
  46. BOOL bRet = TRUE;
  47. HRESULT hrCoInit;
  48. tagDB = SdbFindFirstTag( hCompatDB, TAGID_ROOT, TAG_DATABASE );
  49. if ( tagDB == NULL )
  50. {
  51. // Failed to open DB
  52. return FALSE;
  53. }
  54. hrCoInit = CoInitialize( NULL );
  55. if ( FAILED( hrCoInit ) )
  56. {
  57. iisDebugOut((LOG_TYPE_WARN, _T("Failed to CoInitialize to process AppCompat tag's, hr=0x%8x.\n"), hrCoInit));
  58. return FALSE;
  59. }
  60. tagExe = SdbFindFirstTag( hCompatDB, tagDB, TAG_EXE );
  61. while( tagExe != NULL )
  62. {
  63. if ( !ProcessExeTag( hCompatDB, tagExe ) )
  64. {
  65. // Failed to process tag
  66. iisDebugOut((LOG_TYPE_WARN, _T("Failed to process AppCompat EXE tag.\n")));
  67. bRet = FALSE;
  68. }
  69. // Get the next one
  70. tagExe = SdbFindNextTag( hCompatDB, tagDB, tagExe );
  71. }
  72. CoUninitialize();
  73. return bRet;
  74. }
  75. // ProcessExeTag
  76. //
  77. // Process All of the Exe Tags that we have
  78. //
  79. BOOL
  80. ProcessExeTag( PDB hCompatDB, TAGID tagExe )
  81. {
  82. TAGID tagExeInfo;
  83. BOOL bRet = TRUE;
  84. tagExeInfo = SdbGetFirstChild( hCompatDB, tagExe );
  85. while ( tagExeInfo != NULL )
  86. {
  87. if ( IsIISShim( hCompatDB, tagExeInfo ) )
  88. {
  89. iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Processing IIS Exe AppCompat Info tag.\n")));
  90. if ( !ProcessShimTag( hCompatDB, tagExeInfo ) )
  91. {
  92. iisDebugOut((LOG_TYPE_WARN, _T("Failed to process AppCompat EXE Info tag.\n")));
  93. bRet = FALSE;
  94. }
  95. }
  96. // Get next tag
  97. tagExeInfo = SdbGetNextChild( hCompatDB, tagExe, tagExeInfo );
  98. }
  99. return bRet;
  100. }
  101. // ProcessShimTag
  102. //
  103. // Process the Shim Tag
  104. //
  105. BOOL
  106. ProcessShimTag( PDB hCompatDB, TAGID tagShim )
  107. {
  108. TSTR_PATH strBasePath;
  109. CExtensionList ExtenstionList;
  110. if ( !GetBasePath( &strBasePath, hCompatDB, tagShim ) )
  111. {
  112. // This entry does not have a base path, so ignore
  113. return TRUE;
  114. }
  115. if ( !PathIsDirectory( strBasePath.QueryStr() ) )
  116. {
  117. // The directory does not exist, so it must not be installed
  118. return TRUE;
  119. }
  120. if ( !BuildExtensionList( hCompatDB, tagShim, strBasePath.QueryStr(), &ExtenstionList ) )
  121. {
  122. // Failed to construct List
  123. return FALSE;
  124. }
  125. if ( ExtenstionList.DoesAnItemExist() )
  126. {
  127. if ( !InstallAppInMB( hCompatDB, tagShim, ExtenstionList ) )
  128. {
  129. return FALSE;
  130. }
  131. }
  132. return TRUE;
  133. }
  134. // GetBasePath
  135. //
  136. // Get the Base Path for the Shim Tag we are talking about.
  137. // This is either going to be a physical path or a registry entry with
  138. // the path
  139. //
  140. BOOL
  141. GetBasePath( TSTR_PATH *pstrBasePath, PDB hCompatDB, TAGID tagShim )
  142. {
  143. TSTR strDBPath;
  144. TSTR strType;
  145. ASSERT( hCompatDB != NULL );
  146. ASSERT( tagShim != NULL );
  147. if ( !GetValueFromName( &strDBPath, hCompatDB, tagShim, APPCOMPAT_TAG_BASEPATH ) ||
  148. !GetValueFromName( &strType, hCompatDB, tagShim, APPCOMPAT_TAG_PATHTYPE ) )
  149. {
  150. // Failed to get Base Path
  151. return FALSE;
  152. }
  153. if ( strType.IsEqual( APPCOMPAT_TYPE_PHYSICALPATH ) )
  154. {
  155. // This is a phsycial path, so expand environment variables and return
  156. if ( !pstrBasePath->Copy( strDBPath ) ||
  157. !pstrBasePath->ExpandEnvironmentVariables() )
  158. {
  159. // Failed
  160. return FALSE;
  161. }
  162. return TRUE;
  163. }
  164. // It is a registry key instead, so lets retrieve it
  165. return GetBasePathFromRegistry( pstrBasePath, strDBPath );
  166. }
  167. // GetBasePathFromRegistry
  168. //
  169. // Retrieve the Base Path for an entry, by reading the registry key
  170. // that contains it
  171. //
  172. // Parameters
  173. // pstrBasePath - [out] The path from the registry
  174. // strFullRegPath - [in] The registry path to check
  175. //
  176. BOOL
  177. GetBasePathFromRegistry( TSTR_PATH *pstrBasePath, TSTR &strFullRegPath )
  178. {
  179. TSTR strRegBase;
  180. TSTR strRegPath;
  181. TSTR strRegName;
  182. LPTSTR szFirstSlash;
  183. LPTSTR szLastSlash;
  184. szFirstSlash = _tcschr( strFullRegPath.QueryStr(), _T('\\') );
  185. szLastSlash = _tcsrchr( strFullRegPath.QueryStr(), _T('\\') );
  186. if ( ( szFirstSlash == NULL ) ||
  187. ( szLastSlash == NULL ) ||
  188. ( szLastSlash == szFirstSlash ) )
  189. {
  190. // If there are not atleast 2 '\'s then it is not a correct registry path
  191. return FALSE;
  192. }
  193. // Temporarily Null terminate strings
  194. *szFirstSlash = _T('\0');
  195. *szLastSlash = _T('\0');
  196. if ( !strRegBase.Copy( strFullRegPath.QueryStr() ) ||
  197. !strRegPath.Copy( szFirstSlash + 1 ) ||
  198. !strRegName.Copy( szLastSlash + 1 ) )
  199. {
  200. // Failed to copy path's
  201. *szFirstSlash = _T('\\');
  202. *szLastSlash = _T('\\');
  203. return FALSE;
  204. }
  205. // Insert back the slashes
  206. *szFirstSlash = _T('\\');
  207. *szLastSlash = _T('\\');
  208. return RetrieveRegistryString( pstrBasePath, strRegBase, strRegPath, strRegName );
  209. }
  210. // RetrieveRegistryString
  211. //
  212. // Retrieve a string from the registry
  213. //
  214. // Parameters:
  215. // pstrValue - [out] The value retrieved from the registry
  216. // strRegBase - [in] The base path, ie HKEY_LOCAL_MACHINE
  217. // strRegPath - [in] The path to the registry key
  218. // strRegName - [in] The name of the registry value
  219. //
  220. BOOL
  221. RetrieveRegistryString( TSTR_PATH *pstrValue,
  222. TSTR &strRegBase,
  223. TSTR &strRegPath,
  224. TSTR &strRegName )
  225. {
  226. CRegistry Reg;
  227. HKEY hRoot;
  228. if ( strRegBase.IsEqual( APPCOMPAT_REG_HKLM, FALSE ) )
  229. {
  230. hRoot = HKEY_LOCAL_MACHINE;
  231. }
  232. else
  233. if ( strRegBase.IsEqual( APPCOMPAT_REG_HKCU, FALSE ) )
  234. {
  235. hRoot = HKEY_CURRENT_USER;
  236. }
  237. else
  238. if ( strRegBase.IsEqual( APPCOMPAT_REG_HKCR, FALSE ) )
  239. {
  240. hRoot = HKEY_CLASSES_ROOT;
  241. }
  242. else
  243. if ( strRegBase.IsEqual( APPCOMPAT_REG_HKU, FALSE ) )
  244. {
  245. hRoot = HKEY_USERS;
  246. }
  247. else
  248. if ( strRegBase.IsEqual( APPCOMPAT_REG_HKCC, FALSE ) )
  249. {
  250. hRoot = HKEY_CURRENT_CONFIG;
  251. }
  252. else
  253. {
  254. return FALSE;
  255. }
  256. if ( !Reg.OpenRegistry( hRoot, strRegPath.QueryStr(), KEY_READ ) )
  257. {
  258. // Failed to open registry
  259. return FALSE;
  260. }
  261. if ( !Reg.ReadValueString( strRegName.QueryStr(), pstrValue ) )
  262. {
  263. // Failed to read string from registry
  264. return FALSE;
  265. }
  266. return TRUE;
  267. }
  268. // BuildExtensionList
  269. //
  270. // Build the extension list from the Compat DB for this tag
  271. //
  272. // Parameters:
  273. // hCompatDB - [in] Pointer to compat DB
  274. // tagShim - [in] Tag to process
  275. // szBasePath - [in] Base path for these extensions
  276. // pExtensions - [out] Extensions class to add them too
  277. //
  278. BOOL
  279. BuildExtensionList( PDB hCompatDB,
  280. TAGID tagShim,
  281. LPTSTR szBasePath,
  282. CExtensionList *pExtensions )
  283. {
  284. TSTR_PATH strExtFullPath;
  285. TSTR strExtensions;
  286. TSTR strIndicatorFile;
  287. LPTSTR szExtensions;
  288. LPTSTR szNext;
  289. iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Building extension list.\n") ) );
  290. if ( GetValueFromName( &strIndicatorFile,
  291. hCompatDB,
  292. tagShim,
  293. APPCOMPAT_TAG_SETUPINDICATOR ) )
  294. {
  295. // SetupIndicator File is Set
  296. if ( !strExtFullPath.Copy( szBasePath ) ||
  297. !strExtFullPath.PathAppend( strIndicatorFile ) ||
  298. !pExtensions->SetIndicatorFile( strExtFullPath.QueryStr() ) )
  299. {
  300. // Failed to set indicator file
  301. return FALSE;
  302. }
  303. iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Indicator File found, it is '%s'.\n"), strExtFullPath.QueryStr() ) );
  304. }
  305. if ( !GetValueFromName( &strExtensions,
  306. hCompatDB,
  307. tagShim,
  308. APPCOMPAT_TAG_WEBSVCEXT ) )
  309. {
  310. // No WebSvcExtension to retrieve
  311. return TRUE;
  312. }
  313. iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("Building extension list with '%s'.\n"), strExtensions.QueryStr() ) );
  314. // Get pointer to begining of list
  315. szExtensions = strExtensions.QueryStr();
  316. while ( szExtensions && *szExtensions )
  317. {
  318. szNext = _tcschr( szExtensions, _T(',') );
  319. if ( szNext )
  320. {
  321. *szNext = _T('\0');
  322. szNext++;
  323. }
  324. if ( !strExtFullPath.Copy( szBasePath ) ||
  325. !strExtFullPath.PathAppend( szExtensions ) )
  326. {
  327. // Failed to construct path
  328. return FALSE;
  329. }
  330. if ( !pExtensions->AddItem( strExtFullPath.QueryStr(),
  331. PathFileExists( strExtFullPath.QueryStr() ) ) )
  332. {
  333. // Failed to add item to list
  334. return FALSE;
  335. }
  336. szExtensions = szNext;
  337. }
  338. return TRUE;
  339. }
  340. // InstallAppInMB
  341. //
  342. // Installs the Application Extensions and dependencies into the metabase
  343. // tagShim points to the Shim entry in the AppCompat DB where all App settings reside
  344. //
  345. BOOL
  346. InstallAppInMB( PDB hCompatDB, TAGID tagShim, CExtensionList &ExtensionList )
  347. {
  348. TSTR strGroupId;
  349. TSTR strGroupDesc;
  350. TSTR strAppName;
  351. TSTR strExtGroups;
  352. TSTR strPath;
  353. BOOL bExists;
  354. CSecConLib Helper;
  355. DWORD i;
  356. BOOL bRet;
  357. HRESULT hr;
  358. // Ignore if we can not get this value, since it is not necessary
  359. GetValueFromName( &strExtGroups, hCompatDB, tagShim, APPCOMPAT_DB_ENABLE_EXT_GROUPS );
  360. if ( !GetValueFromName( &strGroupId, hCompatDB, tagShim, APPCOMPAT_DB_GROUPID ) ||
  361. !GetValueFromName( &strGroupDesc, hCompatDB, tagShim, APPCOMPAT_DB_GROUPDESC ) ||
  362. !GetValueFromName( &strAppName, hCompatDB, tagShim, APPCOMPAT_DB_APPNAME ) )
  363. {
  364. iisDebugOut( ( LOG_TYPE_PROGRAM_FLOW,
  365. _T("Could not retrieve all values for App from DB, so will not add to RestrictionList. ('%s','%s','%s','%s')\n"),
  366. strGroupId.QueryStr() ? strGroupId.QueryStr() : _T("<Unknown>"),
  367. strGroupDesc.QueryStr() ? strGroupDesc.QueryStr() : _T("<Unknown>"),
  368. strAppName.QueryStr() ? strAppName.QueryStr() : _T("<Unknown>"),
  369. strExtGroups.QueryStr() ? strExtGroups.QueryStr() : _T("<Unknown>")) );
  370. // Failed to retrieve value
  371. return TRUE;
  372. }
  373. iisDebugOut((LOG_TYPE_PROGRAM_FLOW,
  374. _T("Adding '%s' group to WebSvcRestriction List from AppCompat DB.\n"),
  375. strGroupId.QueryStr() ) );
  376. // Add Extensions
  377. for ( i = 0; i < ExtensionList.QueryNumberofItems(); i++ )
  378. {
  379. if ( !ExtensionList.QueryItem( i, &strPath, &bExists ) )
  380. {
  381. // Failed to retrieve
  382. return FALSE;
  383. }
  384. hr = Helper.AddExtensionFile( strPath.QueryStr(), // Path
  385. g_pTheApp->IsUpgrade() ? true : false, // Image should be enabled
  386. strGroupId.QueryStr(), // GroupID
  387. FALSE, // Not UI deletable
  388. strGroupDesc.QueryStr(),// Group description
  389. METABASEPATH_WWW_ROOT ); // MB location
  390. if ( FAILED( hr ) &&
  391. ( hr != HRESULT_FROM_WIN32(ERROR_DUP_NAME) ) )
  392. {
  393. bRet = FALSE;
  394. iisDebugOut((LOG_TYPE_ERROR, _T("Failed to add extension %s to group %s, hr=0x%8x\n"), strPath.QueryStr(), strGroupId.QueryStr(), hr ));
  395. }
  396. }
  397. // Add Dependencies
  398. if ( *(strGroupId.QueryStr()) != _T('\0') )
  399. {
  400. hr = Helper.AddDependency( strAppName.QueryStr(),
  401. strGroupId.QueryStr(),
  402. METABASEPATH_WWW_ROOT );
  403. if ( FAILED( hr ) &&
  404. ( hr != HRESULT_FROM_WIN32(ERROR_DUP_NAME) ) )
  405. {
  406. bRet = FALSE;
  407. iisDebugOut((LOG_TYPE_ERROR,
  408. _T("Failed to add dependence ( App: %s on GroupID %s ), hr=0x%8x\n"),
  409. strAppName.QueryStr(),
  410. strGroupId.QueryStr(),
  411. hr ));
  412. }
  413. }
  414. // Add all the other "external" groups it depends on
  415. if ( ( *strExtGroups.QueryStr() ) != _T('\0') )
  416. {
  417. LPTSTR szCurrentGroup = strExtGroups.QueryStr();
  418. LPTSTR szNextGroup;
  419. while ( szCurrentGroup && *szCurrentGroup )
  420. {
  421. szNextGroup = _tcschr( szCurrentGroup, _T(',') );
  422. if ( szNextGroup )
  423. {
  424. *szNextGroup = _T('\0');
  425. szNextGroup++;
  426. }
  427. hr = Helper.AddDependency( strAppName.QueryStr(),
  428. szCurrentGroup,
  429. METABASEPATH_WWW_ROOT );
  430. if ( FAILED( hr ) &&
  431. ( hr != HRESULT_FROM_WIN32(ERROR_DUP_NAME) ) )
  432. {
  433. bRet = FALSE;
  434. iisDebugOut((LOG_TYPE_ERROR,
  435. _T("Failed to add dependence ( App: %s on Group %s ), hr = %8x\n"),
  436. strAppName.QueryStr(),
  437. szCurrentGroup,
  438. hr ));
  439. }
  440. szCurrentGroup = szNextGroup;
  441. }
  442. }
  443. return bRet;
  444. }
  445. // IsIISShim
  446. //
  447. // Is the Tag an IIS Shim Tag
  448. //
  449. BOOL
  450. IsIISShim( PDB hCompatDB, TAGID tagCurrentTag )
  451. {
  452. TAG tagType;
  453. TAGID tagShimName;
  454. TSTR strTagName;
  455. tagType = SdbGetTagFromTagID( hCompatDB, tagCurrentTag );
  456. if ( tagType != TAG_SHIM_REF )
  457. {
  458. // We handle only <SHIM> tags
  459. return FALSE;
  460. }
  461. if ( !strTagName.Resize( MAX_PATH ) )
  462. {
  463. // Failed to widen buffer
  464. return FALSE;
  465. }
  466. tagShimName = SdbFindFirstTag( hCompatDB, tagCurrentTag, TAG_NAME );
  467. if ( tagShimName == NULL )
  468. {
  469. // There is not tag name, so this is not an IIS one.
  470. return FALSE;
  471. }
  472. if ( !SdbReadStringTag( hCompatDB, tagShimName, strTagName.QueryStr(), strTagName.QuerySize() ) )
  473. {
  474. // Failed to read string tag
  475. return FALSE;
  476. }
  477. return strTagName.IsEqual( APPCOMPAT_TAG_SHIM_IIS, FALSE );
  478. }
  479. // GetValueFromName
  480. //
  481. // Frab a value out of the Database with the Name we have given
  482. //
  483. // Parameters:
  484. // pstrValue - [out] The value that was in the database
  485. // hCompatDB - [in] Handle to DB
  486. // tagData - [in] The tag to retrieve it from
  487. // szTagName - [in] The name of the tag to retrieve
  488. //
  489. BOOL
  490. GetValueFromName( TSTR *pstrValue, PDB hCompatDB, TAGID tagData, LPCTSTR szTagName )
  491. {
  492. TAGID tagChild;
  493. TAGID tagValue;
  494. LPTSTR szValue;
  495. tagChild = SdbFindFirstNamedTag( hCompatDB, tagData, TAG_DATA, TAG_NAME, szTagName );
  496. if ( tagChild == NULL )
  497. {
  498. // Failed to find tag
  499. return FALSE;
  500. }
  501. tagValue = SdbFindFirstTag( hCompatDB, tagChild, TAG_DATA_STRING );
  502. if ( tagValue == NULL )
  503. {
  504. // Failed to retrieve tag
  505. return FALSE;
  506. }
  507. szValue = SdbGetStringTagPtr( hCompatDB, tagValue );
  508. if ( szValue == NULL )
  509. {
  510. // Not value found, so lets just set to an empty string
  511. szValue = _T("");
  512. }
  513. return pstrValue->Copy( szValue );
  514. }
  515. // Constructor
  516. //
  517. //
  518. CExtensionList::CExtensionList()
  519. {
  520. m_dwNumberofItems = 0;
  521. m_pRoot = NULL;
  522. m_bUseIndicatorFile = FALSE;
  523. m_bIndicatorFileExists = FALSE;
  524. }
  525. // Destructor
  526. //
  527. //
  528. CExtensionList::~CExtensionList()
  529. {
  530. sExtensionItem *pCurrent;
  531. sExtensionItem *pTemp;
  532. pCurrent = m_pRoot;
  533. while ( pCurrent )
  534. {
  535. pTemp = pCurrent;
  536. pCurrent = pCurrent->pNext;
  537. delete pTemp;
  538. }
  539. m_pRoot = NULL;
  540. m_dwNumberofItems = 0;
  541. }
  542. // AddItem
  543. //
  544. // Add an Item to the list
  545. //
  546. // Parameters:
  547. // szPath - Data for item
  548. // bExists - Data for Item
  549. BOOL
  550. CExtensionList::AddItem( LPTSTR szPath, BOOL bExists )
  551. {
  552. sExtensionItem *pNewItem;
  553. sExtensionItem *pLastItem = NULL;
  554. iisDebugOut((LOG_TYPE_PROGRAM_FLOW,
  555. _T("Adding item '%s',0x%8x.\n"),
  556. szPath, bExists ) );
  557. if ( QueryNumberofItems() != 0 )
  558. {
  559. pLastItem = RetrieveItem( QueryNumberofItems() - 1 );
  560. if ( pLastItem == NULL )
  561. {
  562. // For some read we can not get the nth item, which should exist
  563. ASSERT( FALSE );
  564. return FALSE;
  565. }
  566. }
  567. pNewItem = new sExtensionItem;
  568. if ( pNewItem == NULL )
  569. {
  570. return FALSE;
  571. }
  572. if ( !pNewItem->strName.Copy( szPath ) )
  573. {
  574. delete pNewItem;
  575. return FALSE;
  576. }
  577. pNewItem->bExists = bExists;
  578. pNewItem->pNext = NULL;
  579. m_dwNumberofItems++;
  580. if ( pLastItem )
  581. {
  582. pLastItem->pNext = pNewItem;
  583. }
  584. else
  585. {
  586. m_pRoot = pNewItem;
  587. }
  588. return TRUE;
  589. }
  590. // QueryItem
  591. //
  592. // Query the Data on a particular item
  593. //
  594. BOOL
  595. CExtensionList::QueryItem( DWORD dwIndex, TSTR *pstrPath, LPBOOL pbExists)
  596. {
  597. sExtensionItem *pCurrent;
  598. pCurrent = RetrieveItem( dwIndex );
  599. if ( pCurrent == NULL )
  600. {
  601. // That item does not exist
  602. return FALSE;
  603. }
  604. if ( !pstrPath->Copy( pCurrent->strName ) )
  605. {
  606. // Could not copy name
  607. return FALSE;
  608. }
  609. *pbExists = pCurrent->bExists;
  610. return TRUE;
  611. }
  612. // QueryNumberofItems
  613. //
  614. // Query the number of items in the list
  615. //
  616. DWORD
  617. CExtensionList::QueryNumberofItems()
  618. {
  619. return m_dwNumberofItems;
  620. }
  621. // RetrieveItem
  622. //
  623. // Retrieve a specific item by its index
  624. //
  625. sExtensionItem *
  626. CExtensionList::RetrieveItem( DWORD dwIndex )
  627. {
  628. sExtensionItem *pCurrent = m_pRoot;
  629. while ( ( pCurrent ) &&
  630. ( dwIndex != 0 ) )
  631. {
  632. pCurrent = pCurrent->pNext;
  633. dwIndex--;
  634. }
  635. return pCurrent;
  636. }
  637. // DoesAnItemExist
  638. //
  639. // Go through all of the items in our list,
  640. // and determine if any of them have the bExists flag
  641. // set
  642. //
  643. BOOL
  644. CExtensionList::DoesAnItemExist()
  645. {
  646. sExtensionItem *pCurrent = m_pRoot;
  647. if ( m_bUseIndicatorFile )
  648. {
  649. // If an indicator file is used, then just use this
  650. return m_bIndicatorFileExists;
  651. }
  652. while ( pCurrent )
  653. {
  654. if ( pCurrent->bExists )
  655. {
  656. // Found one that exists
  657. return TRUE;
  658. }
  659. pCurrent = pCurrent->pNext;
  660. }
  661. // None existed
  662. return FALSE;
  663. }
  664. // SetIndicatorFile
  665. //
  666. // If an indicator file is set, then use the fact that this is installed
  667. // instead of checking all the other files
  668. //
  669. BOOL
  670. CExtensionList::SetIndicatorFile( LPTSTR szIndicatorFile )
  671. {
  672. m_bUseIndicatorFile = TRUE;
  673. m_bIndicatorFileExists = PathFileExists( szIndicatorFile );
  674. return TRUE;
  675. }