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 */ #include "rapps.h" +#include -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; + DWORD len = 512; + DWORD result; - 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) + 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) { - // 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()); + 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; } } +} - ResultString.ReleaseBuffer(); - return (dwResult != 0 ? TRUE : FALSE); +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 + 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"; + } + + // 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()) + { + 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) { - /* First try */ - if (GetStringWorker(KeyName, L"." CurrentArchitecture, ResultString)) + int nIndex = m_Keys.FindKey(KeyName); + if (nIndex >= 0) { + ResultString = m_Keys.GetValueAt(nIndex); return TRUE; } -#ifndef _M_IX86 - /* On non-x86 architecture we need the architecture specific URL */ - if (KeyName == L"URLDownload") - { - return FALSE; - } -#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 &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 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(); + } + + CachedDirectoryInitialized = TRUE; } - PathAppendW(DirectoryStr, L"rapps"); - Directory.ReleaseBuffer(); - - return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS); + Directory = CachedDirectory; + return !Directory.IsEmpty(); } VOID InitLogs()