diff --git a/common/include/err.hpp b/common/include/err.hpp index 79d2e5e..b0daa9d 100644 --- a/common/include/err.hpp +++ b/common/include/err.hpp @@ -6,6 +6,8 @@ enum Err { ERR_INVALID_ARGUMENTS, ERR_OUT_OF_MEMORY, ERR_ALREADY_RUNNING, + ERR_CREATE_MUTEX, + ERR_MUTEX_TIMEOUT, ERR_CREATE_FILE_MAPPING, ERR_OPEN_FILE_MAPPING, ERR_CREATE_EVENT, diff --git a/common/include/version.hpp b/common/include/version.hpp index d7e4c19..a906781 100644 --- a/common/include/version.hpp +++ b/common/include/version.hpp @@ -1,6 +1,6 @@ #ifndef VERSION_HPP #define VERSION_HPP -#define VERSION_STRING "0.5.0" +#define VERSION_STRING "0.5.1" #endif /* VERSION_HPP */ diff --git a/injector/hook.cpp b/injector/hook.cpp index 558b795..b040d06 100644 --- a/injector/hook.cpp +++ b/injector/hook.cpp @@ -186,7 +186,10 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK IMControl_WndProcHook(int nCod LOG_ERROR("ERROR: GetCompartment(GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION) failed with 0x%0lx", hr); } if (SUCCEEDED(hr)) { - DWORD oldMode = varKeyboardInputModeConversion.lVal; + DWORD oldMode = 0; + if (varKeyboardInputModeConversion.vt == VT_I4 || varKeyboardInputModeConversion.vt == VT_UI4) { + oldMode = varKeyboardInputModeConversion.lVal; + } DWORD newMode = oldMode; if (*g_pSharedData->conversionModeNative) { newMode |= TF_CONVERSIONMODE_NATIVE; @@ -194,6 +197,7 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK IMControl_WndProcHook(int nCod newMode &= ~TF_CONVERSIONMODE_NATIVE; } if (newMode != oldMode) { + varKeyboardInputModeConversion.vt = VT_I4; varKeyboardInputModeConversion.lVal = newMode; hr = keyboardInputModeConversionCompartment->SetValue(0, &varKeyboardInputModeConversion); } diff --git a/main/main.cpp b/main/main.cpp index 4f3e604..566425e 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -167,7 +167,25 @@ int main(int argc, const char *argv[]) { logInit("main"); - // Open shared memory for data sharing, and also for ensuring only one instance is running. + // Use a named mutex for serialization (auto-released when process dies, + // unlike file mapping which can leak when hook DLL remains in target) + HANDLE hMutex = CreateMutexA(NULL, FALSE, "Local\\IMControlMutex"); + if (hMutex == NULL) { + eprintln("%s: CreateMutex() failed with 0x%lx.", argv[0], GetLastError()); + LOG_ERROR("CreateMutex() failed with 0x%lx", GetLastError()); + err = ERR_CREATE_MUTEX; + } + if (!err) { + DWORD dwMutexResult = WaitForSingleObject(hMutex, 10000); + if (dwMutexResult != WAIT_OBJECT_0) { + eprintln("%s: Timed out waiting for mutex.", argv[0]); + LOG_ERROR("Timed out waiting for mutex"); + CloseHandle(hMutex); + return ERR_MUTEX_TIMEOUT; + } + } + + // Open shared memory for data sharing (no longer used as singleton guard) HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, @@ -179,12 +197,6 @@ int main(int argc, const char *argv[]) { LOG_ERROR("CreateFileMapping failed with 0x%lx", GetLastError()); err = ERR_CREATE_FILE_MAPPING; } - if (!err) { - if (GetLastError() == ERROR_ALREADY_EXISTS) { - CloseHandle(hMapFile); - return ERR_ALREADY_RUNNING; - } - } SharedData* pSharedData = NULL; if (!err) { @@ -203,11 +215,16 @@ int main(int argc, const char *argv[]) { } } - HANDLE hEvent = CreateEventA(NULL, TRUE, FALSE, "Local\\IMControlDoneEvent"); - if (hEvent == NULL) { - eprintln("%s: CreateEventA() failed with 0x%lx.", argv[0], GetLastError()); - LOG_ERROR("CreateEventA() failed with 0x%lx", GetLastError()); - err = ERR_CREATE_EVENT; + HANDLE hEvent = NULL; + if (!err) { + hEvent = CreateEventA(NULL, TRUE, FALSE, "Local\\IMControlDoneEvent"); + if (hEvent == NULL) { + eprintln("%s: CreateEventA() failed with 0x%lx.", argv[0], GetLastError()); + LOG_ERROR("CreateEventA() failed with 0x%lx", GetLastError()); + err = ERR_CREATE_EVENT; + } else { + ResetEvent(hEvent); + } } HWND hForegroundWindow = NULL; @@ -405,7 +422,7 @@ int main(int argc, const char *argv[]) { if (!err) { LOG_INFO("Waiting for injector to finish..."); - DWORD dwWaitResult = WaitForSingleObject(hEvent, INFINITE); + DWORD dwWaitResult = WaitForSingleObject(hEvent, 10000); switch (dwWaitResult) { case WAIT_OBJECT_0: LOG_INFO("Injector finished."); @@ -415,6 +432,11 @@ int main(int argc, const char *argv[]) { LOG_ERROR("injector exited with code %d", err); } break; + case WAIT_TIMEOUT: + eprintln("%s: Timed out waiting for injector (10s).", argv[0]); + LOG_ERROR("Timed out waiting for injector (10s)"); + err = ERR_SEND_MESSAGE_TIMEOUT_TIMED_OUT; + break; case WAIT_FAILED: eprintln("%s: WaitForSingleObject() failed with 0x%lx.", argv[0], GetLastError()); LOG_ERROR("WaitForSingleObject() failed with 0x%lx", GetLastError()); @@ -470,6 +492,10 @@ int main(int argc, const char *argv[]) { if (hMapFile != NULL) { CloseHandle(hMapFile); } + if (hMutex != NULL) { + ReleaseMutex(hMutex); + CloseHandle(hMutex); + } LOG_INFO("Exiting with code %d", err);