0% found this document useful (0 votes)
23 views1 page

Using Hooks - Win32 Apps - Microsoft Learn

The document discusses the use of hooks in Windows application development, detailing how to install and release hook procedures using functions like SetWindowsHookEx and UnhookWindowsHookEx. It includes code examples demonstrating the monitoring of system events through various hook types, such as WH_CALLWNDPROC and WH_GETMESSAGE. Additionally, it explains the management of global and thread-specific hooks, including the necessary steps for proper installation and cleanup.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views1 page

Using Hooks - Win32 Apps - Microsoft Learn

The document discusses the use of hooks in Windows application development, detailing how to install and release hook procedures using functions like SetWindowsHookEx and UnhookWindowsHookEx. It includes code examples demonstrating the monitoring of system events through various hook types, such as WH_CALLWNDPROC and WH_GETMESSAGE. Additionally, it explains the management of global and thread-specific hooks, including the necessary steps for proper installation and cleanup.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

We use optional cookies to improve your experience on our websites, such as

through social media connections, and to display personalized advertising based


on your online activity. If you reject optional cookies, only cookies necessary to
provide you the services will be used. You may change your selection by clicking Accept Reject Manage cookies
“Manage Cookies” at the bottom of the page. Privacy Statement Third-Party
Cookies

Learn Discover S Product documentation S Development languages S Topics S  Sign in

Windows App Development Explore S Development S Platforms S Troubleshooting Resources S Dashboard

 Filter by title  / Windows and Messages /  /  Additional resources

Using Hooks
Windows and Messages
T Windows  Training
T Window Classes Article • 01/07/2021 • 6 contributors  Feedback
Learning path
T Window Procedures Use advance techniques in canvas apps
to perform custom updates and
T Messages and Message Queues In this article
optimization - Training
T Timers Installing and Releasing Hook Procedures Use advance techniques in canvas apps
T Window Properties to perform custom updates and
Monitoring System Events
optimization
T Configuration
Hooks
The following code examples demonstrate how to perform the following

tasks associated with hooks:  Documentation


Hooks

Hook Overview Installing and Releasing Hook Procedures SetWindowsHookExW function


Monitoring System Events (winuser.h) - Win32 apps
Using Hooks
Installs an application-defined hook
T Hook Reference procedure into a hook chain. (Unicode)
T Multiple Document Interface (MDI)
Installing and Releasing Hook SetWindowsHookExA function

Procedures
(winuser.h) - Win32 apps
Installs an application-defined hook
procedure into a hook chain. (ANSI)
 Download PDF
You can install a hook procedure by calling the SetWindowsHookEx function
and specifying the type of hook calling the procedure, whether the CallNextHookEx function (winuser.h) -
Win32 apps
procedure should be associated with all threads in the same desktop as the
Passes the hook information to the next
calling thread or with a particular thread, and a pointer to the procedure
hook procedure in the current hook
entry point. chain. A hook procedure can call this…

You must place a global hook procedure in a DLL separate from the Show 5 more
application installing the hook procedure. The installing application must
have the handle to the DLL module before it can install the hook procedure.
To retrieve a handle to the DLL module, call the LoadLibrary function with
the name of the DLL. After you have obtained the handle, you can call the
GetProcAddress function to retrieve a pointer to the hook procedure. Finally,
use SetWindowsHookEx to install the hook procedure address in the
appropriate hook chain. SetWindowsHookEx passes the module handle, a
pointer to the hook-procedure entry point, and 0 for the thread identifier,
indicating that the hook procedure should be associated with all threads in
the same desktop as the calling thread. This sequence is shown in the
following example.

C++ = Copy

HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;

hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll"));
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");

hhookSysMsg = SetWindowsHookEx(
WH_SYSMSGFILTER,
hkprcSysMsg,
hinstDLL,
0);

You can release a thread-specific hook procedure (remove its address from
the hook chain) by calling the UnhookWindowsHookEx function, specifying
the handle to the hook procedure to release. Release a hook procedure as
soon as your application no longer needs it.

