home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
-
- PROGRAM: Tester.c
-
- PURPOSE: DLL that records and plays back test scripts for Windows
- applications
- FUNCTIONS:
-
- LibMain() - automatic initialization function that performs
- one-time start-up processing.
- WEP() - DLL termination function; performs DLL cleanup before
- it is unloaded.
- Tester() - saves instance handle and creates main window
- JournalRecordHook() - A WH_JOURNALRECORD system hook that records
- keyboard and mouse event messages from the
- system queue
- JournalPlaybackHook() - A WH_JOURNALPLAYBACK system hook that plays
- back previously recorded messages
-
- *******************************************************************************/
- #include <windows.h>
- #include "tester.h"
- #include "testinc.h"
-
- static FARPROC fnNextJrnlHookFunc = NULL;
- static GLOBALHANDLE hMemTestScript = NULL;
- static TESTRESULT HaltStatus = TEST_OK;
- static HWND hWnd2Notify;
- static WORD wMsgtoSend;
- static char str[MAXNUMBUFFS*BUFFERSIZE];
- static char strtemp[BUFFERSIZE];
- static LPSTR lpTraceFileName = NULL;
- static OFSTRUCT OfStruct; /* information from OpenFile() */
- static HANDLE hFile;
- static EVENTQSTAT EventStats;
- static BOOL TraceOn;
-
- BOOL FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD cbHeapSize,
- LPSTR lpszCmdLine)
- {
- /* if DLL data seg is MOVEABLE */
- if (cbHeapSize != 0)
- UnlockData(0);
-
- return(TRUE); /* Initialization successful */
- }
-
- int FAR PASCAL WEP(int nParameter)
- {
- if (nParameter == WEP_SYSTEM_EXIT)
- return (1);
- else
- if (nParameter == WEP_FREE_DLL)
- /* DLL use count is zero. Every application that had loaded the DLL
- has freed it. */
- return (1);
- else
- /* Undefined value. Ignore it.*/
- return (1);
- }
- /**************************************************************************
-
- ROUTINE: Tester.c
-
- PURPOSE: Routine that is called by MainWndProc that installs a
- WH_JOURNALRECORD hook, and initiates the recording of events.
- It also installs the WH_JOURNALPLAYBACK hook to playback these
- pre-recorded events.
-
- ***************************************************************************/
- TESTRESULT FAR PASCAL Tester(TESTMODE AutotestMode, HANDLE hMemEvents,
- HWND hWndtoNotify, WORD wMsg,
- BOOL TraceOnFlag, LPSTR lpFileName)
- {
- TESTRESULT TesterReturnCode = TEST_OK;
- LPEVENTMSGMSG lpEvent;
- unsigned int EventQIndex;
-
- switch (AutotestMode)
- {
- case IDD_STARTRECORD:
- /* Save the hWnd to send any stop messages to */
- hWnd2Notify = hWndtoNotify;
- wMsgtoSend = wMsg;
- HaltStatus = TEST_OK;
-
- /* Allocate the memory to hold the test event queue */
- hMemTestScript = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
- MAXEVENTQSIZE * sizeof(EVENTMSG));
- if (hMemTestScript == NULL)
- {
- TesterReturnCode = TEST_NOMEMORY;
- HaltStatus = TEST_NOMEMORY;
- }
- else
- {
- /* Initialize the event queue header */
- EventStats.wNumEvents = 0;
- EventStats.wNumEventsPlayed = 0;
- EventStats.dwStartPlaybackTime = 0;
- EventStats.wTimebetEvents = 0;
- EventStats.wPercentofTime = 0;
- EventStats.wMemUtilized = 0;
- EventStats.wNumEventsBypassed = 0;
- EventStats.wNumIterationsPlayed = 0;
-
-
- /* Start recording events */
- fnNextJrnlHookFunc = SetWindowsHook(WH_JOURNALRECORD,
- (FARPROC)JournalRecordHook);
- TesterReturnCode = TEST_OK;
- }
- break;
-
- case IDD_STOPRECORD:
- if (hMemTestScript == NULL)
- /* Recording not made */
- TesterReturnCode = TEST_INACTIVE;
- else
- {
- /* Stop Recording Events */
-
- UnhookWindowsHook(WH_JOURNALRECORD, (FARPROC)JournalRecordHook);
- /* Adjust the timing in the event chain according to the users
- Request */
- lpEvent = (LPEVENTMSGMSG)GlobalLock(hMemTestScript);
- if (TraceOnFlag)
- {
- TraceOn = TRUE;
- lpTraceFileName = lpFileName;
- /* Write out the recorded events to the trace file */
- for (EventQIndex= 1; EventQIndex < EventStats.wNumEvents;
- EventQIndex++)
- {
- lpEvent[EventQIndex].time -= lpEvent[0].time;
-
- /* Write out the events to the tracefile */
- wsprintf(str,
- "Recorded Event MSG %d= %d; paramL= %x; paramH= %x; time= %ld\n",
- EventQIndex, lpEvent[EventQIndex].message,
- lpEvent[EventQIndex].paramL,
- lpEvent[EventQIndex].paramH,
- lpEvent[EventQIndex].time);
- WriteFile(lpTraceFileName, (LPSTR)&str);
- }
- }
- else
- {
- TraceOn = FALSE;
- lpTraceFileName = NULL;
- }
-
- /* Don't wait to playback the first event */
- lpEvent[0].time = 0;
- GlobalUnlock(hMemTestScript);
- TesterReturnCode = TEST_OK;
- /* Signal to the Autotest app that recording has stopped */
- SendMessage(hWnd2Notify, wMsgtoSend, hMemTestScript, HaltStatus);
- hMemTestScript = NULL;
- }
- break;
-
- case IDD_STARTPLAY:
- /* Save the hWnd to send any stop messages to */
- hWnd2Notify = hWndtoNotify;
- wMsgtoSend = wMsg;
- HaltStatus = TEST_OK;
- if (TraceOnFlag)
- {
- TraceOn = TRUE;
- lpTraceFileName = lpFileName;
- }
- else
- {
- TraceOn = FALSE;
- lpTraceFileName = NULL;
- }
-
- EventStats.wNumIterations = GetProfileInt("autotest",
- "NumberofIterations", 2);
- GetProfileString("autotest","FixedTimingFlag","TRUE",
- EventStats.FixedTiming, 5 );
- if ((EventStats.FixedTiming[0] == 't') ||
- (EventStats.FixedTiming[0] == 'T'))
- EventStats.wTimebetEvents = GetProfileInt("autotest",
- "TimeBetEvents",55);
- else
- EventStats.wPercentofTime = GetProfileInt("autotest",
- "PercentRecordTime", 100);
- EventStats.wNumEventstoBypass = GetProfileInt("autotest",
- "NumEventstoBypass", 5);
- EventStats.wBufferSize = GetProfileInt("autotest","IOBufferSize", 300);
- /* Do not allow a buffer size of less than one or
- greater than 5*BUFFERSIZE */
- if (EventStats.wBufferSize < 1)
- EventStats.wBufferSize = 1;
- else
- if (EventStats.wBufferSize > (15*MAXNUMBUFFS))
- EventStats.wBufferSize = 15*MAXNUMBUFFS;
-
- /* Initialize Event Message structure */
- EventStats.wNumEventsBuffered = EventStats.wBufferSize;
- EventStats.wNumEventsPlayed = 0;
- EventStats.wNumIterationsPlayed = 0;
- EventStats.wNumEventsBypassed = 0;
-
- if (TraceOn)
- {
- /* Write the parameters out to the playback trace file */
- wsprintf(str, "[autotest]\nNumberofIterations= %d\n",
- EventStats.wNumIterations);
- WriteFile(lpTraceFileName, (LPSTR)&str);
- wsprintf(str, "FixedTimingFlag= %s\n",
- (LPSTR)&EventStats.FixedTiming[0]);
- WriteFile(lpTraceFileName, (LPSTR)&str);
- wsprintf(str, "TimebetEvents= %d\n", EventStats.wTimebetEvents);
- WriteFile(lpTraceFileName, (LPSTR)&str);
- wsprintf(str, "PercentRecordTime= %d\n", EventStats.wPercentofTime);
- WriteFile(lpTraceFileName, (LPSTR)&str);
- wsprintf(str, "NumEventstoBypass= %d\n",
- EventStats.wNumEventstoBypass);
- WriteFile(lpTraceFileName, (LPSTR)&str);
- wsprintf(str, "IOBufferSize= %d\n", EventStats.wBufferSize);
- WriteFile(lpTraceFileName, (LPSTR)&str);
- }
-
- str[0] = NULL;
- EventStats.wNumEventsPlayed = 0;
- hMemTestScript = (GLOBALHANDLE)hMemEvents;
- lpEvent = (LPEVENTMSGMSG)GlobalLock(hMemTestScript);
-
- /* Perform calculations on timings */
- for (EventQIndex= 1; EventQIndex < EventStats.wNumEvents;
- EventQIndex++)
- {
- if ((EventStats.FixedTiming[0] == 't') ||
- (EventStats.FixedTiming[0] == 'T'))
- lpEvent[EventQIndex].time = lpEvent[0].time + (EventQIndex *
- EventStats.wTimebetEvents);
- else
- if (EventStats.wPercentofTime > 0)
- lpEvent[EventQIndex].time = (lpEvent[EventQIndex].time *
- EventStats.wPercentofTime /100);
- else
- lpEvent[EventQIndex].time = (lpEvent[EventQIndex].time *
- 1/100);
- }
-
- /* if there are events to playback */
- if (EventStats.wNumEvents != 0)
- {
- /* Initialize time playback is starting */
- EventStats.dwStartPlaybackTime = GetTickCount();
- GlobalUnlock(hMemTestScript);
-
- /* Start recording events */
- fnNextJrnlHookFunc = SetWindowsHook(WH_JOURNALPLAYBACK,
- (FARPROC)JournalPlaybackHook);
- TesterReturnCode = TEST_OK;
- }
- else
- TesterReturnCode = TEST_NOEVENTS;
- break;
-
- case IDD_STOPPLAY:
- UnhookWindowsHook(WH_JOURNALPLAYBACK,
- (FARPROC)JournalPlaybackHook);
-
- /* Signal to the Autotest app that playback has stopped */
- SendMessage(hWnd2Notify, wMsgtoSend, hMemTestScript, HaltStatus);
- hMemTestScript = NULL;
- break;
- }
-
- return (TesterReturnCode);
- }
-
- DWORD FAR PASCAL JournalRecordHook (int nCode, WORD wParam,
- LPEVENTMSGMSG lpEventMsg)
- {
- DWORD dwReturnCode;
- LPEVENTMSGMSG lpEventEntry;
- WORD wNumEvents;
-
- switch (nCode)
- {
- case HC_ACTION:
- /* Check if the number of events exceeds our limit of x'FFFF' */
- wNumEvents = EventStats.wNumEvents + 1;
-
- if (wNumEvents == MAXEVENTQSIZE)
- {
- /* Reached our limit; stop recording */
- HaltStatus = TEST_TOOMANYEVENTS;
- Tester(IDD_STOPRECORD, 0, 0, 0, TraceOn, (LPSTR)NULL);
- }
- else
- {
- /* Append the new event on to the end of the memory block */
- lpEventEntry = (LPEVENTMSGMSG)GlobalLock(hMemTestScript);
- lpEventEntry[EventStats.wNumEvents] = *lpEventMsg;
- EventStats.wNumEvents++;
- GlobalUnlock(hMemTestScript);
- }
- break;
-
- }
-
- dwReturnCode = DefHookProc(nCode, wParam, (LONG)lpEventMsg,
- (FARPROC FAR *)&fnNextJrnlHookFunc);
- return(dwReturnCode);
- }
-
- DWORD FAR PASCAL JournalPlaybackHook (int nCode, WORD wParam,
- LPEVENTMSGMSG lpEventMsg)
- {
- DWORD dwReturnCode = 0;
- DWORD dwDelta = 0;
- LPEVENTMSGMSG lpEventEntry;
- WORD wNumEvntsPlayed;
- DWORD dwTempTime = 0;
- DWORD dwFreeSpace = 0;
-
-
- lpEventEntry = (LPEVENTMSGMSG)GlobalLock(hMemTestScript);
- switch (nCode)
- {
- case HC_SKIP:
- /* Test if user has pressed control break */
- if ((GetAsyncKeyState(VK_CONTROL) & 0x8001)
- && (GetAsyncKeyState(VK_CANCEL) & 0x8001))
- {
- if (TraceOn)
- WriteFile(lpTraceFileName, (LPSTR)&str);
- Tester(IDD_STOPPLAY, (HANDLE)NULL, (HWND)NULL, 0, TraceOn,
- (LPSTR)NULL);
- }
- ++EventStats.wNumEventsPlayed;
- if (EventStats.wNumEventsPlayed > EventStats.wNumEvents)
- {
- ++EventStats.wNumIterationsPlayed;
- if (EventStats.wNumIterationsPlayed < EventStats.wNumIterations)
- {
- EventStats.wNumEventsPlayed = 0;
- EventStats.dwStartPlaybackTime = GetTickCount();
- }
- else
- {
- if (TraceOn)
- WriteFile(lpTraceFileName, (LPSTR)&str);
- Tester(IDD_STOPPLAY, (HANDLE)NULL, (HWND)NULL, 0, TraceOn,
- (LPSTR)NULL);
- }
- }
- /* if Trace Mode is on then capture information to be written
- out to the playback trace file */
- if (TraceOn)
- {
- ++EventStats.wNumEventsBypassed;
- if (EventStats.wNumEventsBypassed > EventStats.wNumEventstoBypass)
- {
- /* Write out data to trace file */
- dwFreeSpace = GetFreeSpace(GMEM_NOT_BANKED);
-
- --EventStats.wNumEventsBuffered;
- /* Buffering required for file I/O */
- wsprintf(strtemp, "Iteration= %d, Event= %d, FreeSpace= %lu\n",
- EventStats.wNumIterationsPlayed,
- EventStats.wNumEventsPlayed, dwFreeSpace);
- lstrcat((LPSTR)&str, (LPSTR)&strtemp);
- if (EventStats.wNumEventsBuffered == 0)
- {
- WriteFile(lpTraceFileName, (LPSTR)&str);
- EventStats.wNumEventsBuffered = EventStats.wBufferSize;
- str[0] = NULL;
- }
- EventStats.wNumEventsBypassed = 0;
- }
- }
- break;
-
- case HC_GETNEXT:
- /* Copy the next event in the event queue into the EVENTMSG
- structure */
- wNumEvntsPlayed = EventStats.wNumEventsPlayed;
- *((LPEVENTMSGMSG)lpEventMsg) = lpEventEntry[wNumEvntsPlayed];
-
- /* Add time delta (Event'n' - Event0) back to Start Playing time */
- ((LPEVENTMSGMSG)lpEventMsg)->time += EventStats.dwStartPlaybackTime;
-
- /* All times are expressed in terms of elapsed time in millisecs since
- system start We have used up some time doing all this processing */
- dwReturnCode = ((LPEVENTMSGMSG)lpEventMsg)->time - GetTickCount();
-
-
- if ((signed long)dwReturnCode < 0)
- dwReturnCode = 0;
-
- break;
-
- }
-
- GlobalUnlock(hMemTestScript);
- dwReturnCode = DefHookProc(nCode, wParam, (LONG)lpEventMsg,
- (FARPROC FAR *)&fnNextJrnlHookFunc);
- return(dwReturnCode);
- }
-
- BOOL WriteFile(LPSTR lpWrFileName, LPSTR lpBuffer)
- {
- HANDLE hFile;
- OFSTRUCT OfStruct; /* information from OpenFile() */
- WORD wLength;
- char wrstring[255];
-
- /* Check if file exists first */
- if (-1 == (hFile = OpenFile(lpWrFileName, (LPOFSTRUCT) &OfStruct,
- OF_READWRITE | OF_EXIST)))
- {
- /* Create it if it does not */
- if (-1 == (hFile = OpenFile(lpWrFileName, (LPOFSTRUCT) &OfStruct,
- OF_CREATE | OF_PROMPT | OF_CANCEL)))
- {
- wsprintf(wrstring,
- "Tester; WriteFile; hWnd2Notify = %x; File %s not found",
- hWnd2Notify, lpWrFileName);
- MessageBox(hWnd2Notify, wrstring, "DEBUG", MB_APPLMODAL |
- MB_OK | MB_ICONHAND);
- return FALSE;
- }
- }
- else
- /* open the existing file */
- if (-1 == (hFile = OpenFile(lpWrFileName, (LPOFSTRUCT) &OfStruct,
- OF_READWRITE | OF_REOPEN)))
- {
- wsprintf(wrstring,
- "WriteFile; hWnd2Notify = %x; Cannot reopen File %s to disk",
- hWnd2Notify, lpWrFileName);
- MessageBox(hWnd2Notify, wrstring, "DEBUG", MB_APPLMODAL |
- MB_OK | MB_ICONHAND);
- return FALSE;
- }
-
- /* Make sure this writes out to the file OK */
- wLength = lstrlen(lpBuffer);
-
- /* Position the file pointer at the end of the file */
- _llseek(hFile, STARTPOSITION, ENDOFFILE);
-
- /* append string to end of file */
- if (wLength != _lwrite(hFile, lpBuffer, wLength))
- {
- _lclose(hFile);
- wsprintf(wrstring,
- "WriteFile; hWnd2Notify = %x; Cannot write File %s to disk",
- hWnd2Notify, lpWrFileName);
- MessageBox(hWnd2Notify, wrstring, "DEBUG", MB_APPLMODAL |
- MB_OK | MB_ICONHAND);
- return FALSE;
- }
- else
- {
- _lclose(hFile);
- }
-
- return TRUE;
- }