mirror of
https://github.com/reactos/reactos.git
synced 2026-06-08 17:02:56 +08:00
[RAPPS] Automatically install package dependencies (#8963)
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
static HKEY g_RootKeyEnum[3] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE};
|
||||
static REGSAM g_RegSamEnum[3] = {0, KEY_WOW64_32KEY, KEY_WOW64_64KEY};
|
||||
#define UNINSTALL_SUBKEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
|
||||
#define MANIFEST_DOTEXT L".txt"
|
||||
|
||||
static inline HKEY
|
||||
GetRootKeyInfo(UINT Index, REGSAM &RegSam)
|
||||
@@ -100,6 +101,24 @@ CAppDB::FindAvailableByPackageName(const CStringW &name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CAvailableApplicationInfo *
|
||||
CAppDB::CreateAvailableAppInstance(const CStringW &PkgName, PCWSTR DBPath)
|
||||
{
|
||||
CAvailableApplicationInfo *pAppInfo;
|
||||
CPathW AppsPath = DBPath ? CPathW(DBPath) : (CPathW(GetDefaultPath()) += RAPPS_DATABASE_SUBDIR);
|
||||
CPathW ManifestPath = CPathW(AppsPath) += PkgName + MANIFEST_DOTEXT;
|
||||
CConfigParser *Parser = new CConfigParser(ManifestPath);
|
||||
int Cat;
|
||||
if (!Parser->GetInt(DB_CATEGORY, Cat))
|
||||
Cat = ENUM_INVALID;
|
||||
|
||||
pAppInfo = new CAvailableApplicationInfo(Parser, PkgName, static_cast<AppsCategories>(Cat), AppsPath);
|
||||
if (pAppInfo->Valid())
|
||||
return pAppInfo;
|
||||
delete pAppInfo;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CAppDB::GetApps(CAtlList<CAppInfo *> &List, AppsCategories Type) const
|
||||
{
|
||||
@@ -127,7 +146,7 @@ CAppDB::EnumerateFiles()
|
||||
CPathW AppsPath = m_BasePath;
|
||||
AppsPath += RAPPS_DATABASE_SUBDIR;
|
||||
CPathW WildcardPath = AppsPath;
|
||||
WildcardPath += L"*.txt";
|
||||
WildcardPath += L"*" MANIFEST_DOTEXT;
|
||||
|
||||
WIN32_FIND_DATAW FindFileData;
|
||||
HANDLE hFind = FindFirstFileW(WildcardPath, &FindFileData);
|
||||
@@ -142,24 +161,13 @@ CAppDB::EnumerateFiles()
|
||||
PathRemoveExtensionW(szPkgName.GetBuffer(MAX_PATH));
|
||||
szPkgName.ReleaseBuffer();
|
||||
|
||||
CAppInfo *Info = FindByPackageName(szPkgName);
|
||||
CAppInfo *Info = FindAvailableByPackageName(szPkgName);
|
||||
ATLASSERT(Info == NULL);
|
||||
if (!Info)
|
||||
{
|
||||
CConfigParser *Parser = new CConfigParser(CPathW(AppsPath) += FindFileData.cFileName);
|
||||
int Cat;
|
||||
if (!Parser->GetInt(DB_CATEGORY, Cat))
|
||||
Cat = ENUM_INVALID;
|
||||
|
||||
Info = new CAvailableApplicationInfo(Parser, szPkgName, static_cast<AppsCategories>(Cat), AppsPath);
|
||||
if (Info->Valid())
|
||||
{
|
||||
Info = CreateAvailableAppInstance(szPkgName, AppsPath);
|
||||
if (Info)
|
||||
m_Available.AddTail(Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete Info;
|
||||
}
|
||||
}
|
||||
|
||||
} while (FindNextFileW(hFind, &FindFileData));
|
||||
@@ -330,7 +338,7 @@ CAppDB::RemoveCached()
|
||||
DeleteWithWildcard(ScrnshotFolder, L"*.tmp");
|
||||
|
||||
// Delete data base files (*.txt)
|
||||
DeleteWithWildcard(AppsPath, L"*.txt");
|
||||
DeleteWithWildcard(AppsPath, L"*" MANIFEST_DOTEXT);
|
||||
|
||||
RemoveDirectoryW(IconPath);
|
||||
RemoveDirectoryW(ScrnshotFolder);
|
||||
|
||||
@@ -120,6 +120,14 @@ CompareVersion(const CStringW &left, const CStringW &right)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CAvailableApplicationInfo::IsInstalled() const
|
||||
{
|
||||
CStringW szRegName;
|
||||
m_Parser->GetString(DB_REGNAME, szRegName);
|
||||
return ::GetInstalledVersion(NULL, szRegName) || ::GetInstalledVersion(NULL, szDisplayName);
|
||||
}
|
||||
|
||||
VOID
|
||||
CAvailableApplicationInfo::InsertVersionInfo(CAppRichEdit *RichEdit)
|
||||
{
|
||||
|
||||
@@ -850,13 +850,11 @@ HRESULT
|
||||
ExtractArchiveForExecution(PCWSTR pszArchive, const CStringW &PackageName, CStringW &TempDir, CStringW &App)
|
||||
{
|
||||
WCHAR TempDirBuf[MAX_PATH], UniqueDir[MAX_PATH];
|
||||
CAppDB db(CAppDB::GetDefaultPath());
|
||||
db.UpdateAvailable();
|
||||
CAvailableApplicationInfo *pAppInfo = db.FindAvailableByPackageName(PackageName);
|
||||
CAvailableApplicationInfo *pAppInfo = CAppDB::CreateAvailableAppInstance(PackageName);
|
||||
Deleter <CAvailableApplicationInfo*>del(pAppInfo);
|
||||
if (!pAppInfo)
|
||||
return HResultFromWin32(ERROR_NOT_FOUND);
|
||||
CConfigParser *pCfg = pAppInfo->GetConfigParser();
|
||||
|
||||
if (!GetTempPathW(_countof(TempDirBuf), TempDirBuf))
|
||||
return E_FAIL;
|
||||
wsprintfW(UniqueDir, L"~%s-%u", RAPPS_NAME, GetCurrentProcessId());
|
||||
|
||||
@@ -47,6 +47,8 @@ class CAppDB
|
||||
CreateInstalledAppByRegistryKey(LPCWSTR Name);
|
||||
static CInstalledApplicationInfo *
|
||||
CreateInstalledAppInstance(LPCWSTR KeyName, BOOL User, REGSAM WowSam);
|
||||
static CAvailableApplicationInfo *
|
||||
CreateAvailableAppInstance(const CStringW &PkgName, PCWSTR DBPath = NULL);
|
||||
|
||||
size_t GetAvailableCount() const
|
||||
{
|
||||
|
||||
@@ -99,6 +99,7 @@ enum InstallerType
|
||||
#define DB_SAVEAS L"SaveAs"
|
||||
#define DB_SILENTARGS L"SilentParameters"
|
||||
#define DB_NTVER L"NTVersion" // "Max-" || "Min-Max" || "Min" || "Min+"
|
||||
#define DB_DEPENDENCIES L"Dependencies"
|
||||
|
||||
#define DB_GENINSTSECTION L"Generate"
|
||||
#define GENERATE_ARPSUBKEY L"RApps" // Our uninstall data is stored here
|
||||
@@ -178,6 +179,8 @@ class CAvailableApplicationInfo : public CAppInfo
|
||||
|
||||
bool
|
||||
IsCompatible() const;
|
||||
bool
|
||||
IsInstalled() const;
|
||||
|
||||
virtual BOOL
|
||||
Valid() const override;
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
#define CurrentArchitecture L"ppc"
|
||||
#endif
|
||||
|
||||
template<class T> struct Deleter
|
||||
{
|
||||
Deleter(T ptr) : p(ptr) {}
|
||||
~Deleter () { delete p; }
|
||||
T p;
|
||||
};
|
||||
|
||||
static inline HRESULT
|
||||
HResultFromWin32(UINT Error)
|
||||
{
|
||||
@@ -46,6 +53,8 @@ UINT
|
||||
ClassifyFile(PCWSTR Path);
|
||||
BOOL
|
||||
OpensWithExplorer(PCWSTR Path);
|
||||
UINT
|
||||
WaitForProcess(HANDLE hProcess);
|
||||
BOOL
|
||||
StartProcess(const CStringW &Path, BOOL Wait);
|
||||
BOOL
|
||||
|
||||
@@ -149,7 +149,10 @@ struct DownloadInfo
|
||||
|
||||
CConfigParser *cfg = static_cast<const CAvailableApplicationInfo&>(AppInfo).GetConfigParser();
|
||||
if (cfg)
|
||||
{
|
||||
cfg->GetString(DB_SAVEAS, szFileName);
|
||||
cfg->GetString(DB_DEPENDENCIES, szDependencies);
|
||||
}
|
||||
}
|
||||
|
||||
bool Equal(const DownloadInfo &other) const
|
||||
@@ -167,6 +170,7 @@ struct DownloadInfo
|
||||
CStringW szPackageName;
|
||||
CStringW szFileName;
|
||||
CStringW szSilentInstallArgs;
|
||||
CStringW szDependencies;
|
||||
ULONG SizeInBytes;
|
||||
};
|
||||
|
||||
@@ -579,6 +583,30 @@ CDownloadManager::Add(const DownloadInfo &Info)
|
||||
if (Info.Equal(m_List[i]))
|
||||
return; // Already in the list
|
||||
}
|
||||
|
||||
if (!Info.szDependencies.IsEmpty())
|
||||
{
|
||||
CStringW deps = Info.szDependencies;
|
||||
for (int pos = 1; pos > 0; deps = deps.Mid(pos + 1))
|
||||
{
|
||||
pos = deps.Find(L'|');
|
||||
CStringW pkg = (pos > 0 ? deps.Left(pos) : deps).Trim();
|
||||
|
||||
// In the future a package might need to specify dependency version or WoW64
|
||||
// information ("vcredist*x64" etc), for now, just remove possible modifiers.
|
||||
int suffix = pkg.FindOneOf(L"*<=>:/\\?");
|
||||
if (suffix > 0)
|
||||
pkg = pkg.Left(suffix);
|
||||
|
||||
CAvailableApplicationInfo *pApp = CAppDB::CreateAvailableAppInstance(pkg);
|
||||
Deleter <CAvailableApplicationInfo*>del(pApp);
|
||||
if (!pApp || pApp->IsInstalled())
|
||||
continue;
|
||||
// Add the dependency before the application in the list
|
||||
Add(DownloadInfo(*pApp, DAF_SILENT));
|
||||
}
|
||||
}
|
||||
|
||||
m_List.Add(Info);
|
||||
if (m_hDlg)
|
||||
m_ListView.LoadList(m_List, start);
|
||||
|
||||
@@ -174,13 +174,36 @@ OpensWithExplorer(PCWSTR Path)
|
||||
return SUCCEEDED(hr) && !StrCmpIW(PathFindFileNameW(szCmd), L"explorer.exe"); // .cab
|
||||
}
|
||||
|
||||
UINT
|
||||
WaitForProcess(HANDLE hProcess)
|
||||
{
|
||||
DWORD code = STILL_ACTIVE;
|
||||
for (;;)
|
||||
{
|
||||
DWORD wait = MsgWaitForMultipleObjects(1, &hProcess, FALSE, INFINITE, QS_ALLEVENTS);
|
||||
if (wait == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: if (wait == WAIT_OBJECT_0) GetExitCodeProcess for MSI reboot codes
|
||||
break;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
BOOL
|
||||
StartProcess(const CStringW &Path, BOOL Wait)
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFOW si;
|
||||
DWORD dwRet;
|
||||
MSG msg;
|
||||
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
@@ -201,37 +224,16 @@ StartProcess(const CStringW &Path, BOOL Wait)
|
||||
if (Wait)
|
||||
{
|
||||
EnableWindow(hMainWnd, FALSE);
|
||||
}
|
||||
|
||||
while (Wait)
|
||||
{
|
||||
dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLEVENTS);
|
||||
if (dwRet == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
WaitForProcess(pi.hProcess);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
|
||||
if (Wait)
|
||||
{
|
||||
EnableWindow(hMainWnd, TRUE);
|
||||
SetForegroundWindow(hMainWnd);
|
||||
// We got the real activation message during MsgWaitForMultipleObjects while
|
||||
// we were disabled, we need to set the focus again now.
|
||||
SetFocus(hMainWnd);
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user