mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-20 04:09:16 +00:00
Improve installer process handling.
(cherry picked from commit ad728785ba31b02ad4d518ec4f9a6508ca27b96d)
This commit is contained in:
@ -54,6 +54,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
|
||||
#define PATCHER_FLAG_INSTALLER 0x10
|
||||
|
||||
typedef bool(*FVerifyReturnCode)(DWORD);
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private Data
|
||||
@ -144,9 +146,12 @@ class plSelfPatcher : public hsThread
|
||||
void IDownloadFile(PatcherWork*& wk);
|
||||
void IVerifyFile(PatcherWork*& wk);
|
||||
void IIssueManifestRequest(PatcherWork*& wk);
|
||||
|
||||
HANDLE ICreateProcess(const wchar* path, const wchar* args, bool forceShell=false) const;
|
||||
void IInstallDep(PatcherWork*& wk);
|
||||
DWORD IWaitProcess(HANDLE hProcess);
|
||||
bool IWaitProcess(HANDLE hProcess, FVerifyReturnCode verify);
|
||||
static bool IValidateExeReturnCode(DWORD returncode);
|
||||
static bool IValidateMsiReturnCode(DWORD returncode);
|
||||
|
||||
void IRun();
|
||||
void IQuit();
|
||||
@ -516,7 +521,7 @@ HANDLE plSelfPatcher::ICreateProcess(const wchar* path, const wchar* args, bool
|
||||
si.cb = sizeof(si);
|
||||
|
||||
wchar cmdline[MAX_PATH];
|
||||
StrPrintf(cmdline, arrsize(cmdline), L"%s %s", path, args);
|
||||
StrPrintf(cmdline, arrsize(cmdline), L"\"%s\" %s", path, args);
|
||||
BOOL result = CreateProcessW(path,
|
||||
cmdline,
|
||||
NULL,
|
||||
@ -576,12 +581,16 @@ void plSelfPatcher::IInstallDep(PatcherWork*& wk)
|
||||
SetText("Installing updates...");
|
||||
AsyncSleep(100);
|
||||
|
||||
bool forceShell = false;
|
||||
wchar process[MAX_PATH];
|
||||
PathGetCurrentDirectory(process, arrsize(process));
|
||||
PathAddFilename(process, process, wk->fFileName, arrsize(process));
|
||||
wchar* extension = PathFindExtension(wk->fFileName);
|
||||
wchar* process;
|
||||
wchar args[MAX_PATH];
|
||||
args[0] = 0;
|
||||
|
||||
bool forceShell = false;
|
||||
FVerifyReturnCode validateptr = NULL;
|
||||
|
||||
// Apply arguments to the process to ensure it doesn't do weird stuff like start a big UI
|
||||
// Creative OpenAL (oalinst.exe) uses '/s' for silent.
|
||||
// The small DirectX 9.0c web installer (dxwebsetup.exe) uses "/q" and pops up an error on invalid args.
|
||||
@ -599,10 +608,11 @@ void plSelfPatcher::IInstallDep(PatcherWork*& wk)
|
||||
|
||||
if (StrStrI(filename, L"vcredist"))
|
||||
StrPack(args, L" /norestart", arrsize(args));
|
||||
process = wk->fFileName;
|
||||
validateptr = IValidateExeReturnCode;
|
||||
} else if (extension && StrCmpI(extension, L".msi") == 0) {
|
||||
StrPrintf(args, arrsize(args), L"/i %s /qr /norestart", wk->fFileName);
|
||||
process = L"msiexec";
|
||||
StrPrintf(args, arrsize(args), L"/i \"%s\" /qr /norestart", process);
|
||||
StrCopy(process, L"msiexec", arrsize(process));
|
||||
validateptr = IValidateMsiReturnCode;
|
||||
forceShell = true;
|
||||
} else {
|
||||
LogMsg(kLogError, L"plSelfPatcher::IInstallDep: Invalid extension '%s' for installer '%s'",
|
||||
@ -614,20 +624,21 @@ void plSelfPatcher::IInstallDep(PatcherWork*& wk)
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::IInstallDep: Installing '%s %s'.", process, args);
|
||||
HANDLE hProcess = ICreateProcess(process, args, forceShell);
|
||||
if (hProcess) {
|
||||
if (IWaitProcess(hProcess) != ERROR_SUCCESS)
|
||||
if (IWaitProcess(hProcess, validateptr)) {
|
||||
IDequeueWork(wk);
|
||||
} else {
|
||||
PathDeleteFile(wk->fFileName);
|
||||
IFatalError(L"Failed to install update.");
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
IDequeueWork(wk);
|
||||
} else {
|
||||
IFatalError(L"Failed to run installer.");
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
DWORD plSelfPatcher::IWaitProcess(HANDLE hProcess)
|
||||
bool plSelfPatcher::IWaitProcess(HANDLE hProcess, FVerifyReturnCode verify)
|
||||
{
|
||||
DWORD returncode = ERROR_SUCCESS;
|
||||
|
||||
// Since we have taken over the worker thread, we need to listen for any very very important
|
||||
// requests added to the queue. The only one we care about is quit, the rest can just go to
|
||||
// HEY HEY! and we're safe to just swallow the notifies. We delete our own request to resume
|
||||
@ -647,41 +658,60 @@ DWORD plSelfPatcher::IWaitProcess(HANDLE hProcess)
|
||||
if (quitWk->fType == kQuit) {
|
||||
LogMsg(kLogPerf, "plSelfPatcher::IWaitProcess: Got shutdown during wait, attempting to terminate process.");
|
||||
TerminateProcess(hProcess, 1);
|
||||
returncode = -1;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
} else if (idx == kWaitProcess) {
|
||||
GetExitCodeProcess(hProcess, &returncode);
|
||||
switch (returncode) {
|
||||
case ERROR_SUCCESS:
|
||||
case ERROR_PRODUCT_VERSION: // It's already installed...
|
||||
case ERROR_SUCCESS_REBOOT_REQUIRED: // LMFTFY s/REQUIRED/DESIRED/
|
||||
case ERROR_SUCCESS_RESTART_REQUIRED:
|
||||
LogMsg(kLogDebug, "plSelfPatcher::IWaitProcess: Process finished successfully!");
|
||||
returncode = ERROR_SUCCESS; // makes life easier for us.
|
||||
break;
|
||||
default:
|
||||
LogMsg(kLogError, "plSelfPatcher::IWaitProcess: Process failed! Returncode: %u", returncode);
|
||||
IFatalError(L"Failed to install update.");
|
||||
break;
|
||||
if (verify) {
|
||||
DWORD returncode = 0;
|
||||
GetExitCodeProcess(hProcess, &returncode);
|
||||
return verify(returncode);
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
} else {
|
||||
FATAL("Invalid wait index");
|
||||
return false;
|
||||
}
|
||||
} else if (waitStatus == WAIT_FAILED) {
|
||||
wchar* error = FormatSystemError();
|
||||
LogMsg(kLogError, "plSelfPatcher::IWaitProcess: WaitForMultipleObjects failed! %s", error);
|
||||
LogMsg(kLogError, L"plSelfPatcher::IWaitProcess: WaitForMultipleObjects failed! %s", error);
|
||||
LocalFree(error);
|
||||
IFatalError(L"Internal Error.");
|
||||
returncode = -1;
|
||||
break;
|
||||
return false;
|
||||
} else {
|
||||
LogMsg(kLogError, "plSelfPatcher::IWaitProcess: Unhandled WaitForMultipleObjects result 0x%x", waitStatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncSleep(10);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
return returncode;
|
||||
//============================================================================
|
||||
bool plSelfPatcher::IValidateExeReturnCode(DWORD returncode)
|
||||
{
|
||||
if (returncode != 1) {
|
||||
LogMsg(kLogDebug, "plSelfPatcher::IValidateExeReturnCode: Process finished successfully! Returncode: %u", returncode);
|
||||
return true;
|
||||
} else {
|
||||
LogMsg(kLogError, "plSelfPatcher::IValidateExeReturnCode: Process failed! Returncode: %u", returncode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
bool plSelfPatcher::IValidateMsiReturnCode(DWORD returncode)
|
||||
{
|
||||
switch (returncode) {
|
||||
case ERROR_SUCCESS:
|
||||
case ERROR_PRODUCT_VERSION:
|
||||
case ERROR_SUCCESS_REBOOT_INITIATED:
|
||||
case ERROR_SUCCESS_REBOOT_REQUIRED:
|
||||
LogMsg(kLogDebug, "plSelfPatcher::IValidateMsiReturnCode: Process finished successfully!");
|
||||
return true;
|
||||
default:
|
||||
LogMsg(kLogError, "plSelfPatcher::IValidateMsiReturnCode: Process failed! Returncode: %u", returncode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
Reference in New Issue
Block a user