Annotation of q_a/samples/minrec/rechook.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.