home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / hookem.zip / HOOKSIMP.TXT
Text File  |  1993-04-22  |  15KB  |  300 lines

  1. /************************************************************************/
  2. /* Copyright 1993 IBM Corporation and CI, Software & Graphic Arts, Inc. */
  3. /*                                                                      */
  4. /*                        All Rights Reserved                           */
  5. /*                                                                      */
  6. /* Permission to use, copy, modify, and distribute this software for    */
  7. /* any purpose and without fee is hereby granted, provided that the     */
  8. /* above copyright notice appear in all copies and that both the        */
  9. /* copyright notice and this permission notice appear in supporting     */
  10. /* documentation, and that the names of IBM or CI not be used in        */
  11. /* advertising or publicity pertaining to distribution of the software  */
  12. /* without specific, written prior permission.                          */
  13. /*                                                                      */
  14. /* IBM & CI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,       */
  15. /* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN  */
  16. /* NO EVENT SHALL IBM OR CI BE LIABLE FOR ANY SPECIAL, INDIRECT OR      */
  17. /* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS  */
  18. /* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE*/
  19. /* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE   */
  20. /* USE OR PERFORMANCE OF THIS SOFTWARE.                                 */
  21. /************************************************************************/
  22. /*                                                                      */
  23. /* The following information represents summaries from an upcoming book,*/
  24. /* "Insider Information: Developing, Debugging and Testing OS/2 2.x     */
  25. /* Applications", by Ivan Biddles and Kelvin Lawrence [QED Publishing]. */
  26. /*                                                                      */
  27. /************************************************************************/
  28.  
  29. Hook Procedures - general rules
  30. ===============================
  31.  
  32.    * Include the EXPENTRY linkage keyword on all hook procedures.
  33.  
  34.    * As with an interrupt handler, the time spent in a hook  procedure
  35.      must be kept to an absolute minimum. (No I/O or Win calls - use a
  36.      separate thread.)
  37.  
  38.    * The playback hook procedure could be called AFTER WinReleaseHook,
  39.      so leave a dummy mouse move message to be returned.
  40.  
  41. Journal Playback Hook
  42. =====================
  43.  
  44. ULONG   EXPENTRY  MyJournalPlaybackHookProc (
  45.                                              HAB    hab,
  46.                                              BOOL   fSkip,
  47.                                              PQMSG  lpqmsg
  48.                                             )
  49.    hab     is  the application thread anchor block
  50.    fSkip   is  TRUE  if the last message has been activated, and
  51.                      a new message is to be prepared
  52.                FALSE if the same message is to be passed again
  53.    lpqmsg  is  a pointer to the QMSG structure to be filled
  54.    
  55. Message timing
  56. --------------
  57.  
  58. Whenever your hook  procedure provides  an event  to PM,  you have  to
  59. ensure that the time at which the  event is  due to  be dispatched  is
  60. kept updated. The return value from your procedure has to reflect  the
  61. number of milliseconds until the message is due.
  62.  
  63. Sample Hook Procedure
  64. ---------------------
  65.  
  66. This procedure assumes that there is a second thread which is reading,
  67. parsing and formatting the events, and placing them in a circular array
  68. accessed via two indices, ulQmsgBottom and ulQmsgTop.
  69.  
  70. The module handle used in the call to WinRelease hook is a variable set
  71. by the playback initiation routine, which it gets from a call to the
  72. DosQueryModuleHandle API.
  73.  
  74. #define MAXQMSGBUFFERSIZE       5000
  75.  
  76.    static       QMSG            qmsgBuffer      [MAXQMSGBUFFERSIZE];
  77.    static       ULONG           ulQmsgBottom    = 0;
  78.    static       ULONG           ulQmsgTop       = 0;
  79.    static       HMODULE         hModule;
  80.  
  81. ULONG EXPENTRY MyJournalPlaybackHookProc (
  82.                                           HAB   hab,
  83.                                           BOOL  fSkip,
  84.                                           PQMSG lpqmsg 
  85.                                          )
  86. {
  87.    static       QMSG            qmsgMouse;
  88.    static       QMSG            qmsgCurrent;
  89.    static       LONG            lLastMsgTime            = 0L;
  90.    static       LONG            lCurrentMsgTime         = 0L;
  91.    static       LONG            lMsgDelay               = 0L;
  92.    static       LONG            lDelayRemaining         = 0L;
  93.    static       LONG            lLastSequencedEventTime = 0L;
  94.                   
  95.                 /*------------------------------------------------------*/
  96.                 /* Store the passed time as the current message time    */
  97.                 /*------------------------------------------------------*/
  98.                         /*----------------------------------------------*/
  99.                         /* Note: if fSkip is TRUE, the lpqmsg pointer   */
  100.                         /*       will be NULL.                          */
  101.                         /*----------------------------------------------*/
  102.    if (lpqmsg) {
  103.       lCurrentMsgTime = lpqmsg->time;
  104.    }
  105.                 /*------------------------------------------------------*/
  106.                 /* The system requests that a NEW message be prepared   */
  107.                 /*------------------------------------------------------*/
  108.    if (fSkip) {
  109.                         /*----------------------------------------------*/
  110.                         /* No more messages on queue - release the hook */
  111.                         /*----------------------------------------------*/
  112.       if (ulQmsgBottom == ulQmsgTop) {
  113.          WinReleaseHook (
  114.                          hab,
  115.                          0L,
  116.                          HK_JOURNALPLAYBACK,
  117.                          (PFN) MyJournalPlaybackHookProc,
  118.                          hModule
  119.                         );
  120.                                 /*--------------------------------------*/
  121.                                 /* Set a mouse move "in place" message  */
  122.                                 /*--------------------------------------*/
  123.          memcpy (&qmsgCurrent, &qmsgMouse, sizeof (QMSG));
  124.       }
  125.                           
  126.                         /*----------------------------------------------*/
  127.                         /* Prepare and pass the next message            */
  128.                         /*----------------------------------------------*/
  129.       else {
  130.                                 /*--------------------------------------*/
  131.                                 /* Update the time of last message      */
  132.                                 /*--------------------------------------*/
  133.          lLastMsgTime = lLastSequencedEventTime;
  134.                                 /*--------------------------------------*/
  135.                                 /* Copy current message from the queue  */
  136.                                 /*--------------------------------------*/
  137.          memcpy (&qmsgCurrent, &(qmsgBuffer [ulQmsgBottom]), sizeof (QMSG));
  138.                                 /*--------------------------------------*/
  139.                                 /* Update the current mouse position so */
  140.                                 /* that the mouse stays put when we     */
  141.                                 /* playback                             */
  142.                                 /*--------------------------------------*/
  143.          if (qmsgCurrent.msg == WM_MOUSEMOVE) {
  144.             qmsgMouse.mp1   = qmsgCurrent.mp1;
  145.             qmsgMouse.mp2   = qmsgCurrent.mp2;
  146.             qmsgMouse.ptl.x = qmsgCurrent.ptl.x;
  147.             qmsgMouse.ptl.y = qmsgCurrent.ptl.y;
  148.          }
  149.                                 /*--------------------------------------*/
  150.                                 /* Update (and wrap) the queue pointer  */
  151.                                 /*--------------------------------------*/
  152.          ulQmsgBottom++;
  153.          if (ulQmsgBottom >= MAXQMSGBUFFERSIZE) {
  154.             ulQmsgBottom=0L;
  155.          }
  156.                                 /*--------------------------------------*/
  157.                                 /* New message - so set up the delay    */
  158.                                 /*               timing variables       */
  159.                                 /*--------------------------------------*/
  160.          lMsgDelay               = qmsgCurrent.time;
  161.          lDelayRemaining         = lMsgDelay - (lCurrentMsgTime - lLastMsgTime);
  162.          if (lDelayRemaining < 0) {
  163.             lDelayRemaining  = 0L;
  164.          }
  165.          lLastSequencedEventTime = lCurrentMsgTime + lDelayRemaining;
  166.          qmsgCurrent.time        = lLastSequencedEventTime;
  167.       }
  168.    } 
  169.                 /*------------------------------------------------------*/
  170.                 /* The system requests a PEEK at the CURRENT message    */
  171.                 /*------------------------------------------------------*/
  172.    else {
  173.                         /*----------------------------------------------*/
  174.                         /* Initialize the variables on the first pass   */
  175.                         /*----------------------------------------------*/
  176.       if (bFirstTimePlaybackHook) {
  177.          bFirstTimePlaybackHook  = 0;
  178.          lLastMsgTime            = 0L;
  179.          lCurrentMsgTime         = 0L;
  180.          lMsgDelay               = 0L;
  181.          lDelayRemaining         = 0L;
  182.          lLastSequencedEventTime = 0L;
  183.                                 /*--------------------------------------*/
  184.                                 /* Initialize the default mouse move    */
  185.                                 /*--------------------------------------*/
  186.          qmsgMouse.hwnd  = HWND_DESKTOP;
  187.          qmsgMouse.msg   = WM_MOUSEMOVE;
  188.          qmsgMouse.mp1   = (MPARAM) 0;
  189.          qmsgMouse.mp2   = (MPARAM) 0;
  190.          qmsgMouse.time  = 0L;
  191.          qmsgMouse.ptl.x = 0L;
  192.          qmsgMouse.ptl.y = 0L;
  193.                                 /*--------------------------------------*/
  194.                                 /* Send the same message as before      */
  195.                                 /*--------------------------------------*/
  196.          if (ulQmsgBottom == ulQmsgTop) {
  197.             memcpy (&qmsgCurrent, &qmsgMouse, sizeof (QMSG));
  198.          }
  199.                                 /*--------------------------------------*/
  200.                                 /* Use the next message in the queue    */
  201.                                 /*--------------------------------------*/
  202.          else {
  203.             memcpy (&qmsgCurrent, &(qmsgBuffer[ulQmsgBottom]), sizeof (QMSG));
  204.                                         /*------------------------------*/
  205.                                         /* New message - so set up the  */
  206.                                         /*      delay timing variables  */
  207.                                         /*------------------------------*/
  208.             lMsgDelay               = qmsgCurrent.time;
  209.             lDelayRemaining         = lMsgDelay - (lCurrentMsgTime - lLastMsgTime);
  210.             if (lDelayRemaining < 0) {
  211.                lDelayRemaining  = 0L;
  212.             }
  213.             lLastSequencedEventTime = lCurrentMsgTime + lDelayRemaining;
  214.             qmsgCurrent.time        = lLastSequencedEventTime;
  215.          }
  216.       }
  217.                         /*----------------------------------------------*/
  218.                         /* Copy current message to the passed pointer   */
  219.                         /*----------------------------------------------*/
  220.       if (lpqmsg) {
  221.          memcpy (lpqmsg, &qmsgCurrent, sizeof (QMSG));
  222.       }
  223.    }
  224.                 /*------------------------------------------------------*/
  225.                 /* Update & return the remaining delay for this message */
  226.                 /*------------------------------------------------------*/
  227.    lDelayRemaining = lMsgDelay - (lCurrentMsgTime - lLastMsgTime);
  228.    if (lDelayRemaining < 0 ) {
  229.       lDelayRemaining = 0L;
  230.    }
  231.    return ((ULONG) delayRemaining);
  232. }
  233.    
  234. Journal Record Hook
  235. ===================
  236.  
  237. VOID  EXPENTRY  MyJournalRecordHookProc (
  238.                                          HAB    hab,
  239.                                          PQMSG  lpqmsg
  240.                                         )
  241.    hab     is  the application thread anchor block
  242.    lpqmsg  is  a pointer to the QMSG structure containing the event
  243.  
  244. Sample Hook Procedure
  245. ---------------------
  246.  
  247. This procedure assumes that there is a second thread which is formatting 
  248. and writing the events to disk. The hook procedure places them in a circular
  249. array accessed via two indices, ulQmsgBottom and ulQmsgTop.
  250.  
  251. To filter out mouse messages (you'll get a mass of messages otherwise), 
  252. set bMouseCritical false.
  253.  
  254. #define MAXQMSGBUFFERSIZE       5000
  255.  
  256.    static       QMSG            qmsgBuffer      [MAXQMSGBUFFERSIZE];
  257.    static       ULONG           ulQmsgBottom    = 0;
  258.    static       ULONG           ulQmsgTop       = 0;
  259.    static       BOOL            bMouseCritical  = FALSE;
  260.  
  261. Note that the hwnd you receive is not significant at this point in the
  262. input stream.
  263.  
  264. VOID  EXPENTRY  MyJournalRecordHookProc (
  265.                                          HAB    hab,
  266.                                          PQMSG  lpqmsg
  267.                                         )
  268. {
  269.                 /*------------------------------------------------------*/
  270.                 /* Filter out mouse moves unless required               */
  271.                 /*------------------------------------------------------*/
  272.    if (bMouseCritical || lpqmsg->msg != WM_MOUSEMOVE) {
  273.       memcpy (& (qmsgBuffer [ulQmsgTop]), lpqmsg, sizeof (QMSG));
  274.                         /*----------------------------------------------*/
  275.                         /* Set the hwnd to null since it is useless at  */
  276.                         /* this point.                                  */
  277.                         /*----------------------------------------------*/
  278.       qmsgBuffer[ulQmsgTop].hwnd = 0L;
  279.                         /*----------------------------------------------*/
  280.                         /* Update the buffer pointer (with wraparound)  */
  281.                         /*----------------------------------------------*/
  282.       ulQmsgTop++;
  283.       if (ulQmsgTop >= MAXQMSGBUFFERSIZE) {
  284.          ulQmsgTop = 0L;
  285.       }
  286.                         /*----------------------------------------------*/
  287.                         /* Circular queue collision situation - the     */
  288.                         /* buffer may need to be expanded               */
  289.                         /*----------------------------------------------*/
  290.       if (ulQmsgTop == ulQmsgBottom) {
  291.                                 /*--------------------------------------*/
  292.                                 /* Output a message - piped to a file   */
  293.                                 /*--------------------------------------*/
  294.          fprintf (stderr, "-- Circular Queue collision: expand MAXQMSGBUFFERSIZE");
  295.       }
  296.    }
  297. }
  298.  
  299.  
  300.