You can release a global hook procedure by using UnhookWindowsHookEx,


but this function does not free the DLL containing the hook procedure. This
is because global hook procedures are called in the process context of every
application in the desktop, causing an implicit call to the LoadLibrary
function for all of those processes. Because a call to the FreeLibrary function
cannot be made for another process, there is then no way to free the DLL.
The system eventually frees the DLL after all processes explicitly linked to the
DLL have either terminated or called FreeLibrary and all processes that called
the hook procedure have resumed processing outside the DLL.

An alternative method for installing a global hook procedure is to provide an


installation function in the DLL, along with the hook procedure. With this
method, the installing application does not need the handle to the DLL
module. By linking with the DLL, the application gains access to the
installation function. The installation function can supply the DLL module
handle and other details in the call to SetWindowsHookEx. The DLL can also
contain a function that releases the global hook procedure; the application
can call this hook-releasing function when terminating.

Monitoring System Events


The following example uses a variety of thread-specific hook procedures to
monitor the system for events affecting a thread. It demonstrates how to
process events for the following types of hook procedures:

WH_CALLWNDPROC
WH_CBT
WH_DEBUG
WH_GETMESSAGE
WH_KEYBOARD
WH_MOUSE
WH_MSGFILTER

The user can install and remove a hook procedure by using the menu. When
a hook procedure is installed and an event that is monitored by the
procedure occurs, the procedure writes information about the event to the
client area of the application's main window.

C++ = Copy

#include <windows.h>
#include <strsafe.h>
#include "app.h"

#pragma comment( lib, "user32.lib")


#pragma comment( lib, "gdi32.lib")

#define NUMHOOKS 7

// Global variables

typedef struct _MYHOOKDATA


{
int nType;
HOOKPROC hkprc;
HHOOK hhook;
} MYHOOKDATA;

MYHOOKDATA myhookdata[NUMHOOKS];

HWND gh_hwndMain;

// Hook procedures

LRESULT WINAPI CallWndProc(int, WPARAM, LPARAM);


LRESULT WINAPI CBTProc(int, WPARAM, LPARAM);
LRESULT WINAPI DebugProc(int, WPARAM, LPARAM);
LRESULT WINAPI GetMsgProc(int, WPARAM, LPARAM);
LRESULT WINAPI KeyboardProc(int, WPARAM, LPARAM);
LRESULT WINAPI MouseProc(int, WPARAM, LPARAM);
LRESULT WINAPI MessageProc(int, WPARAM, LPARAM);

void LookUpTheMessage(PMSG, LPTSTR);

LRESULT WINAPI MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, L


