Skip to content

Commit

Permalink
Handle new window 'Whatsapp Voip' from Whatsapp
Browse files Browse the repository at this point in the history
  • Loading branch information
d4koon committed Nov 3, 2020
1 parent fba454f commit b3b810b
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 80 deletions.
13 changes: 12 additions & 1 deletion WhatsappTray/Helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,4 +365,15 @@ std::string Helper::GetFilepathFromProcessID(DWORD processId)
CloseHandle(processHandle);

return Helper::WideToUtf8(filepath);
}
}

/**
* @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);
}
1 change: 1 addition & 0 deletions WhatsappTray/Helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

96 changes: 30 additions & 66 deletions WhatsappTray/Hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.");
Expand Down Expand Up @@ -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;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion WhatsappTray/TrayManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ TrayManager::TrayManager(HWND _hwndWhatsappTray)

void TrayManager::MinimizeWindowToTray(HWND hwnd)
{
Logger::Info(MODULE_NAME "MinimizeWindowToTray(0x%llX)", reinterpret_cast<uintptr_t>(hwnd));
Logger::Info(MODULE_NAME "MinimizeWindowToTray(0x%08X)", reinterpret_cast<uintptr_t>(hwnd));

// Don't minimize MDI child windows
if ((UINT)GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) return;
Expand Down
40 changes: 28 additions & 12 deletions WhatsappTray/WhatsappTray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ static std::unique_ptr<TrayManager> _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();
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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());
Expand All @@ -312,26 +314,28 @@ 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'
_trayManager = std::make_unique<TrayManager>(_hwndWhatsappTray);

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;
}

/**
Expand Down Expand Up @@ -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<uintptr_t>(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);

Expand All @@ -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;
}

/**
Expand Down

0 comments on commit b3b810b

Please sign in to comment.