|
|
@ -66,26 +66,29 @@ static plClientLauncher s_launcher; |
|
|
|
static UINT s_taskbarCreated = RegisterWindowMessageW(L"TaskbarButtonCreated"); |
|
|
|
static UINT s_taskbarCreated = RegisterWindowMessageW(L"TaskbarButtonCreated"); |
|
|
|
static ITaskbarList3* s_taskbar = nullptr; |
|
|
|
static ITaskbarList3* s_taskbar = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef std::unique_ptr<void, std::function<BOOL(HANDLE)>> handleptr_t; |
|
|
|
|
|
|
|
|
|
|
|
// ===================================================
|
|
|
|
// ===================================================
|
|
|
|
|
|
|
|
|
|
|
|
/** Create a global patcher mutex that is backwards compatible with eap's */ |
|
|
|
/** Create a global patcher mutex that is backwards compatible with eap's */ |
|
|
|
static HANDLE CreatePatcherMutex() |
|
|
|
static handleptr_t CreatePatcherMutex() |
|
|
|
{ |
|
|
|
{ |
|
|
|
return CreateMutexW(nullptr, FALSE, plManifest::PatcherExecutable().AsString().ToWchar()); |
|
|
|
return handleptr_t(CreateMutexW(nullptr, TRUE, plManifest::PatcherExecutable().AsString().ToWchar()), |
|
|
|
|
|
|
|
CloseHandle); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool IsPatcherRunning() |
|
|
|
static bool IsPatcherRunning() |
|
|
|
{ |
|
|
|
{ |
|
|
|
HANDLE mut = CreatePatcherMutex(); |
|
|
|
handleptr_t mut = CreatePatcherMutex(); |
|
|
|
return WaitForSingleObject(mut, 0) != WAIT_OBJECT_0; |
|
|
|
return WaitForSingleObject(mut.get(), 0) != WAIT_OBJECT_0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void WaitForOldPatcher() |
|
|
|
static void WaitForOldPatcher() |
|
|
|
{ |
|
|
|
{ |
|
|
|
HANDLE mut = CreatePatcherMutex(); |
|
|
|
handleptr_t mut = CreatePatcherMutex(); |
|
|
|
DWORD wait = WaitForSingleObject(mut, 0); |
|
|
|
DWORD wait = WaitForSingleObject(mut.get(), 0); |
|
|
|
while (wait != WAIT_OBJECT_0) // :( :( :(
|
|
|
|
while (wait != WAIT_OBJECT_0) // :( :( :(
|
|
|
|
wait = WaitForSingleObject(mut, 100); |
|
|
|
wait = WaitForSingleObject(mut.get(), 100); |
|
|
|
Sleep(1000); // :(
|
|
|
|
Sleep(1000); // :(
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -231,7 +234,7 @@ static void ISetDownloadStatus(const plString& status) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static HANDLE ICreateProcess(const plFileName& exe, const plString& args) |
|
|
|
static handleptr_t ICreateProcess(const plFileName& exe, const plString& args) |
|
|
|
{ |
|
|
|
{ |
|
|
|
STARTUPINFOW si; |
|
|
|
STARTUPINFOW si; |
|
|
|
PROCESS_INFORMATION pi; |
|
|
|
PROCESS_INFORMATION pi; |
|
|
@ -262,7 +265,7 @@ static HANDLE ICreateProcess(const plFileName& exe, const plString& args) |
|
|
|
// So maybe it needs elevation... Or maybe everything arseploded.
|
|
|
|
// So maybe it needs elevation... Or maybe everything arseploded.
|
|
|
|
if (result != FALSE) { |
|
|
|
if (result != FALSE) { |
|
|
|
CloseHandle(pi.hThread); |
|
|
|
CloseHandle(pi.hThread); |
|
|
|
return pi.hProcess; |
|
|
|
return handleptr_t(pi.hProcess, CloseHandle); |
|
|
|
} else if (GetLastError() == ERROR_ELEVATION_REQUIRED) { |
|
|
|
} else if (GetLastError() == ERROR_ELEVATION_REQUIRED) { |
|
|
|
SHELLEXECUTEINFOW info; |
|
|
|
SHELLEXECUTEINFOW info; |
|
|
|
memset(&info, 0, sizeof(info)); |
|
|
|
memset(&info, 0, sizeof(info)); |
|
|
@ -270,9 +273,9 @@ static HANDLE ICreateProcess(const plFileName& exe, const plString& args) |
|
|
|
info.lpFile = file.GetData(); |
|
|
|
info.lpFile = file.GetData(); |
|
|
|
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC; |
|
|
|
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC; |
|
|
|
info.lpParameters = args.ToWchar(); |
|
|
|
info.lpParameters = args.ToWchar(); |
|
|
|
hsAssert(ShellExecuteExW(&info), "ShellExecuteExW phailed"); |
|
|
|
ShellExecuteExW(&info); |
|
|
|
|
|
|
|
|
|
|
|
return info.hProcess; |
|
|
|
return handleptr_t(info.hProcess, CloseHandle); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
wchar_t* msg = nullptr; |
|
|
|
wchar_t* msg = nullptr; |
|
|
|
FormatMessageW( |
|
|
|
FormatMessageW( |
|
|
@ -306,14 +309,13 @@ static bool IInstallRedist(const plFileName& exe) |
|
|
|
ss << " /norestart"; // I don't want to image the accusations of viruses and hacking if this happened...
|
|
|
|
ss << " /norestart"; // I don't want to image the accusations of viruses and hacking if this happened...
|
|
|
|
|
|
|
|
|
|
|
|
// Now fire up the process...
|
|
|
|
// Now fire up the process...
|
|
|
|
HANDLE process = ICreateProcess(exe, ss.GetString()); |
|
|
|
handleptr_t process = ICreateProcess(exe, ss.GetString()); |
|
|
|
if (process) { |
|
|
|
if (process) { |
|
|
|
WaitForSingleObject(process, INFINITE); |
|
|
|
WaitForSingleObject(process.get(), INFINITE); |
|
|
|
|
|
|
|
|
|
|
|
// Get the exit code so we can indicate success/failure to the redist thread
|
|
|
|
// Get the exit code so we can indicate success/failure to the redist thread
|
|
|
|
DWORD code = PLASMA_OK; |
|
|
|
DWORD code = PLASMA_OK; |
|
|
|
hsAssert(GetExitCodeProcess(process, &code), "failed to get redist exit code"); |
|
|
|
GetExitCodeProcess(process.get(), &code); |
|
|
|
CloseHandle(process); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return code != PLASMA_PHAILURE; |
|
|
|
return code != PLASMA_PHAILURE; |
|
|
|
} |
|
|
|
} |
|
|
@ -329,17 +331,14 @@ 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
|
|
|
|
// 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.
|
|
|
|
// done with some service operation and need to go away.
|
|
|
|
if (!exe.AsString().IsEmpty()) { |
|
|
|
if (!exe.AsString().IsEmpty()) { |
|
|
|
HANDLE hEvent = CreateEventW(nullptr, TRUE, FALSE, L"UruPatcherEvent"); |
|
|
|
handleptr_t hEvent = handleptr_t(CreateEventW(nullptr, TRUE, FALSE, L"UruPatcherEvent"), CloseHandle); |
|
|
|
HANDLE process = ICreateProcess(exe, args); |
|
|
|
handleptr_t process = ICreateProcess(exe, args); |
|
|
|
|
|
|
|
|
|
|
|
// if this is the real game client, then we need to make sure it gets this event...
|
|
|
|
// 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) { |
|
|
|
if (plManifest::ClientExecutable().AsString().CompareI(exe.AsString()) == 0) { |
|
|
|
WaitForInputIdle(process, 1000); |
|
|
|
WaitForInputIdle(process.get(), 1000); |
|
|
|
WaitForSingleObject(hEvent, INFINITE); |
|
|
|
WaitForSingleObject(hEvent.get(), INFINITE); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CloseHandle(process); |
|
|
|
|
|
|
|
CloseHandle(hEvent); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// time to hara-kiri...
|
|
|
|
// time to hara-kiri...
|
|
|
@ -399,7 +398,7 @@ int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL |
|
|
|
IShowErrorDialog(text.ToWchar()); |
|
|
|
IShowErrorDialog(text.ToWchar()); |
|
|
|
return PLASMA_OK; |
|
|
|
return PLASMA_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
HANDLE _onePatcherMut = CreatePatcherMutex(); |
|
|
|
HANDLE _onePatcherMut = CreatePatcherMutex().release(); |
|
|
|
|
|
|
|
|
|
|
|
// Initialize the network core
|
|
|
|
// Initialize the network core
|
|
|
|
s_launcher.InitializeNetCore(); |
|
|
|
s_launcher.InitializeNetCore(); |
|
|
|