[RAPPS] Speed up installed application loading

Only load in details when we are going to display them
This commit is contained in:
Mark Jansen 2021-10-03 20:35:13 +02:00
parent 0ed04e3640
commit 143b2a5035
No known key found for this signature in database
GPG key ID: B39240EE84BEAE8B
7 changed files with 149 additions and 180 deletions

View file

@ -398,6 +398,8 @@ BOOL CAppRichEdit::ShowInstalledAppInfo(CInstalledApplicationInfo *Info)
SetText(Info->szDisplayName, CFE_BOLD); SetText(Info->szDisplayName, CFE_BOLD);
InsertText(L"\n", 0); InsertText(L"\n", 0);
Info->EnsureDetailsLoaded();
InsertTextWithString(IDS_INFO_VERSION, CFE_BOLD, Info->szDisplayVersion, 0); InsertTextWithString(IDS_INFO_VERSION, CFE_BOLD, Info->szDisplayVersion, 0);
InsertTextWithString(IDS_INFO_PUBLISHER, CFE_BOLD, Info->szPublisher, 0); InsertTextWithString(IDS_INFO_PUBLISHER, CFE_BOLD, Info->szPublisher, 0);
InsertTextWithString(IDS_INFO_REGOWNER, CFE_BOLD, Info->szRegOwner, 0); InsertTextWithString(IDS_INFO_REGOWNER, CFE_BOLD, Info->szRegOwner, 0);

View file

@ -567,7 +567,7 @@ VOID CMainWindow::OnCommand(WPARAM wParam, LPARAM lParam)
CAvailableApplicationInfo *FocusedApps = (CAvailableApplicationInfo *)m_ApplicationView->GetFocusedItemData(); CAvailableApplicationInfo *FocusedApps = (CAvailableApplicationInfo *)m_ApplicationView->GetFocusedItemData();
if (FocusedApps) if (FocusedApps)
{ {
if (DownloadApplication(FocusedApps, FALSE)) if (DownloadApplication(FocusedApps))
{ {
UpdateApplicationsList(-1); UpdateApplicationsList(-1);
} }
@ -782,7 +782,7 @@ BOOL CMainWindow::InstallApplication(CAvailableApplicationInfo *Info)
{ {
if (Info) if (Info)
{ {
if (DownloadApplication(Info, FALSE)) if (DownloadApplication(Info))
{ {
UpdateApplicationsList(-1); UpdateApplicationsList(-1);
return TRUE; return TRUE;

View file

@ -191,7 +191,6 @@ public:
HWND Create(HWND hwndParent); HWND Create(HWND hwndParent);
BOOL ShowAvailableAppInfo(CAvailableApplicationInfo *Info); BOOL ShowAvailableAppInfo(CAvailableApplicationInfo *Info);
BOOL ShowInstalledAppInfo(CInstalledApplicationInfo *Info); BOOL ShowInstalledAppInfo(CInstalledApplicationInfo *Info);
VOID SetWelcomeText(); VOID SetWelcomeText();

View file

@ -13,5 +13,5 @@ VOID MainWindowLoop(INT nShowCmd);
// Download dialogs // Download dialogs
VOID DownloadApplicationsDB(LPCWSTR lpUrl, BOOL IsOfficial); VOID DownloadApplicationsDB(LPCWSTR lpUrl, BOOL IsOfficial);
BOOL DownloadApplication(CAvailableApplicationInfo* pAppInfo, BOOL bIsModal); BOOL DownloadApplication(CAvailableApplicationInfo* pAppInfo);
BOOL DownloadListOfApplications(const ATL::CSimpleArray<CAvailableApplicationInfo>& AppsList, BOOL bIsModal); BOOL DownloadListOfApplications(const ATL::CSimpleArray<CAvailableApplicationInfo>& AppsList, BOOL bIsModal);

View file

@ -5,41 +5,48 @@
class CInstalledApplicationInfo class CInstalledApplicationInfo
{ {
private:
BOOL m_IsUserKey;
REGSAM m_WowKey;
HKEY m_hSubKey;
CStringW m_szKeyName;
public: public:
BOOL IsUserKey; CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey, const CStringW& szKeyName);
REGSAM WowKey; ~CInstalledApplicationInfo();
HKEY hSubKey;
BOOL bIsUpdate = FALSE;
ATL::CStringW szKeyName; VOID EnsureDetailsLoaded();
CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey);
BOOL GetApplicationRegString(LPCWSTR lpKeyName, ATL::CStringW& String); BOOL GetApplicationRegString(LPCWSTR lpKeyName, ATL::CStringW& String);
BOOL GetApplicationRegDword(LPCWSTR lpKeyName, DWORD *lpValue); BOOL GetApplicationRegDword(LPCWSTR lpKeyName, DWORD *lpValue);
BOOL RetrieveIcon(ATL::CStringW& IconLocation); BOOL RetrieveIcon(ATL::CStringW& IconLocation);
BOOL UninstallApplication(BOOL bModify); BOOL UninstallApplication(BOOL bModify);
LSTATUS RemoveFromRegistry(); LSTATUS RemoveFromRegistry();
ATL::CStringW szDisplayIcon; // These fields are always loaded
ATL::CStringW szDisplayName; BOOL bIsUpdate;
ATL::CStringW szDisplayVersion; CStringW szDisplayIcon;
ATL::CStringW szPublisher; CStringW szDisplayName;
ATL::CStringW szRegOwner; CStringW szDisplayVersion;
ATL::CStringW szProductID; CStringW szComments;
ATL::CStringW szHelpLink;
ATL::CStringW szHelpTelephone; // These details are loaded on demand
ATL::CStringW szReadme; CStringW szPublisher;
ATL::CStringW szContact; CStringW szRegOwner;
ATL::CStringW szURLUpdateInfo; CStringW szProductID;
ATL::CStringW szURLInfoAbout; CStringW szHelpLink;
ATL::CStringW szComments; CStringW szHelpTelephone;
ATL::CStringW szInstallDate; CStringW szReadme;
ATL::CStringW szInstallLocation; CStringW szContact;
ATL::CStringW szInstallSource; CStringW szURLUpdateInfo;
ATL::CStringW szUninstallString; CStringW szURLInfoAbout;
ATL::CStringW szModifyPath; CStringW szInstallDate;
CStringW szInstallLocation;
CStringW szInstallSource;
CStringW szUninstallString;
CStringW szModifyPath;
~CInstalledApplicationInfo();
}; };
typedef BOOL(CALLBACK *APPENUMPROC)(CInstalledApplicationInfo * Info, PVOID param); typedef BOOL(CALLBACK *APPENUMPROC)(CInstalledApplicationInfo * Info, PVOID param);

View file

@ -2,123 +2,122 @@
* PROJECT: ReactOS Applications Manager * PROJECT: ReactOS Applications Manager
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Classes for working with installed applications * PURPOSE: Classes for working with installed applications
* COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org) * COPYRIGHT: Copyright 2009 Dmitry Chapyshev <dmitry@reactos.org>
* Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) * Copyright 2017 Alexander Shaposhnikov <sanchaez@reactos.org>
* Copyright 2020 He Yang (1160386205@qq.com) * Copyright 2020 He Yang <1160386205@qq.com>
* Copyright 2021 Mark Jansen <mark.jansen@reactos.org>
*/ */
#include "rapps.h" #include "rapps.h"
#include "installed.h" #include "installed.h"
#include "misc.h" #include "misc.h"
CInstalledApplicationInfo::CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey) CInstalledApplicationInfo::CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey, const CStringW& szKeyName)
: IsUserKey(bIsUserKey), WowKey(RegWowKey), hSubKey(hKey) : m_IsUserKey(bIsUserKey)
, m_WowKey(RegWowKey)
, m_hSubKey(hKey)
, m_szKeyName(szKeyName)
{ {
// if Initialize failed, hSubKey will be closed automatically and set to zero DWORD dwSize = 0;
bIsUpdate = (RegQueryValueExW(m_hSubKey, L"ParentKeyName", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS);
DWORD dwSize = MAX_PATH, dwType, dwValue;
BOOL bIsSystemComponent;
ATL::CStringW szParentKeyName;
dwType = REG_DWORD;
dwSize = sizeof(DWORD);
if (RegQueryValueExW(hSubKey,
L"SystemComponent",
NULL,
&dwType,
(LPBYTE)&dwValue,
&dwSize) == ERROR_SUCCESS)
{
bIsSystemComponent = (dwValue == 0x1);
}
else
{
bIsSystemComponent = FALSE;
}
dwType = REG_SZ;
dwSize = MAX_PATH * sizeof(WCHAR);
bIsUpdate = (RegQueryValueExW(hSubKey,
L"ParentKeyName",
NULL,
&dwType,
(LPBYTE)szParentKeyName.GetBuffer(MAX_PATH),
&dwSize) == ERROR_SUCCESS);
szParentKeyName.ReleaseBuffer();
if (bIsSystemComponent)
{
CloseHandle(hSubKey);
hSubKey = NULL;
}
} }
CInstalledApplicationInfo::~CInstalledApplicationInfo() CInstalledApplicationInfo::~CInstalledApplicationInfo()
{ {
if (hSubKey) if (m_hSubKey)
{ {
CloseHandle(hSubKey); CloseHandle(m_hSubKey);
hSubKey = NULL; m_hSubKey = NULL;
}
}
void CInstalledApplicationInfo::EnsureDetailsLoaded()
{
// Key not closed, so we have not loaded details yet
if (m_hSubKey)
{
GetApplicationRegString(L"Publisher", szPublisher);
GetApplicationRegString(L"RegOwner", szRegOwner);
GetApplicationRegString(L"ProductID", szProductID);
GetApplicationRegString(L"HelpLink", szHelpLink);
GetApplicationRegString(L"HelpTelephone", szHelpTelephone);
GetApplicationRegString(L"Readme", szReadme);
GetApplicationRegString(L"Contact", szContact);
GetApplicationRegString(L"URLUpdateInfo", szURLUpdateInfo);
GetApplicationRegString(L"URLInfoAbout", szURLInfoAbout);
if (GetApplicationRegString(L"InstallDate", szInstallDate) == FALSE)
{
// It might be a DWORD (Unix timestamp). try again.
DWORD dwInstallTimeStamp;
if (GetApplicationRegDword(L"InstallDate", &dwInstallTimeStamp))
{
FILETIME InstallFileTime;
SYSTEMTIME InstallSystemTime, InstallLocalTime;
UnixTimeToFileTime(dwInstallTimeStamp, &InstallFileTime);
FileTimeToSystemTime(&InstallFileTime, &InstallSystemTime);
// convert to localtime
SystemTimeToTzSpecificLocalTime(NULL, &InstallSystemTime, &InstallLocalTime);
// convert to readable date string
int cchTimeStrLen = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &InstallLocalTime, NULL, 0, 0);
GetDateFormatW(
LOCALE_USER_DEFAULT, // use default locale for current user
0, &InstallLocalTime, NULL, szInstallDate.GetBuffer(cchTimeStrLen), cchTimeStrLen);
szInstallDate.ReleaseBuffer();
}
}
GetApplicationRegString(L"InstallLocation", szInstallLocation);
GetApplicationRegString(L"InstallSource", szInstallSource);
GetApplicationRegString(L"UninstallString", szUninstallString);
GetApplicationRegString(L"ModifyPath",szModifyPath);
CloseHandle(m_hSubKey);
m_hSubKey = NULL;
} }
} }
BOOL CInstalledApplicationInfo::GetApplicationRegString(LPCWSTR lpKeyName, ATL::CStringW& String) BOOL CInstalledApplicationInfo::GetApplicationRegString(LPCWSTR lpKeyName, ATL::CStringW& String)
{ {
DWORD dwSize = 0; DWORD dwAllocated = 0, dwSize, dwType;
String.Empty();
DWORD dwType;
// retrieve the size of value first. // retrieve the size of value first.
if (RegQueryValueExW(hSubKey, if (RegQueryValueExW(m_hSubKey, lpKeyName, NULL, &dwType, NULL, &dwAllocated) != ERROR_SUCCESS ||
lpKeyName, dwType != REG_SZ)
NULL,
&dwType,
NULL,
&dwSize) != ERROR_SUCCESS)
{ {
return FALSE;
}
// TODO: I assume the type as REG_SZ. but I think REG_EXPAND_SZ should be handled correctly too.
if (dwType != REG_SZ)
{
return FALSE;
}
// 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(); String.Empty();
return FALSE; return FALSE;
} }
String.GetBuffer()[dwSize / sizeof(WCHAR)] = L'\0'; // ensure zero terminated
String.ReleaseBuffer(); // query the value
dwSize = dwAllocated;
LSTATUS Result =
RegQueryValueExW(m_hSubKey, lpKeyName, NULL, NULL, (LPBYTE)String.GetBuffer(dwAllocated / sizeof(WCHAR)), &dwSize);
dwSize = min(dwAllocated, dwSize);
// CString takes care of zero-terminating it
String.ReleaseBuffer(dwSize / sizeof(WCHAR));
if (Result != ERROR_SUCCESS)
{
String.Empty();
return FALSE;
}
return TRUE; return TRUE;
} }
BOOL CInstalledApplicationInfo::GetApplicationRegDword(LPCWSTR lpKeyName, DWORD *lpValue) BOOL CInstalledApplicationInfo::GetApplicationRegDword(LPCWSTR lpKeyName, DWORD *lpValue)
{ {
DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD), dwType;
DWORD dwSize = sizeof(DWORD); if (RegQueryValueExW(m_hSubKey,
if (RegQueryValueExW(hSubKey,
lpKeyName, lpKeyName,
NULL, NULL,
&dwType, &dwType,
(LPBYTE)lpValue, (LPBYTE)lpValue,
&dwSize) != ERROR_SUCCESS) &dwSize) != ERROR_SUCCESS || dwType != REG_DWORD)
{ {
return FALSE; return FALSE;
} }
@ -148,7 +147,7 @@ typedef LSTATUS (WINAPI *RegDeleteKeyExWProc)(HKEY, LPCWSTR, REGSAM, DWORD);
LSTATUS CInstalledApplicationInfo::RemoveFromRegistry() LSTATUS CInstalledApplicationInfo::RemoveFromRegistry()
{ {
ATL::CStringW szFullName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + szKeyName; ATL::CStringW szFullName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + m_szKeyName;
HMODULE hMod = GetModuleHandleW(L"advapi32.dll"); HMODULE hMod = GetModuleHandleW(L"advapi32.dll");
RegDeleteKeyExWProc pRegDeleteKeyExW; RegDeleteKeyExWProc pRegDeleteKeyExW;
@ -166,12 +165,12 @@ LSTATUS CInstalledApplicationInfo::RemoveFromRegistry()
if (pRegDeleteKeyExW) if (pRegDeleteKeyExW)
{ {
/* Return it */ /* Return it */
return pRegDeleteKeyExW(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szFullName, WowKey, 0); return pRegDeleteKeyExW(m_IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szFullName, m_WowKey, 0);
} }
} }
/* Otherwise, return non-Ex function */ /* Otherwise, return non-Ex function */
return RegDeleteKeyW(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szFullName); return RegDeleteKeyW(m_IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szFullName);
} }
BOOL CInstalledApps::Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param) BOOL CInstalledApps::Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param)
@ -225,72 +224,34 @@ BOOL CInstalledApps::Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param)
ItemIndex++; ItemIndex++;
szKeyName.ReleaseBuffer(); szKeyName.ReleaseBuffer();
if (RegOpenKeyW(hKey, szKeyName.GetString(), &hSubKey) == ERROR_SUCCESS) if (RegOpenKeyW(hKey, szKeyName, &hSubKey) == ERROR_SUCCESS)
{ {
BOOL bSuccess = FALSE; DWORD dwValue = 0;
CInstalledApplicationInfo *Info = new CInstalledApplicationInfo(RootKeyEnum[i] == HKEY_CURRENT_USER, RegSamEnum[i], hSubKey); BOOL bIsSystemComponent = FALSE;
Info->szKeyName = szKeyName;
// check for failure. if failed to init, Info->hSubKey will be set to NULL dwSize = sizeof(DWORD);
if (Info->hSubKey) if (RegQueryValueExW(hSubKey, L"SystemComponent", NULL, NULL, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS)
{ {
// those items without display name are ignored bIsSystemComponent = (dwValue == 0x1);
if (Info->GetApplicationRegString(L"DisplayName", Info->szDisplayName)) }
{ // Ignore system components
Info->GetApplicationRegString(L"DisplayIcon", Info->szDisplayIcon); if (bIsSystemComponent)
Info->GetApplicationRegString(L"DisplayVersion", Info->szDisplayVersion); {
Info->GetApplicationRegString(L"Publisher", Info->szPublisher); RegCloseKey(hSubKey);
Info->GetApplicationRegString(L"RegOwner", Info->szRegOwner); continue;
Info->GetApplicationRegString(L"ProductID", Info->szProductID);
Info->GetApplicationRegString(L"HelpLink", Info->szHelpLink);
Info->GetApplicationRegString(L"HelpTelephone", Info->szHelpTelephone);
Info->GetApplicationRegString(L"Readme", Info->szReadme);
Info->GetApplicationRegString(L"Contact", Info->szContact);
Info->GetApplicationRegString(L"URLUpdateInfo", Info->szURLUpdateInfo);
Info->GetApplicationRegString(L"URLInfoAbout", Info->szURLInfoAbout);
Info->GetApplicationRegString(L"Comments", Info->szComments);
if (Info->GetApplicationRegString(L"InstallDate", Info->szInstallDate) == FALSE)
{
// It might be a DWORD (Unix timestamp). try again.
DWORD dwInstallTimeStamp;
if (Info->GetApplicationRegDword(L"InstallDate", &dwInstallTimeStamp))
{
FILETIME InstallFileTime;
SYSTEMTIME InstallSystemTime, InstallLocalTime;
UnixTimeToFileTime(dwInstallTimeStamp, &InstallFileTime);
FileTimeToSystemTime(&InstallFileTime, &InstallSystemTime);
// convert to localtime
SystemTimeToTzSpecificLocalTime(NULL, &InstallSystemTime, &InstallLocalTime);
// convert to readable date string
int cchTimeStrLen = GetDateFormatW(LOCALE_USER_DEFAULT,
0,
&InstallLocalTime,
NULL, 0, 0);
GetDateFormatW(LOCALE_USER_DEFAULT, // use default locale for current user
0,
&InstallLocalTime,
NULL, Info->szInstallDate.GetBuffer(cchTimeStrLen), cchTimeStrLen);
Info->szInstallDate.ReleaseBuffer();
}
}
Info->GetApplicationRegString(L"InstallLocation", Info->szInstallLocation);
Info->GetApplicationRegString(L"InstallSource", Info->szInstallSource);
Info->GetApplicationRegString(L"UninstallString", Info->szUninstallString);
Info->GetApplicationRegString(L"ModifyPath", Info->szModifyPath);
bSuccess = TRUE;
}
} }
// close handle BOOL bSuccess = FALSE;
if (Info->hSubKey) CInstalledApplicationInfo *Info = new CInstalledApplicationInfo(RootKeyEnum[i] == HKEY_CURRENT_USER, RegSamEnum[i], hSubKey, szKeyName);
// items without display name are ignored
if (Info->GetApplicationRegString(L"DisplayName", Info->szDisplayName))
{ {
CloseHandle(Info->hSubKey); Info->GetApplicationRegString(L"DisplayIcon", Info->szDisplayIcon);
Info->hSubKey = NULL; Info->GetApplicationRegString(L"DisplayVersion", Info->szDisplayVersion);
Info->GetApplicationRegString(L"Comments", Info->szComments);
bSuccess = TRUE;
} }
if (bSuccess) if (bSuccess)

View file

@ -1030,12 +1030,12 @@ BOOL DownloadListOfApplications(const ATL::CSimpleArray<CAvailableApplicationInf
return TRUE; return TRUE;
} }
BOOL DownloadApplication(CAvailableApplicationInfo* pAppInfo, BOOL bIsModal) BOOL DownloadApplication(CAvailableApplicationInfo* pAppInfo)
{ {
if (!pAppInfo) if (!pAppInfo)
return FALSE; return FALSE;
CDownloadManager::Download(*pAppInfo, bIsModal); CDownloadManager::Download(*pAppInfo, FALSE);
return TRUE; return TRUE;
} }