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
|
#define PATCHER_FLAG_INSTALLER 0x10
|
||||||
|
|
||||||
|
typedef bool(*FVerifyReturnCode)(DWORD);
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* Private Data
|
* Private Data
|
||||||
@ -144,9 +146,12 @@ class plSelfPatcher : public hsThread
|
|||||||
void IDownloadFile(PatcherWork*& wk);
|
void IDownloadFile(PatcherWork*& wk);
|
||||||
void IVerifyFile(PatcherWork*& wk);
|
void IVerifyFile(PatcherWork*& wk);
|
||||||
void IIssueManifestRequest(PatcherWork*& wk);
|
void IIssueManifestRequest(PatcherWork*& wk);
|
||||||
|
|
||||||
HANDLE ICreateProcess(const wchar* path, const wchar* args, bool forceShell=false) const;
|
HANDLE ICreateProcess(const wchar* path, const wchar* args, bool forceShell=false) const;
|
||||||
void IInstallDep(PatcherWork*& wk);
|
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 IRun();
|
||||||
void IQuit();
|
void IQuit();
|
||||||
@ -516,7 +521,7 @@ HANDLE plSelfPatcher::ICreateProcess(const wchar* path, const wchar* args, bool
|
|||||||
si.cb = sizeof(si);
|
si.cb = sizeof(si);
|
||||||
|
|
||||||
wchar cmdline[MAX_PATH];
|
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,
|
BOOL result = CreateProcessW(path,
|
||||||
cmdline,
|
cmdline,
|
||||||
NULL,
|
NULL,
|
||||||
@ -576,12 +581,16 @@ void plSelfPatcher::IInstallDep(PatcherWork*& wk)
|
|||||||
SetText("Installing updates...");
|
SetText("Installing updates...");
|
||||||
AsyncSleep(100);
|
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* extension = PathFindExtension(wk->fFileName);
|
||||||
wchar* process;
|
|
||||||
wchar args[MAX_PATH];
|
wchar args[MAX_PATH];
|
||||||
args[0] = 0;
|
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
|
// 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.
|
// 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.
|
// 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"))
|
if (StrStrI(filename, L"vcredist"))
|
||||||
StrPack(args, L" /norestart", arrsize(args));
|
StrPack(args, L" /norestart", arrsize(args));
|
||||||
process = wk->fFileName;
|
validateptr = IValidateExeReturnCode;
|
||||||
} else if (extension && StrCmpI(extension, L".msi") == 0) {
|
} else if (extension && StrCmpI(extension, L".msi") == 0) {
|
||||||
StrPrintf(args, arrsize(args), L"/i %s /qr /norestart", wk->fFileName);
|
StrPrintf(args, arrsize(args), L"/i \"%s\" /qr /norestart", process);
|
||||||
process = L"msiexec";
|
StrCopy(process, L"msiexec", arrsize(process));
|
||||||
|
validateptr = IValidateMsiReturnCode;
|
||||||
forceShell = true;
|
forceShell = true;
|
||||||
} else {
|
} else {
|
||||||
LogMsg(kLogError, L"plSelfPatcher::IInstallDep: Invalid extension '%s' for installer '%s'",
|
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);
|
LogMsg(kLogDebug, L"plSelfPatcher::IInstallDep: Installing '%s %s'.", process, args);
|
||||||
HANDLE hProcess = ICreateProcess(process, args, forceShell);
|
HANDLE hProcess = ICreateProcess(process, args, forceShell);
|
||||||
if (hProcess) {
|
if (hProcess) {
|
||||||
if (IWaitProcess(hProcess) != ERROR_SUCCESS)
|
if (IWaitProcess(hProcess, validateptr)) {
|
||||||
|
IDequeueWork(wk);
|
||||||
|
} else {
|
||||||
PathDeleteFile(wk->fFileName);
|
PathDeleteFile(wk->fFileName);
|
||||||
|
IFatalError(L"Failed to install update.");
|
||||||
|
}
|
||||||
CloseHandle(hProcess);
|
CloseHandle(hProcess);
|
||||||
IDequeueWork(wk);
|
|
||||||
} else {
|
} else {
|
||||||
IFatalError(L"Failed to run installer.");
|
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
|
// 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
|
// 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
|
// 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) {
|
if (quitWk->fType == kQuit) {
|
||||||
LogMsg(kLogPerf, "plSelfPatcher::IWaitProcess: Got shutdown during wait, attempting to terminate process.");
|
LogMsg(kLogPerf, "plSelfPatcher::IWaitProcess: Got shutdown during wait, attempting to terminate process.");
|
||||||
TerminateProcess(hProcess, 1);
|
TerminateProcess(hProcess, 1);
|
||||||
returncode = -1;
|
return false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else if (idx == kWaitProcess) {
|
} else if (idx == kWaitProcess) {
|
||||||
GetExitCodeProcess(hProcess, &returncode);
|
if (verify) {
|
||||||
switch (returncode) {
|
DWORD returncode = 0;
|
||||||
case ERROR_SUCCESS:
|
GetExitCodeProcess(hProcess, &returncode);
|
||||||
case ERROR_PRODUCT_VERSION: // It's already installed...
|
return verify(returncode);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
break;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
FATAL("Invalid wait index");
|
FATAL("Invalid wait index");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else if (waitStatus == WAIT_FAILED) {
|
} else if (waitStatus == WAIT_FAILED) {
|
||||||
wchar* error = FormatSystemError();
|
wchar* error = FormatSystemError();
|
||||||
LogMsg(kLogError, "plSelfPatcher::IWaitProcess: WaitForMultipleObjects failed! %s", error);
|
LogMsg(kLogError, L"plSelfPatcher::IWaitProcess: WaitForMultipleObjects failed! %s", error);
|
||||||
LocalFree(error);
|
LocalFree(error);
|
||||||
IFatalError(L"Internal Error.");
|
IFatalError(L"Internal Error.");
|
||||||
returncode = -1;
|
return false;
|
||||||
break;
|
} else {
|
||||||
|
LogMsg(kLogError, "plSelfPatcher::IWaitProcess: Unhandled WaitForMultipleObjects result 0x%x", waitStatus);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncSleep(10);
|
AsyncSleep(10);
|
||||||
} while (1);
|
} 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