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