diff --git a/GUI/host/host.cpp b/GUI/host/host.cpp index 18bcc8c..b477e0c 100644 --- a/GUI/host/host.cpp +++ b/GUI/host/host.cpp @@ -4,9 +4,50 @@ #include "defs.h" #include "util.h" #include "../vnrhook/texthook.h" +#include namespace { + char* GetCppExceptionInfo(EXCEPTION_POINTERS* exception) + { + // See https://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 + // Not very reliable so use __try + __try { return ((char****)exception->ExceptionRecord->ExceptionInformation[2])[3][1][1] + 8; } + __except (EXCEPTION_EXECUTE_HANDLER) { return "Could not find"; } + } + + std::wstring lastError = L"Unknown error"; + + LONG WINAPI ExceptionLogger(EXCEPTION_POINTERS* exception) + { + MEMORY_BASIC_INFORMATION info = {}; + VirtualQuery(exception->ExceptionRecord->ExceptionAddress, &info, sizeof(info)); + wchar_t moduleName[MAX_PATH] = {}; + GetModuleFileNameW((HMODULE)info.AllocationBase, moduleName, MAX_PATH); + + std::wstringstream errorMsg; + errorMsg << std::uppercase << std::hex << + L"Error code: " << exception->ExceptionRecord->ExceptionCode << std::endl << + L"Error address: " << (uint64_t)exception->ExceptionRecord->ExceptionAddress << std::endl << + L"Error in module: " << moduleName << std::endl; + + if (exception->ExceptionRecord->ExceptionCode == 0xE06D7363) + errorMsg << L"Additional info: " << GetCppExceptionInfo(exception) << std::endl; + + for (int i = 0; i < exception->ExceptionRecord->NumberParameters; ++i) + errorMsg << L"Additional info: " << exception->ExceptionRecord->ExceptionInformation[i] << std::endl; + + lastError = errorMsg.str(); + + return EXCEPTION_CONTINUE_SEARCH; + } + + void Terminate() + { + MessageBoxW(NULL, lastError.c_str(), L"Textractor ERROR", MB_ICONERROR); + std::abort(); + } + class ProcessRecord { public: @@ -96,6 +137,7 @@ namespace { std::thread([] { + Host::Setup(); SECURITY_DESCRIPTOR pipeSD = {}; InitializeSecurityDescriptor(&pipeSD, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&pipeSD, TRUE, NULL, FALSE); // Allow non-admin processes to connect to pipe created by admin host @@ -146,6 +188,7 @@ namespace { std::thread([] { + Host::Setup(); for (std::wstring last; true; Sleep(50)) if (auto text = Util::GetClipboardText()) if (last != text.value()) @@ -156,6 +199,17 @@ namespace namespace Host { + void Setup() + { + static std::once_flag flag; + std::call_once(flag, [] + { + AddVectoredExceptionHandler(FALSE, ExceptionLogger); + SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)Terminate); + }); + std::set_terminate(Terminate); + } + void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onDestroy, TextThread::OutputCallback output) { OnAttach = onAttach; OnDetach = onDetach; OnCreate = onCreate; OnDestroy = onDestroy; TextThread::Output = output; diff --git a/GUI/host/host.h b/GUI/host/host.h index f14604e..3bafe4b 100644 --- a/GUI/host/host.h +++ b/GUI/host/host.h @@ -8,6 +8,7 @@ typedef std::function)> ThreadEventCallback; namespace Host { + void Setup(); void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onDestroy, TextThread::OutputCallback output); void Close(); diff --git a/GUI/host/textthread.cpp b/GUI/host/textthread.cpp index 5a5e554..43dd255 100644 --- a/GUI/host/textthread.cpp +++ b/GUI/host/textthread.cpp @@ -3,7 +3,14 @@ #include "host.h" #include "util.h" -TextThread::TextThread(ThreadParam tp, HookParam hp, std::wstring name) : handle(threadCounter++), name(name), tp(tp), hp(hp) {} +TextThread::TextThread(ThreadParam tp, HookParam hp, std::wstring name) : + handle(threadCounter++), + name(name), + tp(tp), + hp(hp), + deletionEvent(CreateEventW(nullptr, FALSE, FALSE, NULL)), + flushThread([&] { Host::Setup(); while (WaitForSingleObject(deletionEvent, 10) == WAIT_TIMEOUT) Flush(); }) +{} TextThread::~TextThread() { diff --git a/GUI/host/textthread.h b/GUI/host/textthread.h index d793e89..ecc8625 100644 --- a/GUI/host/textthread.h +++ b/GUI/host/textthread.h @@ -37,8 +37,7 @@ private: std::mutex bufferMutex; std::wstring storage; std::mutex storageMutex; - - HANDLE deletionEvent = CreateEventW(nullptr, FALSE, FALSE, NULL); - std::thread flushThread = std::thread([&] { while (WaitForSingleObject(deletionEvent, 10) == WAIT_TIMEOUT) Flush(); }); - DWORD lastPushTime = GetTickCount(); + HANDLE deletionEvent; + std::thread flushThread; + DWORD lastPushTime; }; diff --git a/GUI/main.cpp b/GUI/main.cpp index 6965cae..c79e034 100644 --- a/GUI/main.cpp +++ b/GUI/main.cpp @@ -1,45 +1,14 @@ #include "mainwindow.h" +#include "host/host.h" +#include "misc.h" #include #include -namespace -{ - char* GetCppExceptionInfo(EXCEPTION_POINTERS* exception) - { - // See https://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273 - // Not very reliable so use __try - __try { return ((char****)exception->ExceptionRecord->ExceptionInformation[2])[3][1][1] + 8; } - __except (EXCEPTION_EXECUTE_HANDLER) { return "Could not find"; } - } - - LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* exception) - { - MEMORY_BASIC_INFORMATION info = {}; - VirtualQuery(exception->ExceptionRecord->ExceptionAddress, &info, sizeof(info)); - wchar_t moduleName[MAX_PATH] = {}; - GetModuleFileNameW((HMODULE)info.AllocationBase, moduleName, MAX_PATH); - - std::wstringstream errorMsg; - errorMsg << std::uppercase << std::hex << - L"Error code: " << exception->ExceptionRecord->ExceptionCode << std::endl << - L"Error address: " << (uint64_t)exception->ExceptionRecord->ExceptionAddress << std::endl << - L"Error in module: " << moduleName << std::endl; - - if (exception->ExceptionRecord->ExceptionCode == 0xE06D7363) - errorMsg << L"Additional info: " << GetCppExceptionInfo(exception) << std::endl; - - for (int i = 0; i < exception->ExceptionRecord->NumberParameters; ++i) - errorMsg << L"Additional info: " << exception->ExceptionRecord->ExceptionInformation[i] << std::endl; - - MessageBoxW(NULL, errorMsg.str().c_str(), L"Textractor ERROR", MB_ICONERROR); - - return EXCEPTION_CONTINUE_SEARCH; - } -} - int main(int argc, char *argv[]) { - SetUnhandledExceptionFilter(ExceptionHandler); + Host::Setup(); + QString exe = GetFullModuleName(GetCurrentProcessId()); + SetCurrentDirectoryW(exe.left(exe.lastIndexOf("\\")).toStdWString().c_str()); QApplication a(argc, argv); MainWindow w; w.show();