Browse Source

Improve installer process handling.

(cherry picked from commit ad728785ba31b02ad4d518ec4f9a6508ca27b96d)
hoikas/newpatcher-1
Adam Johnson 5 years ago committed by rarified
parent
commit
115d308d10
  1. 94
      MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp

94
MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp

@ -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;
}
}
//============================================================================

Loading…
Cancel
Save