windows-nt/Source/XPSP1/NT/shell/cpls/appwzdui/instenum.cpp
2020-09-26 16:20:57 +08:00

369 lines
11 KiB
C++

//---------------------------------------------------------------------------
//
// 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];
wnsprintf(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)
{
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;
}