Skip to content

Commit

Permalink
Merge pull request #118 from D4koon/context_menu_in_text_field_broken
Browse files Browse the repository at this point in the history
Right cick context menu doesnt work in the text field
  • Loading branch information
D4koon authored Jan 15, 2022
2 parents 75c061e + 9c448bd commit cc42dac
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 14 deletions.
119 changes: 106 additions & 13 deletions WhatsappTray/Hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <sstream>
#include <string>
#include <windows.h>
#include <future>
#include <thread>
#include <psapi.h> // OpenProcess()
#include <shobjidl.h> // For ITaskbarList3
//#include <shellscalingapi.h> // For dpi-scaling stuff
Expand Down Expand Up @@ -51,6 +53,8 @@ static uint64_t _iconCounter = 1; // Start with 1 so 0 can be the signal for no
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 */

static bool _showWindowFunctionIsBlocked = false;

// Functions from ReadRegister.asm
extern "C" int64_t ReturnRdx();
extern "C" int64_t ReturnRcx();
Expand All @@ -74,16 +78,18 @@ static std::string GetEnviromentVariable(const std::string& inputString);
static POINT LParamToPoint(LPARAM lParam);
static bool SendMessageToWhatsappTray(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
static bool BlockShowWindowFunction();
static bool UnblockShowWindowFunction();

static void StartInitThread();
void OnWhatsAppFullyInitialized();

bool SaveHIconToFile(HICON hIcon, std::string fileName);
bool SaveHBITMAPToFile(HBITMAP hBitmap, LPCTSTR lpszFileName);
std::string GetWhatsappTrayPath();
intptr_t* GetITaskbarList3Vtable();
intptr_t GetSetOverlayIconMemoryAddressFromVtable(intptr_t* iTaskbarList3_vtableAddress);
bool WriteJumpToFunctionInVtable(intptr_t* iTaskbarList3_vtableAddress, intptr_t dummyFunctionAddr);
HRESULT DummyFunction();
bool WriteJumpToFunctionInVtable(intptr_t* iTaskbarList3_vtableAddress, intptr_t Rerouted_SetOverlayIcon_Address);
HRESULT Rerouted_SetOverlayIcon();

/**
* @brief The entry point for the dll
Expand Down Expand Up @@ -190,17 +196,33 @@ DWORD WINAPI Init(LPVOID lpParam)
auto iTaskbarList3Vtable = GetITaskbarList3Vtable();
_setOverlayIconMemoryAddress = GetSetOverlayIconMemoryAddressFromVtable(iTaskbarList3Vtable);

auto dummyFunctionAddr = (intptr_t)DummyFunction;
LogString("DummyFunction-adress=%llX.", DummyFunction);
auto Rerouted_SetOverlayIcon_Addr = (intptr_t)Rerouted_SetOverlayIcon;
LogString("Rerouted_SetOverlayIcon-address=%llX.", Rerouted_SetOverlayIcon);

if (WriteJumpToFunctionInVtable(iTaskbarList3Vtable, dummyFunctionAddr) == false) {
if (WriteJumpToFunctionInVtable(iTaskbarList3Vtable, Rerouted_SetOverlayIcon_Addr) == false) {
LogString("WriteJumpToFunctionInVtable FAILED");
return 5;
}

// This is a good point to see if WhatsApp is fully initialized, because it sets the overlay-icon very late in the init-process.
std::async(&OnWhatsAppFullyInitialized);

return 0;
}

/**
* @brief WhatsApp is fully initialized
*/
void OnWhatsAppFullyInitialized()
{
LogString("WhatsAppFullyInitialized");

std::this_thread::sleep_for(std::chrono::seconds(5));

// It is no longer necessary to block the ShowWindow()-function, so unblock it again...
UnblockShowWindowFunction();
}

/**
* @brief This is the new main window-proc. After we are done we call the original window-proc.
*
Expand Down Expand Up @@ -300,6 +322,9 @@ static LRESULT APIENTRY RedirectedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L
LogString("Updating the Dpi");
UpdateDpi(_whatsAppWindowHandle);
} else if (uMsg == WM_LBUTTONUP) {
// Unblock ShowWindow()-function if a mouseclick is registered.
UnblockShowWindowFunction();

// Note x and y are clientare-coordiantes
auto clickPoint = LParamToPoint(lParam);
LogString("WM_LBUTTONUP received x=%d y=%d", clickPoint.x, clickPoint.y);
Expand Down Expand Up @@ -329,6 +354,9 @@ static LRESULT APIENTRY RedirectedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L
LogString("Block WM_LBUTTONUP");
return 0;
}
} else if (uMsg == WM_RBUTTONUP) {
// Unblock ShowWindow()-function if a mouseclick is registered.
UnblockShowWindowFunction();
} else if (uMsg == WM_KEYUP) {
LogString("WM_KEYUP received key=%d", wParam);

Expand Down Expand Up @@ -519,6 +547,10 @@ static bool SendMessageToWhatsappTray(UINT message, WPARAM wParam, LPARAM lParam
* This is done because otherwise it messes with the start-minimized-feature of WhatsappTray
*
* Normaly WhatsApp calls ShowWindow() shortly before it is finished with initialization.
*
* @warning This has some sideeffects, see issue 115 and 118
* -> The context-menue in the textfield will be blocked and the SaveAs-dialog is broke, when for example trying to download some documents
* -> Unblock as soon as it is no longer needed!
*/
static bool BlockShowWindowFunction()
{
Expand All @@ -545,13 +577,68 @@ static bool BlockShowWindowFunction()
return false;
}

// Write 0xC3 to the first byte of the function
// Read the first byte of the ShowWindow()-function
auto showWindowFunc_FirstByte = *((uint8_t*)showWindowFunc);
LogString("First byte of the ShowWindow()-function =0X% (before change)" PRIx8 " NOTE: 0xFF is expected", showWindowFunc_FirstByte);

// Write 0xC3 to the first byte of the ShowWindow()-function
// This translate to a "RET"-command so the function will immediatly return instead of the normal jmp-command
*((uint8_t*)showWindowFunc) = 0xC3;

// Read the first byte of the ShowWindow()-function to see that it has worked
auto showWindowFunc_FirstByte = *((uint8_t*)showWindowFunc);
LogString("First byte of the ShowWindow()-function =0x%" PRIx8 " NOTE: 0xC3 is expected", showWindowFunc_FirstByte);
showWindowFunc_FirstByte = *((uint8_t*)showWindowFunc);
LogString("First byte of the ShowWindow()-function =0X% (after change)" PRIx8 " NOTE: 0xC3 is expected", showWindowFunc_FirstByte);

_showWindowFunctionIsBlocked = true;

return true;
}

