1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-20 04:09:16 +00:00

Redist Updating

This is the crowning feature: the whole point of this exercise. You can
now update redists from the client launcher itself. To activate this
functionality, you will need to flag the file 0x10 in the manifest. I
recommend listing your redists in the patcher manifests.
This commit is contained in:
2013-11-29 20:25:52 -05:00
parent d855d86475
commit 1bcd17c850
5 changed files with 219 additions and 45 deletions

View File

@ -52,6 +52,7 @@ Mead, WA 99021
#include "hsWindows.h"
#include "resource.h"
#include <commctrl.h>
#include <shellapi.h>
#include <shlobj.h>
// ===================================================
@ -207,6 +208,108 @@ static void IOnProgressTick(uint64_t curBytes, uint64_t totalBytes, const plStri
// ===================================================
static void ISetDownloadStatus(const plString& status)
{
SetDlgItemTextW(s_dialog, IDC_TEXT, status.ToWchar());
// consider this a reset of the download status...
IShowMarquee();
SetDlgItemTextW(s_dialog, IDC_DLSIZE, L"");
SetDlgItemTextW(s_dialog, IDC_DLSPEED, L"");
if (s_taskbar)
s_taskbar->SetProgressState(s_dialog, TBPF_INDETERMINATE);
}
static HANDLE ICreateProcess(const plFileName& exe, const plString& args)
{
STARTUPINFOW si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
// Create wchar things and stuff :/
plString cmd = plString::Format("%s %s", exe.AsString().c_str(), args.c_str());
plStringBuffer<wchar_t> file = exe.AsString().ToWchar();
plStringBuffer<wchar_t> params = cmd.ToWchar();
// Guess what? CreateProcess isn't smart enough to throw up an elevation dialog... We need ShellExecute for that.
// But guess what? ShellExecute won't run ".exe.tmp" files. GAAAAAAAAHHHHHHHHH!!!!!!!
BOOL result = CreateProcessW(
file,
const_cast<wchar_t*>(params.GetData()),
nullptr,
nullptr,
FALSE,
DETACHED_PROCESS,
nullptr,
nullptr,
&si,
&pi
);
// So maybe it needs elevation... Or maybe everything arseploded.
if (result != FALSE) {
CloseHandle(pi.hThread);
return pi.hProcess;
} else if (GetLastError() == ERROR_ELEVATION_REQUIRED) {
SHELLEXECUTEINFOW info;
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.lpFile = file.GetData();
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC;
info.lpParameters = args.ToWchar();
hsAssert(ShellExecuteExW(&info), "ShellExecuteExW phailed");
return info.hProcess;
} else {
wchar_t buf[2048];
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
GetLastError(),
LANG_USER_DEFAULT,
buf,
arrsize(buf),
nullptr
);
hsMessageBox(buf, L"Error", hsMessageBoxNormal, hsMessageBoxIconError);
}
return nullptr;
}
static bool IInstallRedist(const plFileName& exe)
{
ISetDownloadStatus(plString::Format("Installing... %s", exe.AsString().c_str()));
Sleep(2500); // let's Sleep for a bit so the user can see that we're doing something before the UAC dialog pops up!
// Try to guess some arguments... Unfortunately, the file manifest format is fairly immutable.
plStringStream ss;
if (exe.AsString().CompareI("oalinst.exe") == 0)
ss << "/s"; // rarg nonstandard
else
ss << "/q";
if (exe.AsString().Find("vcredist", plString::kCaseInsensitive) != -1)
ss << " /norestart"; // I don't want to image the accusations of viruses and hacking if this happened...
// Now fire up the process...
HANDLE process = ICreateProcess(exe, ss.GetString());
if (process) {
WaitForSingleObject(process, INFINITE);
// Get the exit code so we can indicate success/failure to the redist thread
DWORD code = PLASMA_OK;
hsAssert(GetExitCodeProcess(process, &code), "failed to get redist exit code");
CloseHandle(process);
return code != PLASMA_PHAILURE;
}
return PLASMA_PHAILURE;
}
static void ILaunchClientExecutable(const plFileName& exe, const plString& args)
{
// Once we start launching something, we no longer need to trumpet any taskbar status
@ -216,38 +319,16 @@ static void ILaunchClientExecutable(const plFileName& exe, const plString& args)
// Only launch a client executable if we're given one. If not, that's probably a cue that we're
// done with some service operation and need to go away.
if (!exe.AsString().IsEmpty()) {
STARTUPINFOW si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
// This event will prevent the game from restarting the patcher
HANDLE hEvent = CreateEventW(nullptr, TRUE, FALSE, L"UruPatcherEvent");
// Fire up ye olde new process
plString cmd = plString::Format("%s %s", exe.AsString().c_str(), args.c_str());
CreateProcessW(
exe.AsString().ToWchar(),
const_cast<wchar_t*>(cmd.ToWchar().GetData()), // windows claims that it may modify this... let's hope that doesn't happen.
nullptr,
nullptr,
FALSE,
DETACHED_PROCESS,
nullptr,
plFileSystem::GetCWD().AsString().ToWchar(),
&si,
&pi
);
HANDLE process = ICreateProcess(exe, args);
// if this is the real game client, then we need to make sure it gets this event...
if (plManifest::ClientExecutable().AsString().CompareI(exe.AsString()) == 0) {
WaitForInputIdle(pi.hProcess, 1000);
WaitForInputIdle(process, 1000);
WaitForSingleObject(hEvent, INFINITE);
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(process);
CloseHandle(hEvent);
}
@ -265,19 +346,6 @@ static void IOnNetError(ENetError result, const plString& msg)
IQuit(PLASMA_PHAILURE);
}
static void ISetDownloadStatus(const plString& status)
{
SetDlgItemTextW(s_dialog, IDC_TEXT, status.ToWchar());
// consider this a reset of the download status...
IShowMarquee();
SetDlgItemTextW(s_dialog, IDC_DLSIZE, L"");
SetDlgItemTextW(s_dialog, IDC_DLSPEED, L"");
if (s_taskbar)
s_taskbar->SetProgressState(s_dialog, TBPF_INDETERMINATE);
}
static void ISetShardStatus(const plString& status)
{
SetDlgItemTextW(s_dialog, IDC_STATUS_TEXT, status.ToWchar());
@ -299,6 +367,7 @@ int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL
// Let's initialize our plClientLauncher friend
s_launcher.ParseArguments();
s_launcher.SetErrorProc(IOnNetError);
s_launcher.SetInstallerProc(IInstallRedist);
s_launcher.SetLaunchClientProc(ILaunchClientExecutable);
s_launcher.SetPatcherFactory(IPatcherFactory);
s_launcher.SetShardProc(ISetShardStatus);