mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 20:18:22 +00:00
[RAPPS] listview refactor (#2970)
This makes it easier to maintain the listview, and better separates the application list and listview. * [RAPPS] fix memory leak when cleanup. some renaming are also done * [RAPPS] move the code adding apps info inside class CAppsListView * [RAPPS] add table view, create listview and AppInfoDisplay inside it * [RAPPS] rename INSTALLED_INFO as CInstalledApplicationInfo now it corresponds with CAvailableApplicationInfo * [RAPPS] add CInstalledApps * [RAPPS] optimize the speed when refreshing listview * [RAPPS] correctly handle Enum for InstalledApps * [RAPPS] make check all working properly (this also fixes some bugs) the old version has some bugs when check all items after switching tags in tree-view * [RAPPS] add handling for wow64 * [RAPPS] use an inline function to replace INSERT_TEXT macro * [RAPPS] fix the bug that StatusBar won't update when switching tags * [RAPPS] now TableView always reset bIsAscending in SetDisplayMode * [RAPPS] rename TableView to ApplicationView * [RAPPS] now bIsAscending would be reset when switching column in listview
This commit is contained in:
parent
4482d0f455
commit
10c0ff7416
8 changed files with 1147 additions and 653 deletions
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
// CAvailableApplicationInfo
|
// CAvailableApplicationInfo
|
||||||
CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam, AvailableStrings& AvlbStrings)
|
CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam, AvailableStrings& AvlbStrings)
|
||||||
: m_IsSelected(FALSE), m_LicenseType(LICENSE_NONE), m_SizeBytes(0), m_sFileName(sFileNameParam),
|
: m_LicenseType(LICENSE_NONE), m_SizeBytes(0), m_sFileName(sFileNameParam),
|
||||||
m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE)
|
m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE)
|
||||||
{
|
{
|
||||||
RetrieveGeneralInfo(AvlbStrings);
|
RetrieveGeneralInfo(AvlbStrings);
|
||||||
|
@ -400,71 +400,127 @@ BOOL CAvailableApps::ForceUpdateAppsDB()
|
||||||
|
|
||||||
BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param)
|
BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param)
|
||||||
{
|
{
|
||||||
|
if (EnumType == ENUM_CAT_SELECTED)
|
||||||
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
||||||
WIN32_FIND_DATAW FindFileData;
|
|
||||||
|
|
||||||
hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), &FindFileData);
|
|
||||||
|
|
||||||
if (hFind == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
{
|
||||||
//no db yet
|
CAvailableApplicationInfo *EnumAvlbInfo = NULL;
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
// enum all object in m_SelectedList and invoke callback
|
||||||
{
|
for(POSITION CurrentPosition = m_SelectedList.GetHeadPosition();
|
||||||
// loop for all the cached entries
|
CurrentPosition && (EnumAvlbInfo = m_SelectedList.GetAt(CurrentPosition));
|
||||||
POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
|
m_SelectedList.GetNext(CurrentPosition))
|
||||||
CAvailableApplicationInfo* Info = NULL;
|
|
||||||
|
|
||||||
while (CurrentListPosition != NULL)
|
|
||||||
{
|
{
|
||||||
POSITION LastListPosition = CurrentListPosition;
|
EnumAvlbInfo->RefreshAppInfo(m_Strings);
|
||||||
Info = m_InfoList.GetNext(CurrentListPosition);
|
|
||||||
|
|
||||||
// do we already have this entry in cache?
|
|
||||||
if (Info->m_sFileName == FindFileData.cFileName)
|
|
||||||
{
|
|
||||||
// is it current enough, or the file has been modified since our last time here?
|
|
||||||
if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->m_ftCacheStamp) == 1)
|
|
||||||
{
|
|
||||||
// recreate our cache, this is the slow path
|
|
||||||
m_InfoList.RemoveAt(LastListPosition);
|
|
||||||
|
|
||||||
delete Info;
|
|
||||||
Info = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// speedy path, compare directly, we already have the data
|
|
||||||
goto skip_if_cached;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a new entry
|
|
||||||
Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
|
|
||||||
|
|
||||||
// set a timestamp for the next time
|
|
||||||
Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
|
|
||||||
m_InfoList.AddTail(Info);
|
|
||||||
|
|
||||||
skip_if_cached:
|
|
||||||
if (EnumType == Info->m_Category
|
|
||||||
|| EnumType == ENUM_ALL_AVAILABLE
|
|
||||||
|| (EnumType == ENUM_CAT_SELECTED && Info->m_IsSelected))
|
|
||||||
{
|
|
||||||
Info->RefreshAppInfo(m_Strings);
|
|
||||||
|
|
||||||
if (lpEnumProc)
|
if (lpEnumProc)
|
||||||
lpEnumProc(Info, m_Strings.szAppsPath.GetString(), param);
|
lpEnumProc(EnumAvlbInfo, TRUE, param);
|
||||||
}
|
}
|
||||||
} while (FindNextFileW(hFind, &FindFileData) != 0);
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||||||
|
WIN32_FIND_DATAW FindFileData;
|
||||||
|
|
||||||
FindClose(hFind);
|
hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), &FindFileData);
|
||||||
return TRUE;
|
|
||||||
|
if (hFind == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
//no db yet
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// loop for all the cached entries
|
||||||
|
POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
|
||||||
|
CAvailableApplicationInfo *Info = NULL;
|
||||||
|
|
||||||
|
while (CurrentListPosition != NULL)
|
||||||
|
{
|
||||||
|
POSITION LastListPosition = CurrentListPosition;
|
||||||
|
Info = m_InfoList.GetNext(CurrentListPosition);
|
||||||
|
|
||||||
|
// do we already have this entry in cache?
|
||||||
|
if (Info->m_sFileName == FindFileData.cFileName)
|
||||||
|
{
|
||||||
|
// is it current enough, or the file has been modified since our last time here?
|
||||||
|
if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->m_ftCacheStamp) == 1)
|
||||||
|
{
|
||||||
|
// recreate our cache, this is the slow path
|
||||||
|
m_InfoList.RemoveAt(LastListPosition);
|
||||||
|
|
||||||
|
// also remove this in selected list (if exist)
|
||||||
|
RemoveSelected(Info);
|
||||||
|
|
||||||
|
delete Info;
|
||||||
|
Info = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// speedy path, compare directly, we already have the data
|
||||||
|
goto skip_if_cached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new entry
|
||||||
|
Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
|
||||||
|
|
||||||
|
// set a timestamp for the next time
|
||||||
|
Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
|
||||||
|
m_InfoList.AddTail(Info);
|
||||||
|
|
||||||
|
skip_if_cached:
|
||||||
|
if (EnumType == Info->m_Category
|
||||||
|
|| EnumType == ENUM_ALL_AVAILABLE)
|
||||||
|
{
|
||||||
|
Info->RefreshAppInfo(m_Strings);
|
||||||
|
|
||||||
|
if (lpEnumProc)
|
||||||
|
{
|
||||||
|
if (m_SelectedList.Find(Info))
|
||||||
|
{
|
||||||
|
lpEnumProc(Info, TRUE, param);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lpEnumProc(Info, FALSE, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (FindNextFileW(hFind, &FindFileData));
|
||||||
|
|
||||||
|
FindClose(hFind);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CAvailableApps::AddSelected(CAvailableApplicationInfo *AvlbInfo)
|
||||||
|
{
|
||||||
|
return m_SelectedList.AddTail(AvlbInfo) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CAvailableApps::RemoveSelected(CAvailableApplicationInfo *AvlbInfo)
|
||||||
|
{
|
||||||
|
POSITION Position = m_SelectedList.Find(AvlbInfo);
|
||||||
|
if (Position)
|
||||||
|
{
|
||||||
|
m_SelectedList.RemoveAt(Position);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID CAvailableApps::RemoveAllSelected()
|
||||||
|
{
|
||||||
|
m_SelectedList.RemoveAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CAvailableApps::GetSelectedCount()
|
||||||
|
{
|
||||||
|
return m_SelectedList.GetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
CAvailableApplicationInfo* CAvailableApps::FindInfo(const ATL::CStringW& szAppName) const
|
CAvailableApplicationInfo* CAvailableApps::FindInfo(const ATL::CStringW& szAppName) const
|
||||||
|
@ -502,23 +558,6 @@ ATL::CSimpleArray<CAvailableApplicationInfo> CAvailableApps::FindInfoList(const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ATL::CSimpleArray<CAvailableApplicationInfo> CAvailableApps::GetSelected() const
|
|
||||||
{
|
|
||||||
ATL::CSimpleArray<CAvailableApplicationInfo> result;
|
|
||||||
POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
|
|
||||||
CAvailableApplicationInfo* Info;
|
|
||||||
|
|
||||||
while (CurrentListPosition != NULL)
|
|
||||||
{
|
|
||||||
Info = m_InfoList.GetNext(CurrentListPosition);
|
|
||||||
if (Info->m_IsSelected)
|
|
||||||
{
|
|
||||||
result.Add(*Info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ATL::CStringW& CAvailableApps::GetFolderPath() const
|
const ATL::CStringW& CAvailableApps::GetFolderPath() const
|
||||||
{
|
{
|
||||||
return m_Strings.szPath;
|
return m_Strings.szPath;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,10 +37,11 @@ struct AvailableStrings
|
||||||
AvailableStrings();
|
AvailableStrings();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CAvailableApplicationInfo
|
class CAvailableApplicationInfo
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
INT m_Category;
|
INT m_Category;
|
||||||
BOOL m_IsSelected;
|
//BOOL m_IsSelected;
|
||||||
LicenseType m_LicenseType;
|
LicenseType m_LicenseType;
|
||||||
ATL::CStringW m_szName;
|
ATL::CStringW m_szName;
|
||||||
ATL::CStringW m_szRegName;
|
ATL::CStringW m_szRegName;
|
||||||
|
@ -98,11 +99,12 @@ private:
|
||||||
inline BOOL FindInLanguages(LCID what) const;
|
inline BOOL FindInLanguages(LCID what) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, LPCWSTR szFolderPath, PVOID param);
|
typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param);
|
||||||
|
|
||||||
class CAvailableApps
|
class CAvailableApps
|
||||||
{
|
{
|
||||||
ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
|
ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
|
||||||
|
ATL::CAtlList< CAvailableApplicationInfo*> m_SelectedList;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static AvailableStrings m_Strings;
|
static AvailableStrings m_Strings;
|
||||||
|
@ -116,9 +118,15 @@ public:
|
||||||
VOID FreeCachedEntries();
|
VOID FreeCachedEntries();
|
||||||
BOOL Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param);
|
BOOL Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param);
|
||||||
|
|
||||||
|
BOOL AddSelected(CAvailableApplicationInfo *AvlbInfo);
|
||||||
|
BOOL RemoveSelected(CAvailableApplicationInfo *AvlbInfo);
|
||||||
|
|
||||||
|
VOID RemoveAllSelected();
|
||||||
|
int GetSelectedCount();
|
||||||
|
|
||||||
CAvailableApplicationInfo* FindInfo(const ATL::CStringW& szAppName) const;
|
CAvailableApplicationInfo* FindInfo(const ATL::CStringW& szAppName) const;
|
||||||
ATL::CSimpleArray<CAvailableApplicationInfo> FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames) const;
|
ATL::CSimpleArray<CAvailableApplicationInfo> FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames) const;
|
||||||
ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const;
|
//ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const;
|
||||||
|
|
||||||
const ATL::CStringW& GetFolderPath() const;
|
const ATL::CStringW& GetFolderPath() const;
|
||||||
const ATL::CStringW& GetAppPath() const;
|
const ATL::CStringW& GetAppPath() const;
|
||||||
|
|
|
@ -3,19 +3,51 @@
|
||||||
#include <windef.h>
|
#include <windef.h>
|
||||||
#include <atlstr.h>
|
#include <atlstr.h>
|
||||||
|
|
||||||
struct INSTALLED_INFO
|
class CInstalledApplicationInfo
|
||||||
{
|
{
|
||||||
HKEY hRootKey;
|
public:
|
||||||
|
BOOL IsUserKey;
|
||||||
|
REGSAM WowKey;
|
||||||
HKEY hSubKey;
|
HKEY hSubKey;
|
||||||
|
BOOL bIsUpdate = FALSE;
|
||||||
|
|
||||||
ATL::CStringW szKeyName;
|
ATL::CStringW szKeyName;
|
||||||
|
|
||||||
|
CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey);
|
||||||
BOOL GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String);
|
BOOL GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String);
|
||||||
|
BOOL UninstallApplication(BOOL bModify);
|
||||||
|
LSTATUS RemoveFromRegistry();
|
||||||
|
|
||||||
|
ATL::CStringW szDisplayName;
|
||||||
|
ATL::CStringW szDisplayVersion;
|
||||||
|
ATL::CStringW szPublisher;
|
||||||
|
ATL::CStringW szRegOwner;
|
||||||
|
ATL::CStringW szProductID;
|
||||||
|
ATL::CStringW szHelpLink;
|
||||||
|
ATL::CStringW szHelpTelephone;
|
||||||
|
ATL::CStringW szReadme;
|
||||||
|
ATL::CStringW szContact;
|
||||||
|
ATL::CStringW szURLUpdateInfo;
|
||||||
|
ATL::CStringW szURLInfoAbout;
|
||||||
|
ATL::CStringW szComments;
|
||||||
|
ATL::CStringW szInstallDate;
|
||||||
|
ATL::CStringW szInstallLocation;
|
||||||
|
ATL::CStringW szInstallSource;
|
||||||
|
ATL::CStringW szUninstallString;
|
||||||
|
ATL::CStringW szModifyPath;
|
||||||
|
|
||||||
|
~CInstalledApplicationInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef INSTALLED_INFO *PINSTALLED_INFO;
|
typedef BOOL(CALLBACK *APPENUMPROC)(CInstalledApplicationInfo * Info, PVOID param);
|
||||||
typedef BOOL(CALLBACK *APPENUMPROC)(INT ItemIndex, ATL::CStringW &Name, PINSTALLED_INFO Info, PVOID param);
|
|
||||||
|
|
||||||
BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC lpEnumProc, PVOID param);
|
class CInstalledApps
|
||||||
BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString);
|
{
|
||||||
|
ATL::CAtlList<CInstalledApplicationInfo *> m_InfoList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BOOL Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param);
|
||||||
|
|
||||||
|
VOID FreeCachedEntries();
|
||||||
|
};
|
||||||
|
|
||||||
BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify);
|
|
||||||
|
|
|
@ -46,3 +46,5 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore);
|
BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore);
|
||||||
|
|
||||||
|
BOOL IsSystem64Bit();
|
||||||
|
|
|
@ -495,7 +495,10 @@ public:
|
||||||
|
|
||||||
virtual ~CUiWindow()
|
virtual ~CUiWindow()
|
||||||
{
|
{
|
||||||
T::DestroyWindow();
|
if (T::IsWindow())
|
||||||
|
{
|
||||||
|
T::DestroyWindow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID GetWindowTextW(ATL::CStringW& szText)
|
VOID GetWindowTextW(ATL::CStringW& szText)
|
||||||
|
|
|
@ -12,149 +12,253 @@
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
BOOL INSTALLED_INFO::GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String)
|
CInstalledApplicationInfo::CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey)
|
||||||
|
: IsUserKey(bIsUserKey), WowKey(RegWowKey), hSubKey(hKey)
|
||||||
{
|
{
|
||||||
BOOL result = ::GetApplicationString(hSubKey, lpKeyName, String.GetBuffer(MAX_PATH));
|
// if Initialize failed, hSubKey will be closed automatically and set to zero
|
||||||
String.ReleaseBuffer();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString)
|
DWORD dwSize = MAX_PATH, dwType, dwValue;
|
||||||
{
|
BOOL bIsSystemComponent;
|
||||||
DWORD dwSize = MAX_PATH * sizeof(WCHAR);
|
ATL::CStringW szParentKeyName;
|
||||||
|
|
||||||
if (RegQueryValueExW(hKey,
|
dwType = REG_DWORD;
|
||||||
lpKeyName,
|
dwSize = sizeof(DWORD);
|
||||||
NULL,
|
|
||||||
NULL,
|
if (RegQueryValueExW(hSubKey,
|
||||||
(LPBYTE) szString,
|
L"SystemComponent",
|
||||||
&dwSize) == ERROR_SUCCESS)
|
NULL,
|
||||||
|
&dwType,
|
||||||
|
(LPBYTE)&dwValue,
|
||||||
|
&dwSize) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return TRUE;
|
bIsSystemComponent = (dwValue == 0x1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bIsSystemComponent = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringCchCopyW(szString, MAX_PATH, L"---");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify)
|
|
||||||
{
|
|
||||||
LPCWSTR szModify = L"ModifyPath";
|
|
||||||
LPCWSTR szUninstall = L"UninstallString";
|
|
||||||
DWORD dwType, dwSize;
|
|
||||||
WCHAR szPath[MAX_PATH];
|
|
||||||
|
|
||||||
dwType = REG_SZ;
|
dwType = REG_SZ;
|
||||||
dwSize = MAX_PATH * sizeof(WCHAR);
|
dwSize = MAX_PATH * sizeof(WCHAR);
|
||||||
if (RegQueryValueExW(ItemInfo->hSubKey,
|
bIsUpdate = (RegQueryValueExW(hSubKey,
|
||||||
bModify ? szModify : szUninstall,
|
L"ParentKeyName",
|
||||||
NULL,
|
NULL,
|
||||||
&dwType,
|
&dwType,
|
||||||
(LPBYTE) szPath,
|
(LPBYTE)szParentKeyName.GetBuffer(MAX_PATH),
|
||||||
&dwSize) != ERROR_SUCCESS)
|
&dwSize) == ERROR_SUCCESS);
|
||||||
|
szParentKeyName.ReleaseBuffer();
|
||||||
|
|
||||||
|
if (bIsSystemComponent)
|
||||||
{
|
{
|
||||||
return FALSE;
|
CloseHandle(hSubKey);
|
||||||
|
hSubKey = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return StartProcess(szPath, TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC lpEnumProc, PVOID param)
|
CInstalledApplicationInfo::~CInstalledApplicationInfo()
|
||||||
{
|
{
|
||||||
DWORD dwSize = MAX_PATH, dwType, dwValue;
|
if (hSubKey)
|
||||||
BOOL bIsSystemComponent, bIsUpdate;
|
{
|
||||||
ATL::CStringW szParentKeyName;
|
CloseHandle(hSubKey);
|
||||||
ATL::CStringW szDisplayName;
|
hSubKey = NULL;
|
||||||
INSTALLED_INFO Info;
|
}
|
||||||
HKEY hKey;
|
}
|
||||||
LONG ItemIndex = 0;
|
|
||||||
|
|
||||||
Info.hRootKey = IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
|
BOOL CInstalledApplicationInfo::GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String)
|
||||||
|
{
|
||||||
|
DWORD dwSize = 0;
|
||||||
|
String.Empty();
|
||||||
|
DWORD dwType;
|
||||||
|
|
||||||
if (RegOpenKeyW(Info.hRootKey,
|
// retrieve the size of value first.
|
||||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
|
if (RegQueryValueExW(hSubKey,
|
||||||
&hKey) != ERROR_SUCCESS)
|
lpKeyName,
|
||||||
|
NULL,
|
||||||
|
&dwType,
|
||||||
|
NULL,
|
||||||
|
&dwSize) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (RegEnumKeyExW(hKey, ItemIndex, Info.szKeyName.GetBuffer(MAX_PATH), &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
// TODO: I assume the type as REG_SZ. but I think REG_EXPAND_SZ should be handled correctly too.
|
||||||
|
if (dwType != REG_SZ)
|
||||||
{
|
{
|
||||||
Info.szKeyName.ReleaseBuffer();
|
return FALSE;
|
||||||
if (RegOpenKeyW(hKey, Info.szKeyName.GetString(), &Info.hSubKey) == ERROR_SUCCESS)
|
}
|
||||||
|
|
||||||
|
// allocate buffer.
|
||||||
|
// attention: dwSize is size in bytes, and RegQueryValueExW does not guarantee the terminating null character.
|
||||||
|
String.GetBuffer(dwSize + sizeof(WCHAR));
|
||||||
|
|
||||||
|
// query the value
|
||||||
|
if (RegQueryValueExW(hSubKey,
|
||||||
|
lpKeyName,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
(LPBYTE)String.GetBuffer(),
|
||||||
|
&dwSize) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
String.ReleaseBuffer();
|
||||||
|
String.Empty();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
String.GetBuffer()[dwSize / sizeof(WCHAR)] = L'\0'; // ensure zero terminated
|
||||||
|
String.ReleaseBuffer();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CInstalledApplicationInfo::UninstallApplication(BOOL bModify)
|
||||||
|
{
|
||||||
|
return StartProcess(bModify ? szModifyPath : szUninstallString, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
LSTATUS CInstalledApplicationInfo::RemoveFromRegistry()
|
||||||
|
{
|
||||||
|
ATL::CStringW szFullName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + szKeyName;
|
||||||
|
|
||||||
|
// TODO: if there are subkeys inside, simply RegDeleteKeyExW will fail
|
||||||
|
// we don't have RegDeleteTree for ReactOS now. (It's a WinVista API)
|
||||||
|
// write a function to delete all subkeys recursively to solve this
|
||||||
|
// or consider letting ReactOS having this API
|
||||||
|
|
||||||
|
return RegDeleteKeyExW(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szFullName, WowKey, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CInstalledApps::Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param)
|
||||||
|
{
|
||||||
|
FreeCachedEntries();
|
||||||
|
|
||||||
|
HKEY RootKeyEnum[3] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE };
|
||||||
|
REGSAM RegSamEnum[3] = { KEY_WOW64_32KEY, KEY_WOW64_32KEY, KEY_WOW64_64KEY };
|
||||||
|
|
||||||
|
int LoopTime;
|
||||||
|
|
||||||
|
// test if the OS is 64 bit.
|
||||||
|
if (IsSystem64Bit())
|
||||||
|
{
|
||||||
|
// loop for all 3 combination.
|
||||||
|
// note that HKEY_CURRENT_USER\Software don't have a redirect
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys#redirected-shared-and-reflected-keys-under-wow64
|
||||||
|
LoopTime = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// loop for 2 combination for KEY_WOW64_32KEY only
|
||||||
|
LoopTime = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop for all combination
|
||||||
|
for (int i = 0; i < LoopTime; i++)
|
||||||
|
{
|
||||||
|
DWORD dwSize = MAX_PATH;
|
||||||
|
HKEY hKey, hSubKey;
|
||||||
|
LONG ItemIndex = 0;
|
||||||
|
ATL::CStringW szKeyName;
|
||||||
|
|
||||||
|
if (RegOpenKeyExW(RootKeyEnum[i],
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
|
||||||
|
NULL,
|
||||||
|
KEY_READ | RegSamEnum[i],
|
||||||
|
&hKey) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
dwType = REG_DWORD;
|
return FALSE;
|
||||||
dwSize = sizeof(DWORD);
|
}
|
||||||
|
|
||||||
if (RegQueryValueExW(Info.hSubKey,
|
while (1)
|
||||||
L"SystemComponent",
|
{
|
||||||
NULL,
|
dwSize = MAX_PATH;
|
||||||
&dwType,
|
if (RegEnumKeyExW(hKey, ItemIndex, szKeyName.GetBuffer(MAX_PATH), &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
||||||
(LPBYTE) &dwValue,
|
|
||||||
&dwSize) == ERROR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
bIsSystemComponent = (dwValue == 0x1);
|
break;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bIsSystemComponent = FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dwType = REG_SZ;
|
ItemIndex++;
|
||||||
dwSize = MAX_PATH * sizeof(WCHAR);
|
|
||||||
bIsUpdate = (RegQueryValueExW(Info.hSubKey,
|
|
||||||
L"ParentKeyName",
|
|
||||||
NULL,
|
|
||||||
&dwType,
|
|
||||||
(LPBYTE) szParentKeyName.GetBuffer(MAX_PATH),
|
|
||||||
&dwSize) == ERROR_SUCCESS);
|
|
||||||
szParentKeyName.ReleaseBuffer();
|
|
||||||
|
|
||||||
dwType = REG_SZ;
|
szKeyName.ReleaseBuffer();
|
||||||
dwSize = MAX_PATH * sizeof(WCHAR);
|
if (RegOpenKeyW(hKey, szKeyName.GetString(), &hSubKey) == ERROR_SUCCESS)
|
||||||
if (RegQueryValueExW(Info.hSubKey,
|
|
||||||
L"DisplayName",
|
|
||||||
NULL,
|
|
||||||
&dwType,
|
|
||||||
(LPBYTE) szDisplayName.GetBuffer(MAX_PATH),
|
|
||||||
&dwSize) == ERROR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
szDisplayName.ReleaseBuffer();
|
BOOL bSuccess = FALSE;
|
||||||
if (EnumType < ENUM_ALL_INSTALLED || EnumType > ENUM_UPDATES)
|
CInstalledApplicationInfo *Info = new CInstalledApplicationInfo(RootKeyEnum[i] == HKEY_CURRENT_USER, RegSamEnum[i], hSubKey);
|
||||||
EnumType = ENUM_ALL_INSTALLED;
|
Info->szKeyName = szKeyName;
|
||||||
|
|
||||||
if (!bIsSystemComponent)
|
// check for failure. if failed to init, Info->hSubKey will be set to NULL
|
||||||
|
if (Info->hSubKey)
|
||||||
{
|
{
|
||||||
if ((EnumType == ENUM_ALL_INSTALLED) || /* All components */
|
// those items without display name are ignored
|
||||||
((EnumType == ENUM_INSTALLED_APPLICATIONS) && (!bIsUpdate)) || /* Applications only */
|
if (Info->GetApplicationString(L"DisplayName", Info->szDisplayName))
|
||||||
((EnumType == ENUM_UPDATES) && (bIsUpdate))) /* Updates only */
|
|
||||||
{
|
{
|
||||||
if (!lpEnumProc(ItemIndex, szDisplayName, &Info, param))
|
Info->GetApplicationString(L"DisplayVersion", Info->szDisplayVersion);
|
||||||
break;
|
Info->GetApplicationString(L"Publisher", Info->szPublisher);
|
||||||
|
Info->GetApplicationString(L"RegOwner", Info->szRegOwner);
|
||||||
|
Info->GetApplicationString(L"ProductID", Info->szProductID);
|
||||||
|
Info->GetApplicationString(L"HelpLink", Info->szHelpLink);
|
||||||
|
Info->GetApplicationString(L"HelpTelephone", Info->szHelpTelephone);
|
||||||
|
Info->GetApplicationString(L"Readme", Info->szReadme);
|
||||||
|
Info->GetApplicationString(L"Contact", Info->szContact);
|
||||||
|
Info->GetApplicationString(L"URLUpdateInfo", Info->szURLUpdateInfo);
|
||||||
|
Info->GetApplicationString(L"URLInfoAbout", Info->szURLInfoAbout);
|
||||||
|
Info->GetApplicationString(L"Comments", Info->szComments);
|
||||||
|
Info->GetApplicationString(L"InstallDate", Info->szInstallDate);
|
||||||
|
Info->GetApplicationString(L"InstallLocation", Info->szInstallLocation);
|
||||||
|
Info->GetApplicationString(L"InstallSource", Info->szInstallSource);
|
||||||
|
Info->GetApplicationString(L"UninstallString", Info->szUninstallString);
|
||||||
|
Info->GetApplicationString(L"ModifyPath", Info->szModifyPath);
|
||||||
|
|
||||||
|
bSuccess = TRUE;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
// close handle
|
||||||
|
if (Info->hSubKey)
|
||||||
|
{
|
||||||
|
CloseHandle(Info->hSubKey);
|
||||||
|
Info->hSubKey = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bSuccess)
|
||||||
|
{
|
||||||
|
// add to InfoList.
|
||||||
|
m_InfoList.AddTail(Info);
|
||||||
|
|
||||||
|
// invoke callback
|
||||||
|
if (lpEnumProc)
|
||||||
{
|
{
|
||||||
RegCloseKey(Info.hSubKey);
|
if ((EnumType == ENUM_ALL_INSTALLED) || /* All components */
|
||||||
|
((EnumType == ENUM_INSTALLED_APPLICATIONS) && (!Info->bIsUpdate)) || /* Applications only */
|
||||||
|
((EnumType == ENUM_UPDATES) && (Info->bIsUpdate))) /* Updates only */
|
||||||
|
{
|
||||||
|
lpEnumProc(Info, param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RegCloseKey(Info.hSubKey);
|
// destory object
|
||||||
|
delete Info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
szDisplayName.ReleaseBuffer();
|
|
||||||
RegCloseKey(Info.hSubKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dwSize = MAX_PATH;
|
szKeyName.ReleaseBuffer();
|
||||||
ItemIndex++;
|
RegCloseKey(hKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Info.szKeyName.ReleaseBuffer();
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID CInstalledApps::FreeCachedEntries()
|
||||||
|
{
|
||||||
|
POSITION InfoListPosition = m_InfoList.GetHeadPosition();
|
||||||
|
|
||||||
|
/* loop and deallocate all the cached app infos in the list */
|
||||||
|
while (InfoListPosition)
|
||||||
|
{
|
||||||
|
CInstalledApplicationInfo *Info = m_InfoList.GetNext(InfoListPosition);
|
||||||
|
delete Info;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_InfoList.RemoveAll();
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
|
|
||||||
static HANDLE hLog = NULL;
|
static HANDLE hLog = NULL;
|
||||||
|
|
||||||
|
static BOOL bIsSys64ResultCached = FALSE;
|
||||||
|
static BOOL bIsSys64Result = FALSE;
|
||||||
|
|
||||||
INT GetWindowWidth(HWND hwnd)
|
INT GetWindowWidth(HWND hwnd)
|
||||||
{
|
{
|
||||||
RECT Rect;
|
RECT Rect;
|
||||||
|
@ -453,3 +456,33 @@ BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore)
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOL IsSystem64Bit()
|
||||||
|
{
|
||||||
|
if (bIsSys64ResultCached)
|
||||||
|
{
|
||||||
|
// just return cached result
|
||||||
|
return bIsSys64Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
typedef void (WINAPI *LPFN_PGNSI)(LPSYSTEM_INFO);
|
||||||
|
LPFN_PGNSI pGetNativeSystemInfo = (LPFN_PGNSI)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo");
|
||||||
|
if (pGetNativeSystemInfo)
|
||||||
|
{
|
||||||
|
pGetNativeSystemInfo(&si);
|
||||||
|
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
|
||||||
|
{
|
||||||
|
bIsSys64Result = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bIsSys64Result = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bIsSys64ResultCached = TRUE; // next time calling this function, it will directly return bIsSys64Result
|
||||||
|
return bIsSys64Result;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue