[RAPPS] Speed up app loading by caching the INI sections

This commit is contained in:
Mark Jansen 2021-09-30 20:19:21 +02:00
parent 6f9dd96dcf
commit 9bdeaca56e
No known key found for this signature in database
GPG key ID: B39240EE84BEAE8B
6 changed files with 156 additions and 98 deletions

View file

@ -1705,6 +1705,12 @@ BOOL CApplicationView::CreateAppInfoDisplay()
return m_AppsInfo->Create(m_hWnd) != NULL; return m_AppsInfo->Create(m_hWnd) != NULL;
} }
void CApplicationView::SetRedraw(BOOL bRedraw)
{
CWindow::SetRedraw(bRedraw);
m_ListView->SetRedraw(bRedraw);
}
VOID CApplicationView::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam) VOID CApplicationView::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
{ {
if (wParam == SIZE_MINIMIZED) if (wParam == SIZE_MINIMIZED)

View file

@ -5,15 +5,28 @@
* COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org) * COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
* Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com) * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
* Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
* Copyright 2021 Mark Jansen <mark.jansen@reactos.org>
*/ */
#include "rapps.h" #include "rapps.h"
#include <debug.h>
CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName)) struct CLocaleSections
{ {
CacheINILocale(); CStringW Locale;
} CStringW LocaleNeutral;
CStringW Section;
};
ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName) struct CSectionNames
{
CLocaleSections ArchSpecific;
CLocaleSections ArchNeutral;
};
static CSectionNames g_Names;
static
ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName)
{ {
ATL::CStringW szDir; ATL::CStringW szDir;
ATL::CStringW szBuffer; ATL::CStringW szBuffer;
@ -24,80 +37,125 @@ ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName)
return szBuffer; return szBuffer;
} }
VOID CConfigParser::CacheINILocale() CConfigParser::CConfigParser(const ATL::CStringW& FileName)
: szConfigPath(GetINIFullPath(FileName))
{ {
// TODO: Set default locale if call fails CacheINI();
// find out what is the current system lang code (e.g. "0a") and append it to SectionLocale }
GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE,
m_szLocaleID.GetBuffer(m_cchLocaleSize), m_cchLocaleSize);
m_szLocaleID.ReleaseBuffer(); void CConfigParser::ReadSection(ATL::CStringW& Buffer, const ATL::CStringW& Section, BOOL isArch)
m_szCachedINISectionLocale = L"Section." + m_szLocaleID; {
DWORD len = 512;
DWORD result;
do
{
len *= 2;
result = GetPrivateProfileSectionW(Section, Buffer.GetBuffer(len), len, szConfigPath);
Buffer.ReleaseBuffer(result);
} while (result == len - 2);
len = 0;
while (len < result)
{
// Explicitly use the null terminator!
CString tmp = Buffer.GetBuffer() + len;
if (tmp.GetLength() > 0)
{
len += tmp.GetLength() + 1;
int idx = tmp.Find('=');
if (idx >= 0)
{
CString key = tmp.Left(idx);
#ifndef _M_IX86
// On non-x86 architecture we need the architecture specific URL
if (!isArch && key == "URLDownload")
{
continue;
}
#endif
// Is this key already present from a more specific translation?
if (m_Keys.FindKey(key) >= 0)
{
continue;
}
CString value = tmp.Mid(idx+1);
m_Keys.Add(key, value);
}
else
{
DPRINT1("ERROR: invalid key/value pair: '%S'\n", tmp.GetString());
}
}
else
{
break;
}
}
}
VOID CConfigParser::CacheINI()
{
// Cache section names
if (g_Names.ArchSpecific.Locale.IsEmpty())
{
CString szLocaleID;
const INT cchLocaleSize = 5;
GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE, szLocaleID.GetBuffer(cchLocaleSize), cchLocaleSize);
szLocaleID.ReleaseBuffer();
CString INISectionLocale = L"Section." + szLocaleID;
g_Names.ArchSpecific.Locale = INISectionLocale + L"." CurrentArchitecture;
g_Names.ArchNeutral.Locale = INISectionLocale;
// turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
if (m_szLocaleID.GetLength() >= 2) if (szLocaleID.GetLength() >= 2)
m_szCachedINISectionLocaleNeutral = L"Section." + m_szLocaleID.Right(2); {
else g_Names.ArchSpecific.LocaleNeutral = L"Section." + szLocaleID.Right(2) + L"." CurrentArchitecture;
m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale; g_Names.ArchNeutral.LocaleNeutral = L"Section." + szLocaleID.Right(2);
} }
BOOL CConfigParser::GetStringWorker(const ATL::CStringW& KeyName, PCWSTR Suffix, ATL::CStringW& ResultString) g_Names.ArchSpecific.Section = L"Section." CurrentArchitecture;
{ g_Names.ArchNeutral.Section = L"Section";
DWORD dwResult;
LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH);
// 1st - find localized strings (e.g. "Section.0c0a")
dwResult = GetPrivateProfileStringW((m_szCachedINISectionLocale + Suffix).GetString(),
KeyName.GetString(),
NULL,
ResultStringBuffer,
MAX_PATH,
szConfigPath.GetString());
if (!dwResult)
{
// 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
dwResult = GetPrivateProfileStringW((m_szCachedINISectionLocaleNeutral + Suffix).GetString(),
KeyName.GetString(),
NULL,
ResultStringBuffer,
MAX_PATH,
szConfigPath.GetString());
if (!dwResult)
{
// 3rd - if they weren't present fallback to standard english strings (just "Section")
dwResult = GetPrivateProfileStringW((ATL::CStringW(L"Section") + Suffix).GetString(),
KeyName.GetString(),
NULL,
ResultStringBuffer,
MAX_PATH,
szConfigPath.GetString());
}
} }
ResultString.ReleaseBuffer(); // Use a shared buffer so that we don't have to re-allocate it every time
return (dwResult != 0 ? TRUE : FALSE); CStringW Buffer;
ReadSection(Buffer, g_Names.ArchSpecific.Locale, TRUE);
if (!g_Names.ArchSpecific.LocaleNeutral.IsEmpty())
{
ReadSection(Buffer, g_Names.ArchSpecific.LocaleNeutral, TRUE);
}
ReadSection(Buffer, g_Names.ArchSpecific.Section, TRUE);
ReadSection(Buffer, g_Names.ArchNeutral.Locale, FALSE);
if (!g_Names.ArchNeutral.LocaleNeutral.IsEmpty())
{
ReadSection(Buffer, g_Names.ArchNeutral.LocaleNeutral, FALSE);
}
ReadSection(Buffer, g_Names.ArchNeutral.Section, FALSE);
} }
BOOL CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString) BOOL CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString)
{ {
/* First try */ int nIndex = m_Keys.FindKey(KeyName);
if (GetStringWorker(KeyName, L"." CurrentArchitecture, ResultString)) if (nIndex >= 0)
{ {
ResultString = m_Keys.GetValueAt(nIndex);
return TRUE; return TRUE;
} }
#ifndef _M_IX86 ResultString.Empty();
/* On non-x86 architecture we need the architecture specific URL */
if (KeyName == L"URLDownload")
{
return FALSE; return FALSE;
} }
#endif
/* Fall back to default */
return GetStringWorker(KeyName, L"", ResultString);
}
BOOL CConfigParser::GetInt(const ATL::CStringW& KeyName, INT& iResult) BOOL CConfigParser::GetInt(const ATL::CStringW& KeyName, INT& iResult)
{ {

View file

@ -351,42 +351,31 @@ private:
BOOL ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId); BOOL ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId);
BOOL CreateToolbar(); BOOL CreateToolbar();
BOOL CreateSearchBar(); BOOL CreateSearchBar();
BOOL CreateComboBox(); BOOL CreateComboBox();
BOOL CreateHSplitter(); BOOL CreateHSplitter();
BOOL CreateListView(); BOOL CreateListView();
BOOL CreateAppInfoDisplay(); BOOL CreateAppInfoDisplay();
VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam); VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam);
VOID OnCommand(WPARAM wParam, LPARAM lParam); VOID OnCommand(WPARAM wParam, LPARAM lParam);
public: public:
CApplicationView(CMainWindow *MainWindow); CApplicationView(CMainWindow *MainWindow);
~CApplicationView(); ~CApplicationView();
static ATL::CWndClassInfo &GetWndClassInfo(); static ATL::CWndClassInfo &GetWndClassInfo();
HWND Create(HWND hwndParent); HWND Create(HWND hwndParent);
void SetRedraw(BOOL bRedraw);
BOOL SetDisplayAppType(APPLICATION_VIEW_TYPE AppType); BOOL SetDisplayAppType(APPLICATION_VIEW_TYPE AppType);
BOOL AddInstalledApplication(CInstalledApplicationInfo *InstAppInfo, LPVOID param); BOOL AddInstalledApplication(CInstalledApplicationInfo *InstAppInfo, LPVOID param);
BOOL AddAvailableApplication(CAvailableApplicationInfo *AvlbAppInfo, BOOL InitCheckState, LPVOID param); BOOL AddAvailableApplication(CAvailableApplicationInfo *AvlbAppInfo, BOOL InitCheckState, LPVOID param);
void CheckAll(); void CheckAll();
PVOID GetFocusedItemData(); PVOID GetFocusedItemData();
int GetItemCount(); int GetItemCount();
VOID AppendTabOrderWindow(int Direction, ATL::CSimpleArray<HWND> &TabOrderList); VOID AppendTabOrderWindow(int Direction, ATL::CSimpleArray<HWND> &TabOrderList);
// this function is called when a item of listview get focus. // this function is called when a item of listview get focus.

