|
|
1.1 ! root 1: // ************************************************************************ ! 2: // ! 3: // Microsoft Developer Support ! 4: // Copyright (c) 1993 Microsoft Corporation ! 5: // ! 6: // ************************************************************************ ! 7: // MODULE : RecHook.C ! 8: // PURPOSE : A Small Win32 Recorder-like Sample Application Hook DLL ! 9: // FUNCTIONS : ! 10: // DllMain() - Dll entry point (via _DLLMainCRTStartup) ! 11: // StartJournalRecord - starts the journal record hook ! 12: // StopJournalRecord - stops the journal record hook ! 13: // StartJournalPlayback - starts the journal playback hook ! 14: // StopJournalPlayback - stops the journal playback hook ! 15: // StopAllJournalling - stops any current journal hook ! 16: // COMMENTS : The Journal Record File contains an EVENTHEADER structure ! 17: // followed by a variable number of EVENTMSG structures. ! 18: // ************************************************************************ ! 19: #define STRICT // strict type checking enabled ! 20: #define UNICODE // make the application unicode complient ! 21: #include <Windows.H> // required for all Windows applications ! 22: ! 23: #include "RecHook.H" ! 24: #include "MinRec.H" // we need IDM_MACRO_STOP ! 25: ! 26: // Internal Defines ! 27: // ----------------------------------------------------------------------- ! 28: #define MINREC_FILENAME TEXT("MinRec.Rec") // File for record/play events ! 29: #define MINREC_SIGNATURE "MinRec\0" // Journal Record File signature ! 30: ! 31: //-- header for the MinRec record/playback file ! 32: typedef struct EVENTHEADER_STRUCT { ! 33: CHAR Signature[7]; ! 34: UINT RecordedMsgCount; ! 35: DWORD BaseMsgTime; ! 36: } EVENTHEADER, *PEVENTHEADER; ! 37: ! 38: //-- various "file global" data ! 39: typedef struct GLOBAL_STRUCT { ! 40: BOOL fRecording; ! 41: BOOL fPlaying; ! 42: BOOL fStopRecording; ! 43: BOOL fStopPlaying; ! 44: UINT PlayedMsgCount; ! 45: UINT RecordedMsgCount; ! 46: DWORD BaseMsgTime; ! 47: DWORD LastMsgTime; ! 48: HANDLE hFile; ! 49: EVENTMSG EventMsg; ! 50: HHOOK hHookRecord; ! 51: HHOOK hHookPlayback; ! 52: HHOOK hHookGetMsg; ! 53: HINSTANCE hInstance; ! 54: } GLOBAL, *PGLOBAL; ! 55: ! 56: // Global Data ! 57: // ----------------------------------------------------------------------- ! 58: GLOBAL Global; // various global data ! 59: ! 60: // Internal Function Prototypes ! 61: // ----------------------------------------------------------------------- ! 62: LRESULT CALLBACK JournalRecordProc ( int, WPARAM, LPARAM ); ! 63: LRESULT CALLBACK JournalPlaybackProc( int, WPARAM, LPARAM ); ! 64: LRESULT CALLBACK GetMsgProc ( int, WPARAM, LPARAM ); ! 65: ! 66: ! 67: // ************************************************************************ ! 68: // FUNCTION : DllMain( HINSTANCE, DWORD, LPVOID ) ! 69: // PURPOSE : DLLMain is called by the C run-time library from the ! 70: // _DLLMainCRTStartup entry point. The DLL entry point gets ! 71: // called (entered) on the following events: "Process Attach", ! 72: // "Thread Attach", "Thread Detach" or "Process Detach". ! 73: // ************************************************************************ ! 74: BOOL WINAPI ! 75: DllMain( HINSTANCE hInstanceDll, DWORD dwReason, LPVOID lpvReserved ) ! 76: { ! 77: switch( dwReason ) { ! 78: ! 79: case DLL_PROCESS_ATTACH: ! 80: Global.fRecording = FALSE; ! 81: Global.fPlaying = FALSE; ! 82: Global.hInstance = hInstanceDll; ! 83: break; ! 84: ! 85: } ! 86: ! 87: return( TRUE ); ! 88: UNREFERENCED_PARAMETER( lpvReserved ); ! 89: } ! 90: ! 91: ! 92: // ************************************************************************ ! 93: // FUNCTION : StartJournalRecord() ! 94: // PURPOSE : creates the record file and installs the record hook. ! 95: // ************************************************************************ ! 96: BOOL ! 97: StartJournalRecord() ! 98: { ! 99: // Do not allow recording while playing back ! 100: if( Global.fPlaying ) { ! 101: MessageBox( GetFocus(), ! 102: TEXT( "Sorry, recording while\n" ) ! 103: TEXT( "playing is not allowed." ), ! 104: TEXT( "MinRec - Notice!" ), ! 105: MB_ICONINFORMATION | MB_OK ); ! 106: return( FALSE ); ! 107: } ! 108: ! 109: // Create and open the journal record file and set the file pointer to ! 110: // just past the journal record file header ! 111: Global.hFile = CreateFile( (LPCTSTR) MINREC_FILENAME, GENERIC_WRITE, ! 112: 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); ! 113: SetFilePointer( Global.hFile, (LONG) sizeof(EVENTHEADER), NULL, ! 114: FILE_BEGIN ); ! 115: ! 116: // Initialize the recorded message count to zero and set recording flag ! 117: Global.RecordedMsgCount = 0; ! 118: Global.fRecording = TRUE; ! 119: ! 120: // Set the GetMsg hook to trap Ctrl+Esc, Alt+Esc and Ctrl+Alt+Del. ! 121: Global.hHookGetMsg = SetWindowsHookEx( WH_GETMESSAGE, GetMsgProc, ! 122: Global.hInstance, 0 ); ! 123: ! 124: // Set the Journal Record hook. ! 125: Global.hHookRecord = SetWindowsHookEx( WH_JOURNALRECORD, JournalRecordProc, ! 126: Global.hInstance, 0 ); ! 127: ! 128: return( TRUE ); ! 129: } ! 130: ! 131: ! 132: // ************************************************************************ ! 133: // FUNCTION : JournalRecordProc() ! 134: // PURPOSE : processes the journal record events by writing them to the ! 135: // record file one event at a time. ! 136: // ************************************************************************ ! 137: LRESULT CALLBACK ! 138: JournalRecordProc( int nCode, WPARAM wParam, LPARAM lParam ) ! 139: { ! 140: if( nCode < 0 || Global.fStopRecording ) ! 141: return( CallNextHookEx( Global.hHookRecord, nCode, wParam, lParam ) ); ! 142: ! 143: switch( nCode ) { ! 144: ! 145: case HC_ACTION: { ! 146: LPEVENTMSG lpEventMsg; ! 147: DWORD dwBytesWritten; ! 148: ! 149: lpEventMsg = (LPEVENTMSG) lParam; ! 150: ! 151: // user pressed Ctrl+Break to cancel journal recording ! 152: if( (lpEventMsg->message == WM_KEYDOWN) ! 153: && (LOBYTE(lpEventMsg->paramL) == VK_CANCEL) ) { ! 154: StopAllJournalling(); ! 155: } ! 156: else { ! 157: // write the event message to the Recorded Journal file ! 158: WriteFile( Global.hFile, (LPCSTR) lParam, sizeof(EVENTMSG), ! 159: &dwBytesWritten, NULL ); ! 160: lpEventMsg = (LPEVENTMSG) lParam; ! 161: Global.RecordedMsgCount++; ! 162: if( Global.RecordedMsgCount == 1) ! 163: Global.BaseMsgTime = lpEventMsg->time; ! 164: } ! 165: break; ! 166: } ! 167: ! 168: case HC_SYSMODALON: ! 169: // halt recording ! 170: Global.fStopRecording = TRUE; ! 171: break; ! 172: ! 173: case HC_SYSMODALOFF: ! 174: // resume recording ! 175: Global.fStopRecording = FALSE; ! 176: break; ! 177: ! 178: } ! 179: ! 180: return( CallNextHookEx( Global.hHookRecord, nCode, wParam, lParam ) ); ! 181: UNREFERENCED_PARAMETER( wParam ); ! 182: } ! 183: ! 184: ! 185: // ************************************************************************ ! 186: // FUNCTION : StopJournalRecord() ! 187: // PURPOSE : unhooks the record hook, records the record file header and ! 188: // closes the file. ! 189: // ************************************************************************ ! 190: BOOL ! 191: StopJournalRecord() ! 192: { ! 193: EVENTHEADER EventHeader; ! 194: ! 195: // Remove the Journal Record hook if recording ! 196: if( Global.fRecording ) { ! 197: DWORD dwBytesWritten; ! 198: ! 199: // remove the record hook ! 200: UnhookWindowsHookEx( Global.hHookRecord ); ! 201: ! 202: // remove the get message hook ! 203: UnhookWindowsHookEx( Global.hHookGetMsg ); ! 204: ! 205: // Copy Recorded Journal header data to temporary buffer ! 206: lstrcpyA( EventHeader.Signature, MINREC_SIGNATURE ); ! 207: EventHeader.RecordedMsgCount = Global.RecordedMsgCount; ! 208: EventHeader.BaseMsgTime = Global.BaseMsgTime; ! 209: ! 210: // Open Recorded Journal file and update the file header and close ! 211: // the file ! 212: SetFilePointer( Global.hFile, 0, NULL, FILE_BEGIN ); ! 213: WriteFile( Global.hFile, (LPCSTR) &EventHeader, sizeof(EVENTHEADER), ! 214: &dwBytesWritten, NULL ); ! 215: CloseHandle( Global.hFile ); ! 216: ! 217: // Clear recording flag ! 218: Global.fRecording = FALSE; ! 219: } ! 220: ! 221: return( TRUE ); ! 222: } ! 223: ! 224: ! 225: // ************************************************************************ ! 226: // FUNCTION : StartJournalPlayback() ! 227: // PURPOSE : opens the playback file and reads the header and installs the ! 228: // playback hook. ! 229: // ************************************************************************ ! 230: BOOL ! 231: StartJournalPlayback() ! 232: { ! 233: EVENTHEADER EventHeader; ! 234: DWORD dwBytesRead; ! 235: ! 236: // Allow infinite playback loop ! 237: if( Global.fRecording ) { ! 238: StopJournalRecord(); ! 239: MessageBox( GetFocus(), ! 240: TEXT( "Infinite playback\n" ) ! 241: TEXT( "loop recorded!" ), ! 242: TEXT( "MinRec - Notice!" ), ! 243: MB_ICONINFORMATION | MB_OK ); ! 244: return( FALSE ); ! 245: } ! 246: if( Global.fPlaying ) { ! 247: StopJournalPlayback(); ! 248: } ! 249: ! 250: // Open Recorded Journal file ! 251: Global.hFile = CreateFile( (LPCTSTR) MINREC_FILENAME, GENERIC_READ, ! 252: 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); ! 253: if( Global.hFile == INVALID_HANDLE_VALUE ) { ! 254: MessageBox( GetFocus(), ! 255: TEXT( "The default Journal Record File\n" ) ! 256: TEXT( "MINREC.REC could not be found.\n" ), ! 257: TEXT( "MinRec - Error!" ), ! 258: MB_ICONEXCLAMATION | MB_OK ); ! 259: return( FALSE ); ! 260: } ! 261: ! 262: // Quick check, file size should be at least the length of the header ! 263: if( GetFileSize( Global.hFile, NULL ) < sizeof(EVENTHEADER) ) { ! 264: MessageBox( GetFocus(), ! 265: TEXT( "The file MINREC.REC is not a \n" ) ! 266: TEXT( "valid MinRec Journal Record file.\n" ), ! 267: TEXT( "MinRec - Error!" ), ! 268: MB_ICONEXCLAMATION | MB_OK ); ! 269: return( FALSE ); ! 270: } ! 271: ! 272: // Read Recorded Journal file header ! 273: SetFilePointer( Global.hFile, 0L, NULL, FILE_BEGIN ); ! 274: ReadFile( Global.hFile, (LPVOID) &EventHeader, sizeof(EVENTHEADER), ! 275: &dwBytesRead, NULL ); ! 276: ! 277: // Quick check, the signature of the file must be "MinRec" ! 278: if( lstrcmpA( EventHeader.Signature, MINREC_SIGNATURE ) != 0 ) { ! 279: MessageBox( GetFocus(), ! 280: TEXT( "The file MINREC.REC does not\n" ) ! 281: TEXT( "contain a valid MinRec signature." ), ! 282: TEXT( "MinRec - Error!" ), ! 283: MB_ICONEXCLAMATION | MB_OK ); ! 284: return( FALSE ); ! 285: } ! 286: ! 287: // store the header values ! 288: Global.RecordedMsgCount = EventHeader.RecordedMsgCount; ! 289: Global.BaseMsgTime = EventHeader.BaseMsgTime; ! 290: Global.LastMsgTime = EventHeader.BaseMsgTime; ! 291: ! 292: // If no messages were recorded, none to play back. ! 293: if( Global.RecordedMsgCount == 0 ) { ! 294: MessageBox( GetFocus(), ! 295: TEXT( "Sorry, nothing was recorded, so\n") ! 296: TEXT( "there is nothing to playback." ), ! 297: TEXT( "MinRec - Notice!" ), ! 298: MB_ICONINFORMATION | MB_OK); ! 299: return( FALSE ); ! 300: } ! 301: ! 302: // Initialize the played message count to zero and set the play flag ! 303: Global.PlayedMsgCount = 0; ! 304: Global.fPlaying = TRUE; ! 305: ! 306: // Get the first recorded message from the file and store it ! 307: ReadFile( Global.hFile, (LPVOID) &(Global.EventMsg), sizeof(EVENTMSG), ! 308: &dwBytesRead, NULL ); ! 309: ! 310: // Set the GetMsg hook to trap Ctrl+Break, Ctrl+Esc and Ctrl+Alt+Del. ! 311: Global.hHookGetMsg = SetWindowsHookEx( WH_GETMESSAGE, GetMsgProc, ! 312: Global.hInstance, 0 ); ! 313: ! 314: // Set the Journal Playback hook ! 315: Global.hHookPlayback = SetWindowsHookEx( WH_JOURNALPLAYBACK, ! 316: JournalPlaybackProc, Global.hInstance, 0 ); ! 317: ! 318: return( TRUE ); ! 319: } ! 320: ! 321: ! 322: // ************************************************************************ ! 323: // FUNCTION : JournalPlaybackProc() ! 324: // PURPOSE : processes the journal playback events by reading in the ! 325: // playback file one event at a time. ! 326: // ************************************************************************ ! 327: LRESULT CALLBACK ! 328: JournalPlaybackProc( int nCode, WPARAM wParam, LPARAM lParam ) ! 329: { ! 330: if( nCode < 0 || Global.fStopPlaying ) ! 331: return( CallNextHookEx( Global.hHookPlayback, nCode, wParam, lParam ) ); ! 332: ! 333: switch( nCode ) { ! 334: ! 335: case HC_GETNEXT: { ! 336: LRESULT SleepTime = Global.EventMsg.time - Global.LastMsgTime; ! 337: ! 338: // copy the current ready event message to lParam ! 339: CopyMemory( (PVOID) lParam, (CONST VOID*) &(Global.EventMsg), ! 340: sizeof(EVENTMSG) ); ! 341: Global.LastMsgTime = Global.EventMsg.time; ! 342: return( SleepTime ); ! 343: } ! 344: ! 345: case HC_SKIP: { ! 346: if( ++Global.PlayedMsgCount > Global.RecordedMsgCount ) { ! 347: StopJournalPlayback(); ! 348: return( (LRESULT) 0L ); ! 349: } ! 350: else { ! 351: DWORD dwBytesRead; ! 352: ! 353: // Get the next recorded message from the file and store it ! 354: // in the static buffer for the next HC_GETNEXT message ! 355: ReadFile( Global.hFile, (LPVOID) &(Global.EventMsg), sizeof(EVENTMSG), ! 356: &dwBytesRead, NULL ); ! 357: break; ! 358: } ! 359: } ! 360: ! 361: case HC_SYSMODALON: ! 362: // halt playback ! 363: Global.fStopPlaying = TRUE; ! 364: break; ! 365: ! 366: case HC_SYSMODALOFF: ! 367: // resume playback ! 368: Global.fStopPlaying = FALSE; ! 369: break; ! 370: ! 371: } ! 372: ! 373: return( CallNextHookEx( Global.hHookPlayback, nCode, wParam, lParam ) ); ! 374: UNREFERENCED_PARAMETER( wParam ); ! 375: } ! 376: ! 377: ! 378: // ************************************************************************ ! 379: // FUNCTION : StopJournalPlayback() ! 380: // PURPOSE : unhooks the playback hook and closes the playback file. ! 381: // ************************************************************************ ! 382: BOOL ! 383: StopJournalPlayback() ! 384: { ! 385: // Remove the Playback Journal hook if playing ! 386: if( Global.fPlaying ) { ! 387: ! 388: // remove the playback hook ! 389: UnhookWindowsHookEx( Global.hHookPlayback ); ! 390: ! 391: // remove the get message hook ! 392: UnhookWindowsHookEx( Global.hHookGetMsg ); ! 393: ! 394: // close the journal record file ! 395: CloseHandle( Global.hFile ); ! 396: ! 397: // Clear playback flag ! 398: Global.fPlaying = FALSE; ! 399: } ! 400: ! 401: return( TRUE ); ! 402: } ! 403: ! 404: ! 405: // ************************************************************************ ! 406: // FUNCTION : StopAllJournalling() ! 407: // PURPOSE : stops (unhooks) any current journal hook started (hooked) by ! 408: // this application. ! 409: // ************************************************************************ ! 410: BOOL ! 411: StopAllJournalling( ) ! 412: { ! 413: if( Global.fRecording ) ! 414: StopJournalRecord(); ! 415: if( Global.fPlaying ) ! 416: StopJournalPlayback(); ! 417: ! 418: return( TRUE ); ! 419: } ! 420: ! 421: ! 422: // ************************************************************************ ! 423: // FUNCTION : GetMsgProc() ! 424: // PURPOSE : installs a get message hook to monitor messages sent to the ! 425: // queue so we can trap the WM_CANCELJOURNAL message send by the ! 426: // system when the user presses Ctrl+Esc, Alt+Esc or ! 427: // Ctrl+Alt+Del which cancels the journal hook. ! 428: // COMMENTS : WM_CANCELJOURNAL gets sent to the thread which installs the ! 429: // hook but the hWnd of this message is NULL and thus does not ! 430: // get dispatched. Thus this hook is used to retrieve this ! 431: // message. ! 432: // ************************************************************************ ! 433: LRESULT CALLBACK ! 434: GetMsgProc( int nCode, WPARAM wParam, LPARAM lParam ) ! 435: { ! 436: static LPMSG lpMsg; ! 437: ! 438: if( nCode < 0 ) ! 439: return( CallNextHookEx( Global.hHookGetMsg, nCode, wParam, lParam ) ); ! 440: ! 441: lpMsg = (LPMSG) lParam; ! 442: switch( lpMsg->message ) { ! 443: ! 444: // user pressed Ctrl+Esc, Alt+Esc or Ctrl+Alt+Del, the system will ! 445: // automatically stop all journalling. ! 446: case WM_CANCELJOURNAL: ! 447: StopAllJournalling(); ! 448: MessageBox( GetFocus(), ! 449: TEXT( "The user has pressed either\n" ) ! 450: TEXT( "Ctrl+Esc, Alt+Esc or Ctrl+Alt+Del\n" ) ! 451: TEXT( "and thus the system has automatically\n" ) ! 452: TEXT( "canceled all journalling.\n" ), ! 453: TEXT( "MinRec - Notice!" ), ! 454: MB_ICONINFORMATION | MB_OK ); ! 455: break; ! 456: ! 457: } ! 458: ! 459: return( CallNextHookEx( Global.hHookGetMsg, nCode, wParam, lParam ) ); ! 460: UNREFERENCED_PARAMETER( wParam ); ! 461: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.