forked from reactos/reactos
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Previously, there would be function duplication between installed and available applications. Now this is handled with polymorphism, which allows to re-use a lot of code. Additionally, toolbar buttons are properly disabled now. The mutex used to guard rapps' single instance is renamed, so that the 'new' and old rapps can be run at the same time for testing. CORE-18459
- Loading branch information
1 parent
0cd80c1
commit 33c2903
Showing
30 changed files
with
3,729 additions
and
4,047 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,291 @@ | ||
/* | ||
* PROJECT: ReactOS Applications Manager | ||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) | ||
* PURPOSE: Classes for working with available applications | ||
* COPYRIGHT: Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) | ||
* Copyright 2020 He Yang (1160386205@qq.com) | ||
* Copyright 2021-2023 Mark Jansen <mark.jansen@reactos.org> | ||
*/ | ||
|
||
#include "rapps.h" | ||
#include "applicationdb.h" | ||
#include "configparser.h" | ||
#include "settings.h" | ||
|
||
|
||
static HKEY g_RootKeyEnum[3] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE}; | ||
static REGSAM g_RegSamEnum[3] = {KEY_WOW64_32KEY, KEY_WOW64_32KEY, KEY_WOW64_64KEY}; | ||
#define UNINSTALL_SUBKEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall" | ||
|
||
static VOID | ||
ClearList(CAtlList<CApplicationInfo *> &list) | ||
{ | ||
POSITION InfoListPosition = list.GetHeadPosition(); | ||
while (InfoListPosition) | ||
{ | ||
CApplicationInfo *Info = list.GetNext(InfoListPosition); | ||
delete Info; | ||
} | ||
list.RemoveAll(); | ||
} | ||
|
||
CApplicationDB::CApplicationDB(const CStringW &path) : m_BasePath(path) | ||
{ | ||
m_BasePath.Canonicalize(); | ||
} | ||
|
||
CApplicationInfo * | ||
CApplicationDB::FindByPackageName(const CStringW &name) | ||
{ | ||
POSITION CurrentListPosition = m_Available.GetHeadPosition(); | ||
while (CurrentListPosition) | ||
{ | ||
CApplicationInfo *Info = m_Available.GetNext(CurrentListPosition); | ||
if (Info->szIdentifier == name) | ||
{ | ||
return Info; | ||
} | ||
} | ||
return NULL; | ||
} | ||
|
||
void | ||
CApplicationDB::GetApps(CAtlList<CApplicationInfo *> &List, AppsCategories Type) const | ||
{ | ||
const BOOL UseInstalled = IsInstalledEnum(Type); | ||
const CAtlList<CApplicationInfo *> &list = UseInstalled ? m_Installed : m_Available; | ||
const BOOL IncludeAll = UseInstalled ? (Type == ENUM_ALL_INSTALLED) : (Type == ENUM_ALL_AVAILABLE); | ||
|
||
POSITION CurrentListPosition = list.GetHeadPosition(); | ||
while (CurrentListPosition) | ||
{ | ||
CApplicationInfo *Info = list.GetNext(CurrentListPosition); | ||
|
||
if (IncludeAll || Type == Info->iCategory) | ||
{ | ||
List.AddTail(Info); | ||
} | ||
} | ||
} | ||
|
||
BOOL | ||
CApplicationDB::EnumerateFiles() | ||
{ | ||
ClearList(m_Available); | ||
|
||
CPathW AppsPath = m_BasePath; | ||
AppsPath += L"rapps"; | ||
CPathW WildcardPath = AppsPath; | ||
WildcardPath += L"*.txt"; | ||
|
||
WIN32_FIND_DATAW FindFileData; | ||
HANDLE hFind = FindFirstFileW(WildcardPath, &FindFileData); | ||
if (hFind == INVALID_HANDLE_VALUE) | ||
{ | ||
return FALSE; | ||
} | ||
|
||
do | ||
{ | ||
CStringW szPkgName = FindFileData.cFileName; | ||
PathRemoveExtensionW(szPkgName.GetBuffer(MAX_PATH)); | ||
szPkgName.ReleaseBuffer(); | ||
|
||
CApplicationInfo *Info = FindByPackageName(szPkgName); | ||
ATLASSERT(Info == NULL); | ||
if (!Info) | ||
{ | ||
CConfigParser *Parser = new CConfigParser(FindFileData.cFileName); | ||
int Cat; | ||
if (!Parser->GetInt(L"Category", Cat)) | ||
Cat = ENUM_INVALID; | ||
|
||
Info = new CAvailableApplicationInfo(Parser, szPkgName, static_cast<AppsCategories>(Cat), AppsPath); | ||
if (Info->Valid()) | ||
{ | ||
m_Available.AddTail(Info); | ||
} | ||
else | ||
{ | ||
delete Info; | ||
} | ||
} | ||
|
||
} while (FindNextFileW(hFind, &FindFileData)); | ||
|
||
FindClose(hFind); | ||
return TRUE; | ||
} | ||
|
||
VOID | ||
CApplicationDB::UpdateAvailable() | ||
{ | ||
if (!CreateDirectoryW(m_BasePath, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) | ||
return; | ||
|
||
if (EnumerateFiles()) | ||
return; | ||
|
||
DownloadApplicationsDB( | ||
SettingsInfo.bUseSource ? SettingsInfo.szSourceURL : APPLICATION_DATABASE_URL, !SettingsInfo.bUseSource); | ||
|
||
CPathW AppsPath = m_BasePath; | ||
AppsPath += L"rapps"; | ||
if (!ExtractFilesFromCab(APPLICATION_DATABASE_NAME, m_BasePath, AppsPath)) | ||
return; | ||
|
||
CPathW CabFile = m_BasePath; | ||
CabFile += APPLICATION_DATABASE_NAME; | ||
DeleteFileW(CabFile); | ||
|
||
EnumerateFiles(); | ||
} | ||
|
||
VOID | ||
CApplicationDB::UpdateInstalled() | ||
{ | ||
// Remove all old entries | ||
ClearList(m_Installed); | ||
|
||
int LoopKeys = 2; | ||
|
||
if (IsSystem64Bit()) | ||
{ | ||
// loop for all 3 combination. | ||
// note that HKEY_CURRENT_USER\Software don't have a redirect | ||
// https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys#redirected-shared-and-reflected-keys-under-wow64 | ||
LoopKeys = 3; | ||
} | ||
|
||
for (int keyIndex = 0; keyIndex < LoopKeys; keyIndex++) | ||
{ | ||
LONG ItemIndex = 0; | ||
WCHAR szKeyName[MAX_PATH]; | ||
|
||
CRegKey hKey; | ||
if (hKey.Open(g_RootKeyEnum[keyIndex], UNINSTALL_SUBKEY, KEY_READ | g_RegSamEnum[keyIndex]) != ERROR_SUCCESS) | ||
{ | ||
continue; | ||
} | ||
|
||
while (1) | ||
{ | ||
DWORD dwSize = _countof(szKeyName); | ||
if (hKey.EnumKey(ItemIndex, szKeyName, &dwSize) != ERROR_SUCCESS) | ||
{ | ||
break; | ||
} | ||
|
||
ItemIndex++; | ||
|
||
CRegKey hSubKey; | ||
if (hSubKey.Open(hKey, szKeyName, KEY_READ) == ERROR_SUCCESS) | ||
{ | ||
DWORD dwValue = 0; | ||
|
||
dwSize = sizeof(DWORD); | ||
if (RegQueryValueExW(hSubKey, L"SystemComponent", NULL, NULL, (LPBYTE)&dwValue, &dwSize) == | ||
ERROR_SUCCESS && | ||
dwValue == 1) | ||
{ | ||
// Ignore system components | ||
continue; | ||
} | ||
|
||
BOOL bIsUpdate = | ||
(RegQueryValueExW(hSubKey, L"ParentKeyName", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS); | ||
|
||
CInstalledApplicationInfo *Info = new CInstalledApplicationInfo( | ||
hSubKey.Detach(), szKeyName, bIsUpdate ? ENUM_UPDATES : ENUM_INSTALLED_APPLICATIONS, keyIndex); | ||
|
||
if (Info->Valid()) | ||
{ | ||
m_Installed.AddTail(Info); | ||
} | ||
else | ||
{ | ||
delete Info; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
static void | ||
DeleteWithWildcard(const CPathW &Dir, const CStringW &Filter) | ||
{ | ||
HANDLE hFind = INVALID_HANDLE_VALUE; | ||
WIN32_FIND_DATAW FindFileData; | ||
|
||
CPathW DirWithFilter = Dir; | ||
DirWithFilter += Filter; | ||
|
||
hFind = FindFirstFileW(DirWithFilter, &FindFileData); | ||
|
||
if (hFind == INVALID_HANDLE_VALUE) | ||
return; | ||
|
||
do | ||
{ | ||
CPathW szTmp = Dir; | ||
szTmp += FindFileData.cFileName; | ||
|
||
if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) | ||
{ | ||
DeleteFileW(szTmp); | ||
} | ||
} while (FindNextFileW(hFind, &FindFileData) != 0); | ||
FindClose(hFind); | ||
} | ||
|
||
VOID | ||
CApplicationDB::RemoveCached() | ||
{ | ||
// Delete icons | ||
CPathW AppsPath = m_BasePath; | ||
AppsPath += L"rapps"; | ||
CPathW IconPath = AppsPath; | ||
IconPath += L"icons"; | ||
DeleteWithWildcard(IconPath, L"*.ico"); | ||
|
||
// Delete leftover screenshots | ||
CPathW ScrnshotFolder = AppsPath; | ||
ScrnshotFolder += L"screenshots"; | ||
DeleteWithWildcard(ScrnshotFolder, L"*.tmp"); | ||
|
||
// Delete data base files (*.txt) | ||
DeleteWithWildcard(AppsPath, L"*.txt"); | ||
|
||
RemoveDirectoryW(IconPath); | ||
RemoveDirectoryW(ScrnshotFolder); | ||
RemoveDirectoryW(AppsPath); | ||
RemoveDirectoryW(m_BasePath); | ||
} | ||
|
||
BOOL | ||
CApplicationDB::RemoveInstalledAppFromRegistry(const CApplicationInfo *Info) | ||
{ | ||
// Validate that this is actually an installed app / update | ||
ATLASSERT(Info->iCategory == ENUM_INSTALLED_APPLICATIONS || Info->iCategory == ENUM_UPDATES); | ||
if (Info->iCategory != ENUM_INSTALLED_APPLICATIONS && Info->iCategory != ENUM_UPDATES) | ||
return FALSE; | ||
|
||
// Grab the index in the registry keys | ||
const CInstalledApplicationInfo *InstalledInfo = static_cast<const CInstalledApplicationInfo *>(Info); | ||
ATLASSERT(InstalledInfo->iKeyIndex >= 0 && InstalledInfo->iKeyIndex < (int)_countof(g_RootKeyEnum)); | ||
if (InstalledInfo->iKeyIndex < 0 && InstalledInfo->iKeyIndex >= (int)_countof(g_RootKeyEnum)) | ||
return FALSE; | ||
|
||
int keyIndex = InstalledInfo->iKeyIndex; | ||
|
||
// Grab the registry key name | ||
CStringW Name = InstalledInfo->szIdentifier; | ||
|
||
// Recursively delete this key | ||
CRegKey Uninstall; | ||
if (Uninstall.Open(g_RootKeyEnum[keyIndex], UNINSTALL_SUBKEY, KEY_READ | KEY_WRITE | g_RegSamEnum[keyIndex]) != | ||
ERROR_SUCCESS) | ||
return FALSE; | ||
|
||
return Uninstall.RecurseDeleteKey(Name) == ERROR_SUCCESS; | ||
} |
Oops, something went wrong.