View file

@ -5,18 +5,11 @@
class CConfigParser class CConfigParser
{ {
// Locale names cache
const static INT m_cchLocaleSize = 5;
ATL::CStringW m_szLocaleID;
ATL::CStringW m_szCachedINISectionLocale;
ATL::CStringW m_szCachedINISectionLocaleNeutral;
const ATL::CStringW szConfigPath; const ATL::CStringW szConfigPath;
CSimpleMap<CStringW, CStringW> m_Keys;
ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName); void CacheINI();
VOID CacheINILocale(); void ReadSection(ATL::CStringW& Buffer, const ATL::CStringW& Section, BOOL isArch);
BOOL GetStringWorker(const ATL::CStringW& KeyName, PCWSTR Suffix, ATL::CStringW& ResultString);
public: public:
CConfigParser(const ATL::CStringW& FileName); CConfigParser(const ATL::CStringW& FileName);

View file

@ -71,13 +71,9 @@ private:
VOID InitCategoriesList(); VOID InitCategoriesList();
BOOL CreateStatusBar(); BOOL CreateStatusBar();
BOOL CreateTreeView(); BOOL CreateTreeView();
BOOL CreateApplicationView(); BOOL CreateApplicationView();
BOOL CreateVSplitter(); BOOL CreateVSplitter();
BOOL CreateLayout(); BOOL CreateLayout();
VOID LayoutCleanup(); VOID LayoutCleanup();
@ -99,11 +95,8 @@ private:
VOID OnCommand(WPARAM wParam, LPARAM lParam); VOID OnCommand(WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EnumInstalledAppProc(CInstalledApplicationInfo *Info); BOOL CALLBACK EnumInstalledAppProc(CInstalledApplicationInfo *Info);
BOOL CALLBACK EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState); BOOL CALLBACK EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState);
static BOOL CALLBACK s_EnumInstalledAppProc(CInstalledApplicationInfo *Info, PVOID param); static BOOL CALLBACK s_EnumInstalledAppProc(CInstalledApplicationInfo *Info, PVOID param);
static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param); static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param);
static BOOL CALLBACK s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param); static BOOL CALLBACK s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param);

