From 23c7828506d896289985bc215572ec0afaf7c418 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 4 Jan 2016 13:05:42 +0100 Subject: [PATCH] Fix connect protocol. Still needs some cleanup, but it's in an acceptable state. Therefore issue is fixed!. --- src/Components/Modules/ConnectProtocol.cpp | 549 +++++---------------- src/Components/Modules/ConnectProtocol.hpp | 22 +- src/Components/Modules/IPCPipe.cpp | 2 + src/Components/Modules/Singleton.cpp | 20 +- src/STDInclude.hpp | 1 + 5 files changed, 145 insertions(+), 449 deletions(-) diff --git a/src/Components/Modules/ConnectProtocol.cpp b/src/Components/Modules/ConnectProtocol.cpp index 2bbae823..9c77f7a7 100644 --- a/src/Components/Modules/ConnectProtocol.cpp +++ b/src/Components/Modules/ConnectProtocol.cpp @@ -1,38 +1,47 @@ #include "..\..\STDInclude.hpp" -#include + +using namespace std::literals; namespace Components { -#define MAX_PROCESSES 1024 + ConnectProtocol::Container ConnectProtocol::ConnectContainer = { false, false, "" }; - int evaluated = 0; - //Declarations SendMessage stuff - DWORD proc_id = 0, proc_win_id = 0; - HWND console, con_in; + bool ConnectProtocol::Evaluated() + { + return ConnectProtocol::ConnectContainer.Evaluated; + } + + bool ConnectProtocol::Used() + { + if (!ConnectProtocol::Evaluated()) + { + ConnectProtocol::EvaluateProtocol(); + } + + return (ConnectProtocol::ConnectContainer.ConnectString.size() > 0); + } bool ConnectProtocol::InstallProtocol() { - HKEY hKey; - LPCTSTR sk = TEXT("SOFTWARE\\Classes\\iw4x\\shell\\open\\command"); - LPCTSTR data = "URL:iw4x Protocol"; - LPCTSTR value = TEXT("URL Protocol"); - char ownPth[MAX_PATH] = {0}; - char workdir[MAX_PATH] = {0}; - char regred[MAX_PATH] = {0}; + HKEY hKey = NULL; + std::string data; + + char ownPth[MAX_PATH] = { 0 }; + char workdir[MAX_PATH] = { 0 }; + char regred[MAX_PATH] = { 0 }; + DWORD dwsize = MAX_PATH; HMODULE hModule = GetModuleHandle(NULL); + if (hModule != NULL) { - if (GetModuleFileName(hModule, ownPth, MAX_PATH) == ERROR) { - OutputDebugString("ownPth = Error"); return false; } - + if (GetModuleFileName(hModule, workdir, MAX_PATH) == ERROR) { - OutputDebugString("workdir = Error"); return false; } else @@ -44,30 +53,22 @@ namespace Components } else { - return false; } } - //OutputDebugString(Utils::VA("EXE Path: %s", ownPth)); } else { - //OutputDebugString(Utils::VA("Cant get executable path")); return false; } - - - /*OutputDebugString(Utils::VA("EXE Path: %s", ownPth)); - OutputDebugString(Utils::VA("EXE Path2: %s", workdir));*/ - SetCurrentDirectory(workdir); - LONG openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey); + LONG openRes = RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x\\shell\\open\\command", 0, KEY_ALL_ACCESS, &hKey); if (openRes == ERROR_SUCCESS) { //Insert Check of the Key Value here, so the protocol will work even if the game was moved. - openRes = RegQueryValueEx(hKey, 0, 0, 0, LPBYTE(regred), &dwsize); + openRes = RegQueryValueEx(hKey, 0, 0, 0, reinterpret_cast(regred), &dwsize); if (openRes == ERROR_SUCCESS) { char* endPt = strstr(regred, "\" \"%1\""); @@ -77,211 +78,96 @@ namespace Components } else { - OutputDebugString("endPt = Null"); return false; } - char* regredPtr = regred; regredPtr++; - ////DBG(("Reg Read1: %s", regredPtr)); - - RegCloseKey(hKey); if (strcmp(regredPtr, ownPth)) { - ////DBG("Protocol changed, reinstall"); - //sk = TEXT("SOFTWARE\\Classes\\iw4x"); - //openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey); - //if (openRes == ERROR_SUCCESS) - //{ - // ////DBG("Protocol is corrupted, reinstall"); - // RegDeleteKey(hKey, 0); - // RegCloseKey(hKey); - - //} - sk = TEXT("SOFTWARE\\Classes\\iw4x"); - openRes = RegDeleteKey(HKEY_CURRENT_USER, sk); - if (openRes != ERROR_SUCCESS) - { - ////DBG("Protocol is corrupted, reinstall"); - - //RegCloseKey(hKey); - - - } - } - else{ - ////DBG("Protocol is already installed"); - return true; - } - } - else{ - //openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey); - //if (openRes == ERROR_SUCCESS) - //{ - // ////DBG("Protocol is corrupted, reinstall"); - // RegDeleteKey(hKey, 0); - // RegCloseKey(hKey); - - //} - sk = TEXT("SOFTWARE\\Classes\\iw4x"); - openRes = RegDeleteKey(HKEY_CURRENT_USER, sk); - if (openRes != ERROR_SUCCESS) - { - ////DBG("Protocol is corrupted, reinstall"); - - //RegCloseKey(hKey); - - - } - - } - - //////DBG("Protocol is already installed"); - //return true; - - } - else - { - sk = TEXT("SOFTWARE\\Classes\\iw4x"); - openRes = RegDeleteKey(HKEY_CURRENT_USER, sk); - if (openRes != ERROR_SUCCESS) - { - ////DBG("Protocol is corrupted, reinstall"); - //return false; - //RegCloseKey(hKey); - - - } - } - - sk = TEXT("SOFTWARE\\Classes"); - data = "URL:iw4x Protocol"; - value = TEXT("URL Protocol"); - openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey); - - if (openRes == ERROR_SUCCESS) - { - ////DBG("Success opening SOFTWARE\\Classes."); - sk = TEXT("iw4x"); - openRes = RegCreateKeyEx(hKey, sk, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); - - if (openRes == ERROR_SUCCESS) - { - ////DBG("Success creating SOFTWARE\\Classes\\iw3mp."); - openRes = RegSetValueEx(hKey, value, 0, REG_SZ, (LPBYTE)data, strlen(data) + 1); - - if (openRes == ERROR_SUCCESS) - { - ////DBG("Success writing URL:iw4x Protocol"); - data = TEXT(""); - openRes = RegSetValueEx(hKey, value, 0, REG_SZ, (LPBYTE)data, strlen(data) + 1); - - if (openRes == ERROR_SUCCESS) - { - ////DBG("Success writing URL Protocol"); - sk = TEXT("DefaultIcon"); - openRes = RegCreateKeyEx(hKey, sk, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); - - if (openRes == ERROR_SUCCESS) - { - ////DBG("Success creating SOFTWARE\\Classes\\iw3mp\\DefaultIcon"); - data = Utils::VA("%s,1", ownPth); - openRes = RegSetValueEx(hKey, 0, 0, REG_SZ, (LPBYTE)data, strlen(data) + 1); - - if (openRes == ERROR_SUCCESS) - { - openRes = RegCloseKey(hKey); - - if (openRes == ERROR_SUCCESS) - { - sk = TEXT("SOFTWARE\\Classes\\iw4x"); - openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey); - - if (openRes == ERROR_SUCCESS) - { - sk = TEXT("shell\\open\\command"); - openRes = RegCreateKeyEx(hKey, sk, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); - - if (openRes == ERROR_SUCCESS) - { - data = Utils::VA("\"%s\" \"%s\"", ownPth, "%1"); - ////DBG(("Command is %s", data)); - openRes = RegSetValueEx(hKey, 0, 0, REG_SZ, (LPBYTE)data, strlen(data) + 1); - - if (openRes == ERROR_SUCCESS) - { - RegCloseKey(hKey); - - } - else - { - ////DBG("Error writing shell command to registry"); - RegCloseKey(hKey); - return false; - } - } - else - { - ////DBG("Error creating Key shell\\open\\command"); - //RegCloseKey(hKey); - return false; - } - } - else - { - ////DBG("Error opening SOFTWARE\\Classes\\iw3mp"); - //RegCloseKey(hKey); - return false; - } - } - else - { - ////DBG("Error closing DefaultIcon Key"); - RegCloseKey(hKey); - return false; - } - } - else - { - ////DBG("Error writing EXE Path,1 to DefaultIcon Key"); - RegCloseKey(hKey); - return false; - } - } - else - { - ////DBG("Error creating subkey DefaultIcon"); - //RegCloseKey(hKey); - return false; - } - } - else - { - ////DBG("Error writing URL Protocol"); - RegCloseKey(hKey); - return false; - } + openRes = RegDeleteKey(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x"); } else { - ////DBG("Error writing URL:iw4x Protocol Code: %d", openRes); - RegCloseKey(hKey); - return false; + return true; } } else { - ////DBG("Error creating key SOFTWARE\\Classes\\iw3mp"); - //RegCloseKey(hKey); - return false; + openRes = RegDeleteKey(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x"); } } else { - ////DBG("Error opening key."); + openRes = RegDeleteKey(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x"); + } + + // Open SOFTWARE\\Classes + openRes = RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Classes", 0, KEY_ALL_ACCESS, &hKey); + + if (openRes != ERROR_SUCCESS) + { + return false; + } + + // Create SOFTWARE\\Classes\\iw4x + openRes = RegCreateKeyEx(hKey, "iw4x", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); + + if (openRes != ERROR_SUCCESS) + { + return false; + } + + // Write URL:iw4x Protocol + data = "URL:iw4x Protocol"; + openRes = RegSetValueEx(hKey, "URL Protocol", 0, REG_SZ, reinterpret_cast(data.data()), data.size() + 1); + + if (openRes != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return false; + } + + // Create SOFTWARE\\Classes\\iw4x\\DefaultIcon + openRes = RegCreateKeyEx(hKey, "DefaultIcon", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); + + if (openRes != ERROR_SUCCESS) + { + return false; + } + + data = Utils::VA("%s,1", ownPth); + openRes = RegSetValueEx(hKey, 0, 0, REG_SZ, reinterpret_cast(data.data()), data.size() + 1); + RegCloseKey(hKey); + + if (openRes != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return false; + } + + openRes = RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x", 0, KEY_ALL_ACCESS, &hKey); + + if (openRes != ERROR_SUCCESS) + { + return false; + } + + openRes = RegCreateKeyEx(hKey, "shell\\open\\command", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); + + if (openRes != ERROR_SUCCESS) + { + return false; + } + + data = Utils::VA("\"%s\" \"%s\"", ownPth, "%1"); + openRes = RegSetValueEx(hKey, 0, 0, REG_SZ, reinterpret_cast(data.data()), data.size() + 1); + RegCloseKey(hKey); + + if (openRes != ERROR_SUCCESS) + { return false; } @@ -290,23 +176,17 @@ namespace Components void ConnectProtocol::EvaluateProtocol() { - if (evaluated) return; - evaluated = 1; - OutputDebugString("Evaluated = 1"); + if (ConnectProtocol::ConnectContainer.Evaluated) return; + ConnectProtocol::ConnectContainer.Evaluated = true; + char* args = GetCommandLine(); - OutputDebugString("GetCommandLine"); char* substr = strstr(args, "iw4x://"); if (!substr || substr == args) { - OutputDebugString("substr==args"); - OutputDebugString(substr); - OutputDebugString("substr==args"); - OutputDebugString(args); return; } - substr += 7; char* substr2 = strstr(substr, "/"); if (substr2 != NULL) @@ -315,220 +195,45 @@ namespace Components } else { - OutputDebugString("substr2 = NULL"); return; } - ////DBG(("Connecting to: %s", substr)); - OutputDebugString(Utils::VA("connect %s", substr)); - - Command::Execute(Utils::VA("connect %s;", substr), true); + ConnectProtocol::ConnectContainer.ConnectString = substr; } - BOOL ConnectProtocol::InvokeConnect() - { - - char* args = GetCommandLineA(); - char* substr = strstr(args, "iw4x://"); - - ////DBG("Mutex give us a Handle = %d", mutex); - ////DBG("Last Error = %d", GetLastError()); - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - if (!substr || substr == args) - { - // Not started using the protocol - return FALSE; - } - - //Now we have to get the Window Handle of the Console and the Handle of the Input field - ////DBG("The Game is already running"); - FindEditHandle("iw4x.exe"); - - substr += 7; - char* substr2 = strstr(substr, "/"); - if (substr2 != NULL) - { - *substr2 = 0; - } - else - { - return false; - } - - if (proc_id != 0) - { - - if (con_in != NULL) - { - SendMessageA(con_in, WM_SETTEXT, NULL, (LPARAM)Utils::VA("connect %s;", substr)); - SendMessageA(con_in, WM_CHAR, 0xD, 0); - } - - } - else - { - return FALSE; - ////DBG("Did not find Process by Name iw4x"); - } - - ////DBG("Exit this Instance"); - return TRUE; - - } - else - { - if (substr && substr != args) - { - // Skip intro - *(BYTE*)0x60BECF = 0xEB; - return FALSE; - } - return FALSE; - } - return FALSE; - } - - - ConnectProtocol::ConnectProtocol() { - OutputDebugString("Installing Protocol"); + // IPC handler + IPCPipe::On("connect", [] (std::string data) + { + Command::Execute(Utils::VA("connect %s", data.data()), false); + }); + + // Invocation handler + // TODO: Don't call it every frame, once is enough! + Renderer::OnFrame([] () + { + if (!ConnectProtocol::ConnectContainer.Invoked && ConnectProtocol::Used()) + { + ConnectProtocol::ConnectContainer.Invoked = true; + Command::Execute(Utils::VA("connect %s", ConnectProtocol::ConnectContainer.ConnectString.data()), false); + } + }); + ConnectProtocol::InstallProtocol(); ConnectProtocol::EvaluateProtocol(); - } - - //Send Connect Command to running iw4x instance - BOOL CALLBACK ConnectProtocol::EnumWindowsProc(__in HWND hWnd, __in LPARAM lParam) { - - DWORD id = GetWindowThreadProcessId(hWnd, &id); - DWORD id2 = GetWindowThreadProcessId(FindWindowFromProcessId(proc_id), &id2); - //DBG("process id: %d %d Real ID: %d", id, id2, proc_id); - if (id == id2) + // Fire protocol handlers + // Make sure this happens after the pipe-initialization! + if (!Singleton::IsFirstInstance()) { - //printf("THEY MATCH!process id: %d\n", id); - char buffer[256]; - GetWindowText(hWnd, (LPSTR)buffer, 255); - char* endPtr = strstr(buffer, "Console"); - if (endPtr != 0) - { - //DBG(("Got Process Window Handle: %d, Window Text = %s", hWnd, buffer)); - console = hWnd; - EnumChildWindows(console, EnumChildProc, NULL); - return FALSE; - } - + IPCPipe::Write("connect", ConnectProtocol::ConnectContainer.ConnectString); + ExitProcess(0); } - else{ - //DBG(("Got no Process Window Handle!!!!!!!!!!!!")); - } - - return TRUE; - } - - BOOL CALLBACK ConnectProtocol::EnumChildProc(HWND hwnd, LPARAM lParam) { - char buffer[256]; - - GetClassName(hwnd, (LPSTR)buffer, 255); - char* endPtr = strstr(buffer, "Edit"); - if (endPtr != 0) + else { - con_in = hwnd; - //DBG("Got Handle of Edit Field: %d", hwnd); - return FALSE; + // Only skip intro here, invocation will be done later. + Utils::Hook::Set(0x60BECF, 0xEB); } - - - return TRUE; - - } - - struct EnumData { - DWORD dwProcessId; - HWND hWnd; - }; - - BOOL CALLBACK ConnectProtocol::EnumProc(HWND hWnd, LPARAM lParam) { - // Retrieve storage location for communication data - EnumData& ed = *(EnumData*)lParam; - DWORD dwProcessId = 0x0; - // Query process ID for hWnd - GetWindowThreadProcessId(hWnd, &dwProcessId); - // Apply filter - if you want to implement additional restrictions, - // this is the place to do so. - if (ed.dwProcessId == dwProcessId) { - // Found a window matching the process ID - ed.hWnd = hWnd; - // Report success - SetLastError(ERROR_SUCCESS); - // Stop enumeration - return FALSE; - } - // Continue enumeration - return TRUE; - } - - void ConnectProtocol::FindEditHandle(__in_z LPCTSTR lpcszFileName) - { - LPDWORD lpdwProcessIds; - LPTSTR lpszBaseName; - HANDLE hProcess; - DWORD i, cdwProcesses, dwProcessId = 0; - - lpdwProcessIds = (LPDWORD)HeapAlloc(GetProcessHeap(), 0, MAX_PROCESSES*sizeof(DWORD)); - if (lpdwProcessIds != NULL) - { - if (EnumProcesses(lpdwProcessIds, MAX_PROCESSES*sizeof(DWORD), &cdwProcesses)) - { - lpszBaseName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR)); - if (lpszBaseName != NULL) - { - cdwProcesses /= sizeof(DWORD); - for (i = 0; i < cdwProcesses; i++) - { - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, lpdwProcessIds[i]); - if (hProcess != NULL) - { - if (GetModuleBaseName(hProcess, NULL, lpszBaseName, MAX_PATH) > 0) - { - //DBG(("Process Name = %s", lpszBaseName)); - if (!lstrcmpi(lpszBaseName, lpcszFileName)) - { - //DBG("Stage 8"); - dwProcessId = lpdwProcessIds[i]; - CloseHandle(hProcess); - proc_id = dwProcessId; - EnumWindows(EnumWindowsProc, NULL); - if (con_in != NULL) - { - break; - } - - } - } - CloseHandle(hProcess); - } - } - HeapFree(GetProcessHeap(), 0, (LPVOID)lpszBaseName); - } - } - HeapFree(GetProcessHeap(), 0, (LPVOID)lpdwProcessIds); - } - //DBG("Return %d", dwProcessId); - //return dwProcessId; - } - // Main entry - HWND ConnectProtocol::FindWindowFromProcessId(DWORD dwProcessId) { - EnumData ed = { dwProcessId }; - if (!EnumWindows(EnumProc, (LPARAM)&ed) && - (GetLastError() == ERROR_SUCCESS)) { - return ed.hWnd; - } - return NULL; - } - // Helper method for convenience - HWND ConnectProtocol::FindWindowFromProcess(HANDLE hProcess) { - return FindWindowFromProcessId(GetProcessId(hProcess)); } } diff --git a/src/Components/Modules/ConnectProtocol.hpp b/src/Components/Modules/ConnectProtocol.hpp index faebcae4..a552c4e5 100644 --- a/src/Components/Modules/ConnectProtocol.hpp +++ b/src/Components/Modules/ConnectProtocol.hpp @@ -6,18 +6,20 @@ namespace Components ConnectProtocol(); const char* GetName() { return "ConnectProtocol"; }; - static void EvaluateProtocol(); - static BOOL InvokeConnect(); + static bool Evaluated(); + static bool Used(); private: - static bool InstallProtocol(); + struct Container + { + bool Evaluated; + bool Invoked; + std::string ConnectString; + }; - //Additional Functions for InvokeConnect - static void FindEditHandle(__in_z LPCTSTR lpcszFileName); - static BOOL CALLBACK EnumProc(HWND hWnd, LPARAM lParam); - static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam); - static BOOL CALLBACK EnumWindowsProc(__in HWND hWnd, __in LPARAM lParam); - static HWND FindWindowFromProcessId(DWORD dwProcessId); - static HWND FindWindowFromProcess(HANDLE hProcess); + static Container ConnectContainer; + + static void EvaluateProtocol(); + static bool InstallProtocol(); }; } \ No newline at end of file diff --git a/src/Components/Modules/IPCPipe.cpp b/src/Components/Modules/IPCPipe.cpp index 67dabd40..732bf7e1 100644 --- a/src/Components/Modules/IPCPipe.cpp +++ b/src/Components/Modules/IPCPipe.cpp @@ -207,6 +207,8 @@ namespace Components IPCPipe::IPCPipe() { + if (Dedicated::IsDedicated()) return; + // Server pipe IPCPipe::ServerPipe = new Pipe(); IPCPipe::ServerPipe->OnConnect(IPCPipe::ConnectClient); diff --git a/src/Components/Modules/Singleton.cpp b/src/Components/Modules/Singleton.cpp index 4f4c6640..0b48e35b 100644 --- a/src/Components/Modules/Singleton.cpp +++ b/src/Components/Modules/Singleton.cpp @@ -14,24 +14,10 @@ namespace Components if (Dedicated::IsDedicated()) return; Singleton::FirstInstance = (CreateMutex(NULL, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS); - //Checking if the instance is for the connect protocol - if (!Singleton::FirstInstance) + + if (!Singleton::FirstInstance && !ConnectProtocol::Used() && MessageBoxA(0, "Do you want to start another instance?", "Game already running", MB_ICONEXCLAMATION | MB_YESNO) == IDNO) { - if (ConnectProtocol::InvokeConnect() == TRUE) - { - //Connect command was successfuly sent to the first instance, exiting the second game instance now. - ExitProcess(0); - } - else - { - //No connect command was provided, continuing with normal processing. - if (!Singleton::FirstInstance && MessageBoxA(0, "Do you want to start another instance?", "Game already running", MB_ICONEXCLAMATION | MB_YESNO) == IDNO) - { - ExitProcess(0); - } - } + ExitProcess(0); } - - } } diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index be5868d9..ca36ebb3 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "Utils\Utils.hpp" #include "Utils\WebIO.hpp"