{
static BOOL afHooks[NUMHOOKS];
int index;
static HMENU hmenu;

gh_hwndMain = hwndMain;

switch (uMsg)
{
case WM_CREATE:

// Save the menu handle

hmenu = GetMenu(hwndMain);

// Initialize structures with hook data. The menu-item id


// defined as 0 through 6 in the header file app.h. They
// identify array elements both here and during the WM_CO

myhookdata[IDM_CALLWNDPROC].nType = WH_CALLWNDPROC;
myhookdata[IDM_CALLWNDPROC].hkprc = CallWndProc;
myhookdata[IDM_CBT].nType = WH_CBT;
myhookdata[IDM_CBT].hkprc = CBTProc;
myhookdata[IDM_DEBUG].nType = WH_DEBUG;
myhookdata[IDM_DEBUG].hkprc = DebugProc;
myhookdata[IDM_GETMESSAGE].nType = WH_GETMESSAGE;
myhookdata[IDM_GETMESSAGE].hkprc = GetMsgProc;
myhookdata[IDM_KEYBOARD].nType = WH_KEYBOARD;
myhookdata[IDM_KEYBOARD].hkprc = KeyboardProc;
myhookdata[IDM_MOUSE].nType = WH_MOUSE;
myhookdata[IDM_MOUSE].hkprc = MouseProc;
myhookdata[IDM_MSGFILTER].nType = WH_MSGFILTER;
myhookdata[IDM_MSGFILTER].hkprc = MessageProc;

// Initialize all flags in the array to FALSE.

memset(afHooks, FALSE, sizeof(afHooks));

return 0;

case WM_COMMAND:
switch (LOWORD(wParam))
{
// The user selected a hook command from the menu.

case IDM_CALLWNDPROC:
case IDM_CBT:
case IDM_DEBUG:
case IDM_GETMESSAGE:
case IDM_KEYBOARD:
case IDM_MOUSE:
case IDM_MSGFILTER:

// Use the menu-item identifier as an index


// into the array of structures with hook data.

index = LOWORD(wParam);

// If the selected type of hook procedure isn't


// installed yet, install it and check the
// associated menu item.

if (!afHooks[index])
{
myhookdata[index].hhook = SetWindowsHookEx(
myhookdata[index].nType,
myhookdata[index].hkprc,
(HINSTANCE) NULL, GetCurrentThreadId());
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_CHECKED);
afHooks[index] = TRUE;
}

// If the selected type of hook procedure is


// already installed, remove it and remove the
// check mark from the associated menu item.

else
{
UnhookWindowsHookEx(myhookdata[index].hhook);
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_UNCHECKED);
afHooks[index] = FALSE;
}

default:
return (DefWindowProc(hwndMain, uMsg, wParam,
lParam));
}
break;

//
// Process other messages.
//

default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}

/****************************************************************
WH_CALLWNDPROC hook procedure
****************************************************************/

LRESULT WINAPI CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)


{
CHAR szCWPBuf[256];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;

if (nCode < 0) // do not process message


return CallNextHookEx(myhookdata[IDM_CALLWNDPROC].hhook, nCod

// Call an application-defined function that converts a message


// constant to a string and copies it to a buffer.

LookUpTheMessage((PMSG) lParam, szMsg);

hdc = GetDC(gh_hwndMain);

switch (nCode)
{
case HC_ACTION:
hResult = StringCchPrintf(szCWPBuf, 256/sizeof(TCHAR),
"CALLWNDPROC - tsk: %ld, msg: %s, %d times ",
wParam, szMsg, c++);
if (FAILED(hResult))
{
// TODO: writer error handler
}
hResult = StringCchLength(szCWPBuf, 256/sizeof(TCHAR), &c
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 15, szCWPBuf, cch);
break;

default:
break;
}

ReleaseDC(gh_hwndMain, hdc);

return CallNextHookEx(myhookdata[IDM_CALLWNDPROC].hhook, nCode, w


}

/****************************************************************
WH_GETMESSAGE hook procedure
****************************************************************/

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)


{
CHAR szMSGBuf[256];
CHAR szRem[16];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;

if (nCode < 0) // do not process message


return CallNextHookEx(myhookdata[IDM_GETMESSAGE].hhook, nCode
wParam, lParam);

switch (nCode)
{
case HC_ACTION:
switch (wParam)
{
case PM_REMOVE:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR),
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case PM_NOREMOVE:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR),
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

default:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR),
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}

// Call an application-defined function that converts a


// message constant to a string and copies it to a
// buffer.

LookUpTheMessage((PMSG) lParam, szMsg);

hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szMSGBuf, 256/sizeof(TCHAR),
"GETMESSAGE - wParam: %s, msg: %s, %d times ",
szRem, szMsg, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szMSGBuf, 256/sizeof(TCHAR), &c
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 35, szMSGBuf, cch);
break;

default:
break;
}

ReleaseDC(gh_hwndMain, hdc);

return CallNextHookEx(myhookdata[IDM_GETMESSAGE].hhook, nCode, wP


}

/****************************************************************
WH_DEBUG hook procedure
****************************************************************/