View file

@ -140,17 +140,36 @@ BOOL StartProcess(const ATL::CStringW& Path, BOOL Wait)
BOOL GetStorageDirectory(ATL::CStringW& Directory) BOOL GetStorageDirectory(ATL::CStringW& Directory)
{ {
LPWSTR DirectoryStr = Directory.GetBuffer(MAX_PATH); static CStringW CachedDirectory;
if (!SHGetSpecialFolderPathW(NULL, DirectoryStr, CSIDL_LOCAL_APPDATA, TRUE)) static BOOL CachedDirectoryInitialized = FALSE;
if (!CachedDirectoryInitialized)
{ {
Directory.ReleaseBuffer(); LPWSTR DirectoryStr = CachedDirectory.GetBuffer(MAX_PATH);
return FALSE; BOOL bHasPath = SHGetSpecialFolderPathW(NULL, DirectoryStr, CSIDL_LOCAL_APPDATA, TRUE);
if (bHasPath)
{
PathAppendW(DirectoryStr, L"rapps");
}
CachedDirectory.ReleaseBuffer();
if (bHasPath)
{
if (!CreateDirectoryW(CachedDirectory, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
{
CachedDirectory.Empty();
}
}
else
{
CachedDirectory.Empty();
} }
PathAppendW(DirectoryStr, L"rapps"); CachedDirectoryInitialized = TRUE;
Directory.ReleaseBuffer(); }
return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS); Directory = CachedDirectory;
return !Directory.IsEmpty();
} }
VOID InitLogs() VOID InitLogs()