yquake2remaster/src/win-wrapper/wrapper.c
Daniel Gibson 7db5c71f3a quake2.exe wrapper puts Q2 window in foreground
because it sucks when you start quake2.exe and the game starts in the
background
2019-05-08 03:04:12 +02:00

131 lines
4.1 KiB
C

/*
* Just a trivial stupid wrapper quake2.exe that starts yquake2.exe.
* It calls it with the whole path (assuming it's in same directory as this wrapper)
* and passes the commandline
*
* This should allow us to rename the real executable to yquake2.exe (to hopefully
* avoid trouble with whatever stupid thing interferes with mouse input once
* console has been opened if the games executable is called quake2.exe)
* while avoiding confusion for people upgrading their yq2 installation who still have
* shortcuts (possibly in Steam) to quake2.exe that would otherwise launch an old version.
*
* Can be built with just
* $ gcc -Wall -o quake2.exe wrapper.c
* in our mingw build environment, will only depend on kernel32.dll and MSVCRT.DLL then,
* which should be available on every Windows installation.
*
* (C) 2017 Daniel Gibson
* License:
* This software is dual-licensed to the public domain and under the following
* license: you are granted a perpetual, irrevocable license to copy, modify,
* publish, and distribute this file as you see fit.
* No warranty implied; use at your own risk.
*
* So you can do whatever you want with this code, including copying it
* (or parts of it) into your own source.
*/
#include <windows.h>
#include <wchar.h>
#include <stdio.h>
static const WCHAR WRAPPED_EXE[] = L"yquake2.exe";
// the struct and OnGetWindowByProcess taken from https://stackoverflow.com/a/17166455
typedef struct {
DWORD pid;
HWND hwnd;
} WINDOWPROCESSINFO;
static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam)
{
WINDOWPROCESSINFO *infoPtr = (WINDOWPROCESSINFO *)lParam;
DWORD check = 0;
BOOL br = TRUE;
GetWindowThreadProcessId(hwnd, &check);
if (check == infoPtr->pid)
{
infoPtr->hwnd = hwnd;
br = FALSE;
}
return br;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WCHAR* cmdLine = GetCommandLineW();
WCHAR exePath[2048];
WCHAR* lastBackSlash = exePath;
int maxLenSafe = sizeof(exePath)/sizeof(WCHAR) - wcslen(WRAPPED_EXE);
// get full path to this executable..
DWORD len = GetModuleFileNameW(NULL, exePath, maxLenSafe);
if(len <= 0 || len == maxLenSafe) {
// an error occured, clear exe path
exePath[0] = 0;
} else {
// .. cut off executable name (after last backslash in path)
lastBackSlash = wcsrchr(exePath, L'\\');
if(lastBackSlash != NULL) {
lastBackSlash[1] = 0;
} else {
// if there was no backslash, fall back to using only the wrapped exe name
// (appended to empty exePath buffer)
lastBackSlash = exePath;
lastBackSlash[0] = 0;
}
}
// .. append wrapped executable name to path ..
// should be safe, because maxLenSafe subtracted WRAPPED_EXE's length
// (and that's very conservative, we removed the original .exe name after all)
wcscat(lastBackSlash, WRAPPED_EXE);
// .. and start the wrapped executable
{
STARTUPINFOW si = {0};
PROCESS_INFORMATION pi = {0};
BOOL ret = FALSE;
si.cb = sizeof(si);
ret = CreateProcessW(exePath, cmdLine,
NULL, // process security attributes
NULL, // thread security attributes
FALSE, // don't inherit handles
0, // no creation flag
NULL, // environment block - no changes, use ours
NULL, // don't change CWD
&si, &pi);
if(!ret)
{
fprintf(stderr, "Couldn't CreateProcess() (%ld).\n", GetLastError());
return 1;
}
Sleep(1000); // wait until yq2 should have created the window
// send window to foreground, as shown in https://stackoverflow.com/a/17166455
// first we need to get its HWND
WINDOWPROCESSINFO info;
info.pid = GetProcessId(pi.hProcess);
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
// wait for wrapped exe to exit
WaitForSingleObject(pi.hProcess, INFINITE);
// close the process and thread object handles
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
return 0;
}