https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9bdeaca56e8e01473d9858...
commit 9bdeaca56e8e01473d9858a1b7ea4bbdbbc836cf Author: Mark Jansen mark.jansen@reactos.org AuthorDate: Thu Sep 30 20:19:21 2021 +0200 Commit: Mark Jansen mark.jansen@reactos.org CommitDate: Sun Oct 3 20:26:25 2021 +0200
[RAPPS] Speed up app loading by caching the INI sections --- base/applications/rapps/appview.cpp | 6 + base/applications/rapps/configparser.cpp | 182 ++++++++++++++++--------- base/applications/rapps/include/appview.h | 13 +- base/applications/rapps/include/configparser.h | 13 +- base/applications/rapps/include/gui.h | 7 - base/applications/rapps/misc.cpp | 35 +++-- 6 files changed, 157 insertions(+), 99 deletions(-)
diff --git a/base/applications/rapps/appview.cpp b/base/applications/rapps/appview.cpp index c15c3ab1172..631eecbad9c 100644 --- a/base/applications/rapps/appview.cpp +++ b/base/applications/rapps/appview.cpp @@ -1705,6 +1705,12 @@ BOOL CApplicationView::CreateAppInfoDisplay() 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) { if (wParam == SIZE_MINIMIZED) diff --git a/base/applications/rapps/configparser.cpp b/base/applications/rapps/configparser.cpp index 5e191da800b..d5c65991daa 100644 --- a/base/applications/rapps/configparser.cpp +++ b/base/applications/rapps/configparser.cpp @@ -2,18 +2,31 @@ * PROJECT: ReactOS Applications Manager * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Config parser - * 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 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 <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 szBuffer; @@ -24,79 +37,124 @@ ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName) return szBuffer; }
-VOID CConfigParser::CacheINILocale() +CConfigParser::CConfigParser(const ATL::CStringW& FileName) + : szConfigPath(GetINIFullPath(FileName)) { - // TODO: Set default locale if call fails - // 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(); - m_szCachedINISectionLocale = L"Section." + m_szLocaleID; - - // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part - if (m_szLocaleID.GetLength() >= 2) - m_szCachedINISectionLocaleNeutral = L"Section." + m_szLocaleID.Right(2); - else - m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale; + CacheINI(); }
-BOOL CConfigParser::GetStringWorker(const ATL::CStringW& KeyName, PCWSTR Suffix, ATL::CStringW& ResultString) +void CConfigParser::ReadSection(ATL::CStringW& Buffer, const ATL::CStringW& Section, BOOL isArch) { - 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) + DWORD len = 512; + DWORD result; + + do { - // 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) + 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 { - // 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()); + break; } } - - ResultString.ReleaseBuffer(); - return (dwResult != 0 ? TRUE : FALSE); }
-BOOL CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString) +VOID CConfigParser::CacheINI() { - /* First try */ - if (GetStringWorker(KeyName, L"." CurrentArchitecture, ResultString)) + // Cache section names + if (g_Names.ArchSpecific.Locale.IsEmpty()) { - return TRUE; + 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 + if (szLocaleID.GetLength() >= 2) + { + g_Names.ArchSpecific.LocaleNeutral = L"Section." + szLocaleID.Right(2) + L"." CurrentArchitecture; + g_Names.ArchNeutral.LocaleNeutral = L"Section." + szLocaleID.Right(2); + } + + g_Names.ArchSpecific.Section = L"Section." CurrentArchitecture; + g_Names.ArchNeutral.Section = L"Section"; }
-#ifndef _M_IX86 - /* On non-x86 architecture we need the architecture specific URL */ - if (KeyName == L"URLDownload") + // Use a shared buffer so that we don't have to re-allocate it every time + CStringW Buffer; + + ReadSection(Buffer, g_Names.ArchSpecific.Locale, TRUE); + if (!g_Names.ArchSpecific.LocaleNeutral.IsEmpty()) { - return FALSE; + 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) +{ + int nIndex = m_Keys.FindKey(KeyName); + if (nIndex >= 0) + { + ResultString = m_Keys.GetValueAt(nIndex); + return TRUE; } -#endif
- /* Fall back to default */ - return GetStringWorker(KeyName, L"", ResultString); + ResultString.Empty(); + return FALSE; }
BOOL CConfigParser::GetInt(const ATL::CStringW& KeyName, INT& iResult) diff --git a/base/applications/rapps/include/appview.h b/base/applications/rapps/include/appview.h index 192a59c7489..b625d5ed296 100644 --- a/base/applications/rapps/include/appview.h +++ b/base/applications/rapps/include/appview.h @@ -351,42 +351,31 @@ private: BOOL ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId);
BOOL CreateToolbar(); - BOOL CreateSearchBar(); - BOOL CreateComboBox(); - BOOL CreateHSplitter(); - BOOL CreateListView(); - BOOL CreateAppInfoDisplay();
VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam); - VOID OnCommand(WPARAM wParam, LPARAM lParam); public:
CApplicationView(CMainWindow *MainWindow); - ~CApplicationView();
static ATL::CWndClassInfo &GetWndClassInfo();
HWND Create(HWND hwndParent); - + void SetRedraw(BOOL bRedraw); BOOL SetDisplayAppType(APPLICATION_VIEW_TYPE AppType);
BOOL AddInstalledApplication(CInstalledApplicationInfo *InstAppInfo, LPVOID param); - BOOL AddAvailableApplication(CAvailableApplicationInfo *AvlbAppInfo, BOOL InitCheckState, LPVOID param);
void CheckAll(); - PVOID GetFocusedItemData(); - int GetItemCount(); - VOID AppendTabOrderWindow(int Direction, ATL::CSimpleArray<HWND> &TabOrderList);
// this function is called when a item of listview get focus. diff --git a/base/applications/rapps/include/configparser.h b/base/applications/rapps/include/configparser.h index 5df9150269c..7ccfa115bd4 100644 --- a/base/applications/rapps/include/configparser.h +++ b/base/applications/rapps/include/configparser.h @@ -5,18 +5,11 @@
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; + CSimpleMap<CStringW, CStringW> m_Keys;
- ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName); - VOID CacheINILocale(); - BOOL GetStringWorker(const ATL::CStringW& KeyName, PCWSTR Suffix, ATL::CStringW& ResultString); + void CacheINI(); + void ReadSection(ATL::CStringW& Buffer, const ATL::CStringW& Section, BOOL isArch);
public: CConfigParser(const ATL::CStringW& FileName); diff --git a/base/applications/rapps/include/gui.h b/base/applications/rapps/include/gui.h index 1d8b6141ece..738379d7a1e 100644 --- a/base/applications/rapps/include/gui.h +++ b/base/applications/rapps/include/gui.h @@ -71,13 +71,9 @@ private: VOID InitCategoriesList();
BOOL CreateStatusBar(); - BOOL CreateTreeView(); - BOOL CreateApplicationView(); - BOOL CreateVSplitter(); - BOOL CreateLayout();
VOID LayoutCleanup(); @@ -99,11 +95,8 @@ private: VOID OnCommand(WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EnumInstalledAppProc(CInstalledApplicationInfo *Info); - BOOL CALLBACK EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState); - static BOOL CALLBACK s_EnumInstalledAppProc(CInstalledApplicationInfo *Info, PVOID param); - static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param);
static BOOL CALLBACK s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param); diff --git a/base/applications/rapps/misc.cpp b/base/applications/rapps/misc.cpp index 742d4d67bb4..b5d142828ff 100644 --- a/base/applications/rapps/misc.cpp +++ b/base/applications/rapps/misc.cpp @@ -140,17 +140,36 @@ BOOL StartProcess(const ATL::CStringW& Path, BOOL Wait)
BOOL GetStorageDirectory(ATL::CStringW& Directory) { - LPWSTR DirectoryStr = Directory.GetBuffer(MAX_PATH); - if (!SHGetSpecialFolderPathW(NULL, DirectoryStr, CSIDL_LOCAL_APPDATA, TRUE)) + static CStringW CachedDirectory; + static BOOL CachedDirectoryInitialized = FALSE; + + if (!CachedDirectoryInitialized) { - Directory.ReleaseBuffer(); - return FALSE; - } + LPWSTR DirectoryStr = CachedDirectory.GetBuffer(MAX_PATH); + 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"); - Directory.ReleaseBuffer(); + CachedDirectoryInitialized = TRUE; + }
- return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS); + Directory = CachedDirectory; + return !Directory.IsEmpty(); }
VOID InitLogs()