home *** CD-ROM | disk | FTP | other *** search
/ Windoware / WINDOWARE_1_6.iso / source / adg_4-6 / recorder.c < prev    next >
C/C++ Source or Header  |  1991-02-21  |  10KB  |  307 lines

  1. /****************************************************************************
  2. Module name: Recorder.C
  3. Programmer : Jeffrey M. Richter.
  4. *****************************************************************************/
  5.  
  6. #include "..\nowindws.h"
  7. #undef NOCOLOR
  8. #undef NOKERNEL
  9. #undef NOMEMMGR
  10. #undef NOMSG
  11. #undef NOSHOWWINDOW
  12. #undef NOUSER
  13. #undef NOWH
  14. #undef NOWINMESSAGES
  15. #undef NOWINSTYLES
  16. #include <windows.h>
  17. #include "Recorder.h"
  18.  
  19. //****************************************************************************
  20. static FARPROC       _fnNextJrnlHookFunc = NULL;
  21. static GLOBALHANDLE  _hMemEvents = NULL;
  22. static RECRESULT     _PrematureHalt = REC_OK;
  23.  
  24. DWORD FAR PASCAL JrnlRecHookFunc (int nCode, WORD wParam, LPEVENTMSGMSG lpEventMsg);
  25. DWORD FAR PASCAL JrnlPlybkHookFunc (int nCode, WORD wParam, LPEVENTMSGMSG lpEventMsg);
  26.  
  27. // Statistical information that appears at the beginning of the memory block.
  28. typedef struct {
  29.    WORD wNumEvents, wNumEventsPlayed; DWORD dwStartTime;
  30. } RECORDSTAT, FAR *LPRECORDSTAT;
  31.  
  32.  
  33. BOOL FAR PASCAL LibMain (HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpCmdLine) {
  34.    if (cbHeapSize != 0) UnlockData(0); // Let data segment move
  35.    return(TRUE);  // return TRUE if initialization is successful
  36. }
  37.  
  38. int FAR PASCAL WEP (int nSystemExit) {
  39.    switch (nSystemExit) {
  40.       case WEP_SYSTEM_EXIT:   // System is shutting down.
  41.          break;
  42.       case WEP_FREE_DLL:      // Usage count is zero (0)
  43.          break;
  44.    }
  45.    return(1);                 // WEP function successful.
  46. }
  47.  
  48.  
  49. RECRESULT FAR PASCAL Recorder (RECORDMODE RecordMode, WORD wParam, LONG lParam) {
  50.    static HWND hWndNotify = NULL;
  51.    static WORD wMsgNotify = WM_NULL;
  52.    static RECORDMODE LastRecordMode = -1;
  53.    RECRESULT RecResult = REC_OK;
  54.    WORD wNumEvents;
  55.    LPRECORDSTAT lpRecordStat;
  56.    LPEVENTMSGMSG lpEvent;
  57.  
  58.    switch (RecordMode) {
  59.  
  60.       case RM_STARTRECORD:
  61.          // wParam: Not used.
  62.          // LOWORD(lParam): hWnd to end stop msg to.
  63.          // HIWORD(lParam): Message to send to hWnd.
  64.          // Returns: REC_ACTIVE, REC_NOMEMORY, REC_OK
  65.  
  66.          if (_hMemEvents) { RecResult = REC_ACTIVE; break; }
  67.  
  68.          // Save information so that it can be used by RM_STOPRECORD.
  69.          hWndNotify = (HWND) LOWORD(lParam);
  70.          wMsgNotify = (WORD) HIWORD(lParam);
  71.  
  72.          // Assume the recording will be stopped by the user.
  73.          _PrematureHalt = REC_OK;
  74.  
  75.          // Allocate memory block to hold the statistical data.
  76.          _hMemEvents = GlobalAlloc(GMEM_MOVEABLE, sizeof(RECORDSTAT));
  77.          if (_hMemEvents == NULL) { RecResult = REC_NOMEMORY; break; }
  78.  
  79.          // Initialize the statistical data.
  80.          lpRecordStat = (LPRECORDSTAT) GlobalLock(_hMemEvents);
  81.          lpRecordStat->wNumEvents = lpRecordStat->wNumEventsPlayed = 0;
  82.          GlobalUnlock(_hMemEvents);
  83.  
  84.          // Turn on the event recording.
  85.          _fnNextJrnlHookFunc =
  86.             SetWindowsHook(WH_JOURNALRECORD, (FARPROC) JrnlRecHookFunc);
  87.  
  88.          RecResult = REC_OK;
  89.          break;
  90.  
  91.  
  92.       case RM_STOPRECORD:
  93.          // wParam: Not used.
  94.          // lParam: Not used.
  95.          // Returns: REC_INACTIVE, REC_OK
  96.  
  97.          if (_hMemEvents == NULL) { RecResult = REC_INACTIVE; break; }
  98.  
  99.          if (LastRecordMode == RM_STARTPLAY) { break; }
  100.  
  101.          // Stop the recording of events.
  102.          UnhookWindowsHook(WH_JOURNALRECORD, (FARPROC) JrnlRecHookFunc);
  103.  
  104.          // Modify all of the 'time' members in the EVENTMSG structures.
  105.          lpRecordStat = (LPRECORDSTAT) GlobalLock(_hMemEvents);
  106.          lpEvent = (LPEVENTMSGMSG) &lpRecordStat[1];
  107.          wNumEvents = lpRecordStat->wNumEvents;
  108.          while (wNumEvents > 1)
  109.             lpEvent[--wNumEvents].time -= lpEvent[0].time;
  110.  
  111.          lpEvent[0].time = 0;
  112.          GlobalUnlock(_hMemEvents);
  113.          RecResult = REC_OK;
  114.  
  115.          // Send message to specified window to notify it 
  116.          // that recording has stopped.
  117.          SendMessage(hWndNotify, wMsgNotify, _hMemEvents, _PrematureHalt);
  118.  
  119.          _hMemEvents = NULL;
  120.          break;
  121.  
  122.  
  123.       case RM_STARTPLAY:
  124.          // wParam: GLOBALHANDLE to macro
  125.          // lParam: LOWORD(lParam) = hWnd to end stop msg to.
  126.          // lParam: HIWORD(lParam) = Message to send to hWnd.
  127.          // Returns: REC_ACTIVE, REC_OK, REC_NOEVENTS
  128.  
  129.          if (_hMemEvents != NULL) { RecResult = REC_ACTIVE; break; }
  130.  
  131.          // Save information so that it can be used by RM_STOPRECORD.
  132.          hWndNotify = (HWND) LOWORD(lParam);
  133.          wMsgNotify = (WORD) HIWORD(lParam);
  134.  
  135.          // Assume the playing will be stopped after all 
  136.          // events have been played.
  137.          _PrematureHalt = REC_OK;
  138.  
  139.          _hMemEvents = (GLOBALHANDLE) wParam;
  140.  
  141.          // Initialize statistical data.
  142.          lpRecordStat = (LPRECORDSTAT) GlobalLock(_hMemEvents);
  143.          wNumEvents = lpRecordStat->wNumEvents;
  144.          lpRecordStat->wNumEventsPlayed = 0;
  145.  
  146.          // Save the time when playback is started.
  147.          lpRecordStat->dwStartTime = GetTickCount();
  148.  
  149.          GlobalUnlock(_hMemEvents);
  150.          if (wNumEvents == 0) { RecResult = REC_NOEVENTS; break; }
  151.  
  152.          _fnNextJrnlHookFunc =
  153.             SetWindowsHook(WH_JOURNALPLAYBACK, (FARPROC) JrnlPlybkHookFunc);
  154.  
  155.          break;
  156.  
  157.  
  158.       case RM_STOPPLAY:
  159.          // Stop playing the recorded events.
  160.          UnhookWindowsHook(WH_JOURNALPLAYBACK, (FARPROC) JrnlPlybkHookFunc);
  161.          _hMemEvents = NULL;
  162.          RecResult = REC_OK;
  163.  
  164.          // Send message to specified window to notify it 
  165.          // that playing has stopped.
  166.          SendMessage(hWndNotify, wMsgNotify, 0, _PrematureHalt);
  167.          break;
  168.    }
  169.  
  170.    LastRecordMode = RecordMode;
  171.    return(RecResult);
  172. }
  173.  
  174.  
  175.  
  176. DWORD FAR PASCAL JrnlRecHookFunc (int nCode, WORD wParam, LPEVENTMSGMSG lpEventMsg) {
  177.    static BOOL fPause = FALSE;
  178.    LPRECORDSTAT lpRecordStat;
  179.    LPEVENTMSGMSG lpEvent;
  180.    BOOL fCallDefProc = FALSE;
  181.    DWORD dwResult = 0;
  182.    WORD wNumEvents;
  183.    GLOBALHANDLE hMemTemp;
  184.  
  185.    switch (nCode) {
  186.  
  187.       case HC_ACTION:
  188.          fCallDefProc = TRUE;
  189.  
  190.          // If a system-modal dialog box is up, don't record the event.
  191.          if (fPause) break;
  192.  
  193.          // Determine the number of events in the memory block now.
  194.          lpRecordStat = (LPRECORDSTAT) GlobalLock(_hMemEvents);
  195.          wNumEvents = lpRecordStat->wNumEvents + 1;
  196.          GlobalUnlock(_hMemEvents);
  197.          if (wNumEvents == 0xffff) {
  198.             // Too many events recorded, stop recording.
  199.             _PrematureHalt = REC_TOOMANY;
  200.             Recorder(RM_STOPRECORD, 0, 0);
  201.             break;
  202.          }
  203.  
  204.          // Increase the size of the memory block to hold the new event.
  205.          hMemTemp = GlobalReAlloc(_hMemEvents,
  206.             sizeof(RECORDSTAT) + wNumEvents * sizeof(EVENTMSG), GMEM_MOVEABLE);
  207.          if (hMemTemp == NULL) {
  208.             // Insufficient memory, stop recording.
  209.             _PrematureHalt = REC_NOMEMORY;
  210.             Recorder(RM_STOPRECORD, 0, 0);
  211.             break;
  212.          }
  213.  
  214.          _hMemEvents = hMemTemp;
  215.  
  216.          // Append the new event to the end of the memory block.
  217.          lpRecordStat = (LPRECORDSTAT) GlobalLock(_hMemEvents);
  218.          lpEvent = (LPEVENTMSGMSG) &lpRecordStat[1];
  219.          lpEvent[lpRecordStat->wNumEvents] = *lpEventMsg;
  220.          lpRecordStat->wNumEvents++;
  221.          GlobalUnlock(_hMemEvents);
  222.          break;
  223.  
  224.       case HC_SYSMODALON:
  225.          // Stop recording events while the system-modal dialog box is up.
  226.          fPause = TRUE;
  227.          fCallDefProc = TRUE;
  228.          break;
  229.  
  230.       case HC_SYSMODALOFF:
  231.          // The system-modal dialog box is gone, stop recording and 
  232.          // notify the that recording has stopped.
  233.          fPause = FALSE;
  234.          _PrematureHalt = REC_SYSMODALON;
  235.          Recorder(RM_STOPRECORD, 0, 0);
  236.          break;
  237.  
  238.       default:
  239.          fCallDefProc = TRUE;
  240.          break;
  241.    }
  242.  
  243.    if (fCallDefProc)
  244.       dwResult = DefHookProc(nCode, wParam, (LONG) lpEventMsg,
  245.          (FARPROC FAR *) &_fnNextJrnlHookFunc);
  246.  
  247.    return(dwResult);
  248. }
  249.  
  250.  
  251.  
  252. DWORD FAR PASCAL JrnlPlybkHookFunc (int nCode, WORD wParam, LPEVENTMSGMSG lpEventMsg) {
  253.    BOOL fCallDefProc = FALSE;
  254.    DWORD dwResult = 0;
  255.    LPRECORDSTAT lpRecordStat;
  256.    LPEVENTMSGMSG lpEvent;
  257.  
  258.    lpRecordStat = (LPRECORDSTAT) GlobalLock(_hMemEvents);
  259.    switch (nCode) {
  260.  
  261.       case HC_SKIP:
  262.          // Prepare to return the next event the next time the hook code is
  263.          // HC_GETNEXT.  If all events have been played, stop playing.
  264.          if (++lpRecordStat->wNumEventsPlayed == lpRecordStat->wNumEvents)
  265.             Recorder(RM_STOPPLAY, 0, 0);
  266.          break;
  267.  
  268.       case HC_GETNEXT:
  269.          // Copy the current event to the EVENTMSG 
  270.          // structure pointed to by lParam.
  271.          lpEvent = (LPEVENTMSGMSG) &lpRecordStat[1];
  272.          *lpEventMsg = lpEvent[lpRecordStat->wNumEventsPlayed];
  273.  
  274.          // Adjust the 'time' by adding the time that playback started,
  275.          lpEventMsg->time += lpRecordStat->dwStartTime;
  276.  
  277.          // Return the number of milliseconds Windows should wait
  278.          // before processing the event.
  279.          dwResult = lpEventMsg->time - GetTickCount();
  280.  
  281.          // If the event occurred in the past, have Windows process it now.
  282.          if ((signed long) dwResult < 0) dwResult = 0;
  283.          break;
  284.  
  285.       case HC_SYSMODALOFF:
  286.          // When the system-modal dialog box is removed, stop playing the
  287.          // events and notify the application.
  288.          _PrematureHalt = REC_SYSMODALON;
  289.          Recorder(RM_STOPPLAY, 0, 0);
  290.          fCallDefProc = TRUE;
  291.          break;
  292.  
  293.       case HC_SYSMODALON:
  294.       default:
  295.          fCallDefProc = TRUE;
  296.          break;
  297.  
  298.    }
  299.    GlobalUnlock(_hMemEvents);
  300.  
  301.    if (fCallDefProc)
  302.       dwResult = DefHookProc(nCode, wParam, (LONG) lpEventMsg,
  303.             (FARPROC FAR *) &_fnNextJrnlHookFunc); 
  304.  
  305.    return(dwResult);
  306. }
  307.