|
|
//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation
//
// File: instenum.cpp
//
// The current order of enumeration is Legacy --> Darwin --> SMS
//
// History:
// 1-18-97 by dli
//------------------------------------------------------------------------
#include "priv.h"
#include "instenum.h"
#include "instapp.h"
#include "sccls.h"
// constructor
CEnumInstalledApps::CEnumInstalledApps(void) : _cRef(1), _bEnumLegacy(TRUE), _dwCIA(-1) //_bEnumDarwin(FALSE)
{ DllAddRef();
TraceAddRef(CEnumInstalledApps, _cRef); // Start off enumerating legacy apps, then switch to
// enumerating darwin apps.
ASSERT(_hkeyUninstall == NULL);
}
// destructor
CEnumInstalledApps::~CEnumInstalledApps() { if (_hkeyUninstall) { RegCloseKey(_hkeyUninstall); _hkeyUninstall = NULL; }
DllRelease(); }
// IEnumInstalledApps::QueryInterface
HRESULT CEnumInstalledApps::QueryInterface(REFIID riid, LPVOID * ppvOut) { static const QITAB qit[] = { QITABENT(CEnumInstalledApps, IEnumInstalledApps), // IID_IEnumInstalledApps
{ 0 }, };
return QISearch(this, qit, riid, ppvOut); }
// IUnknown::AddRef
ULONG CEnumInstalledApps::AddRef() { _cRef++; TraceAddRef(CEnumInstalledApps, _cRef); return _cRef; }
// IUnknown::Release
ULONG CEnumInstalledApps::Release() { _cRef--; TraceRelease(CEnumInstalledApps, _cRef); if (_cRef > 0) return _cRef;
delete this; return 0; }
#define REGSTR_VAL_UNINSTALLER_WINDOWSINSTALLER TEXT("WindowsInstaller")
#define REGSTR_VAL_UNINSTALLER_SYSTEMCOMPONENT TEXT("SystemComponent")
HRESULT CEnumInstalledApps::_GetNextLegacyAppFromRegistry(IInstalledApp ** ppia) { HRESULT hres = S_FALSE; LONG lRet; HKEY hkeySub = NULL; TCHAR szKeyName[MAX_PATH]; DWORD dwType; BOOL bTryAgain;
do { ULONG cchKeyName = ARRAYSIZE(szKeyName); FILETIME ftLast;
bTryAgain = FALSE; // Start enumerationg subkeys under _hkeyUninstall
if (RegEnumKeyEx(_hkeyUninstall, _iIndexEach, szKeyName, &cchKeyName, NULL, NULL, NULL, &ftLast) == ERROR_SUCCESS) { _iIndexEach++;
// Open the key and get the subkey name
lRet = RegOpenKeyEx(_hkeyUninstall, szKeyName, 0, KEY_READ, &hkeySub); if (lRet == ERROR_SUCCESS) { TCHAR szProduct[MAX_PATH];
// Don't enumerate system components
DWORD dwSysComponent = 0; DWORD cbSysComponent = SIZEOF(dwSysComponent); lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_SYSTEMCOMPONENT, 0, &dwType, (PBYTE)&dwSysComponent, &cbSysComponent); if ((lRet != ERROR_SUCCESS) || (dwSysComponent != 1)) { // Don't enumerate Darwin apps, who has WindowsInstaller set to 1
ULONG uDarwin; ULONG cbDarwin = SIZEOF(uDarwin); lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_WINDOWSINSTALLER, 0, &dwType, (PBYTE)&uDarwin, &cbDarwin); if ((lRet != ERROR_SUCCESS) || (uDarwin != 1)) {
// Get the DisplayName value
ULONG cbProductName = SIZEOF(szProduct); lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_DISPLAYNAME, 0, &dwType, (PBYTE)szProduct, &cbProductName); if (lRet == ERROR_SUCCESS) { TCHAR szUninstall[MAX_INFO_STRING];
// we proceed even if the below SHQueryValueEx fails, so we need
// to zero initialize
szUninstall[0] = 0;
// Get the uninstaller string
ULONG cbUninstall = SIZEOF(szUninstall); lRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_COMMANDLINE, 0, &dwType, (PBYTE)szUninstall, &cbUninstall);
// NOTE: We don't create CInstalledApp Object if there is no "Uninstall" key
// should we just delete this from registry?
if (lRet == ERROR_SUCCESS) { // Create new CInstalledApp Object
CInstalledApp * pia = new CInstalledApp(hkeySub, szKeyName, szProduct, szUninstall, _dwCIA); if (pia) { *ppia = SAFECAST(pia, IInstalledApp *); hres = S_OK; } else hres = E_OUTOFMEMORY; break; // We found an app, return
} } } } // In failure cases, go to the next one and try again
RegCloseKey(hkeySub); bTryAgain = TRUE; continue; // (hkeySub is owned and closed by the CInstalledApp object)
} } else { RegCloseKey(_hkeyUninstall); _hkeyUninstall = NULL; } } while (bTryAgain);
return hres; }
typedef struct LEGACYAPPREGKEY { HKEY hkRoot; LPCTSTR pszSubkey; } LEGACYAPPREGKEY;
const LEGACYAPPREGKEY c_rgLegacy[] = { { HKEY_LOCAL_MACHINE, REGSTR_PATH_UNINSTALL }, // CIA_LM_NATIVE
{ HKEY_CURRENT_USER, REGSTR_PATH_UNINSTALL }, // CIA_CU_NATIVE
#ifdef _WIN64
{ HKEY_LOCAL_MACHINE, REGSTR_PATH_ALTUNINSTALL }, // CIA_LM_ALT
{ HKEY_CURRENT_USER, REGSTR_PATH_ALTUNINSTALL }, // CIA_CU_ALT
#endif
};
// Gets the next legacy app from the registry "uninstall" key
HRESULT CEnumInstalledApps::_GetNextLegacyApp(IInstalledApp ** ppia) { HRESULT hres = S_FALSE;
restart: // If we don't have an active enumeration key, then try to make a new one
while (_hkeyUninstall == NULL && ++_dwCIA < ARRAYSIZE(c_rgLegacy)) { _iIndexEach = 0; // restart the RegEnumKey
RegOpenKeyEx(c_rgLegacy[_dwCIA].hkRoot, c_rgLegacy[_dwCIA].pszSubkey, 0, KEY_READ, &_hkeyUninstall); }
if (_hkeyUninstall) { // Enumerate the next one
hres = _GetNextLegacyAppFromRegistry(ppia);
if (hres == S_FALSE) { // No more from that key, try another one
// (_GetNextLegacyAppFromRegistry sets _hkeyUninstall = NULL when it returns S_FALSE)
goto restart; } }
return hres; }
HRESULT CEnumInstalledApps::_GetNextDarwinApp(IInstalledApp ** ppia) { HRESULT hres = S_FALSE; TCHAR szProductID[GUIDSTR_MAX];
BOOL bContinue; do { bContinue = FALSE; UINT uRet = TW32(MsiEnumProducts(_iIndexEach, szProductID)); if (uRet == ERROR_SUCCESS) { BOOL bTake = TRUE; // Do we want to show this app, default to yes.
_iIndexEach++; // increment the counter
HKEY hkeySub = NULL; DWORD dwType; TCHAR szRegKey[MAX_PATH]; StringCchPrintf(szRegKey, ARRAYSIZE(szRegKey), TEXT("%s\\%s"), REGSTR_PATH_UNINSTALL, szProductID);
// Open this key in the registry
uRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_READ, &hkeySub); if (uRet == ERROR_SUCCESS) { // Don't enumerate system components
DWORD dwSysComponent = 0; DWORD cbSysComponent = SIZEOF(dwSysComponent); uRet = SHQueryValueEx(hkeySub, REGSTR_VAL_UNINSTALLER_SYSTEMCOMPONENT, 0, &dwType, (PBYTE)&dwSysComponent, &cbSysComponent); if ((uRet == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwSysComponent == 1)) bTake = FALSE;
RegCloseKey(hkeySub); }
if (bTake) { INSTALLSTATE is = MsiQueryProductState(szProductID);
if ((is != INSTALLSTATE_DEFAULT) && (is != INSTALLSTATE_ADVERTISED)) bTake = FALSE;
// NOTE: INSTALLSTATE_ADVERTISED means assigned apps
if (bTake) { CInstalledApp * pia = new CInstalledApp(szProductID); if (pia) { *ppia = SAFECAST(pia, IInstalledApp *); hres = S_OK; } else hres = E_OUTOFMEMORY; break; } } bContinue = TRUE; } else { switch(uRet) { //
// MsiEnumProducts can return ERROR_CALL_NOT_IMPLEMENTED
// on embedded SKU. Act as if enumeration is complete.
//
case ERROR_CALL_NOT_IMPLEMENTED: case ERROR_NO_MORE_ITEMS: //
// Enumeration is complete.
//
break;
case ERROR_ACCESS_DENIED: hres = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); break; default: //
// Some error other than "access denied" occured.
// Continue enumerating products.
//
_iIndexEach++; bContinue = TRUE; break; } } } while (bContinue); return hres; }
// IEnumInstalledApps::Next
// We allow only one app at a time.
STDMETHODIMP CEnumInstalledApps::Next(IInstalledApp ** ppia) { HRESULT hres = S_FALSE; if (_bEnumLegacy) { hres = _GetNextLegacyApp(ppia); if (hres == S_FALSE) { // End of the enumeration for legacy apps
_bEnumLegacy = FALSE; _iIndexEach = 0; goto EnumDarwinNow; } } else { EnumDarwinNow: hres = _GetNextDarwinApp(ppia); } return hres; }
// IEnumInstalledApps::Reset
STDMETHODIMP CEnumInstalledApps::Reset(void) { // Start off enumerating legacy apps, then switch to
// enumerating darwin apps.
_bEnumLegacy = TRUE; _dwCIA = -1; _iIndexEach = 0;
return S_OK; }
/*----------------------------------------------------------
Purpose: Create-instance function for class factory
*/ STDAPI CEnumInstalledApps_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi) { // aggregation checking is handled in class factory
HRESULT hres = E_OUTOFMEMORY; CEnumInstalledApps * pObj = new CEnumInstalledApps(); if (pObj) { *ppunk = SAFECAST(pObj, IEnumInstalledApps *); hres = S_OK; }
return hres; }
|