//================================================
// Matt Pietrek
// Microsoft Systems Journal, March 1997
// FILE: CONSOLE_WM_TIMER.CPP
// To build: "CL CONSOLE_WM_TIMER.CPP USER32.LIB"
//================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <conio.h>
// A do-nothing TIMERPROC. Simply prints out the parameters
VOID CALLBACK MyTimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
int main()
{
// Set up a 50 millisecond timer which calls MyTimerProc
SetTimer( 0, 0, 0x50, (TIMERPROC)MyTimerProc );
printf( "A timer proc has been set up. Press any key to exit.\n");
getch(); // Wait for user response. This gives enough time for at
// least one timer cycle to have elapsed
return 0;
}
VOID CALLBACK MyTimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
{
printf( "In MyTimerProc: hwnd:%X uMsg:%X idEvent:%X dwTime:%X\n",
hwnd, uMsg, idEvent, dwTime );
}
Figure 2 CONSOLE_WM_TIMER2.CPP
//================================================
// Matt Pietrek
// Microsoft Systems Journal, March 1997
// FILE: CONSOLE_WM_TIMER2.CPP
// To build: "CL CONSOLE_WM_TIMER2.CPP USER32.LIB"
//================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <conio.h>
// A do-nothing TIMERPROC. Simply prints out the parameters
VOID CALLBACK MyTimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
int main()
{
// Set up a 50 millisecond timer which calls MyTimerProc
SetTimer( 0, 0, 0x50, (TIMERPROC)MyTimerProc );
printf( "A timer proc has been set up. Press any key to call "
"GetMessage/DispatchMessage\n" );
getch(); // Wait for user response. This gives enough time for at
// least one timer cycle to have elapsed
MSG msg = { 0, 0, 0, 0 };
// Get the message, and dispatch it. This causes MyTimerProc to be
// invoked.
if ( GetMessage(&msg, 0, 0, 0) )
DispatchMessage( &msg );
return 0;
}
VOID CALLBACK MyTimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
{
printf( "In MyTimerProc: hwnd:%X uMsg:%X idEvent:%X dwTime:%X\n",
hwnd, uMsg, idEvent, dwTime );
}
Figure 3 Ring 3 DispatchMessage Pseudocode
//=================================================
// Matt Pietrek
// Microsoft Systems Journal, March 1997
// Pseudocode for ring 3 portion of DispatchMessage
//=================================================
LONG DispatchMessageA( CONST MSG *lpmsg )
{
return DispatchMessageWorker( lpmsg, 1 ); // 0 == UNICODE, 1 = ANSI
}
LONG DispatchMessageWorker( CONST MSG *lpmsg, BOOL fAnsi )
{
if ( lpmsg->message == 0xFFFE0000 )
{
_UserSetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
// If we have a non-null HWND, convert it to a pointer to the user mode
// WND structure. We'll use this ptr extensively.
if ( lpmsg->hwnd )
{
pWnd = @ValidateHwnd( lpmsg->hwnd );
if ( !pWnd )
return 0;
}
else
pWnd = 0;
if ( (lpmsg->message != WM_TIMER) && (lpmsg->message != WM_SYSTIMER) )
{
begin_normal_message:
if ( pWnd == 0 ) // Sanity check. We'd better have a valid window!
return 0;
DWORD save_wParam = lpmsg->wParam;
if ( (lpmsg->message != WM_PAINT) && !(pWnd->someFlags9E & 4) )
{
if ( IsWindowUnicode( lpmsg->hwnd ) )
{
if ( fAnsi )
RtlMBMessageWParamCharToWCS( lpmsg->message, save_wParam );
else
RtlWCSMessageWParamCharToMB( lpmsg->message, save_wParam );
}
// Is the high bit in the wndproc address set? If so, this is a
// 16 bit window, and pfnWndProc is a 16:16 far address. To get
// the real address, turn off the high bit (0x80000000)
if ( 0 == (pWnd->pfnWndProc & 0x80000000) )
{
pWnd->pfnWndProc( lpmsg->hwnd, lpmsg->message,
lpmsg->wParam, lpmsg->lParam );
}
else
{
pfnWowWndProcEx( lpmsg->hwnd, lpmsg->message, save_wParam,
lpmsg->lParam, lpmsg->message, pWnd->0x90 );
}
}
else // WM_PAINT, or something else...
{
if ( fAnsi )
_RtlMBMessageWParamCharToWCS( lpmsg->message, save_wParam );
_NtUserDispatchMessage( lpmsg );
}
lpmsg->wParam = save_wParam;
}
else // WM_TIMER && WM_SYSTIMER
{
TIMERPROC pfnTimerCallback = lpmsg->lParam;
if ( pfnTimerCallback == 0 )
goto begin_normal_message;
if ( lpmsg->message == WM_SYSTIMER )
return _NtUserDispatchMessage( lpmsg );
return pfnTimerCallback( lpmsg->hwnd,
lpmsg->message,
lpmsg->wParam, // wTimerId
GetTickCount() ); // actually, an inline
// version of the code
// in KERNEL32.DLL
}
}
Figure 4 WM_TIMER_TOAST.CPP
//================================================
// Matt Pietrek
// Microsoft Systems Journal, March 1997
// FILE: WM_TIMER_TOAST.CPP
// To build: "CL WM_TIMER_TOAST.CPP USER32.LIB"
//================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
int main()
{
// Get the HWND of the tray, which is owned by the Explorer process
HWND hWndToToast = FindWindow( "Shell_TrayWnd", 0 );
if ( hWndToToast )
{
// Post the deadly WM_TIMER message.
PostMessage( hWndToToast, WM_TIMER, 123, 0x87654321 );
}
return 0;
}