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.

753 lines
18 KiB

  1. //
  2. // Author: DebiM
  3. // Date: September 1996
  4. //
  5. // File: csacc.cxx
  6. //
  7. // Class Store Manager implementation for a client desktop.
  8. //
  9. // This source file contains implementations for IClassAccess
  10. // interface for CClassAccess object.
  11. // It also contains the IEnumPackage implementation for the
  12. // aggregate of all class containers seen by the caller.
  13. //
  14. //
  15. //---------------------------------------------------------------------
  16. #include "cstore.hxx"
  17. /**
  18. void
  19. LogCsPathError(
  20. WCHAR * pwszContainerPath,
  21. HRESULT hr );
  22. **/
  23. #define MAXCLASSSTORES 10
  24. IClassAccess *GetNextValidClassStore(PCLASSCONTAINER *pStoreList,
  25. DWORD cStores,
  26. DWORD *pcount);
  27. extern HRESULT GetUserClassStores(
  28. PCLASSCONTAINER **ppStoreList,
  29. DWORD *pcStores);
  30. //
  31. // Link list pointer for Class Containers Seen
  32. //
  33. extern CLASSCONTAINER *gpContainerHead;
  34. //
  35. // Link list pointer for User Profiles Seen
  36. //
  37. extern USERPROFILE *gpUserHead;
  38. //
  39. // Global Class Factory for Class Container
  40. //
  41. extern CAppContainerCF *pCF;
  42. //
  43. // Critical Section used during operations on list of class stores
  44. //
  45. extern CRITICAL_SECTION ClassStoreBindList;
  46. //
  47. // CClassAccess implementation
  48. //
  49. CClassAccess::CClassAccess()
  50. {
  51. m_uRefs = 1;
  52. m_cCalls = 0;
  53. }
  54. CClassAccess::~CClassAccess()
  55. {
  56. }
  57. //----------------------------------------------------------------------
  58. //
  59. //
  60. #ifdef DBG
  61. void PrintClassSpec(
  62. uCLSSPEC * pclsspec // Class Spec (GUID/Ext/MIME)
  63. )
  64. {
  65. STRINGGUID szClsid;
  66. if (pclsspec->tyspec == TYSPEC_CLSID)
  67. {
  68. StringFromGUID (pclsspec->tagged_union.clsid, szClsid);
  69. CSDbgPrint((" ... GetClassSpecInfo by CLSID = %ws\n", szClsid));
  70. }
  71. if (pclsspec->tyspec == TYSPEC_PROGID)
  72. {
  73. CSDbgPrint((" ... GetClassSpecInfo by ProgID = %ws\n",
  74. pclsspec->tagged_union.pProgId));
  75. }
  76. if (pclsspec->tyspec == TYSPEC_MIMETYPE)
  77. {
  78. CSDbgPrint((" ... GetClassSpecInfo by MimeType = %ws\n",
  79. pclsspec->tagged_union.pMimeType));
  80. }
  81. if (pclsspec->tyspec == TYSPEC_FILEEXT)
  82. {
  83. CSDbgPrint((" ... GetClassSpecInfo by FileExt = %ws\n",
  84. pclsspec->tagged_union.pFileExt));
  85. }
  86. if (pclsspec->tyspec == TYSPEC_IID)
  87. {
  88. StringFromGUID (pclsspec->tagged_union.iid, szClsid);
  89. CSDbgPrint((" ... GetClassSpecInfo by IID = %ws\n", szClsid));
  90. }
  91. }
  92. #endif
  93. //----------------------------------------------------------------------
  94. HRESULT STDMETHODCALLTYPE
  95. CClassAccess::GetAppInfo(
  96. uCLSSPEC * pclsspec, // Class Spec (GUID/Ext/MIME)
  97. QUERYCONTEXT * pQryContext, // Query Attributes
  98. INSTALLINFO * pInstallInfo
  99. )
  100. //
  101. // This is the most common method to access the Class Store.
  102. // It queries the class store for implementations for a specific
  103. // Class Id, or File Ext, or ProgID or MIME type.
  104. //
  105. // If a matching implementation is available for the object type,
  106. // client architecture, locale and class context pointer to the
  107. // binary is returned.
  108. {
  109. //
  110. // Assume that this method is called in the security context
  111. // of the user process. Hence there is no need to impersonate.
  112. //
  113. //
  114. // Get the list of Class Stores for this user
  115. //
  116. PCLASSCONTAINER *pStoreList;
  117. ULONG cStores=0;
  118. HRESULT hr;
  119. ULONG i;
  120. ULONG chEaten;
  121. IMoniker *pmk;
  122. LPBC pbc;
  123. IClassAccess *pICA = NULL;
  124. #ifdef DBG
  125. PrintClassSpec(pclsspec);
  126. #endif
  127. hr = GetUserClassStores(
  128. &pStoreList,
  129. &cStores);
  130. if (!SUCCEEDED(hr))
  131. {
  132. return hr;
  133. }
  134. //RpcImpersonateClient( NULL );
  135. for (i=0; i < cStores; i++)
  136. {
  137. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
  138. continue;
  139. //
  140. // Call method on this store
  141. //
  142. pICA->AddRef();
  143. hr = pICA->GetAppInfo(
  144. pclsspec,
  145. pQryContext,
  146. pInstallInfo);
  147. // Release it after use.
  148. pICA->Release();
  149. //
  150. // Special case error return E_INVALIDARG
  151. // Do not continue to look, return this.
  152. //
  153. if (hr == E_INVALIDARG)
  154. {
  155. //RevertToSelf();
  156. return hr;
  157. }
  158. //
  159. // maintain access counters
  160. //
  161. (pStoreList[i])->cAccess++;
  162. if (SUCCEEDED(hr))
  163. {
  164. //RevertToSelf();
  165. return hr;
  166. }
  167. else
  168. {
  169. (pStoreList[i])->cNotFound++;
  170. CSDbgPrint(("CS: .. CClassAccess::GetClassSpecInfo() returned 0x%x\n", hr));
  171. }
  172. }
  173. //RevertToSelf();
  174. return CS_E_PACKAGE_NOTFOUND;
  175. }
  176. //
  177. // GetNextValidClassStore
  178. //
  179. //
  180. IClassAccess *GetNextValidClassStore(CLASSCONTAINER **pStoreList, DWORD cStores, DWORD *pcount)
  181. {
  182. HRESULT hr = S_OK;
  183. IClassAccess *pretICA = NULL;
  184. // BUGBUG:: Probably should move this inside the for loops so that the
  185. // read accesses to gpClassStore do not get serialized. Debi?
  186. EnterCriticalSection (&ClassStoreBindList);
  187. for (pStoreList += (*pcount); (*pcount) < cStores; (*pcount)++, pStoreList++)
  188. {
  189. if ((*pStoreList)->gpClassStore != NULL)
  190. {
  191. hr = S_OK;
  192. break;
  193. }
  194. if (FALSE) // ((*pStoreList)->cBindFailures >= MAX_BIND_ATTEMPTS)
  195. {
  196. // Number of continuous failures have reached MAX_BIND_ATTEMPTS
  197. // for this container.
  198. // Will temporarily disable lookups in this container.
  199. // Report it in EventLog once
  200. //
  201. if ((*pStoreList)->cBindFailures == MAX_BIND_ATTEMPTS)
  202. {
  203. //LogCsPathError((*pStoreList)->pszClassStorePath, hr);
  204. (*pStoreList)->cBindFailures++;
  205. }
  206. continue;
  207. }
  208. else
  209. {
  210. CSDbgPrint(("CS: .. Connecting to Store %d \n ... %ws..\n",
  211. (*pcount),
  212. (*pStoreList)->pszClassStorePath));
  213. //
  214. // Bind to this Class Store
  215. //
  216. if (wcsncmp ((*pStoreList)->pszClassStorePath, L"ADCS:", 5) == 0)
  217. {
  218. //
  219. // If the Storename starts with ADCS
  220. // it is NTDS based implementation. Call directly.
  221. //
  222. hr = pCF->CreateConnectedInstance(
  223. ((*pStoreList)->pszClassStorePath + 5),
  224. (void **)&((*pStoreList)->gpClassStore));
  225. }
  226. else
  227. {
  228. //
  229. // Support for Third Party Pluggable
  230. // Class Stores is not in Beta1.
  231. //
  232. #if 1
  233. hr = E_NOTIMPL;
  234. #else
  235. ULONG chEaten;
  236. IMoniker *pmk;
  237. LPBC pbc;
  238. pbc = NULL;
  239. hr = CreateBindCtx (0, &pbc);
  240. if (!SUCCEEDED(hr))
  241. {
  242. continue;
  243. }
  244. pmk = NULL;
  245. chEaten = 0;
  246. hr = MkParseDisplayName (pbc,
  247. (*pStoreList)->pszClassStorePath,
  248. &chEaten,
  249. &pmk);
  250. if (SUCCEEDED(hr))
  251. {
  252. hr = pmk->BindToObject (pbc,
  253. NULL,
  254. IID_IClassAccess,
  255. (void **)&((*pStoreList)->gpClassStore));
  256. pmk->Release();
  257. }
  258. pbc->Release();
  259. #endif
  260. }
  261. if (SUCCEEDED(hr))
  262. {
  263. (*pStoreList)->cBindFailures = 0;
  264. hr = S_OK;
  265. break;
  266. }
  267. if (!SUCCEEDED(hr))
  268. {
  269. CSDbgPrint(("CS: ... Failed to connect to this store\n"));
  270. if ((*pStoreList)->cBindFailures == 0)
  271. {
  272. // First failue or First failure after successful
  273. // binding.
  274. // Report it in EventLog
  275. //
  276. //LogCsPathError((*pStoreList)->pszClassStorePath, hr);
  277. }
  278. ((*pStoreList)->cBindFailures) ++;
  279. continue;
  280. }
  281. }
  282. }
  283. if ((*pcount) != cStores)
  284. pretICA = (*pStoreList)->gpClassStore;
  285. LeaveCriticalSection (&ClassStoreBindList);
  286. return pretICA;
  287. }
  288. /*
  289. HRESULT STDMETHODCALLTYPE
  290. CClassAccess::GetUpgrades (
  291. ULONG cClasses,
  292. CLSID *pClassList, // CLSIDs Installed
  293. CSPLATFORM Platform,
  294. LCID Locale,
  295. PACKAGEINFOLIST *pPackageInfoList)
  296. {
  297. //
  298. // Assume that this method is called in the security context
  299. // of the user process. Hence there is no need to impersonate.
  300. //
  301. PCLASSCONTAINER *pStoreList;
  302. DWORD cStores=0;
  303. HRESULT hr;
  304. ULONG i;
  305. IClassRefresh *pIClassRefresh = NULL;
  306. PACKAGEINFOLIST PackageInfoList;
  307. IClassAccess *pICA = NULL;
  308. pPackageInfoList->cPackInfo = NULL;
  309. pPackageInfoList->pPackageInfo = NULL;
  310. //
  311. // Get the list of Class Stores for this user
  312. //
  313. hr = GetUserClassStores(
  314. &pStoreList,
  315. &cStores);
  316. if (!SUCCEEDED(hr))
  317. {
  318. return hr;
  319. }
  320. RpcImpersonateClient( NULL );
  321. for (i=0; i < cStores; i++)
  322. {
  323. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
  324. continue;
  325. //
  326. // Call method on this store
  327. //
  328. if (FAILED(pICA->QueryInterface(IID_IClassRefresh,
  329. (void **)&pIClassRefresh)))
  330. continue;
  331. hr = pIClassRefresh->GetUpgrades(
  332. cClasses,
  333. pClassList,
  334. Platform,
  335. Locale,
  336. &PackageInfoList);
  337. pIClassRefresh->Release();
  338. pIClassRefresh = NULL;
  339. if (hr == E_INVALIDARG)
  340. {
  341. RevertToSelf();
  342. return hr;
  343. }
  344. if (SUCCEEDED(hr) && (PackageInfoList.cPackInfo > 0))
  345. {
  346. //
  347. // Add to the existing list of upgrades
  348. //
  349. UINT cCount = pPackageInfoList->cPackInfo;
  350. if (cCount)
  351. {
  352. PACKAGEINFO *pInfo = pPackageInfoList->pPackageInfo;
  353. pPackageInfoList->pPackageInfo =
  354. (PACKAGEINFO *) CoTaskMemAlloc
  355. ((cCount + PackageInfoList.cPackInfo) * sizeof(PACKAGEINFO));
  356. memcpy (pPackageInfoList->pPackageInfo,
  357. pInfo,
  358. cCount * sizeof(PACKAGEINFO));
  359. memcpy ((pPackageInfoList->pPackageInfo)+cCount,
  360. PackageInfoList.pPackageInfo,
  361. PackageInfoList.cPackInfo * sizeof(PACKAGEINFO));
  362. CoTaskMemFree (pInfo);
  363. pPackageInfoList->cPackInfo += PackageInfoList.cPackInfo;
  364. }
  365. else
  366. {
  367. pPackageInfoList->cPackInfo = PackageInfoList.cPackInfo;
  368. pPackageInfoList->pPackageInfo = PackageInfoList.pPackageInfo;
  369. }
  370. }
  371. }
  372. RevertToSelf();
  373. return S_OK;
  374. }
  375. HRESULT STDMETHODCALLTYPE
  376. CClassAccess::CommitUpgrades ()
  377. {
  378. //
  379. // Assume that this method is called in the security context
  380. // of the user process. Hence there is no need to impersonate.
  381. //
  382. PCLASSCONTAINER *pStoreList;
  383. DWORD cStores=0;
  384. HRESULT hr;
  385. ULONG i;
  386. IClassRefresh *pIClassRefresh;
  387. IClassAccess *pICA = NULL;
  388. //
  389. // Get the list of Class Stores for this user
  390. //
  391. hr = GetUserClassStores(
  392. &pStoreList,
  393. &cStores);
  394. if (!SUCCEEDED(hr))
  395. {
  396. return hr;
  397. }
  398. RpcImpersonateClient( NULL );
  399. for (i=0; i < cStores; i++)
  400. {
  401. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
  402. continue;
  403. //
  404. // Call method on this store
  405. //
  406. if (FAILED(pICA->QueryInterface(IID_IClassRefresh,
  407. (void **)&pIClassRefresh)))
  408. continue;
  409. hr = pIClassRefresh->CommitUpgrades();
  410. pIClassRefresh->Release();
  411. }
  412. RevertToSelf();
  413. return hr;
  414. }
  415. */
  416. HRESULT STDMETHODCALLTYPE CClassAccess::EnumPackages(
  417. LPOLESTR pszPackageName,
  418. GUID *pCategory,
  419. ULONGLONG *pLastUsn,
  420. DWORD dwAppFlags, // AppType options
  421. IEnumPackage **ppIEnumPackage)
  422. {
  423. //
  424. // Get the list of Class Stores for this user
  425. //
  426. PCLASSCONTAINER *pStoreList;
  427. DWORD cStores=0;
  428. HRESULT hr;
  429. ULONG i;
  430. IEnumPackage *Enum[MAXCLASSSTORES];
  431. ULONG cEnum = 0;
  432. CMergedEnumPackage *EnumMerged;
  433. IClassAccess *pICA = NULL;
  434. //
  435. // Get the list of Class Stores for this user
  436. //
  437. hr = GetUserClassStores(
  438. &pStoreList,
  439. &cStores);
  440. *ppIEnumPackage = NULL;
  441. if (!SUCCEEDED(hr))
  442. {
  443. return hr;
  444. }
  445. if (cStores == 0)
  446. {
  447. return CS_E_NO_CLASSSTORE;
  448. }
  449. //RpcImpersonateClient( NULL );
  450. for (i=0; i < cStores; i++)
  451. {
  452. if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
  453. continue;
  454. //
  455. // Call method on this store
  456. //
  457. hr = pICA->EnumPackages (pszPackageName,
  458. pCategory,
  459. pLastUsn,
  460. dwAppFlags,
  461. &(Enum[cEnum]));
  462. if (hr == E_INVALIDARG)
  463. {
  464. //RevertToSelf();
  465. return hr;
  466. }
  467. if (SUCCEEDED(hr))
  468. cEnum++;
  469. }
  470. EnumMerged = new CMergedEnumPackage;
  471. hr = EnumMerged->Initialize(Enum, cEnum);
  472. if (FAILED(hr))
  473. {
  474. for (i = 0; i < cEnum; i++)
  475. Enum[i]->Release();
  476. delete EnumMerged;
  477. }
  478. else
  479. {
  480. hr = EnumMerged->QueryInterface(IID_IEnumPackage, (void **)ppIEnumPackage);
  481. if (FAILED(hr))
  482. delete EnumMerged;
  483. }
  484. //RevertToSelf();
  485. return hr;
  486. }
  487. //--------------------------------------------------------------
  488. CMergedEnumPackage::CMergedEnumPackage()
  489. {
  490. m_pcsEnum = NULL;
  491. m_cEnum = 0;
  492. m_csnum = 0;
  493. m_dwRefCount = 0;
  494. }
  495. CMergedEnumPackage::~CMergedEnumPackage()
  496. {
  497. ULONG i;
  498. for (i = 0; i < m_cEnum; i++)
  499. m_pcsEnum[i]->Release();
  500. CoTaskMemFree(m_pcsEnum);
  501. }
  502. HRESULT __stdcall CMergedEnumPackage::QueryInterface(REFIID riid,
  503. void * * ppObject)
  504. {
  505. *ppObject = NULL; //gd
  506. if ((riid==IID_IUnknown) || (riid==IID_IEnumPackage))
  507. {
  508. *ppObject=(IEnumPackage *) this;
  509. }
  510. else
  511. {
  512. return E_NOINTERFACE;
  513. }
  514. AddRef();
  515. return S_OK;
  516. }
  517. ULONG __stdcall CMergedEnumPackage::AddRef()
  518. {
  519. InterlockedIncrement((long*) &m_dwRefCount);
  520. return m_dwRefCount;
  521. }
  522. ULONG __stdcall CMergedEnumPackage::Release()
  523. {
  524. ULONG dwRefCount;
  525. if ((dwRefCount = InterlockedDecrement((long*) &m_dwRefCount))==0)
  526. {
  527. delete this;
  528. return 0;
  529. }
  530. return dwRefCount;
  531. }
  532. HRESULT __stdcall CMergedEnumPackage::Next(
  533. ULONG celt,
  534. PACKAGEDISPINFO *rgelt,
  535. ULONG *pceltFetched)
  536. {
  537. ULONG count=0, total = 0;
  538. HRESULT hr = S_OK;
  539. //RpcImpersonateClient( NULL );
  540. for (; m_csnum < m_cEnum; m_csnum++)
  541. {
  542. count = 0;
  543. hr = m_pcsEnum[m_csnum]->Next(celt, rgelt+total, &count);
  544. if (hr == E_INVALIDARG)
  545. {
  546. //RevertToSelf();
  547. return hr;
  548. }
  549. total += count;
  550. celt -= count;
  551. if (!celt)
  552. break;
  553. }
  554. if (pceltFetched)
  555. *pceltFetched = total;
  556. //RevertToSelf();
  557. if (!celt)
  558. return S_OK;
  559. return S_FALSE;
  560. }
  561. HRESULT __stdcall CMergedEnumPackage::Skip(
  562. ULONG celt)
  563. {
  564. PACKAGEDISPINFO *pPackageInfo = NULL;
  565. HRESULT hr = S_OK;
  566. ULONG cgot = 0, i;
  567. pPackageInfo = (PACKAGEDISPINFO *)CoTaskMemAlloc(sizeof(PACKAGEDISPINFO)*celt);
  568. hr = Next(celt, pPackageInfo, &cgot);
  569. for (i = 0; i < cgot; i++)
  570. ReleasePackageInfo(pPackageInfo+i);
  571. CoTaskMemFree(pPackageInfo);
  572. return hr;
  573. }
  574. HRESULT __stdcall CMergedEnumPackage::Reset()
  575. {
  576. ULONG i;
  577. //RpcImpersonateClient( NULL );
  578. for (i = 0; ((i <= m_csnum) && (i < m_cEnum)); i++)
  579. m_pcsEnum[i]->Reset(); // ignoring all error values
  580. m_csnum = 0;
  581. //RevertToSelf();
  582. return S_OK;
  583. }
  584. HRESULT __stdcall CMergedEnumPackage::Clone(IEnumPackage **ppIEnumPackage)
  585. {
  586. ULONG i;
  587. CMergedEnumPackage *pClone;
  588. IEnumPackage *pcsEnumCloned[MAXCLASSSTORES];
  589. //RpcImpersonateClient( NULL );
  590. pClone = new CMergedEnumPackage;
  591. for ( i = 0; i < m_cEnum; i++)
  592. m_pcsEnum[i]->Clone(&(pcsEnumCloned[i]));
  593. pClone->m_csnum = m_csnum;
  594. pClone->Initialize(pcsEnumCloned, m_cEnum);
  595. *ppIEnumPackage = (IEnumPackage *)pClone;
  596. pClone->AddRef();
  597. //RevertToSelf();
  598. return S_OK;
  599. }
  600. HRESULT CMergedEnumPackage::Initialize(IEnumPackage **pcsEnum, ULONG cEnum)
  601. {
  602. ULONG i;
  603. m_csnum = 0;
  604. m_pcsEnum = (IEnumPackage **)CoTaskMemAlloc(sizeof(IEnumPackage *) * cEnum);
  605. if (!m_pcsEnum)
  606. return E_OUTOFMEMORY;
  607. for (i = 0; i < cEnum; i++)
  608. m_pcsEnum[i] = pcsEnum[i];
  609. m_cEnum = cEnum;
  610. return S_OK;
  611. }