https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9bdeaca56e8e01473d985…
commit 9bdeaca56e8e01473d9858a1b7ea4bbdbbc836cf
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Thu Sep 30 20:19:21 2021 +0200
Commit: Mark Jansen <mark.jansen(a)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(a)reactos.org)
+ * COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry(a)reactos.org)
* Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros(a)gmail.com)
- * Copyright 2017 Alexander Shaposhnikov (sanchaez(a)reactos.org)
+ * Copyright 2017 Alexander Shaposhnikov (sanchaez(a)reactos.org)
+ * Copyright 2021 Mark Jansen <mark.jansen(a)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()