[RAPPS] Add ExeInZip installer type to support running installers in zip files (#7866)

This commit is contained in:
Whindmar Saksit 2025-04-29 15:39:22 +02:00 committed by GitHub
parent eb91f91569
commit 37e2c59096
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 111 additions and 25 deletions

View file

@ -11,6 +11,7 @@
#include "appdb.h" #include "appdb.h"
#include "configparser.h" #include "configparser.h"
#include "settings.h" #include "settings.h"
#include "misc.h"
static HKEY g_RootKeyEnum[3] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE}; static HKEY g_RootKeyEnum[3] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE};
@ -34,6 +35,14 @@ CAppDB::CAppDB(const CStringW &path) : m_BasePath(path)
m_BasePath.Canonicalize(); m_BasePath.Canonicalize();
} }
CStringW
CAppDB::GetDefaultPath()
{
CStringW path;
GetStorageDirectory(path);
return path;
}
CAvailableApplicationInfo * CAvailableApplicationInfo *
CAppDB::FindAvailableByPackageName(const CStringW &name) CAppDB::FindAvailableByPackageName(const CStringW &name)
{ {

View file

@ -380,10 +380,11 @@ CAvailableApplicationInfo::GetInstallerType() const
{ {
CStringW str; CStringW str;
m_Parser->GetString(DB_INSTALLER, str); m_Parser->GetString(DB_INSTALLER, str);
if (str.CompareNoCase(DB_GENINSTSECTION) == 0) if (str.CompareNoCase(DB_INSTALLER_GENERATE) == 0)
return INSTALLER_GENERATE; return INSTALLER_GENERATE;
else if (str.CompareNoCase(DB_INSTALLER_EXEINZIP) == 0)
return INSTALLER_UNKNOWN; return INSTALLER_EXEINZIP;
return INSTALLER_UNKNOWN;
} }
BOOL BOOL

View file

@ -60,7 +60,7 @@ BOOL IsZipFile(PCWSTR Path)
static int static int
ExtractFilesFromZip(LPCWSTR Archive, const CStringW &OutputDir, ExtractFilesFromZip(LPCWSTR Archive, const CStringW &OutputDir,
EXTRACTCALLBACK Callback, void *Cookie) EXTRACTCALLBACK Callback, void *Context)
{ {
const UINT pkzefsutf8 = 1 << 11; // APPNOTE; APPENDIX D const UINT pkzefsutf8 = 1 << 11; // APPNOTE; APPENDIX D
zlib_filefunc64_def zff; zlib_filefunc64_def zff;
@ -97,7 +97,7 @@ ExtractFilesFromZip(LPCWSTR Archive, const CStringW &OutputDir,
fileatt = LOBYTE(fi.external_fa); fileatt = LOBYTE(fi.external_fa);
if (!NotifyFileExtractCallback(path, fi.uncompressed_size, fileatt, if (!NotifyFileExtractCallback(path, fi.uncompressed_size, fileatt,
Callback, Cookie)) Callback, Context))
continue; // Skip file continue; // Skip file
path = BuildPath(OutputDir, path); path = BuildPath(OutputDir, path);
@ -136,22 +136,31 @@ ExtractFilesFromZip(LPCWSTR Archive, const CStringW &OutputDir,
static UINT static UINT
ExtractZip(LPCWSTR Archive, const CStringW &OutputDir, ExtractZip(LPCWSTR Archive, const CStringW &OutputDir,
EXTRACTCALLBACK Callback, void *Cookie) EXTRACTCALLBACK Callback, void *Context)
{ {
int zerr = ExtractFilesFromZip(Archive, OutputDir, Callback, Cookie); int zerr = ExtractFilesFromZip(Archive, OutputDir, Callback, Context);
return zerr == UNZ_ERRNO ? GetLastError() : zerr ? ERROR_INTERNAL_ERROR : 0; return zerr == UNZ_ERRNO ? GetLastError() : zerr ? ERROR_INTERNAL_ERROR : 0;
} }
static UINT static UINT
ExtractCab(LPCWSTR Archive, const CStringW &OutputDir, ExtractCab(LPCWSTR Archive, const CStringW &OutputDir,
EXTRACTCALLBACK Callback, void *Cookie) EXTRACTCALLBACK Callback, void *Context)
{ {
if (ExtractFilesFromCab(Archive, OutputDir, Callback, Cookie)) if (ExtractFilesFromCab(Archive, OutputDir, Callback, Context))
return ERROR_SUCCESS; return ERROR_SUCCESS;
UINT err = GetLastError(); UINT err = GetLastError();
return err ? err : ERROR_INTERNAL_ERROR; return err ? err : ERROR_INTERNAL_ERROR;
} }
static UINT
ExtractArchive(LPCWSTR Archive, const CStringW &OutputDir, EXTRACTCALLBACK Callback, void *Context)
{
BOOL isCab = LOBYTE(ClassifyFile(Archive)) == 'C';
return isCab ? ExtractCab(Archive, OutputDir, Callback, Context)
: ExtractZip(Archive, OutputDir, Callback, Context);
}
enum { IM_STARTPROGRESS = WM_APP, IM_PROGRESS, IM_END }; enum { IM_STARTPROGRESS = WM_APP, IM_PROGRESS, IM_END };
static struct CommonInfo static struct CommonInfo
@ -430,9 +439,9 @@ AddUninstallOperationsFromDB(LPCWSTR Name, WCHAR UnOp, CStringW PathPrefix = CSt
} }
static BOOL CALLBACK static BOOL CALLBACK
ExtractCallback(const EXTRACTCALLBACKINFO &, void *Cookie) ExtractCallback(const EXTRACTCALLBACKINFO &, void *Context)
{ {
InstallInfo &Info = *(InstallInfo *) Cookie; InstallInfo &Info = *(InstallInfo *)Context;
Info.Count += 1; Info.Count += 1;
return TRUE; return TRUE;
} }
@ -501,11 +510,7 @@ ExtractAndInstallThread(LPVOID Parameter)
ErrorBox(Info.Error); ErrorBox(Info.Error);
if (!Info.Error) if (!Info.Error)
{ Info.Error = ExtractArchive(Archive, tempdir, ExtractCallback, &Info);
BOOL isCab = LOBYTE(ClassifyFile(tempdir)) == 'C';
Info.Error = isCab ? ExtractCab(Archive, tempdir, ExtractCallback, &Info)
: ExtractZip(Archive, tempdir, ExtractCallback, &Info);
}
if (!Info.Error) if (!Info.Error)
{ {
@ -835,3 +840,46 @@ UninstallGenerated(CInstalledApplicationInfo &AppInfo, UninstallCommandFlags Fla
g_pInfo = &Info; g_pInfo = &Info;
return CreateUI(Info.Silent, UninstallThread) ? !Info.Error : FALSE; return CreateUI(Info.Silent, UninstallThread) ? !Info.Error : FALSE;
} }
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);
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());
TempDir = BuildPath(TempDirBuf, UniqueDir);
HRESULT hr = HResultFromWin32(CreateDirectoryTree(TempDir));
if (FAILED(hr))
return hr;
hr = HResultFromWin32(ExtractArchive(pszArchive, TempDir, NULL, NULL));
if (SUCCEEDED(hr))
{
CStringW Exe;
if (pCfg->GetSectionString(DB_EXEINZIPSECTION, DB_EXEINZIP_EXE, Exe) <= 0)
{
WIN32_FIND_DATAW wfd;
HANDLE hFind = FindFirstFileW(Exe = BuildPath(TempDir, L"*.exe"), &wfd);
if (hFind != INVALID_HANDLE_VALUE)
{
FindClose(hFind);
Exe = wfd.cFileName;
}
}
App = BuildPath(TempDir, Exe);
if (GetFileAttributesW(App) & FILE_ATTRIBUTE_DIRECTORY)
hr = HResultFromWin32(ERROR_FILE_NOT_FOUND);
}
if (FAILED(hr) && !TempDir.IsEmpty())
DeleteDirectoryTree(TempDir, hMainWnd);
return hr;
}

View file

@ -23,6 +23,9 @@ class CAppDB
public: public:
CAppDB(const CStringW &path); CAppDB(const CStringW &path);
static CStringW
GetDefaultPath();
VOID VOID
GetApps(CAtlList<CAppInfo *> &List, AppsCategories Type) const; GetApps(CAtlList<CAppInfo *> &List, AppsCategories Type) const;
CAvailableApplicationInfo * CAvailableApplicationInfo *

View file

@ -83,6 +83,7 @@ enum InstallerType
{ {
INSTALLER_UNKNOWN, INSTALLER_UNKNOWN,
INSTALLER_GENERATE, // .zip file automatically converted to installer by rapps INSTALLER_GENERATE, // .zip file automatically converted to installer by rapps
INSTALLER_EXEINZIP,
}; };
#define DB_VERSION L"Version" #define DB_VERSION L"Version"
@ -90,12 +91,17 @@ enum InstallerType
#define DB_PUBLISHER L"Publisher" #define DB_PUBLISHER L"Publisher"
#define DB_REGNAME L"RegName" #define DB_REGNAME L"RegName"
#define DB_INSTALLER L"Installer" #define DB_INSTALLER L"Installer"
#define DB_INSTALLER_GENERATE L"Generate"
#define DB_INSTALLER_EXEINZIP L"ExeInZip"
#define DB_SCOPE L"Scope" // User or Machine #define DB_SCOPE L"Scope" // User or Machine
#define DB_SAVEAS L"SaveAs" #define DB_SAVEAS L"SaveAs"
#define DB_GENINSTSECTION L"Generate" #define DB_GENINSTSECTION L"Generate"
#define GENERATE_ARPSUBKEY L"RApps" // Our uninstall data is stored here #define GENERATE_ARPSUBKEY L"RApps" // Our uninstall data is stored here
#define DB_EXEINZIPSECTION L"ExeInZip"
#define DB_EXEINZIP_EXE L"Exe"
class CAppRichEdit; class CAppRichEdit;
class CConfigParser; class CConfigParser;
@ -234,3 +240,5 @@ BOOL
UninstallGenerated(CInstalledApplicationInfo &AppInfo, UninstallCommandFlags Flags); UninstallGenerated(CInstalledApplicationInfo &AppInfo, UninstallCommandFlags Flags);
BOOL BOOL
ExtractAndRunGeneratedInstaller(const CAvailableApplicationInfo &AppInfo, LPCWSTR Archive); ExtractAndRunGeneratedInstaller(const CAvailableApplicationInfo &AppInfo, LPCWSTR Archive);
HRESULT
ExtractArchiveForExecution(PCWSTR pszArchive, const CStringW &PackageName, CStringW &TempDir, CStringW &App);

View file

@ -16,6 +16,12 @@
#define CurrentArchitecture L"ppc" #define CurrentArchitecture L"ppc"
#endif #endif
static inline HRESULT
HResultFromWin32(UINT Error)
{
return HRESULT_FROM_WIN32(Error);
}
static inline UINT static inline UINT
ErrorFromHResult(HRESULT hr) ErrorFromHResult(HRESULT hr)
{ {

View file

@ -1058,10 +1058,8 @@ run:
// run it // run it
if (Info.DLType == DLTYPE_APPLICATION) if (Info.DLType == DLTYPE_APPLICATION)
{ {
CStringW app, params; CStringW app, params, tempdir;
SHELLEXECUTEINFOW shExInfo = {0}; SHELLEXECUTEINFOW shExInfo = { sizeof(shExInfo), SEE_MASK_NOCLOSEPROCESS, hDlg };
shExInfo.cbSize = sizeof(shExInfo);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExInfo.lpVerb = L"open"; shExInfo.lpVerb = L"open";
shExInfo.lpFile = Path; shExInfo.lpFile = Path;
shExInfo.lpParameters = L""; shExInfo.lpParameters = L"";
@ -1077,6 +1075,16 @@ run:
GetModuleFileNameW(NULL, const_cast<LPWSTR>(shExInfo.lpFile), MAX_PATH); GetModuleFileNameW(NULL, const_cast<LPWSTR>(shExInfo.lpFile), MAX_PATH);
app.ReleaseBuffer(); app.ReleaseBuffer();
} }
else if (Info.IType == INSTALLER_EXEINZIP)
{
HRESULT hr = ExtractArchiveForExecution(Path, Info.szPackageName, tempdir, app);
if (FAILED(hr))
{
ShowLastError(hDlg, FALSE, hr);
goto end;
}
shExInfo.lpFile = app;
}
/* FIXME: Do we want to log installer status? */ /* FIXME: Do we want to log installer status? */
WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, Info.szName); WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, Info.szName);
@ -1102,6 +1110,11 @@ run:
{ {
ShowLastError(hMainWnd, FALSE, GetLastError()); ShowLastError(hMainWnd, FALSE, GetLastError());
} }
if (!tempdir.IsEmpty())
{
DeleteDirectoryTree(tempdir, hDlg);
}
} }
end: end:
@ -1117,8 +1130,8 @@ end:
if (bCancelled || (SettingsInfo.bDelInstaller && Info.DLType == DLTYPE_APPLICATION)) if (bCancelled || (SettingsInfo.bDelInstaller && Info.DLType == DLTYPE_APPLICATION))
{ {
// Don't delete .zip/.cab files so the user can extract from them // Don't delete .zip/.cab files so the user can extract from them
if (bCancelled || Info.IType == INSTALLER_GENERATE || !OpensWithExplorer(Path) || if (bCancelled || Info.IType == INSTALLER_GENERATE || Info.IType == INSTALLER_EXEINZIP ||
HIBYTE(ClassifyFile(Path)) != PERCEIVED_TYPE_COMPRESSED) !OpensWithExplorer(Path) || HIBYTE(ClassifyFile(Path)) != PERCEIVED_TYPE_COMPRESSED)
{ {
DeleteFileW(Path); DeleteFileW(Path);
} }

View file

@ -331,9 +331,7 @@ ParseCmdAndExecute(LPWSTR lpCmdLine, BOOL bIsFirstLaunch, int nCmdShow)
if (!argv) if (!argv)
return FALSE; return FALSE;
CStringW Directory; CAppDB db(CAppDB::GetDefaultPath());
GetStorageDirectory(Directory);
CAppDB db(Directory);
BOOL bAppwizMode = (argc > 1 && MatchCmdOption(argv[1], CMD_KEY_APPWIZ)); BOOL bAppwizMode = (argc > 1 && MatchCmdOption(argv[1], CMD_KEY_APPWIZ));
if (!bAppwizMode) if (!bAppwizMode)