HOOK.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

/*****************************************************************************\
*
* Module: hook.c
*
* Contains the message hooking functions for the Windows debugging Spy
* SDK applet.
*
* Functions:
*
* CreateHookThread()
* HookMain()
* HookWndProc()
* SetSpyHook()
* SetWindowToSpyOn()
* DbgPrintf()
*
* Comments:
*
\*****************************************************************************/

#include "spy.h"


PRIVATE BOOL gfProcessHooks = TRUE;


/*****************************************************************************\
* CreateHookThread
*
* Creates the hook thread.
*
* Arguments:
* none
*
* Returns:
* BOOL - Whether or not hook create succeeeded.
\*****************************************************************************/

BOOL
CreateHookThread(
VOID
)
{
WNDCLASS wc;
DWORD Id;

//
// Register a class for the hook stuff to forward its messages to.
//
wc.hCursor = NULL; // this window never shown, so no
wc.hIcon = NULL; // cursor or icon are necessary
wc.lpszMenuName = NULL;
wc.lpszClassName = HOOKWINDOWCLASS;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hInstance = ghInst;
wc.style = 0;
wc.lpfnWndProc = HookWndProc;
wc.cbWndExtra = sizeof(HWND) + sizeof(HWND);
wc.cbClsExtra = 0;

if (!RegisterClass(&wc))
return FALSE;

//
// Now create another thread to handle the new queue
//
if (!(ghHookThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HookMain,
0L, STANDARD_RIGHTS_REQUIRED, &Id)))
return FALSE;

return TRUE;
}



/*****************************************************************************\
* HookMain
*
* Main window procedure for the Hook window
*
\*****************************************************************************/

DWORD
HookMain(
LPVOID lpv
)
{
MSG msg;

//
// Create a hidden window for all to find, but not to see
//
ghwndSpyHook = CreateWindow(HOOKWINDOWCLASS, HOOKWINDOWNAME,
WS_OVERLAPPEDWINDOW,
0, 0, 0, 0,
(HWND) NULL, /* no parent */
(HMENU) NULL, /* use class menu */
(HANDLE) ghInst, /* handle to window instance */
(LPSTR) NULL /* no params to pass on */
);

if (!ghwndSpyHook)
{
ExitThread(0);
}

SetWindowToSpyOn(HWND_ALL);

//
// Polling forwarded messages from hook's event queue
//
while (IsWindow(ghwndSpyHook) && GetMessage(&msg, ghwndSpyHook, 0, 0))
{
if (gfProcessHooks)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

ghwndSpyHook = NULL;

return 0; // not reached
}



/*****************************************************************************\
* HookWndProc
*
* Window procedure for the spy hook.
*
* Arguments:
* HWND hwnd - handle to the hook window.
* UINT msg - message sent to hook window.
* WPARAM wParam - message parameter.
* LPARAM lParam - message parameter.
*
* Returns:
* The value that the proc should return, based on the processing
* of the specific WM_COMMAND message received.
\*****************************************************************************/

LRESULT CALLBACK
HookWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
switch (msg)
{
//
// New message for Win32 - allows the application to pass data to another application.
//
case WM_COPYDATA:
{
MSG msgT;

msgT.hwnd = (HWND)wParam;
msgT.message = ((PCOPYDATASTRUCT)lParam)->dwData;
msgT.wParam = ((PSPYMSGDATA)((PCOPYDATASTRUCT)lParam)->lpData)->wParam;
msgT.lParam = ((PSPYMSGDATA)((PCOPYDATASTRUCT)lParam)->lpData)->lParam;
//DbgPrintf("S Received Message hwnd:%8.8x msg:%d", msgT.hwnd, msgT.message);
PrintMsg(&msgT);
//DbgPrintf("S Printed Message hwnd:%8.8x msg:%d", msgT.hwnd, msgT.message);
}

return TRUE;

case WM_CREATE:
//
// Initialize the second HWND in the window words to be the
// window handle of the spy app. This will be queried by
// the hook DLL.
//
SetWindowLong(hwnd, sizeof(HWND), (LONG)ghwndSpyApp);
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;

case WM_NCDESTROY:
gfProcessHooks = FALSE;
break;
}

return DefWindowProc(hwnd, msg, wParam, lParam);
}



/*****************************************************************************\
* SetSpyHook
*
* Sets the windows hooks used to trap the messages. After this
* is called with a TRUE for fSet, the messages will start flowing
* through the hook DLL.
*
* Arguments:
* BOOL fSet - TRUE to hook, FALSE to unhook.
*
* Returns:
* TRUE if successful.
*
\*****************************************************************************/

BOOL
SetSpyHook(
BOOL fSet
)
{
static HHOOK hhkGetMessage = NULL;
static HHOOK hhkCallWndProc = NULL;
static HANDLE hmodHook;

if (fSet)
{
if (!hmodHook)
{
if (!(hmodHook = LoadLibrary("hook")))
{
Message(MB_OK | MB_ICONEXCLAMATION,
LoadResourceString(IDS_ERROR_CANT_LOAD_DLL));
return FALSE;
}
}

if (!hhkGetMessage)
{
if (!(hhkGetMessage = SetWindowsHookEx(WH_GETMESSAGE,
(HOOKPROC)GetProcAddress(hmodHook, "SpyGetMsgProc"), hmodHook, 0)))
{
return FALSE;
}
}

if (!hhkCallWndProc)
{
if (!(hhkCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC,
(HOOKPROC)GetProcAddress(hmodHook, "SpyCallWndProc"), hmodHook, 0)))
{
UnhookWindowsHookEx(hhkGetMessage);
return FALSE;
}
}
}
else
{
if (hhkGetMessage)
{
UnhookWindowsHookEx(hhkGetMessage);
hhkGetMessage = NULL;
}

if (hhkCallWndProc)
{
UnhookWindowsHookEx(hhkCallWndProc);
hhkCallWndProc = NULL;
}
}

return TRUE;
}



/*****************************************************************************\
* SetWindowToSpyOn
*
* Sets the current window to spy on to the specified hwnd. This hwnd can
* also be the special value HWND_ALL to specify that all windows should
* be spy'd upon.
*
* Arguments:
* HWND hwndSpyingOn - Window handle to spy on, or HWND_ALL for all windows.
*
* Returns:
* VOID
\*****************************************************************************/

VOID
SetWindowToSpyOn(
HWND hwndSpyingOn
)
{
ghwndSpyingOn = hwndSpyingOn;
gfSpyAll = (ghwndSpyingOn == HWND_ALL) ? TRUE : FALSE;
SetWindowLong(ghwndSpyHook, 0, (LONG)ghwndSpyingOn);
SetSpyCaption();
}



#ifdef DBG
/****************************************************************************
* DBGprintf
*
* This debugging function prints out a string to the debug output.
* An optional set of substitutional parameters can be specified,
* and the final output will be the processed result of these combined
* with the format string, just like printf. A newline is always
* output after every call to this function.
*
* Arguments:
* LPTSTR fmt - Format string (printf style).
* ... - Variable number of arguments.
*
* Returns:
* VOID
****************************************************************************/

VOID DbgPrintf(
LPTSTR fmt,
...
)
{
va_list marker;
TCHAR szBuf[256];

va_start(marker, fmt);
wvsprintf(szBuf, fmt, marker);
va_end(marker);

OutputDebugString(szBuf);
OutputDebugString(TEXT("\r\n"));
}
#endif