Sweep the Minesweeper






4.92/5 (7 votes)
Mar 20, 2001

183206

3006
This article shows how to inject your code into another applications address space and then subclass their window to force it to act as you desire.
Introduction
Have you ever been challenged by anyone? If your answer is yes than it is easy for you to understand my feeling when I, being a Microsoft Windows Developer (just pretending), was challenged by a Java Developer over Microsoft Windows Minesweeper (winmine.exe). How amazing was it that this person criticized Microsoft (and there is nothing wrong with that!) and then did all of their Java Development using Microsoft Platform :)
I asked for some days to practice Minesweeper. During those days I realized that I might not be able to trounce that guy in a speed trial. So being a Microsoft Windows Developer I decided to act as Microsoft Windows Developer (I don't mean cheating!).
I decided to stop the timer of Minesweeper. To get inside Minesweeper's
address space I choose WH_CBT
hook and wait for the HCBT_CREATEWND
notification in
my CBTProc(ShellDll_MainHook)
. Whenever a window with a class name
"Minesweeper" came into being I subclassed it for future needs. There is no problem in subclassing because at that moment I am in the address space of the
process that created this window. In the new WndProc
of Minesweeper I stop any
WM_TIMER
messages proceeding. As a result, this stops the timer during the game.
LRESULT CALLBACK ShellDll_MainHook(int nCode, WPARAM wParam, LPARAM lParam) { TCHAR szClass[MAX_PATH] = {0}; if(nCode '<' 0) return CallNextHookEx(g_hShellHook, nCode, wParam, lParam); if(nCode == HCBT_CREATEWND) { HWND hwndToNewWindow = reinterpret_cast<HWND>(wParam); GetClassName(hwndToNewWindow, szClass, MAX_PATH); if(!lstrcmpi(szClass, __TEXT("Minesweeper"))) { g_hwndToMineWindow = hwndToNewWindow; if(IsWindowUnicode(g_hwndToMineWindow)) { pfnWndProc = (WNDPROC)SetWindowLongW(g_hwndToMineWindow, GWL_WNDPROC, (LPARAM)(WNDPROC)MineSweeper_SubClassWndProc); } else { pfnWndProc = (WNDPROC)SetWindowLongA(g_hwndToMineWindow, GWL_WNDPROC, (LPARAM)(WNDPROC)MineSweeper_SubClassWndProc); } } } return CallNextHookEx(g_hShellHook, nCode, wParam, lParam); }
For more information about Hooks see Kayle Marsh's article about Win32 Hooks in MSDN. For sub-classing see MSDN and http://www.codeproject.com/useritems/safesubclassing.asp
I wrote all the code for the hook and subclassing in a Dynamic Link Library (MinesweeperHook.dll) as is the requirement. To set the Hook I made another application, which on starting sets the hook and waits for Minesweeper while resting in the Tray Notification Area (System Tray). You can unset the hook by closing this application. Just right mouse click and then select close from the menu. This
application (MinesweeperExe.exe) sets the hook using MinesweeperHook's exported
function ShellDll_Hook()
, and then uses Shell_NotifyIcon()
to display the Tray
Notification area icon. Before exiting it unsets the hook by calling
MinesweeperHook's exported function ShellDll_UnhHook()
.
In DllMain()
of MinesweeperHook.dll, it is necessary to un-subclass the
Minesweeper because after unsetting the hook our DLL will no longer stay in the
Minesweeper's address space. This is the case when we are playing "winmine"
and we close the MinesweeperExe.exe through its context menu.
Finally, don't tell me if you find my coding style similar to Dino Esposito :)