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.

373 lines
12 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // File: instenum.cpp
  6. //
  7. // The current order of enumeration is Legacy --> Darwin --> SMS
  8. //
  9. // History:
  10. // 1-18-97 by dli
  11. //------------------------------------------------------------------------
  12. #include "priv.h"
  13. #include "instenum.h"
  14. #include "instapp.h"
  15. #include "sccls.h"
  16. // constructor
  17. CEnumInstalledApps::CEnumInstalledApps(void) : _cRef(1), _bEnumLegacy(TRUE), _dwCIA(-1) //_bEnumDarwin(FALSE)
  18. {
  19. DllAddRef();
  20. TraceAddRef(CEnumInstalledApps, _cRef);
  21. // Start off enumerating legacy apps, then switch to
  22. // enumerating darwin apps.
  23. ASSERT(_hkeyUninstall == NULL);
  24. }
  25. // destructor
  26. CEnumInstalledApps::~CEnumInstalledApps()
  27. {
  28. if (_hkeyUninstall)
  29. {
  30. RegCloseKey(_hkeyUninstall);
  31. _hkeyUninstall = NULL;
  32. }
  33. DllRelease();
  34. }
  35. // IEnumInstalledApps::QueryInterface
  36. HRESULT CEnumInstalledApps::QueryInterface(REFIID riid, LPVOID * ppvOut)
  37. {
  38. static const QITAB qit[] = {
  39. QITABENT(CEnumInstalledApps, IEnumInstalledApps), // IID_IEnumInstalledApps
  40. { 0 },
  41. };
  42. return QISearch(this, qit, riid, ppvOut);
  43. }
  44. // IUnknown::AddRef
  45. ULONG CEnumInstalledApps::AddRef()
  46. {
  47. _cRef++;
  48. TraceAddRef(CEnumInstalledApps, _cRef);
  49. return _cRef;
  50. }
  51. // IUnknown::Release
  52. ULONG CEnumInstalledApps::Release()
  53. {
  54. _cRef--;
  55. TraceRelease(CEnumInstalledApps, _cRef);
  56. if (_cRef > 0)
  57. return _cRef;
  58. delete this;
  59. return 0;
  60. }
  61. #define REGSTR_VAL_UNINSTALLER_WINDOWSINSTALLER TEXT("WindowsInstaller")
  62. #define REGSTR_VAL_UNINSTALLER_SYSTEMCOMPONENT TEXT("SystemComponent")
  63. HRESULT CEnumInstalledApps::_GetNextLegacyAppFromRegistry(IInstalledApp ** ppia)
  64. {
  65. HRESULT hres = S_FALSE;
  66. LONG lRet;
  67. HKEY hkeySub = NULL;
  68. TCHAR szKeyName[MAX_PATH];
  69. DWORD dwType;
  70. BOOL bTryAgain;
  71. do
  72. {
  73. ULONG cchKeyName = ARRAYSIZE(szKeyName);
  74. FILETIME ftLast;
  75. bTryAgain = FALSE;
  76. // Start enumerationg subkeys under _hkeyUninstall
  77. if (RegEnumKeyEx(_hkeyUninstall, _iIndexEach, szKeyName, &cchKeyName, NULL,
  78. NULL, NULL, &ftLast) == ERROR_SUCCESS)
  79. {
  80. _iIndexEach++;
  81. // Open the key and get the subkey name
  82. lRet = RegOpenKeyEx(_hkeyUninstall, szKeyName, 0, KEY_READ, &hkeySub);
  83. if (lRet == ERROR_SUCCESS)
  84. {
  85. TCHAR szProduct[MAX_PATH];
  86. // Don't enumerate system components
  87. DWORD dwSysComponent = 0;
  88. DWORD cbSysComponent = SIZEOF(dwSysComponent);
  89. lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_SYSTEMCOMPONENT, 0, &dwType,
  90. (PBYTE)&dwSysComponent, &cbSysComponent);
  91. if ((lRet != ERROR_SUCCESS) || (dwSysComponent != 1))
  92. {
  93. // Don't enumerate Darwin apps, who has WindowsInstaller set to 1
  94. ULONG uDarwin;
  95. ULONG cbDarwin = SIZEOF(uDarwin);
  96. lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_WINDOWSINSTALLER, 0, &dwType,
  97. (PBYTE)&uDarwin, &cbDarwin);
  98. if ((lRet != ERROR_SUCCESS) || (uDarwin != 1))
  99. {
  100. // Get the DisplayName value
  101. ULONG cbProductName = SIZEOF(szProduct);
  102. lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_DISPLAYNAME, 0, &dwType,
  103. (PBYTE)szProduct, &cbProductName);
  104. if (lRet == ERROR_SUCCESS)
  105. {
  106. TCHAR szUninstall[MAX_INFO_STRING];
  107. // we proceed even if the below SHQueryValueEx fails, so we need
  108. // to zero initialize
  109. szUninstall[0] = 0;
  110. // Get the uninstaller string
  111. ULONG cbUninstall = SIZEOF(szUninstall);
  112. lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_COMMANDLINE, 0, &dwType, (PBYTE)szUninstall, &cbUninstall);
  113. // NOTE: We don't create CInstalledApp Object if there is no "Uninstall" key
  114. // should we just delete this from registry?
  115. if (lRet == ERROR_SUCCESS)
  116. {
  117. // Create new CInstalledApp Object
  118. CInstalledApp * pia = new CInstalledApp(hkeySub, szKeyName, szProduct, szUninstall, _dwCIA);
  119. if (pia)
  120. {
  121. *ppia = SAFECAST(pia, IInstalledApp *);
  122. hres = S_OK;
  123. }
  124. else
  125. hres = E_OUTOFMEMORY;
  126. break; // We found an app, return
  127. }
  128. }
  129. }
  130. }
  131. // In failure cases, go to the next one and try again
  132. RegCloseKey(hkeySub);
  133. bTryAgain = TRUE;
  134. continue;
  135. // (hkeySub is owned and closed by the CInstalledApp object)
  136. }
  137. }
  138. else
  139. {
  140. RegCloseKey(_hkeyUninstall);
  141. _hkeyUninstall = NULL;
  142. }
  143. } while (bTryAgain);
  144. return hres;
  145. }
  146. typedef struct LEGACYAPPREGKEY {
  147. HKEY hkRoot;
  148. LPCTSTR pszSubkey;
  149. } LEGACYAPPREGKEY;
  150. const LEGACYAPPREGKEY c_rgLegacy[] = {
  151. { HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL }, // CIA_LM_NATIVE
  152. { HKEY_CURRENT_USER, REGSTR_PATH_UNINSTALL }, // CIA_CU_NATIVE
  153. #ifdef _WIN64
  154. { HKEY_LOCAL_MACHINE, REGSTR_PATH_ALTUNINSTALL }, // CIA_LM_ALT
  155. { HKEY_CURRENT_USER, REGSTR_PATH_ALTUNINSTALL }, // CIA_CU_ALT
  156. #endif
  157. };
  158. // Gets the next legacy app from the registry "uninstall" key
  159. HRESULT CEnumInstalledApps::_GetNextLegacyApp(IInstalledApp ** ppia)
  160. {
  161. HRESULT hres = S_FALSE;
  162. restart:
  163. // If we don't have an active enumeration key, then try to make a new one
  164. while (_hkeyUninstall == NULL && ++_dwCIA < ARRAYSIZE(c_rgLegacy))
  165. {
  166. _iIndexEach = 0; // restart the RegEnumKey
  167. RegOpenKeyEx(c_rgLegacy[_dwCIA].hkRoot,
  168. c_rgLegacy[_dwCIA].pszSubkey,
  169. 0, KEY_READ, &_hkeyUninstall);
  170. }
  171. if (_hkeyUninstall)
  172. {
  173. // Enumerate the next one
  174. hres = _GetNextLegacyAppFromRegistry(ppia);
  175. if (hres == S_FALSE)
  176. {
  177. // No more from that key, try another one
  178. // (_GetNextLegacyAppFromRegistry sets _hkeyUninstall = NULL when it returns S_FALSE)
  179. goto restart;
  180. }
  181. }
  182. return hres;
  183. }
  184. HRESULT CEnumInstalledApps::_GetNextDarwinApp(IInstalledApp ** ppia)
  185. {
  186. HRESULT hres = S_FALSE;
  187. TCHAR szProductID[GUIDSTR_MAX];
  188. BOOL bContinue;
  189. do
  190. {
  191. bContinue = FALSE;
  192. UINT uRet = TW32(MsiEnumProducts(_iIndexEach, szProductID));
  193. if (uRet == ERROR_SUCCESS)
  194. {
  195. BOOL bTake = TRUE; // Do we want to show this app, default to yes.
  196. _iIndexEach++; // increment the counter
  197. HKEY hkeySub = NULL;
  198. DWORD dwType;
  199. TCHAR szRegKey[MAX_PATH];
  200. StringCchPrintf(szRegKey, ARRAYSIZE(szRegKey), TEXT("%s\\%s"), REGSTR_PATH_UNINSTALL, szProductID);
  201. // Open this key in the registry
  202. uRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_READ, &hkeySub);
  203. if (uRet == ERROR_SUCCESS)
  204. {
  205. // Don't enumerate system components
  206. DWORD dwSysComponent = 0;
  207. DWORD cbSysComponent = SIZEOF(dwSysComponent);
  208. uRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_SYSTEMCOMPONENT, 0, &dwType,
  209. (PBYTE)&dwSysComponent, &cbSysComponent);
  210. if ((uRet == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwSysComponent == 1))
  211. bTake = FALSE;
  212. RegCloseKey(hkeySub);
  213. }
  214. if (bTake)
  215. {
  216. INSTALLSTATE is = MsiQueryProductState(szProductID);
  217. if ((is != INSTALLSTATE_DEFAULT) && (is != INSTALLSTATE_ADVERTISED))
  218. bTake = FALSE;
  219. // NOTE: INSTALLSTATE_ADVERTISED means assigned apps
  220. if (bTake)
  221. {
  222. CInstalledApp * pia = new CInstalledApp(szProductID);
  223. if (pia)
  224. {
  225. *ppia = SAFECAST(pia, IInstalledApp *);
  226. hres = S_OK;
  227. }
  228. else
  229. hres = E_OUTOFMEMORY;
  230. break;
  231. }
  232. }
  233. bContinue = TRUE;
  234. }
  235. else
  236. {
  237. switch(uRet)
  238. {
  239. //
  240. // MsiEnumProducts can return ERROR_CALL_NOT_IMPLEMENTED
  241. // on embedded SKU. Act as if enumeration is complete.
  242. //
  243. case ERROR_CALL_NOT_IMPLEMENTED:
  244. case ERROR_NO_MORE_ITEMS:
  245. //
  246. // Enumeration is complete.
  247. //
  248. break;
  249. case ERROR_ACCESS_DENIED:
  250. hres = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  251. break;
  252. default:
  253. //
  254. // Some error other than "access denied" occured.
  255. // Continue enumerating products.
  256. //
  257. _iIndexEach++;
  258. bContinue = TRUE;
  259. break;
  260. }
  261. }
  262. } while (bContinue);
  263. return hres;
  264. }
  265. // IEnumInstalledApps::Next
  266. // We allow only one app at a time.
  267. STDMETHODIMP CEnumInstalledApps::Next(IInstalledApp ** ppia)
  268. {
  269. HRESULT hres = S_FALSE;
  270. if (_bEnumLegacy)
  271. {
  272. hres = _GetNextLegacyApp(ppia);
  273. if (hres == S_FALSE)
  274. {
  275. // End of the enumeration for legacy apps
  276. _bEnumLegacy = FALSE;
  277. _iIndexEach = 0;
  278. goto EnumDarwinNow;
  279. }
  280. }
  281. else
  282. {
  283. EnumDarwinNow:
  284. hres = _GetNextDarwinApp(ppia);
  285. }
  286. return hres;
  287. }
  288. // IEnumInstalledApps::Reset
  289. STDMETHODIMP CEnumInstalledApps::Reset(void)
  290. {
  291. // Start off enumerating legacy apps, then switch to
  292. // enumerating darwin apps.
  293. _bEnumLegacy = TRUE;
  294. _dwCIA = -1;
  295. _iIndexEach = 0;
  296. return S_OK;
  297. }
  298. /*----------------------------------------------------------
  299. Purpose: Create-instance function for class factory
  300. */
  301. STDAPI CEnumInstalledApps_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  302. {
  303. // aggregation checking is handled in class factory
  304. HRESULT hres = E_OUTOFMEMORY;
  305. CEnumInstalledApps * pObj = new CEnumInstalledApps();
  306. if (pObj)
  307. {
  308. *ppunk = SAFECAST(pObj, IEnumInstalledApps *);
  309. hres = S_OK;
  310. }
  311. return hres;
  312. }