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.

559 lines
16 KiB

  1. // Appmgr.cpp : Implementation of CShellAppManager
  2. #include "priv.h"
  3. #include "appmgr.h"
  4. #include "instenum.h"
  5. #include "util.h"
  6. #include "pubenum.h"
  7. #include "sccls.h"
  8. const TCHAR c_szTSMsiHackKey[] = TEXT("Software\\Policies\\Microsoft\\Windows\\Installer\\Terminal Server");
  9. const TCHAR c_szTSMsiHackValue[] = TEXT("EnableAdminRemote");
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CShellAppManager
  12. // constructor
  13. CShellAppManager::CShellAppManager() : _cRef(1)
  14. {
  15. DllAddRef();
  16. TraceAddRef(CShellAppManager, _cRef);
  17. ASSERT(_hdpaPub == NULL);
  18. InitializeCriticalSection(&_cs);
  19. HDCA hdca = DCA_Create();
  20. if (hdca)
  21. {
  22. // Enumerate all of the Application Publishers
  23. DCA_AddItemsFromKey(hdca, HKEY_LOCAL_MACHINE, REGSTR_PATH_APPPUBLISHER);
  24. if (DCA_GetItemCount(hdca) > 0)
  25. {
  26. _Lock();
  27. // Create our internal list of IAppPublisher *
  28. _hdpaPub = DPA_Create(4);
  29. if(_hdpaPub)
  30. {
  31. int idca;
  32. for (idca = 0; idca < DCA_GetItemCount(hdca); idca++)
  33. {
  34. IAppPublisher * pap;
  35. if (FAILED(DCA_CreateInstance(hdca, idca, IID_IAppPublisher, (LPVOID *) &pap)))
  36. continue;
  37. ASSERT(IS_VALID_CODE_PTR(pap, IAppPublisher));
  38. if (DPA_AppendPtr(_hdpaPub, pap) == DPA_ERR)
  39. {
  40. pap->Release();
  41. break;
  42. }
  43. }
  44. // if we have no pointers in this array, don't bother create one
  45. if (DPA_GetPtrCount(_hdpaPub) == 0)
  46. {
  47. DPA_Destroy(_hdpaPub);
  48. _hdpaPub = NULL;
  49. }
  50. }
  51. _Unlock();
  52. }
  53. DCA_Destroy(hdca);
  54. }
  55. if (IsTerminalServicesRunning())
  56. {
  57. // Hack for MSI work on Terminal Server
  58. HKEY hkeyMsiHack = NULL;
  59. DWORD lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szTSMsiHackKey, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyMsiHack);
  60. if (lRet == ERROR_FILE_NOT_FOUND)
  61. {
  62. lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szTSMsiHackKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE | KEY_SET_VALUE,
  63. NULL, &hkeyMsiHack, NULL);
  64. }
  65. if (lRet == ERROR_SUCCESS)
  66. {
  67. DWORD dwType = 0;
  68. DWORD dwTSMsiHack = 0;
  69. DWORD cbSize = SIZEOF(dwTSMsiHack);
  70. if ((ERROR_SUCCESS != RegQueryValueEx(hkeyMsiHack, c_szTSMsiHackValue, 0, &dwType, (LPBYTE)&dwTSMsiHack, &cbSize))
  71. || (dwType != REG_DWORD) || (dwTSMsiHack != 1))
  72. {
  73. dwTSMsiHack = 1;
  74. if (RegSetValueEx(hkeyMsiHack, c_szTSMsiHackValue, 0, REG_DWORD, (LPBYTE)&dwTSMsiHack, SIZEOF(dwTSMsiHack)) == ERROR_SUCCESS)
  75. _bCreatedTSMsiHack = TRUE;
  76. }
  77. RegCloseKey(hkeyMsiHack);
  78. }
  79. }
  80. }
  81. // destructor
  82. CShellAppManager::~CShellAppManager()
  83. {
  84. if (_bCreatedTSMsiHack)
  85. {
  86. ASSERT(IsTerminalServicesRunning());
  87. HKEY hkeyMsiHack;
  88. DWORD lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szTSMsiHackKey, 0, KEY_SET_VALUE, &hkeyMsiHack);
  89. if (ERROR_SUCCESS == lRet)
  90. {
  91. RegDeleteValue(hkeyMsiHack, c_szTSMsiHackValue);
  92. RegCloseKey(hkeyMsiHack);
  93. }
  94. }
  95. _Lock();
  96. // The order below is important
  97. if (_hdsaCategoryList)
  98. _DestroyInternalCategoryList();
  99. if (_hdpaPub)
  100. _DestroyAppPublisherList();
  101. _Unlock();
  102. DeleteCriticalSection(&_cs);
  103. DllRelease();
  104. }
  105. // Recursively destroys a GUIDLIST
  106. void CShellAppManager::_DestroyGuidList(GUIDLIST * pGuidList)
  107. {
  108. ASSERT(IS_VALID_WRITE_PTR(pGuidList, GUIDLIST));
  109. if (pGuidList->pNextGuid)
  110. _DestroyGuidList(pGuidList->pNextGuid);
  111. LocalFree(pGuidList);
  112. }
  113. void CShellAppManager::_DestroyCategoryItem(CATEGORYITEM * pci)
  114. {
  115. ASSERT(IS_VALID_WRITE_PTR(pci, CATEGORYITEM));
  116. if (pci->pszDescription)
  117. LocalFree(pci->pszDescription);
  118. if (pci->pGuidList)
  119. _DestroyGuidList(pci->pGuidList);
  120. }
  121. // Destroys our Category List Table
  122. void CShellAppManager::_DestroyInternalCategoryList()
  123. {
  124. // The caller must enter the lock first
  125. ASSERT(0 < _cRefLock);
  126. ASSERT(IS_VALID_HANDLE(_hdsaCategoryList, DSA));
  127. int idsa;
  128. for (idsa = 0; idsa < DSA_GetItemCount(_hdsaCategoryList); idsa++)
  129. {
  130. CATEGORYITEM * pci = (CATEGORYITEM *)DSA_GetItemPtr(_hdsaCategoryList, idsa);
  131. if (pci)
  132. _DestroyCategoryItem(pci);
  133. }
  134. DSA_Destroy(_hdsaCategoryList);
  135. }
  136. // Destroys our list of IAppPublisher *
  137. void CShellAppManager::_DestroyAppPublisherList()
  138. {
  139. // The caller must enter the lock first
  140. ASSERT(0 < _cRefLock);
  141. ASSERT(IS_VALID_HANDLE(_hdpaPub, DPA));
  142. int idpa;
  143. for (idpa = 0; idpa < DPA_GetPtrCount(_hdpaPub); idpa++)
  144. {
  145. IAppPublisher * pap = (IAppPublisher *)DPA_GetPtr(_hdpaPub, idpa);
  146. if (EVAL(pap))
  147. pap->Release();
  148. }
  149. DPA_Destroy(_hdpaPub);
  150. _hdpaPub = NULL;
  151. }
  152. // IShellAppManager::QueryInterface
  153. HRESULT CShellAppManager::QueryInterface(REFIID riid, LPVOID * ppvOut)
  154. {
  155. static const QITAB qit[] = {
  156. QITABENT(CShellAppManager, IShellAppManager), // IID_IShellAppManager
  157. { 0 },
  158. };
  159. return QISearch(this, qit, riid, ppvOut);
  160. }
  161. // IShellAppManager::AddRef
  162. ULONG CShellAppManager::AddRef()
  163. {
  164. ULONG cRef = InterlockedIncrement(&_cRef);
  165. TraceAddRef(CShellAppManager, cRef);
  166. return cRef;
  167. }
  168. // IShellAppManager::Release
  169. ULONG CShellAppManager::Release()
  170. {
  171. ASSERT( 0 != _cRef );
  172. ULONG cRef = InterlockedDecrement(&_cRef);
  173. TraceRelease(CShellAppManager, cRef);
  174. if ( 0 == cRef )
  175. {
  176. delete this;
  177. }
  178. return cRef;
  179. }
  180. void CShellAppManager::_Lock(void)
  181. {
  182. EnterCriticalSection(&_cs);
  183. DEBUG_CODE( _cRefLock++; )
  184. }
  185. void CShellAppManager::_Unlock(void)
  186. {
  187. DEBUG_CODE( _cRefLock--; )
  188. LeaveCriticalSection(&_cs);
  189. }
  190. STDMETHODIMP CShellAppManager::GetNumberofInstalledApps(DWORD * pdwResult)
  191. {
  192. return E_NOTIMPL;
  193. }
  194. STDMETHODIMP CShellAppManager::EnumInstalledApps(IEnumInstalledApps ** ppeia)
  195. {
  196. HRESULT hres = E_FAIL;
  197. CEnumInstalledApps * peia = new CEnumInstalledApps();
  198. if (peia)
  199. {
  200. *ppeia = SAFECAST(peia, IEnumInstalledApps *);
  201. hres = S_OK;
  202. }
  203. else
  204. hres = E_OUTOFMEMORY;
  205. return hres;
  206. }
  207. HRESULT CShellAppManager::_AddCategoryToList(APPCATEGORYINFO * pai, IAppPublisher * pap)
  208. {
  209. // The caller must enter the lock first
  210. ASSERT(0 < _cRefLock);
  211. if (pai == NULL || _hdsaCategoryList == NULL)
  212. return E_FAIL;
  213. ASSERT(IS_VALID_CODE_PTR(pap, IAppPublisher));
  214. // Allocate a GUIDLIST item first
  215. GUIDLIST * pgl = (GUIDLIST *)LocalAlloc(LPTR, SIZEOF(GUIDLIST));
  216. if (!pgl)
  217. return E_OUTOFMEMORY;
  218. pgl->CatGuid = pai->AppCategoryId;
  219. pgl->papSupport = pap;
  220. // Search in the CategoryList
  221. int idsa;
  222. for (idsa = 0; idsa < DSA_GetItemCount(_hdsaCategoryList); idsa++)
  223. {
  224. CATEGORYITEM * pci = (CATEGORYITEM *)DSA_GetItemPtr(_hdsaCategoryList, idsa);
  225. if (pci)
  226. {
  227. // If we find an empty spot, fill it
  228. if (pci->pszDescription == NULL)
  229. {
  230. CATEGORYITEM ci = {0};
  231. ci.pszDescription = StrDupW(pai->pszDescription);
  232. ci.pGuidList = pgl;
  233. pgl->pNextGuid = NULL;
  234. if (DSA_InsertItem(_hdsaCategoryList, idsa, &ci) == -1)
  235. {
  236. LocalFree(ci.pszDescription);
  237. break;
  238. }
  239. }
  240. // If we find an entry with the same description text, add our GUID to the GuidList
  241. else if(!lstrcmpi(pai->pszDescription, pci->pszDescription))
  242. {
  243. pgl->pNextGuid = pci->pGuidList;
  244. pci->pGuidList = pgl;
  245. break;
  246. }
  247. }
  248. else
  249. ASSERT(0);
  250. }
  251. // We ran out of items in the list, and didn't run into an identical category string
  252. if (idsa == DSA_GetItemCount(_hdsaCategoryList))
  253. {
  254. CATEGORYITEM ci = {0};
  255. ci.pszDescription = StrDupW(pai->pszDescription);
  256. ci.pGuidList = pgl;
  257. pgl->pNextGuid = NULL;
  258. if (DSA_AppendItem(_hdsaCategoryList, &ci) == -1)
  259. LocalFree(ci.pszDescription);
  260. }
  261. return S_OK;
  262. }
  263. HRESULT CShellAppManager::_BuildInternalCategoryList()
  264. {
  265. HRESULT hres = E_OUTOFMEMORY;
  266. // The caller must enter the lock first
  267. ASSERT(0 < _cRefLock);
  268. ASSERT(IsValidHDPA(_hdpaPub));
  269. // We have just one valid version of _hdsaCategoryList, so we should never call this function
  270. // again once _hdsaCategoryList is created.
  271. ASSERT(_hdsaCategoryList == NULL);
  272. // Is the structure automatically filled with zero?
  273. _hdsaCategoryList = DSA_Create(SIZEOF(CATEGORYITEM), CATEGORYLIST_GROW);
  274. if (_hdsaCategoryList)
  275. {
  276. int idpa;
  277. for (idpa = 0; idpa < DPA_GetPtrCount(_hdpaPub); idpa++)
  278. {
  279. IAppPublisher * pap = (IAppPublisher *)DPA_GetPtr(_hdpaPub, idpa);
  280. ASSERT(pap);
  281. if (pap)
  282. {
  283. UINT i;
  284. APPCATEGORYINFOLIST AppCatList;
  285. if (SUCCEEDED(pap->GetCategories(&AppCatList)))
  286. {
  287. if ((AppCatList.cCategory > 0) && AppCatList.pCategoryInfo)
  288. {
  289. for (i = 0; i < AppCatList.cCategory; i++)
  290. _AddCategoryToList(&AppCatList.pCategoryInfo[i], pap);
  291. _DestroyCategoryList(&AppCatList);
  292. }
  293. }
  294. }
  295. hres = S_OK;
  296. }
  297. }
  298. return hres;
  299. }
  300. // Compile a multi string of categories and return it to the caller
  301. HRESULT CShellAppManager::_CompileCategoryList(PSHELLAPPCATEGORYLIST psacl)
  302. {
  303. HRESULT hres = E_FAIL;
  304. ASSERT(IS_VALID_READ_PTR(psacl, SHELLAPPCATEGORYLIST));
  305. // Don't do anything if we have an empty list
  306. if (_hdsaCategoryList && (DSA_GetItemCount(_hdsaCategoryList) > 0))
  307. {
  308. psacl->pCategory = (PSHELLAPPCATEGORY) SHAlloc(DSA_GetItemCount(_hdsaCategoryList) * SIZEOF(SHELLAPPCATEGORY));
  309. if (psacl->pCategory)
  310. {
  311. int idsa;
  312. for (idsa = 0; idsa < DSA_GetItemCount(_hdsaCategoryList); idsa++)
  313. {
  314. CATEGORYITEM * pci = (CATEGORYITEM *)DSA_GetItemPtr(_hdsaCategoryList, idsa);
  315. if (pci && pci->pszDescription)
  316. {
  317. if (SUCCEEDED(SHStrDup(pci->pszDescription, &psacl->pCategory[idsa].pszCategory)))
  318. {
  319. ASSERT(IS_VALID_STRING_PTR(psacl->pCategory[idsa].pszCategory, -1));
  320. psacl->cCategories++;
  321. }
  322. else
  323. break;
  324. }
  325. }
  326. hres = S_OK;
  327. }
  328. else
  329. hres = E_OUTOFMEMORY;
  330. }
  331. return hres;
  332. }
  333. // IShellAppManager::GetPublishedAppCategories
  334. STDMETHODIMP CShellAppManager::GetPublishedAppCategories(PSHELLAPPCATEGORYLIST psacl)
  335. {
  336. HRESULT hres = E_INVALIDARG;
  337. if (psacl)
  338. {
  339. ASSERT(IS_VALID_READ_PTR(psacl, SHELLAPPCATEGORYLIST));
  340. ZeroMemory(psacl, SIZEOF(SHELLAPPCATEGORYLIST));
  341. // NOTE: keep the check inside the lock! So that only one thread
  342. // is allowed in.
  343. _Lock();
  344. // Do we have any app publishers in our list at all
  345. if (_hdpaPub)
  346. {
  347. if (_hdsaCategoryList == NULL)
  348. _BuildInternalCategoryList();
  349. hres = _CompileCategoryList(psacl);
  350. }
  351. _Unlock();
  352. }
  353. return hres;
  354. }
  355. GUIDLIST * CShellAppManager::_FindGuidListForCategory(LPCWSTR pszDescription)
  356. {
  357. // The caller must enter the lock first
  358. ASSERT(0 < _cRefLock);
  359. if (_hdsaCategoryList)
  360. {
  361. int idsa;
  362. for (idsa = 0; idsa < DSA_GetItemCount(_hdsaCategoryList); idsa++)
  363. {
  364. CATEGORYITEM * pci = (CATEGORYITEM *)DSA_GetItemPtr(_hdsaCategoryList, idsa);
  365. if (pci && pci->pszDescription && !lstrcmpi(pszDescription, pci->pszDescription))
  366. return pci->pGuidList;
  367. }
  368. }
  369. return NULL;
  370. }
  371. extern void _DestroyHdpaEnum(HDPA hdpaEnum);
  372. // IShellAppManager::EnumPublishedApps
  373. STDMETHODIMP CShellAppManager::EnumPublishedApps(LPCWSTR pszCategory, IEnumPublishedApps ** ppepa)
  374. {
  375. HRESULT hres = E_OUTOFMEMORY;
  376. ASSERT(pszCategory == NULL || IS_VALID_STRING_PTRW(pszCategory, -1));
  377. // hdpaEnum is the list of IEnumPublishedApp * we pass to the constructor of CShellEnumPublishedApps
  378. HDPA hdpaEnum = DPA_Create(4);
  379. if (hdpaEnum)
  380. {
  381. // If no category is required, we enumerate all
  382. if (pszCategory == NULL)
  383. {
  384. _Lock();
  385. if (_hdpaPub)
  386. {
  387. int idpa;
  388. for (idpa = 0; idpa < DPA_GetPtrCount(_hdpaPub); idpa++)
  389. {
  390. IAppPublisher * pap = (IAppPublisher *)DPA_GetPtr(_hdpaPub, idpa);
  391. IEnumPublishedApps * pepa;
  392. if (pap && SUCCEEDED(pap->EnumApps(NULL, &pepa)))
  393. {
  394. ASSERT(IS_VALID_CODE_PTR(pepa, IEnumPublishedApps));
  395. if (DPA_AppendPtr(hdpaEnum, pepa) == DPA_ERR)
  396. {
  397. pepa->Release();
  398. break;
  399. }
  400. }
  401. }
  402. }
  403. _Unlock();
  404. }
  405. else
  406. {
  407. _Lock();
  408. // If there is no Category list, let's build one
  409. if (_hdsaCategoryList == NULL)
  410. _BuildInternalCategoryList();
  411. // Otherwise we find the GuidList and enumerate all the guys in the list
  412. GUIDLIST * pgl = _FindGuidListForCategory(pszCategory);
  413. while (pgl && pgl->papSupport)
  414. {
  415. ASSERT(IS_VALID_READ_PTR(pgl, GUIDLIST) && IS_VALID_CODE_PTR(pgl->papSupport, IAppPulisher));
  416. IEnumPublishedApps * pepa;
  417. if (SUCCEEDED(pgl->papSupport->EnumApps(&pgl->CatGuid, &pepa)))
  418. {
  419. ASSERT(IS_VALID_CODE_PTR(pepa, IEnumPublishedApps));
  420. if (DPA_AppendPtr(hdpaEnum, pepa) == DPA_ERR)
  421. {
  422. pepa->Release();
  423. break;
  424. }
  425. }
  426. pgl = pgl->pNextGuid;
  427. }
  428. _Unlock();
  429. }
  430. }
  431. // Even if we have no enumerators we return success and pass back an empty enumerator
  432. CShellEnumPublishedApps * psepa = new CShellEnumPublishedApps(hdpaEnum);
  433. if (psepa)
  434. {
  435. *ppepa = SAFECAST(psepa, IEnumPublishedApps *);
  436. hres = S_OK;
  437. }
  438. else
  439. {
  440. hres = E_OUTOFMEMORY;
  441. if (hdpaEnum)
  442. _DestroyHdpaEnum(hdpaEnum);
  443. }
  444. return hres;
  445. }
  446. EXTERN_C STDAPI InstallAppFromFloppyOrCDROM(HWND hwnd);
  447. STDMETHODIMP CShellAppManager::InstallFromFloppyOrCDROM(HWND hwndParent)
  448. {
  449. return InstallAppFromFloppyOrCDROM(hwndParent);
  450. }
  451. /*----------------------------------------------------------
  452. Purpose: Create-instance function for class factory
  453. */
  454. STDAPI CShellAppManager_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  455. {
  456. // aggregation checking is handled in class factory
  457. HRESULT hres = E_OUTOFMEMORY;
  458. CShellAppManager* pObj = new CShellAppManager();
  459. if (pObj)
  460. {
  461. *ppunk = SAFECAST(pObj, IShellAppManager *);
  462. hres = S_OK;
  463. }
  464. return hres;
  465. }