Rework launcher logic
This commit is contained in:
parent
6c94aad9b2
commit
b015c0cce4
@ -112,7 +112,7 @@ void init_injection(HMODULE hModule) {
|
|||||||
load_mice_config();
|
load_mice_config();
|
||||||
|
|
||||||
// We're in a new context now, so need to reconfigure
|
// We're in a new context now, so need to reconfigure
|
||||||
setup_logging();
|
setup_logging(GetParentProcessId());
|
||||||
log_info(plfBoot, "Handover complete. Now executing within %ls", exeName);
|
log_info(plfBoot, "Handover complete. Now executing within %ls", exeName);
|
||||||
|
|
||||||
init_com_devices();
|
init_com_devices();
|
||||||
|
@ -261,7 +261,7 @@ unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCo
|
|||||||
jvs_read(gpioByteIndex);
|
jvs_read(gpioByteIndex);
|
||||||
jvs_read(gpioByteData);
|
jvs_read(gpioByteData);
|
||||||
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
|
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
|
||||||
(cmd - JVS_CMD_WRITE_GPIO2) + 1, gpioByteIndex, gpioByteData);
|
(cmd - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JVS_CMD_COIN_DECREASE:
|
case JVS_CMD_COIN_DECREASE:
|
||||||
|
@ -6,26 +6,35 @@ const wchar_t* HOOK_BINARIES[] = {
|
|||||||
L"app\\GmSync.exe",
|
L"app\\GmSync.exe",
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DISABLE_PROC_SPAWNING
|
|
||||||
|
|
||||||
BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
|
BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
|
||||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||||
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
|
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
|
||||||
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
||||||
LPCSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
LPCSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
||||||
LPPROCESS_INFORMATION lpProcessInformation) {
|
LPPROCESS_INFORMATION lpProcessInformation) {
|
||||||
|
if (dwCreationFlags & CREATE_SUSPENDED) {
|
||||||
|
return TrueCreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes,
|
||||||
|
lpThreadAttributes, bInheritHandles, dwCreationFlags,
|
||||||
|
lpEnvironment, lpCurrentDirectory, lpStartupInfo,
|
||||||
|
lpProcessInformation);
|
||||||
|
}
|
||||||
|
|
||||||
log_info(plfProcesses, "CreateProcessA %s %s", lpApplicationName, lpCommandLine);
|
log_info(plfProcesses, "CreateProcessA %s %s", lpApplicationName, lpCommandLine);
|
||||||
|
|
||||||
return TrueCreateProcessA("mxAuthDisc.bat", "", lpProcessAttributes,
|
// return TrueCreateProcessA("mxAuthDisc.bat", "", lpProcessAttributes, lpThreadAttributes,
|
||||||
lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
|
// bInheritHandles, dwCreationFlags, lpEnvironment,
|
||||||
lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
|
// lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
|
||||||
|
|
||||||
HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
// HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
SetEvent(fake_evt);
|
// SetEvent(fake_evt);
|
||||||
|
|
||||||
|
HANDLE hProcess = start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine,
|
||||||
|
MICELIB, FALSE, 0, "", 0);
|
||||||
|
|
||||||
if (lpProcessInformation) {
|
if (lpProcessInformation) {
|
||||||
lpProcessInformation->hProcess = fake_evt;
|
lpProcessInformation->hProcess = hProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||||
@ -34,61 +43,72 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
|||||||
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
||||||
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
||||||
LPPROCESS_INFORMATION lpProcessInformation) {
|
LPPROCESS_INFORMATION lpProcessInformation) {
|
||||||
// #ifdef DISABLE_PROC_SPAWNING
|
|
||||||
// log_error(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
|
||||||
// return FALSE;
|
|
||||||
// #else
|
|
||||||
log_info(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
log_info(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
||||||
|
|
||||||
// log_info(plfProcesses, "CreateProcessW %ls", lpApplicationName);
|
|
||||||
|
|
||||||
// lpProcessInformation->hThread = GetDummyHandle();
|
|
||||||
// return TRUE;
|
|
||||||
|
|
||||||
CHAR applicationName[MAX_PATH + 1];
|
CHAR applicationName[MAX_PATH + 1];
|
||||||
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName,
|
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
HANDLE child;
|
int nMultiChars = WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, NULL, 0, NULL, NULL);
|
||||||
CHAR commandLine[MAX_PATH + 1];
|
LPSTR commandLine = malloc(nMultiChars);
|
||||||
WCHAR commandLineW[MAX_PATH + 1];
|
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, nMultiChars, NULL, NULL);
|
||||||
WCHAR micePathW[MAX_PATH + 1];
|
|
||||||
GetModuleFileNameW(NULL, micePathW, MAX_PATH);
|
|
||||||
|
|
||||||
HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
// WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof
|
||||||
SetEvent(fake_evt);
|
// applicationName,
|
||||||
|
// NULL, NULL);
|
||||||
|
|
||||||
|
// HANDLE child;
|
||||||
|
// CHAR commandLine[MAX_PATH + 1];
|
||||||
|
// WCHAR commandLineW[MAX_PATH + 1];
|
||||||
|
// WCHAR micePathW[MAX_PATH + 1];
|
||||||
|
// GetModuleFileNameW(NULL, micePathW, MAX_PATH);
|
||||||
|
|
||||||
|
// HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
// SetEvent(fake_evt);
|
||||||
|
|
||||||
|
// return TrueCreateProcessA(applicationName, commandLine, lpProcessAttributes, lpThreadAttributes,
|
||||||
|
// bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory,
|
||||||
|
// lpStartupInfo, lpProcessInformation);
|
||||||
|
|
||||||
|
HANDLE hProcess = start_and_inject(INVALID_HANDLE_VALUE, applicationName, commandLine, MICELIB,
|
||||||
|
TRUE, 0, NULL, 0);
|
||||||
if (lpProcessInformation) {
|
if (lpProcessInformation) {
|
||||||
lpProcessInformation->hProcess = fake_evt;
|
lpProcessInformation->hProcess = hProcess;
|
||||||
lpProcessInformation->hThread = GetDummyHandle();
|
lpProcessInformation->hThread = GetDummyHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_game(plfProcesses, "hP: %08x", hProcess);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (lpCommandLine != NULL) {
|
// if (lpCommandLine != NULL) {
|
||||||
log_error(plfProcesses, "!!");
|
// log_error(plfProcesses, "!!");
|
||||||
return FALSE;
|
// return FALSE;
|
||||||
// WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL,
|
// // WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine,
|
||||||
// NULL);
|
// NULL,
|
||||||
// child = start_and_inject(applicationName, commandLine, MICELIB, false, 0, NULL,
|
// // NULL);
|
||||||
// CREATE_NEW_CONSOLE);
|
// // child = start_and_inject(INVALID_HANDLE_VALUE, applicationName, commandLine, MICELIB,
|
||||||
} else {
|
// // false, 0, NULL,
|
||||||
dwCreationFlags |= CREATE_NEW_CONSOLE;
|
// // CREATE_NEW_CONSOLE);
|
||||||
wsprintfW(commandLineW, L"mice -b %ls", lpApplicationName);
|
// } else {
|
||||||
printf("%ls %ls\n", micePathW, commandLineW);
|
// dwCreationFlags |= CREATE_NEW_CONSOLE;
|
||||||
BOOL ret =
|
// wsprintfW(commandLineW, L"mice -b %ls", lpApplicationName);
|
||||||
TrueCreateProcessW(L"mice.cmd", commandLineW, lpProcessAttributes, lpThreadAttributes,
|
// printf("%ls %ls\n", micePathW, commandLineW);
|
||||||
bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory,
|
// BOOL ret =
|
||||||
lpStartupInfo, lpProcessInformation);
|
// TrueCreateProcessW(L"mice.cmd", commandLineW, lpProcessAttributes,
|
||||||
printf("%d\n", ret);
|
// lpThreadAttributes,
|
||||||
return ret;
|
// bInheritHandles, dwCreationFlags, lpEnvironment,
|
||||||
// CHAR commandLine[]
|
// lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
|
||||||
// child =
|
// printf("%d\n", ret);
|
||||||
// start_and_inject(applicationName, NULL, MICELIB, false, 0, NULL, CREATE_NEW_CONSOLE);
|
// return ret;
|
||||||
}
|
// // CHAR commandLine[]
|
||||||
|
// // child =
|
||||||
|
// // start_and_inject(INVALID_HANDLE_VALUE, applicationName, NULL, MICELIB, false, 0,
|
||||||
|
// // NULL, CREATE_NEW_CONSOLE);
|
||||||
|
// }
|
||||||
|
|
||||||
return !FAILED(child);
|
// return !FAILED(child);
|
||||||
// #endif
|
// // #endif
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
|
BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
|
||||||
|
@ -13,6 +13,7 @@ BOOL RemoveDataForHandle(HANDLE hObject, DWORD type);
|
|||||||
HANDLE GetDummyHandle();
|
HANDLE GetDummyHandle();
|
||||||
void BytesToHex(char* hex_buffer, BYTE* bytes, DWORD nbytes);
|
void BytesToHex(char* hex_buffer, BYTE* bytes, DWORD nbytes);
|
||||||
void PrintStack(void);
|
void PrintStack(void);
|
||||||
|
DWORD GetParentProcessId(void);
|
||||||
|
|
||||||
BOOL PathEqual(LPCSTR path1, LPCSTR path2);
|
BOOL PathEqual(LPCSTR path1, LPCSTR path2);
|
||||||
BOOL PathPrefix(LPCSTR path, LPCSTR prefix);
|
BOOL PathPrefix(LPCSTR path, LPCSTR prefix);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#define _WIN32_WINNT 0x0600
|
#define _WIN32_WINNT 0x0600
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
|
||||||
#include "../hooks/files.h"
|
#include "../hooks/files.h"
|
||||||
|
|
||||||
@ -156,15 +157,14 @@ void make_dirs(const char* path) {
|
|||||||
void* open_mapped_file(LPCWSTR path, DWORD size, HANDLE* file, HANDLE* file_mapping) {
|
void* open_mapped_file(LPCWSTR path, DWORD size, HANDLE* file, HANDLE* file_mapping) {
|
||||||
make_dirs(path);
|
make_dirs(path);
|
||||||
*file = _CreateFileW(path, GENERIC_READ | GENERIC_WRITE,
|
*file = _CreateFileW(path, GENERIC_READ | GENERIC_WRITE,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS,
|
||||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (*file == INVALID_HANDLE_VALUE) {
|
if (*file == INVALID_HANDLE_VALUE) {
|
||||||
log_error(plfMisc, "Failed to CreateFileW(%ls): %d", path, GetLastError());
|
log_error(plfMisc, "Failed to CreateFileW(%ls): %d", path, GetLastError());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*file_mapping =
|
*file_mapping = CreateFileMappingW(*file, NULL, PAGE_READWRITE, 0, size, NULL);
|
||||||
CreateFileMappingW(*file, NULL, PAGE_READWRITE, 0, size, NULL);
|
|
||||||
|
|
||||||
if (*file_mapping == INVALID_HANDLE_VALUE) {
|
if (*file_mapping == INVALID_HANDLE_VALUE) {
|
||||||
CloseHandle(*file);
|
CloseHandle(*file);
|
||||||
@ -186,3 +186,23 @@ void* open_mapped_file(LPCWSTR path, DWORD size, HANDLE* file, HANDLE* file_mapp
|
|||||||
}
|
}
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD GetParentProcessIdFor(DWORD pid) {
|
||||||
|
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
PROCESSENTRY32 pe = { 0 };
|
||||||
|
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
|
||||||
|
if (Process32First(h, &pe)) {
|
||||||
|
do {
|
||||||
|
if (pe.th32ProcessID == pid) {
|
||||||
|
CloseHandle(h);
|
||||||
|
return pe.th32ParentProcessID;
|
||||||
|
}
|
||||||
|
} while (Process32Next(h, &pe));
|
||||||
|
}
|
||||||
|
CloseHandle(h);
|
||||||
|
return (DWORD)-1;
|
||||||
|
}
|
||||||
|
DWORD GetParentProcessId(void) {
|
||||||
|
return GetParentProcessIdFor(GetCurrentProcessId());
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ int boot_delay = 0;
|
|||||||
char exe_name[MAX_PATH + 1] = "";
|
char exe_name[MAX_PATH + 1] = "";
|
||||||
char commandline[MAX_PATH + 1] = "";
|
char commandline[MAX_PATH + 1] = "";
|
||||||
|
|
||||||
void print_help(char* exe) {
|
static void print_help(char* exe) {
|
||||||
log_info(plfBoot, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe);
|
log_info(plfBoot, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe);
|
||||||
log_info(plfBoot, " -h: Print this help message and exit");
|
log_info(plfBoot, " -h: Print this help message and exit");
|
||||||
log_info(plfBoot, " -b: Specify the game binary to use");
|
log_info(plfBoot, " -b: Specify the game binary to use");
|
||||||
@ -19,7 +19,7 @@ void print_help(char* exe) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_cmdline(int argc, char* argv[]) {
|
static bool parse_cmdline(int argc, char* argv[]) {
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-h") == 0) {
|
if (strcmp(argv[i], "-h") == 0) {
|
||||||
print_help(argv[0]);
|
print_help(argv[0]);
|
||||||
@ -77,9 +77,102 @@ bool parse_cmdline(int argc, char* argv[]) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
|
||||||
|
// Enable colour support in conhost
|
||||||
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
if (GetConsoleMode(hConsole, &dwMode))
|
||||||
|
SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||||
|
|
||||||
|
HANDLE hLogFile = INVALID_HANDLE_VALUE;
|
||||||
|
if (MiceConfig.mice.log_to_file) {
|
||||||
|
hLogFile = CreateFileA(MiceConfig.mice.log_file, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||||
|
CREATE_ALWAYS, 0, NULL);
|
||||||
|
if (hLogFile == INVALID_HANDLE_VALUE) {
|
||||||
|
fprintf(stderr, "Failed to initialise logging: open %s failed: %d",
|
||||||
|
MiceConfig.mice.log_file, GetLastError());
|
||||||
|
ExitProcess(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OVERLAPPED ov;
|
||||||
|
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
ov.Offset = ov.OffsetHigh = 0;
|
||||||
|
ov.hEvent = hEvent;
|
||||||
|
|
||||||
|
char readBuffer[4096];
|
||||||
|
DWORD nRead, nBytes;
|
||||||
|
while (1) {
|
||||||
|
nRead = nBytes = 0;
|
||||||
|
ReadFile(*pSlot, readBuffer, sizeof readBuffer, &nRead, &ov);
|
||||||
|
GetOverlappedResult(*pSlot, &ov, &nBytes, TRUE);
|
||||||
|
DWORD nWrote;
|
||||||
|
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), readBuffer, nBytes, &nWrote, NULL);
|
||||||
|
|
||||||
|
if (hLogFile != INVALID_HANDLE_VALUE) {
|
||||||
|
// The only VT100 sequences being used are colours, so this lazy approach works
|
||||||
|
BOOL inVt100 = FALSE;
|
||||||
|
for (int i = 0; i < nBytes; i++) {
|
||||||
|
if (readBuffer[i] == '\033') {
|
||||||
|
inVt100 = TRUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inVt100 && readBuffer[i] == 'm') {
|
||||||
|
inVt100 = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!inVt100) WriteFile(hLogFile, &(readBuffer[i]), 1, &nWrote, NULL);
|
||||||
|
}
|
||||||
|
FlushFileBuffers(hLogFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL setup_mailslot(void) {
|
||||||
|
DWORD pid = GetCurrentProcessId();
|
||||||
|
char slotName[MAX_PATH + 1];
|
||||||
|
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", pid);
|
||||||
|
|
||||||
|
HANDLE* pSlot = malloc(sizeof(HANDLE));
|
||||||
|
if (pSlot == NULL) {
|
||||||
|
fprintf(stderr, "malloc(pSlot) failed\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
*pSlot = CreateMailslotA(slotName, 0, MAILSLOT_WAIT_FOREVER, NULL);
|
||||||
|
if (*pSlot == INVALID_HANDLE_VALUE) {
|
||||||
|
fprintf(stderr, "Creation of mailslot failed %d\n", GetLastError());
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateThread(NULL, 0, MiceMailslotWatcher, pSlot, 0, NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because logging is via a mailslot, we need to give it a chance to flush messages before
|
||||||
|
* terminating. While we could engineer something overly fancy, the only situation this ever occurs
|
||||||
|
* is in the main() function just below.
|
||||||
|
*
|
||||||
|
* I'll let the code speak for itself.
|
||||||
|
*/
|
||||||
|
static int terminate(int err) {
|
||||||
|
Sleep(100);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE hGameProc = INVALID_HANDLE_VALUE;
|
||||||
|
HANDLE hJob = INVALID_HANDLE_VALUE;
|
||||||
|
BOOL WINAPI MiceHandlerRoutine(DWORD CtrlType) {
|
||||||
|
if (hJob != INVALID_HANDLE_VALUE) CloseHandle(hJob);
|
||||||
|
// if (hGameProc != INVALID_HANDLE_VALUE) TerminateProcess(hGameProc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
load_mice_config();
|
load_mice_config();
|
||||||
setup_logging();
|
if (!setup_mailslot()) return 1;
|
||||||
|
setup_logging(GetCurrentProcessId());
|
||||||
|
|
||||||
log_info(plfBoot, "Micetools version: %s", MICE_VERSION);
|
log_info(plfBoot, "Micetools version: %s", MICE_VERSION);
|
||||||
|
|
||||||
@ -87,7 +180,7 @@ int main(int argc, char* argv[]) {
|
|||||||
GetCurrentDirectory(MAX_PATH, workDir);
|
GetCurrentDirectory(MAX_PATH, workDir);
|
||||||
log_info(plfBoot, "Current directory: %s", workDir);
|
log_info(plfBoot, "Current directory: %s", workDir);
|
||||||
|
|
||||||
if (!parse_cmdline(argc, argv)) return 0;
|
if (!parse_cmdline(argc, argv)) return terminate(0);
|
||||||
|
|
||||||
if (exe_name[0] == '\0' && MiceConfig.launcher.game_binary[0] != '\0') {
|
if (exe_name[0] == '\0' && MiceConfig.launcher.game_binary[0] != '\0') {
|
||||||
snprintf(exe_name, sizeof exe_name, "%s", MiceConfig.launcher.game_binary);
|
snprintf(exe_name, sizeof exe_name, "%s", MiceConfig.launcher.game_binary);
|
||||||
@ -98,13 +191,13 @@ int main(int argc, char* argv[]) {
|
|||||||
if (exe_name[0] == '\0') {
|
if (exe_name[0] == '\0') {
|
||||||
if (!locate_game(exe_name, MAX_PATH + 1)) {
|
if (!locate_game(exe_name, MAX_PATH + 1)) {
|
||||||
log_error(plfBoot, "Fatal: Failed to locate a game");
|
log_error(plfBoot, "Fatal: Failed to locate a game");
|
||||||
return 0;
|
return terminate(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DWORD dwAttrib = GetFileAttributes(exe_name);
|
DWORD dwAttrib = GetFileAttributes(exe_name);
|
||||||
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
|
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
log_error(plfBoot, "Fatal: %s: no such file found", exe_name);
|
log_error(plfBoot, "Fatal: %s: no such file found", exe_name);
|
||||||
return 0;
|
return terminate(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,19 +208,26 @@ int main(int argc, char* argv[]) {
|
|||||||
char micepath[MAX_PATH + 1];
|
char micepath[MAX_PATH + 1];
|
||||||
if (!locate_library(micepath, MAX_PATH + 1)) {
|
if (!locate_library(micepath, MAX_PATH + 1)) {
|
||||||
log_error(plfBoot, "Fatal: Failed to locate micelib. Check your mice_dll setting!");
|
log_error(plfBoot, "Fatal: Failed to locate micelib. Check your mice_dll setting!");
|
||||||
return 0;
|
return terminate(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* extra_injections = MiceConfig.launcher.inject;
|
hJob = CreateJobObject(NULL, NULL);
|
||||||
HANDLE game_proc =
|
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
|
||||||
start_and_inject(exe_name, commandline, micepath, debug_wait, boot_delay, extra_injections, 0);
|
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||||
if (!game_proc) return -1;
|
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
|
||||||
|
|
||||||
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
|
char* extra_injections = MiceConfig.launcher.inject;
|
||||||
|
hGameProc = start_and_inject(hJob, exe_name, commandline, micepath, debug_wait, boot_delay,
|
||||||
|
extra_injections, 0);
|
||||||
|
if (!hGameProc) return terminate(-1);
|
||||||
|
|
||||||
|
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
|
||||||
|
|
||||||
|
if (FAILED(WaitForSingleObject(hGameProc, INFINITE))) {
|
||||||
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
|
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
|
||||||
} else {
|
} else {
|
||||||
log_info(plfBoot, "Shutting down");
|
log_info(plfBoot, "Shutting down");
|
||||||
CloseHandle(game_proc);
|
CloseHandle(hGameProc);
|
||||||
}
|
}
|
||||||
return 0;
|
return terminate(0);
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@ COMMENT("")
|
|||||||
SECTION(mice, "General mice settings")
|
SECTION(mice, "General mice settings")
|
||||||
COMMENT("Trace logging (6) is intensive, and should only be used when debugging")
|
COMMENT("Trace logging (6) is intensive, and should only be used when debugging")
|
||||||
CFG_int(mice, log_level, 4, "1 = Game\n2 = Error\n3 = Warning\n4 = Info\n5 = Misc\n6 = Trace")
|
CFG_int(mice, log_level, 4, "1 = Game\n2 = Error\n3 = Warning\n4 = Info\n5 = Misc\n6 = Trace")
|
||||||
CFG_bool(mice, log_to_file, false, "Also log out to log_file")
|
CFG_bool(mice, log_to_file, true, "Also log out to log_file")
|
||||||
CFG_int(mice, file_log_level, 5, "1 = Game\n2 = Error\n3 = Warning\n4 = Info\n5 = Misc\n6 = Trace")
|
|
||||||
CFG_str(mice, log_file, "log.txt", "The file to log to if log_to_file is enabled")
|
CFG_str(mice, log_file, "log.txt", "The file to log to if log_to_file is enabled")
|
||||||
CFG_bool(mice, apply_patches, true, "Load and apply patches from patches_file at runtime")
|
CFG_bool(mice, apply_patches, true, "Load and apply patches from patches_file at runtime")
|
||||||
CFG_str(mice, patches_file, "patches.index", "The file to read patches from")
|
CFG_str(mice, patches_file, "patches.index", "The file to read patches from")
|
||||||
|
@ -2,18 +2,20 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
bool inject_debug_wait(HANDLE process) {
|
bool inject_debug_wait(HANDLE process) {
|
||||||
BOOL present;
|
BOOL present;
|
||||||
|
|
||||||
fprintf(stderr, "Waiting for debugger to attach.\n");
|
log_info(plfBoot, "Waiting for debugger to attach.");
|
||||||
do {
|
do {
|
||||||
Sleep(1000);
|
Sleep(1000);
|
||||||
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
|
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
|
||||||
fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError());
|
log_error(plfBoot, "Fatal: CheckRemoteDebuggerPresent failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} while (!present);
|
} while (!present);
|
||||||
fprintf(stderr, "Debugger attached, resuming\n");
|
log_info(plfBoot, "Debugger attached, resuming");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result) {
|
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result) {
|
||||||
@ -22,33 +24,33 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
|
|||||||
LPVOID arg_addr =
|
LPVOID arg_addr =
|
||||||
VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||||
if (arg_addr == NULL) {
|
if (arg_addr == NULL) {
|
||||||
fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: VirtualAllocEx failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
|
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
|
||||||
fprintf(stderr, "Fatal: WriteProcessMemory failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: WriteProcessMemory failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE remote_thread =
|
HANDLE remote_thread =
|
||||||
CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
|
CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
|
||||||
if (remote_thread == INVALID_HANDLE_VALUE) {
|
if (remote_thread == INVALID_HANDLE_VALUE) {
|
||||||
fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: CreateRemoteThread failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
|
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
|
||||||
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: WaitForSingleObject failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(GetExitCodeThread(remote_thread, result))) {
|
if (FAILED(GetExitCodeThread(remote_thread, result))) {
|
||||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: GetExitCodeThread failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (*result == 0) {
|
if (*result == 0) {
|
||||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n");
|
log_error(plfProcesses, "Fatal: GetExitCodeThread failed: result == 0");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,13 +59,13 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
|
|||||||
bool inject_dll(HANDLE process, LPCSTR inject) {
|
bool inject_dll(HANDLE process, LPCSTR inject) {
|
||||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||||
if (kernel32 == NULL) {
|
if (kernel32 == NULL) {
|
||||||
fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: GetModuleHandleA failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
|
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
|
||||||
if (addr_LoadLibraryA == NULL) {
|
if (addr_LoadLibraryA == NULL) {
|
||||||
fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: GetProcAddress failed: %d", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +73,8 @@ bool inject_dll(HANDLE process, LPCSTR inject) {
|
|||||||
return remote_call(process, addr_LoadLibraryA, inject, &result);
|
return remote_call(process, addr_LoadLibraryA, inject, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait, DWORD delay,
|
HANDLE start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait,
|
||||||
LPCSTR extra_injections, DWORD flags) {
|
DWORD delay, LPCSTR extra_injections, DWORD flags) {
|
||||||
STARTUPINFOA startupInfo;
|
STARTUPINFOA startupInfo;
|
||||||
PROCESS_INFORMATION processInformation = { 0 };
|
PROCESS_INFORMATION processInformation = { 0 };
|
||||||
|
|
||||||
@ -87,26 +89,32 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wa
|
|||||||
// Does the exe we're starting exist?
|
// Does the exe we're starting exist?
|
||||||
found = SearchPathA(NULL, path, NULL, 0, NULL, NULL);
|
found = SearchPathA(NULL, path, NULL, 0, NULL, NULL);
|
||||||
if (found == 0) {
|
if (found == 0) {
|
||||||
fprintf(stderr, "Fatal: Cannot start %s: not found\n", path);
|
log_error(plfProcesses, "Fatal: Cannot start %s: not found", path);
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
if (inject != NULL) {
|
||||||
// Does the DLL we want to inject exist?
|
// Does the DLL we want to inject exist?
|
||||||
found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
|
found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
|
||||||
if (found == 0) {
|
if (found == 0) {
|
||||||
fprintf(stderr, "Fatal: Cannot inject %s: not found\n", inject);
|
log_error(plfProcesses, "Fatal: Cannot inject %s: not found", inject);
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the binary
|
// Start the binary
|
||||||
flags |= CREATE_SUSPENDED;
|
flags |= CREATE_SUSPENDED;
|
||||||
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, flags, NULL, NULL, &startupInfo,
|
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, flags, NULL, NULL, &startupInfo,
|
||||||
&processInformation)) {
|
&processInformation)) {
|
||||||
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: CreateProcessA(%s, %s) failed: %d", path, cmdline,
|
||||||
|
GetLastError());
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hJob != INVALID_HANDLE_VALUE) AssignProcessToJobObject(hJob, processInformation.hProcess);
|
||||||
|
|
||||||
if (debug_wait)
|
if (debug_wait)
|
||||||
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
|
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
|
||||||
|
if (inject != NULL)
|
||||||
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
||||||
|
|
||||||
if (extra_injections != NULL && extra_injections[0] != '\0') {
|
if (extra_injections != NULL && extra_injections[0] != '\0') {
|
||||||
@ -125,13 +133,13 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wa
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (delay) {
|
if (delay) {
|
||||||
fprintf(stderr, "Delaying for %dms\n", delay);
|
log_info(plfBoot, "Delaying for %dms", delay);
|
||||||
Sleep(delay);
|
Sleep(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Injection completed, let the program continue execution
|
// Injection completed, let the program continue execution
|
||||||
if (FAILED(ResumeThread(processInformation.hThread))) {
|
if (FAILED(ResumeThread(processInformation.hThread))) {
|
||||||
fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: ResumeThread failed: %d", GetLastError());
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,14 +148,14 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wa
|
|||||||
abort:
|
abort:
|
||||||
if (processInformation.hProcess && processInformation.hProcess != INVALID_HANDLE_VALUE) {
|
if (processInformation.hProcess && processInformation.hProcess != INVALID_HANDLE_VALUE) {
|
||||||
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
|
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
|
||||||
fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: CloseHandle(hProcess) failed: %d", GetLastError());
|
||||||
|
|
||||||
if (!TerminateProcess(processInformation.hProcess, 1))
|
if (!TerminateProcess(processInformation.hProcess, 1))
|
||||||
fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: TerminateProcess failed: %d", GetLastError());
|
||||||
}
|
}
|
||||||
if (processInformation.hThread && processInformation.hThread != INVALID_HANDLE_VALUE) {
|
if (processInformation.hThread && processInformation.hThread != INVALID_HANDLE_VALUE) {
|
||||||
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
|
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
|
||||||
fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError());
|
log_error(plfProcesses, "Fatal: CloseHandle(hThread) failed: %d", GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
return INVALID_HANDLE_VALUE;
|
return INVALID_HANDLE_VALUE;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait, DWORD delay,
|
HANDLE start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait,
|
||||||
LPCSTR extra_injections, DWORD flags);
|
DWORD delay, LPCSTR extra_injections, DWORD flags);
|
||||||
|
|
||||||
#define MICELIB "mice.dll"
|
#define MICELIB "mice.dll"
|
||||||
|
@ -17,14 +17,14 @@
|
|||||||
#include "log_facilities.def"
|
#include "log_facilities.def"
|
||||||
#undef _LF
|
#undef _LF
|
||||||
|
|
||||||
|
static BOOL logIsMaster = FALSE;
|
||||||
|
|
||||||
extern WCHAR exeName[MAX_PATH + 1];
|
extern WCHAR exeName[MAX_PATH + 1];
|
||||||
extern DWORD imageOffset;
|
extern DWORD imageOffset;
|
||||||
|
|
||||||
extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
|
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
|
||||||
|
|
||||||
BOOL HAS_COLOUR = FALSE;
|
|
||||||
|
|
||||||
char _log_prelude[64];
|
char _log_prelude[64];
|
||||||
char* log_prelude() {
|
char* log_prelude() {
|
||||||
time_t rawtime;
|
time_t rawtime;
|
||||||
@ -65,13 +65,12 @@ void __stdcall amLogCallback(DWORD level, char* format) {
|
|||||||
DWORD pLogcb;
|
DWORD pLogcb;
|
||||||
DWORD* ppLogcb;
|
DWORD* ppLogcb;
|
||||||
|
|
||||||
|
HANDLE hSlot;
|
||||||
|
|
||||||
static char log_buf[1024];
|
static char log_buf[1024];
|
||||||
int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list args) {
|
int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list args) {
|
||||||
// Early-return if we have nothing to do
|
// Early-return if we have nothing to do
|
||||||
if (MiceConfig.mice.log_level < log_level &&
|
if (MiceConfig.mice.log_level < log_level) return 0;
|
||||||
(!MiceConfig.mice.log_to_file || MiceConfig.mice.file_log_level < log_level)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: These are all horrible bodges
|
// TODO: These are all horrible bodges
|
||||||
// if (wcscmp(exeName, L"mxnetwork.exe") == 0) {
|
// if (wcscmp(exeName, L"mxnetwork.exe") == 0) {
|
||||||
@ -88,30 +87,21 @@ int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list
|
|||||||
|
|
||||||
char prefix = LOG_PREFIXES[log_level];
|
char prefix = LOG_PREFIXES[log_level];
|
||||||
|
|
||||||
EnterCriticalSection(&logger_lock);
|
|
||||||
|
|
||||||
int col_len = strlen(log_colours[log_level]);
|
int col_len = strlen(log_colours[log_level]);
|
||||||
|
|
||||||
|
EnterCriticalSection(&logger_lock);
|
||||||
int log_len = snprintf(log_buf, _countof(log_buf), "%s%s%c:%s:", log_colours[log_level],
|
int log_len = snprintf(log_buf, _countof(log_buf), "%s%s%c:%s:", log_colours[log_level],
|
||||||
log_prelude(), prefix, facility->m_name);
|
log_prelude(), prefix, facility->m_name);
|
||||||
log_len += vsnprintf(log_buf + log_len, _countof(log_buf) - log_len, format, args);
|
log_len += vsnprintf(log_buf + log_len, _countof(log_buf) - log_len, format, args);
|
||||||
log_len += snprintf(log_buf + log_len, _countof(log_buf) - log_len, "%s\n", COLOR_RESET);
|
log_len += snprintf(log_buf + log_len, _countof(log_buf) - log_len, "%s\n", COLOR_RESET);
|
||||||
log_buf[_countof(log_buf) - 1] = '\0';
|
log_buf[_countof(log_buf) - 1] = '\0';
|
||||||
|
|
||||||
if (MiceConfig.mice.log_level >= log_level) {
|
if (hSlot != INVALID_HANDLE_VALUE) {
|
||||||
HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE);
|
WriteFile(hSlot, log_buf, log_len, NULL, NULL);
|
||||||
WriteFile(sout, log_buf, log_len, NULL, NULL);
|
} else {
|
||||||
// FlushFileBuffers(sout);
|
// This should never happen, but there's no harm being prepared in case it does
|
||||||
}
|
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), log_buf, log_len, NULL, NULL);
|
||||||
|
|
||||||
if (MiceConfig.mice.log_to_file && MiceConfig.mice.file_log_level >= log_level) {
|
|
||||||
if (log_file && log_file != INVALID_HANDLE_VALUE) {
|
|
||||||
// Replace the colour reset with a newline, then skip the prefix when writing
|
|
||||||
log_buf[log_len - col_len] = '\n';
|
|
||||||
log_buf[log_len - col_len + 1] = '\0';
|
|
||||||
WriteFile(log_file, log_buf + col_len, log_len - col_len - sizeof(COLOR_RESET), NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&logger_lock);
|
LeaveCriticalSection(&logger_lock);
|
||||||
@ -178,23 +168,18 @@ int _log_game(PLOG_FACILITY facility, const char* format, ...) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_logging() {
|
void setup_logging(DWORD slotPid) {
|
||||||
// Force stdio even for GUI applications
|
char slotName[MAX_PATH + 1];
|
||||||
// AttachConsole(ATTACH_PARENT_PROCESS);
|
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", slotPid);
|
||||||
|
|
||||||
// Enable colour in CMD
|
hSlot = CreateFile(slotName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
DWORD dwMode = 0;
|
if (hSlot == INVALID_HANDLE_VALUE) {
|
||||||
if (GetConsoleMode(hConsole, &dwMode))
|
fprintf(stderr, "Fatal: Failed to open mailslot %s", slotName);
|
||||||
HAS_COLOUR = SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
ExitProcess(2);
|
||||||
|
}
|
||||||
|
|
||||||
InitializeCriticalSection(&logger_lock);
|
InitializeCriticalSection(&logger_lock);
|
||||||
|
|
||||||
if (MiceConfig.mice.log_to_file) {
|
|
||||||
if (log_file == INVALID_HANDLE_VALUE && MiceConfig.mice.log_file[0] != '\0')
|
|
||||||
log_file = CreateFileA(MiceConfig.mice.log_file, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
||||||
CREATE_ALWAYS, 0, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_stack(PLOG_FACILITY facility) {
|
void log_stack(PLOG_FACILITY facility) {
|
||||||
|
@ -38,7 +38,7 @@ int vlog_game(PLOG_FACILITY facility, const char* format, va_list args);
|
|||||||
|
|
||||||
void log_stack(PLOG_FACILITY facility);
|
void log_stack(PLOG_FACILITY facility);
|
||||||
|
|
||||||
void setup_logging();
|
void setup_logging(DWORD slotPid);
|
||||||
|
|
||||||
// Disable some logging entirely at build time for speed
|
// Disable some logging entirely at build time for speed
|
||||||
#define COMPILE_LOG_LEVEL 6
|
#define COMPILE_LOG_LEVEL 6
|
||||||
|
Loading…
Reference in New Issue
Block a user