#include #include #include #include #include #include void print(char const *fmt, ...); LPTSTR GetErrorMessage(); BOOL IsChildProcess(DWORD parentID, DWORD childID) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32; if (hSnapshot == INVALID_HANDLE_VALUE) return FALSE; pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hSnapshot, &pe32)) { do { if (pe32.th32ParentProcessID == parentID && pe32.th32ProcessID == childID) { CloseHandle(hSnapshot); return TRUE; } } while (Process32Next(hSnapshot, &pe32)); } CloseHandle(hSnapshot); return FALSE; } BOOL FileExists(LPCTSTR szPath) { DWORD dwAttrib = GetFileAttributes(szPath); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } void LaunchGame(int argc, char **argv) { char *gamePath = ""; int startArg = 1; if (argc > 1) { print("Checking if %s is a valid file\n", argv[1]); if (FileExists(argv[1])) { print("Checking if %s is a valid executable\n", argv[1]); DWORD dwBinaryType; if (!GetBinaryType(argv[1], &dwBinaryType)) { MessageBox(NULL, GetErrorMessage(), "GetBinaryType", MB_OK | MB_ICONSTOP); ExitProcess(1); } print("Executable type: %d\n", dwBinaryType); gamePath = argv[1]; startArg = 2; } else { MessageBox(NULL, "Invalid game path specified", NULL, MB_OK | MB_ICONSTOP); print("%s is not a valid file\n", argv[1]); ExitProcess(1); } } else if (argc == 1) { print("No game path specified. Idling...\n"); while (TRUE) Sleep(1000); } else { MessageBox(NULL, "No game path specified", NULL, MB_OK | MB_ICONSTOP); ExitProcess(1); } STARTUPINFO game_si; PROCESS_INFORMATION game_pi; ZeroMemory(&game_si, sizeof(STARTUPINFO)); game_si.cb = sizeof(STARTUPINFO); game_si.hStdOutput = INVALID_HANDLE_VALUE; game_si.hStdError = INVALID_HANDLE_VALUE; game_si.dwFlags |= STARTF_USESTDHANDLES; char *gameArgs = LocalAlloc(LPTR, 512); for (int i = startArg; i < argc; i++) { assert(strlen(gameArgs) + strlen(argv[i]) < 512); gameArgs = strcat(gameArgs, argv[i]); gameArgs = strcat(gameArgs, " "); } print("Launching \"%s\" with arguments \"%s\"\n", gamePath, gameArgs); if (!CreateProcess(gamePath, gameArgs, NULL, NULL, FALSE, 0, NULL, NULL, &game_si, &game_pi)) { MessageBox(NULL, GetErrorMessage(), "CreateProcess", MB_OK | MB_ICONSTOP); ExitProcess(1); } LocalFree(gameArgs); DWORD parentID = game_pi.dwProcessId; print("Waiting for PID %d to exit...\n", game_pi.dwProcessId); WaitForSingleObject(game_pi.hProcess, INFINITE); print("PID %d exited\n", game_pi.dwProcessId); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32; if (hSnapshot != INVALID_HANDLE_VALUE) { pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hSnapshot, &pe32)) { do { if (IsChildProcess(parentID, pe32.th32ProcessID)) { WaitForSingleObject(OpenProcess(SYNCHRONIZE, FALSE, pe32.th32ProcessID), INFINITE); print("Waiting for PID %d\n", pe32.th32ProcessID); } } while (Process32Next(hSnapshot, &pe32)); } CloseHandle(hSnapshot); } else { MessageBox(NULL, GetErrorMessage(), "CreateToolhelp32Snapshot", MB_OK | MB_ICONSTOP); ExitProcess(0); } CloseHandle(game_pi.hProcess); print("Game exited\n"); }