From b3b810bf90234b943fe5cb7bba41374b9c667fc6 Mon Sep 17 00:00:00 2001 From: d4koon Date: Tue, 3 Nov 2020 09:33:43 +0100 Subject: [PATCH] Handle new window 'Whatsapp Voip' from Whatsapp --- WhatsappTray/Helper.cpp | 13 ++++- WhatsappTray/Helper.h | 1 + WhatsappTray/Hook.cpp | 96 +++++++++++------------------------ WhatsappTray/TrayManager.cpp | 2 +- WhatsappTray/WhatsappTray.cpp | 40 ++++++++++----- 5 files changed, 72 insertions(+), 80 deletions(-) diff --git a/WhatsappTray/Helper.cpp b/WhatsappTray/Helper.cpp index afb5caf..c84474a 100644 --- a/WhatsappTray/Helper.cpp +++ b/WhatsappTray/Helper.cpp @@ -365,4 +365,15 @@ std::string Helper::GetFilepathFromProcessID(DWORD processId) CloseHandle(processHandle); return Helper::WideToUtf8(filepath); -} \ No newline at end of file +} + +/** + * @brief Gets the text of a window. + */ +std::string Helper::GetWindowTitle(const HWND hwnd) +{ + char windowNameBuffer[2000]; + GetWindowTextA(hwnd, windowNameBuffer, sizeof(windowNameBuffer)); + + return std::string(windowNameBuffer); +} diff --git a/WhatsappTray/Helper.h b/WhatsappTray/Helper.h index c53d130..a3c22c0 100644 --- a/WhatsappTray/Helper.h +++ b/WhatsappTray/Helper.h @@ -50,5 +50,6 @@ class Helper static std::wstring GetFilenameFromPath(std::wstring path); static std::string ResolveLnk(HWND hwnd, LPCSTR lpszLinkFile); static std::string GetFilepathFromProcessID(DWORD processId); + static std::string GetWindowTitle(const HWND hwnd); }; diff --git a/WhatsappTray/Hook.cpp b/WhatsappTray/Hook.cpp index 49ce449..dad0400 100644 --- a/WhatsappTray/Hook.cpp +++ b/WhatsappTray/Hook.cpp @@ -49,9 +49,6 @@ static DWORD _processID = NULL; static HWND _whatsAppWindowHandle = NULL; static WNDPROC _originalWndProc = NULL; -static HWND _tempWindowHandle = NULL; /* For GetTopLevelWindowhandleWithName() */ -static std::string _searchedWindowTitle; /* For GetTopLevelWindowhandleWithName() */ - static UINT _dpiX; /* The horizontal dpi-size. Is set in Windows settings. Default 100% = 96 */ static UINT _dpiY; /* The vertical dpi-size. Is set in Windows settings. Default 100% = 96 */ @@ -61,9 +58,6 @@ static void UpdateDpi(HWND hwnd); // NOTE: extern "C" is important to disable name-mangling, so that the functions can be found with GetProcAddress(), which is used in WhatsappTray.cpp extern "C" DLLIMPORT LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam); static HWND GetTopLevelWindowhandleWithName(std::string searchedWindowTitle); -static BOOL CALLBACK FindTopLevelWindowhandleWithNameCallback(HWND hwnd, LPARAM lParam); -static bool WindowhandleIsToplevelWithTitle(HWND hwnd, std::string searchedWindowTitle); -static bool IsTopLevelWhatsApp(HWND hwnd); static std::string GetWindowTitle(HWND hwnd); static std::string GetFilepathFromProcessID(DWORD processId); static std::string WideToUtf8(const std::wstring& inputString); @@ -94,7 +88,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) break; } case DLL_PROCESS_DETACH: { - LogString("Detach hook.dll from ProcessID: 0x%08X",_processID); + LogString("Detach hook.dll from ProcessID: 0x%08X", _processID); // Remove our window-proc from the chain by setting the original window-proc. if (_originalWndProc != NULL) { @@ -189,14 +183,14 @@ static LRESULT APIENTRY RedirectedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L LogString("SC_MINIMIZE received"); // Here i check if the windowtitle matches. Vorher hatte ich das Problem das sich Chrome auch minimiert hat. - if (IsTopLevelWhatsApp(hwnd)) { + if (hwnd == _whatsAppWindowHandle) { SendMessageToWhatsappTray(WM_WA_MINIMIZE_BUTTON_PRESSED); } } } else if (uMsg == WM_NCDESTROY) { LogString("WM_NCDESTROY received"); - if (IsTopLevelWhatsApp(hwnd)) { + if (hwnd == _whatsAppWindowHandle) { auto successfulSent = SendMessageToWhatsappTray(WM_WHAHTSAPP_CLOSING); if (successfulSent) { LogString("WM_WHAHTSAPP_CLOSING successful sent."); @@ -315,71 +309,41 @@ LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam) */ static HWND GetTopLevelWindowhandleWithName(std::string searchedWindowTitle) { - _tempWindowHandle = NULL; - - _searchedWindowTitle = searchedWindowTitle; - EnumWindows(FindTopLevelWindowhandleWithNameCallback, NULL); - - return _tempWindowHandle; -} - -/** - * @brief Search the window-handle for the current process - * - * Be carefull, one process can have multiple windows. - * Thats why the window-title also gets checked. - */ -static BOOL CALLBACK FindTopLevelWindowhandleWithNameCallback(HWND hwnd, LPARAM lParam) -{ - DWORD processId; - auto result = GetWindowThreadProcessId(hwnd, &processId); - - // Check processId and Title - // Already observerd an instance where the processId alone lead to an false match! - if (_processID == processId) { - // Found the matching processId - - if (WindowhandleIsToplevelWithTitle(hwnd, _searchedWindowTitle)) { - // The window is the root-window + HWND iteratedHwnd = NULL; + while (true) { + iteratedHwnd = FindWindowExA(NULL, iteratedHwnd, NULL, WHATSAPP_CLIENT_NAME); + if (iteratedHwnd == NULL) { + return NULL; + } - _tempWindowHandle = hwnd; + DWORD processId; + DWORD threadId = GetWindowThreadProcessId(iteratedHwnd, &processId); - // Stop enumeration - return false; + // Check processId and Title + // Already observerd an instance where the processId alone lead to an false match! + if (_processID != processId) { + // processId does not match -> continue looking + continue; } - } + // Found matching processId - // Continue enumeration - return true; -} + if (iteratedHwnd != GetAncestor(iteratedHwnd, GA_ROOT)) { + //LogString("Window is not a toplevel-window"); + continue; + } -/** - * @brief Returns true if the window-handle and the title match - */ -static bool WindowhandleIsToplevelWithTitle(HWND hwnd, std::string searchedWindowTitle) -{ - if (hwnd != GetAncestor(hwnd, GA_ROOT)) { - //LogString("Window is not a toplevel-window"); - return false; - } + auto windowTitle = GetWindowTitle(iteratedHwnd); + // Also check length because compare also matches strings that are longer like 'WhatsApp Voip' + if (windowTitle.compare(searchedWindowTitle) != 0 || windowTitle.length() != strlen(WHATSAPP_CLIENT_NAME)) { + //LogString("windowTitle='" + windowTitle + "' does not match '" WHATSAPP_CLIENT_NAME "'"); + continue; + } - auto windowTitle = GetWindowTitle(hwnd); - if (windowTitle.compare(searchedWindowTitle) != 0) { - //LogString("windowTitle='" + windowTitle + "' does not match '" WHATSAPP_CLIENT_NAME "'"); - return false; + // Window handle found + break; } - return true; -} - -/** - * To verify that we found the correct window: - * 1. Check if its a toplevel-window (below desktop) - * 2. Match the window-name with whatsapp. - */ -static bool IsTopLevelWhatsApp(HWND hwnd) -{ - return WindowhandleIsToplevelWithTitle(hwnd, WHATSAPP_CLIENT_NAME); + return iteratedHwnd; } /** diff --git a/WhatsappTray/TrayManager.cpp b/WhatsappTray/TrayManager.cpp index 3fc3ae6..c07ec9d 100644 --- a/WhatsappTray/TrayManager.cpp +++ b/WhatsappTray/TrayManager.cpp @@ -41,7 +41,7 @@ TrayManager::TrayManager(HWND _hwndWhatsappTray) void TrayManager::MinimizeWindowToTray(HWND hwnd) { - Logger::Info(MODULE_NAME "MinimizeWindowToTray(0x%llX)", reinterpret_cast(hwnd)); + Logger::Info(MODULE_NAME "MinimizeWindowToTray(0x%08X)", reinterpret_cast(hwnd)); // Don't minimize MDI child windows if ((UINT)GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) return; diff --git a/WhatsappTray/WhatsappTray.cpp b/WhatsappTray/WhatsappTray.cpp index 7520b41..29ac924 100644 --- a/WhatsappTray/WhatsappTray.cpp +++ b/WhatsappTray/WhatsappTray.cpp @@ -65,7 +65,7 @@ static std::unique_ptr _trayManager; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -static void InitWhatsappTray(); +static bool InitWhatsappTray(); static HWND StartWhatsapp(); static HWND FindWhatsapp(); static void TryClosePreviousWhatsappTrayInstance(); @@ -141,7 +141,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara // See default case for handling of this message s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); - InitWhatsappTray(); + if (InitWhatsappTray() == false) { + DestroyWindow(_hwndWhatsappTray); + } } break; case WM_COMMAND: { switch (LOWORD(wParam)) { @@ -288,7 +290,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara /** * @brief Initializes WhatsappTray */ -static void InitWhatsappTray() +static bool InitWhatsappTray() { // Setup the settings for launch on windows startup. SetLaunchOnWindowsStartupSetting(AppData::LaunchOnWindowsStartup.Get()); @@ -312,7 +314,7 @@ static void InitWhatsappTray() if (!(_hLib = LoadLibrary("Hook.dll"))) { Logger::Error(MODULE_NAME "::WinMain() - Error loading Hook.dll."); MessageBox(NULL, "Error loading Hook.dll.", "WhatsappTray", MB_OK | MB_ICONERROR); - return; + return false; } // TrayManager needs to be ready before WhatsApp is started to handle 'start minimized' @@ -320,18 +322,20 @@ static void InitWhatsappTray() if (StartWhatsapp() == nullptr) { MessageBoxA(NULL, "Error launching WhatsApp. Examine the logs for details", "WhatsappTray", MB_OK); - return; + return false; } _trayManager->AddWindowToTray(_hwndWhatsapp); if (SetHook() == false) { Logger::Error(MODULE_NAME "::WinMain() - Error setting hook."); - return; + return false; } // Send a WM_WHATSAPP_API_NEW_MESSAGE-message when a new WhatsApp-message has arrived. WhatsAppApi::NotifyOnNewMessage([]() { PostMessageA(_hwndWhatsappTray, WM_WHATSAPP_API_NEW_MESSAGE, 0, 0); }); + + return true; } /** @@ -428,15 +432,27 @@ static HWND StartWhatsapp() */ static HWND FindWhatsapp() { - HWND currentWindow = NULL; + HWND iteratedHwnd = NULL; while (true) { - currentWindow = FindWindowExA(NULL, currentWindow, NULL, WHATSAPP_CLIENT_NAME); - if (currentWindow == NULL) { + iteratedHwnd = FindWindowExA(NULL, iteratedHwnd, NULL, WHATSAPP_CLIENT_NAME); + if (iteratedHwnd == NULL) { return NULL; } + auto windowTitle = Helper::GetWindowTitle(iteratedHwnd); + Logger::Info(MODULE_NAME "::FindWhatsapp() - Found window with title: '%s' hwnd=0x%08X", windowTitle.c_str(), reinterpret_cast(iteratedHwnd)); + + if (IsWindowVisible(iteratedHwnd) == false) { + continue; + } + + // Also check length because compare also matches strings that are longer like 'WhatsApp Voip' + if (windowTitle.compare(WHATSAPP_CLIENT_NAME) != 0 && windowTitle.length() == strlen(WHATSAPP_CLIENT_NAME)) { + continue; + } + DWORD processId; - DWORD threadId = GetWindowThreadProcessId(currentWindow, &processId); + DWORD threadId = GetWindowThreadProcessId(iteratedHwnd, &processId); auto filepath = Helper::GetFilepathFromProcessID(processId); @@ -453,11 +469,11 @@ static HWND FindWhatsapp() continue; } - Logger::Info(MODULE_NAME "::FindWhatsapp() - Found match."); + Logger::Info(MODULE_NAME "::FindWhatsapp() - Found match"); break; } - return currentWindow; + return iteratedHwnd; } /**