LRESULT CALLBACK DebugProc(int nCode, WPARAM wParam, LPARAM lParam)


{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;

if (nCode < 0) // do not process message


return CallNextHookEx(myhookdata[IDM_DEBUG].hhook, nCode,
wParam, lParam);

hdc = GetDC(gh_hwndMain);

switch (nCode)
{
case HC_ACTION:
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"DEBUG - nCode: %d, tsk: %ld, %d times ",
nCode,wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch)
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 55, szBuf, cch);
break;

default:
break;
}

ReleaseDC(gh_hwndMain, hdc);

return CallNextHookEx(myhookdata[IDM_DEBUG].hhook, nCode, wParam,


}

/****************************************************************
WH_CBT hook procedure
****************************************************************/

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)


{
CHAR szBuf[128];
CHAR szCode[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;

if (nCode < 0) // do not process message


return CallNextHookEx(myhookdata[IDM_CBT].hhook, nCode, wPara
lParam);

hdc = GetDC(gh_hwndMain);

switch (nCode)
{
case HCBT_ACTIVATE:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_CLICKSKIPPED:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_CREATEWND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_DESTROYWND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_KEYSKIPPED:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_MINMAX:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_MOVESIZE:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_QS:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_SETFOCUS:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case HCBT_SYSCOMMAND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

default:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "Unkno
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR), "CBT - nCode
szCode, wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 75, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);

return CallNextHookEx(myhookdata[IDM_CBT].hhook, nCode, wParam, l


}

/****************************************************************
WH_MOUSE hook procedure
****************************************************************/

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)


{
CHAR szBuf[128];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;

if (nCode < 0) // do not process the message


return CallNextHookEx(myhookdata[IDM_MOUSE].hhook, nCode,
wParam, lParam);

// Call an application-defined function that converts a message


// constant to a string and copies it to a buffer.

LookUpTheMessage((PMSG) lParam, szMsg);

hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"MOUSE - nCode: %d, msg: %s, x: %d, y: %d, %d times ",
nCode, szMsg, LOWORD(lParam), HIWORD(lParam), c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 95, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);

return CallNextHookEx(myhookdata[IDM_MOUSE].hhook, nCode, wParam,


}

/****************************************************************
WH_KEYBOARD hook procedure
****************************************************************/

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam


{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;

if (nCode < 0) // do not process message


return CallNextHookEx(myhookdata[IDM_KEYBOARD].hhook, nCode,
wParam, lParam);

hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR), "KEYBOARD - n
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 115, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);

return CallNextHookEx(myhookdata[IDM_KEYBOARD].hhook, nCode, wPar


}

/****************************************************************
WH_MSGFILTER hook procedure
****************************************************************/

LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam)


{
CHAR szBuf[128];
CHAR szMsg[16];
CHAR szCode[32];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;

if (nCode < 0) // do not process message


return CallNextHookEx(myhookdata[IDM_MSGFILTER].hhook, nCode,
wParam, lParam);

switch (nCode)
{
case MSGF_DIALOGBOX:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_D
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case MSGF_MENU:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_M
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

case MSGF_SCROLLBAR:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_S
if (FAILED(hResult))
{
// TODO: write error handler
}
break;

default:
hResult = StringCchPrintf(szCode, 128/sizeof(TCHAR), "Unk
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}

// Call an application-defined function that converts a message


// constant to a string and copies it to a buffer.

LookUpTheMessage((PMSG) lParam, szMsg);

hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"MSGFILTER nCode: %s, msg: %s, %d times ",
szCode, szMsg, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 135, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);

return CallNextHookEx(myhookdata[IDM_MSGFILTER].hhook, nCode, wPa


}

Feedback
Was this page helpful?  Yes  No

Provide product feedback | Get help at Microsoft Q&A

 English (United States) Your Privacy Choices 0 Theme S

Manage cookies Previous Versions Blog Contribute Privacy Terms of Use Trademarks © Microsoft 2025

You might also like