/**
* @brief Restore the ShowWindow()-function so that WhatsApp can call it again.
*/
static bool UnblockShowWindowFunction()
{
if (_showWindowFunctionIsBlocked == true) {
LogString("Unblock ShowWindow()-function");

// Get the User32.dll-handle
auto hLib = LoadLibrary("User32.dll");
if (hLib == NULL) {
LogString("Error loading User32.dll");
return false;
}
LogString("loading User32.dll finished");

// Get the address of the ShowWindow()-function of the User32.dll
auto showWindowFunc = (HOOKPROC)GetProcAddress(hLib, "ShowWindow");
if (showWindowFunc == NULL) {
LogString("The function 'ShowWindow' was NOT found");
return false;
}
LogString("The function 'ShowWindow' was NOT found (0x%" PRIx64 ")", showWindowFunc);

// Change the protection-level of this memory-region, because it normaly has read,execute
// NOTE: If this is not done WhatsApp will crash!
DWORD oldProtect;
if (VirtualProtect(showWindowFunc, 20, PAGE_EXECUTE_READWRITE, &oldProtect) == NULL) {
return false;
}

// Read the first byte of the ShowWindow()-function
auto showWindowFunc_FirstByte = *((uint8_t*)showWindowFunc);
LogString("First byte of the ShowWindow()-function =0X% (before change)" PRIx8 " NOTE: 0xC3 is expected", showWindowFunc_FirstByte);

// Write 0xFF to the first byte of the ShowWindow()-function
// This should restore the original function
*((uint8_t*)showWindowFunc) = 0xFF;

// Read the first byte of the ShowWindow()-function to see that it has worked
showWindowFunc_FirstByte = *((uint8_t*)showWindowFunc);
LogString("First byte of the ShowWindow()-function =0X% (after change)" PRIx8 " NOTE: 0xFF is expected", showWindowFunc_FirstByte);

_showWindowFunctionIsBlocked = false;
}

return true;
}
Expand Down Expand Up @@ -583,6 +670,9 @@ void StartInitThread()
//CloseHandle(threadHandle);
}

/**
* @brief Save a HIcon to a file
*/
bool SaveHIconToFile(HICON hIcon, std::string fileName)
{
ICONINFO picInfo;
Expand All @@ -602,6 +692,9 @@ bool SaveHIconToFile(HICON hIcon, std::string fileName)
return retValue;
}

/**
* @brief Save a HBitmap to a file
*/
bool SaveHBITMAPToFile(HBITMAP hBitmap, LPCTSTR fileName)
{
DWORD dwPaletteSize = 0, dwDIBSize = 0;
Expand Down Expand Up @@ -757,9 +850,9 @@ intptr_t GetSetOverlayIconMemoryAddressFromVtable(intptr_t* iTaskbarList3_vtable
}

/**
* @brief Write address of dummy-function to vtable of ITaskbarList3
* @brief Write address of the Rerouted_SetOverlayIcon()-function to vtable of ITaskbarList3
*/
bool WriteJumpToFunctionInVtable(intptr_t* iTaskbarList3_vtableAddress, intptr_t dummyFunctionAddr)
bool WriteJumpToFunctionInVtable(intptr_t* iTaskbarList3_vtableAddress, intptr_t Rerouted_SetOverlayIcon_Address)
{
auto iTaskbarList3_vtableAddress_To_SetOverlayIcon = iTaskbarList3_vtableAddress + 18;

Expand All @@ -773,13 +866,13 @@ bool WriteJumpToFunctionInVtable(intptr_t* iTaskbarList3_vtableAddress, intptr_t
return false;
}

// Write address of dummy-function to v-table
*(iTaskbarList3_vtableAddress_To_SetOverlayIcon) = dummyFunctionAddr;
// Write address of Rerouted_SetOverlayIcon()-function to v-table
*(iTaskbarList3_vtableAddress_To_SetOverlayIcon) = Rerouted_SetOverlayIcon_Address;

return true;
}

HRESULT DummyFunction()
HRESULT Rerouted_SetOverlayIcon()
{
// WARNING: The registers values have to be read before any other code is executed!
// Otherwise it is likely that the values are overwritten
Expand Down
2 changes: 1 addition & 1 deletion WhatsappTray/Version.rc2
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#define MAJOR 1
#define MINOR 9
#define PATCH 0
#define IS_DEBUG 3
#define IS_DEBUG 6

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
Expand Down

0 comments on commit cc42dac

Please sign in to comment.