|
|
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.