Copyright © Microsoft Corporation. This document is an archived reproduction of a version originally published by Microsoft. It may have slight formatting modifications for consistency and to improve readability.
Figure 1   CONSOLE_WM_TIMER.CPP


 //================================================
 // 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;
 }