home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / spy / spyhook.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-10  |  27.3 KB  |  867 lines

  1. /***********************************************************************\
  2. * spyhook.c - Spy global input hook interface library
  3. * Created by Microsoft Corporation, 1989
  4. *
  5. * This dynlink is needed because global input hooks must reside in a DLL.
  6. \***********************************************************************/
  7. #define INCL_DOSPROCESS
  8. #define    INCL_WINHEAP
  9. #define    INCL_WINHOOKS
  10. #define    INCL_WINWINDOWMGR
  11. #include <os2.h>
  12. #include "spyhook.h"
  13.  
  14. ULONG spyhookSem = 0L;          /* global semaphore for this module */
  15. HMODULE hmodSpy;                /* dynlink module handle            */
  16. SHORT    SpybHooks;             /* Which hook do we use?            */
  17.  
  18. HAB habOwner = (HAB)0;          /* Hook owner's anchor block        */
  19. HMQ hmqOwner = (HMQ)0;          /* Hook owner's message queue       */
  20. BOOL fRecording = FALSE;        /* Are we recording now?            */
  21. BOOL fAnythingToWatch = FALSE;  /* Is there anything to watch?      */
  22. BOOL fDispMsgsNotInList = TRUE; /* Disp msgs not in list?           */
  23.  
  24. /* Define array of window handles that we are going to process */
  25. BOOL fProcessAllFrames = FALSE; /* Are we processing all frame messages?*/
  26. BOOL fProcessAllWindows = FALSE;/* Are we processing all windows?*/
  27. HWND *pahwndSpy = NULL;         /* Array of hwnds to spy on, no max here */
  28. int  chwndSpy = 0;          /* Max windows to spy */
  29.  
  30. /* Define array of HMQ's to spy on */
  31. HMQ *pahmqSpy = NULL;           /* HMQ list to spy on */
  32. int chmqSpy = 0;                /* Count of hmqs we are spying on */
  33.  
  34.  
  35. /* Define message filter array */
  36. UCHAR rgMessageFilter[MAXMSGFILTERBYTES] = "";
  37. UCHAR  GMsgEnableAndType(USHORT);       /* Is message in message list?*/
  38. VOID   GrabMsgDataWords(SHORT, UCHAR);  /* Get extra words for message */
  39. VOID   CopyStruct(UCHAR FAR *pbSrc, UCHAR FAR *pbDst, SHORT cb);/* Copy bytes */
  40.  
  41. /* Define an array of messages to pass to whomever calls us */
  42. ULONG spyMsgSem =  0L;          /* global semaphore for this module */
  43.  
  44. QMSGSPY  rgqmsgSpy[MAXMSGCNT];  /* Array of messages to process */
  45. SHORT cmsgSpy = 0;              /* Count of messages yet to be read */
  46. SHORT imsgWrite = 0;            /* Index to message to write out */
  47. SHORT imsgRead = 0;             /* Index to message to read */
  48.  
  49. HHEAP hheapSpyHook;             /* Heap for SpyHook DLL */
  50. SHORT acbMPTypes[MP_MASK+1] = { /* Number of desired bytes to extract */
  51.     0,                          /* Normal fields, no pointers */
  52.     sizeof(SWP),                /* MPT_SWP */
  53.     sizeof(RECTL),              /* MPT_RECTL */
  54.     0,                          /* MPT_WNDPRMS we don't process yet */
  55.     sizeof(QMSG)                /* MPT_QMSG */
  56. };
  57.  
  58.  
  59. /* Information for getting selector information in different PID context */
  60. PID     pidLNSpy = 0xffff;      /* Which process */
  61. USHORT  selectorLNSpy = 0;      /* Which Selector */
  62. WHOISINFO   whoIsLNSpy;         /* Symbol information */
  63. int     rcLNSpy = -1;           /* Return code */
  64.  
  65.  
  66. /* Define all external functions */
  67. extern VOID  BuildStackTrace(CHAR FAR *, SHORT, SHORT);
  68.  
  69. /* Define all function prototypes */
  70. VOID SpyCheckPIDForSymbol(VOID);
  71. BOOL FAR PASCAL SpyInputHook(HAB, PQMSG, USHORT);
  72. BOOL FAR PASCAL SpySendMsgHook(HAB, PSMHSTRUCT, USHORT);
  73. VOID PASCAL Init(HMODULE);
  74.  
  75. /***********************************************************************\
  76. * BOOL FAR PASCAL SpyInputHook( hab, lpqmsg, fs )
  77. * HAB hab;
  78. * PQMSG  lpqmsg;
  79. * USHORT    fs;
  80. *
  81. * Effect:  This is the global input hook procedure.  Note that hook
  82. *   procedures can be chained, so we always return FALSE to pass the
  83. *   message to the next guy in the chain.
  84. *
  85. * Return value:  FALSE to pass message to next hook procedure.
  86. \***********************************************************************/
  87. BOOL FAR PASCAL SpyInputHook( hab, lpqmsg, fs )
  88. HAB    hab;
  89. PQMSG    lpqmsg;
  90. USHORT  fs;
  91. {
  92.     UCHAR       bMPType;
  93.  
  94.     /*
  95.      * Check first to see if we are looking for a process's symbols
  96.      */
  97.     if (pidLNSpy != 0xffff)
  98.         SpyCheckPIDForSymbol();
  99.  
  100.     /*
  101.      * First check to see if we are processing any hook messages
  102.      */
  103.     if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT))
  104.         return (FALSE); /* No, let the next one have it now */
  105.  
  106.     /*
  107.      * See if we have any messages to process - re-check to make sure we
  108.      * don't overwrite our queue.
  109.      */
  110.     if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0)
  111.         return (FALSE);
  112.     if (cmsgSpy < MAXMSGCNT) {
  113.         if (SpyFWindowInList(lpqmsg->hwnd, FALSE) &&
  114.                 (bMPType = GMsgEnableAndType(lpqmsg->msg))) {
  115.             rgqmsgSpy[imsgWrite].fs = fs;       /* Save the flags */
  116.             rgqmsgSpy[imsgWrite].qmsg = *lpqmsg;   /* Save the message */
  117.  
  118.             GrabMsgDataWords(imsgWrite, bMPType);
  119.             imsgWrite++;
  120.  
  121.             if (imsgWrite == MAXMSGCNT)
  122.                 imsgWrite = 0;  /* Wrap around */
  123.             cmsgSpy++;
  124.             DosSemClear((HSEM)(PULONG)&spyMsgSem);
  125.         }
  126.     }
  127.  
  128.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  129.     return FALSE;   /* Let system take normal action */
  130. }
  131.  
  132.  
  133. /***********************************************************************\
  134. * BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask )
  135. * HAB        hab;
  136. * PSMHSTRUCT    lpsmh;
  137. * BOOL        fInterTask;
  138. *
  139. * Effect:  This is the global input hook procedure.  Note that hook
  140. *   procedures can be chained, so we always return FALSE to pass the
  141. *   message to the next guy in the chain.
  142. *
  143. * Return value:  FALSE to pass message to next hook procedure.
  144. \***********************************************************************/
  145. BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask )
  146. HAB        hab;
  147. PSMHSTRUCT      lpsmh;
  148. BOOL            fInterTask;
  149. {
  150.     UCHAR           bMPType;
  151.     PIDINFO         pidinfo;
  152.  
  153.     /*
  154.      * Check first to see if we are looking for a process's symbols
  155.      */
  156.     if (pidLNSpy != 0xffff)
  157.         SpyCheckPIDForSymbol();
  158.  
  159.     /*
  160.      * First check to see if we are processing any hook messages
  161.      */
  162.     if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT))
  163.         return (FALSE); /* No, let the next one have it now */
  164.  
  165.     /*
  166.      * See if we have any messages to process
  167.      */
  168.     if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0)
  169.         return (FALSE);
  170.     /* Make sure no one got in by mistake */
  171.     if (cmsgSpy < MAXMSGCNT) {
  172.         if (SpyFWindowInList(lpsmh->hwnd, FALSE) &&
  173.                 (bMPType = GMsgEnableAndType(lpsmh->msg))) {
  174.             /*
  175.              * Store out message, must move pieces separately
  176.              */
  177.             rgqmsgSpy[imsgWrite].fs = fInterTask;
  178.             rgqmsgSpy[imsgWrite].qmsg.hwnd = lpsmh->hwnd;
  179.             rgqmsgSpy[imsgWrite].qmsg.msg  = lpsmh->msg;
  180.             rgqmsgSpy[imsgWrite].qmsg.mp1  = lpsmh->mp1;
  181.             rgqmsgSpy[imsgWrite].qmsg.mp2  = lpsmh->mp2;
  182.             rgqmsgSpy[imsgWrite].qmsg.time = (ULONG)-1;
  183.             rgqmsgSpy[imsgWrite].qmsg.ptl.x  = 0;
  184.             rgqmsgSpy[imsgWrite].qmsg.ptl.y  = 0;
  185.  
  186.             GrabMsgDataWords(imsgWrite, bMPType);
  187.  
  188.             /* Now get the PID/TID info, and do the stack backtrace */
  189.             DosGetPID(&pidinfo);
  190.             rgqmsgSpy[imsgWrite].pidSend = pidinfo.pid;
  191.             rgqmsgSpy[imsgWrite].tidSend = pidinfo.tid;
  192.             BuildStackTrace((CHAR FAR *)rgqmsgSpy[imsgWrite].pvoidStack,
  193.                     CALLSTOSKIP, MAXSTRACE);
  194.  
  195.             imsgWrite++;
  196.             if (imsgWrite == MAXMSGCNT)
  197.                 imsgWrite = 0;  /* Wrap around */
  198.             cmsgSpy++;
  199.             DosSemClear((HSEM)(PULONG)&spyMsgSem);
  200.         }
  201.     }
  202.  
  203.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  204.     return FALSE;   /* Let system take normal action */
  205. }
  206.  
  207.  
  208. /***********************************************************************\
  209. * BOOL FAR PASCAL SpyInstallHook( hab, hmq, fSendMessage, bHooks)
  210. *
  211. * Effect:  This routine installs a system-wide HK_INPUT hook.  The hab
  212. *   hmq are remembered for message posting.  Note that we only allow
  213. *   one input hook to be installed through this routine, but other
  214. *   apps may call WinSetHook directly.
  215. *
  216. * Returns value:  TRUE if hook installed successfully, FALSE otherwise.
  217. \***********************************************************************/
  218. BOOL FAR PASCAL SpyInstallHook( hab, hmq, bHooks )
  219. HAB     hab;
  220. HMQ     hmq;
  221. USHORT  bHooks;
  222. {
  223.     BOOL fRet;
  224.     SEL  selHeap;
  225.  
  226.     DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
  227.  
  228.     /*
  229.      * If this is the first time through, we need to create a local heap
  230.      * to store message information.
  231.      */
  232.     if (hheapSpyHook == NULL) {
  233.         selHeap = (SEL)(((ULONG)((PSZ)&hheapSpyHook)) >> 16);
  234.         hheapSpyHook = WinCreateHeap(selHeap, 1024, 0, 0, 100,
  235.             HM_MOVEABLE | HM_VALIDSIZE);
  236.         if (hheapSpyHook == NULL)
  237.             return (FALSE);
  238.     }
  239.  
  240.  
  241.  
  242.     /*
  243.      * Look at hook index.
  244.      *
  245.      * if it equals  HK_INPUT then
  246.      *        install a system-wide input hook
  247.      * else
  248.      *        set system wide SENDMSG hook
  249.      */
  250.     SpybHooks = bHooks;
  251.     if (SpybHooks & SPYH_INPUT)
  252.         fRet = WinSetHook( hab, (HMQ)0, HK_INPUT, (PFN)SpyInputHook,
  253.                     hmodSpy );
  254.  
  255.     if (SpybHooks & SPYH_SENDMSG)
  256.         fRet = WinSetHook( hab, (HMQ)0, HK_SENDMSG, (PFN)SpySendMsgHook,
  257.                     hmodSpy );
  258.     if (fRet) {
  259.         habOwner = hab;
  260.         hmqOwner = hmq;
  261.     }
  262.  
  263.     DosSemSet((HSEM)(PULONG)&spyMsgSem);    /* Init, no messages avail */
  264.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  265.  
  266.     return fRet;
  267. }
  268.  
  269.  
  270.  
  271. /***********************************************************************\
  272. * BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd)
  273. *
  274. * Effect:  This routine sets the list of window that we are interested
  275. *   in watching the messages for.
  276. *
  277. * Returns value:  TRUE
  278. \***********************************************************************/
  279. BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd )
  280. SHORT       chwnd;
  281. HWND FAR    *rghwnd;
  282. {
  283.     SHORT   i;
  284.     HWND    *phwndT;
  285.  
  286.     DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
  287.  
  288.     if (pahwndSpy) {
  289.         WinFreeMem(hheapSpyHook, (char *)pahwndSpy, sizeof(HWND) * chwndSpy);
  290.         pahwndSpy = NULL;
  291.     }
  292.  
  293.  
  294.     chwndSpy = chwnd;
  295.  
  296.     if (chwndSpy > 0 ) {
  297.  
  298.         phwndT = pahwndSpy = (HWND *) WinAllocMem(hheapSpyHook,
  299.                 sizeof(HWND) * chwndSpy);
  300.  
  301.         if (phwndT != NULL) {
  302.             for (i=0; i < chwnd; i++) {
  303.                 *phwndT++ = *rghwnd++;
  304.             }
  305.         } else
  306.             chwndSpy = 0;
  307.     }
  308.  
  309.     fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
  310.             fProcessAllWindows || fProcessAllFrames;
  311.  
  312.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  313.     return(TRUE);
  314. }
  315.  
  316.  
  317. /***********************************************************************\
  318. * BOOL FAR PASCAL SpyGetWindowList( chwnd, rghwnd)
  319. *
  320. * Effect:  This routine sets the list of window that we are interested
  321. *   in watching the messages for.
  322. *
  323. * Returns value:  TRUE
  324. \***********************************************************************/
  325. SHORT FAR PASCAL SpyGetWindowList( chwnd, rghwnd )
  326. SHORT       chwnd;
  327. HWND FAR    *rghwnd;
  328. {
  329.     SHORT   i;
  330.     HWND    *phwndT;
  331.  
  332.     DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
  333.  
  334.     if (chwnd > chwndSpy)
  335.             chwnd = chwndSpy;
  336.  
  337.     phwndT = pahwndSpy;
  338.     for (i=0; i < chwnd; i++) {
  339.         *rghwnd++ = *pahwndSpy++;
  340.     }
  341.  
  342.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  343.  
  344.     return(chwnd);
  345. }
  346.  
  347.  
  348.  
  349.  
  350. /***********************************************************************\
  351. * BOOL FAR PASCAL SpySetQueueList( chmq, rghmq )
  352. *
  353. * Effect:  This routine sets the list of queues whose messages we watch.
  354. *
  355. * Returns value:  TRUE
  356. \***********************************************************************/
  357. BOOL FAR PASCAL SpySetQueueList( chmq, rghmq )
  358. SHORT       chmq;
  359. HMQ FAR    *rghmq;
  360. {
  361.     SHORT   i;
  362.     HMQ     *phmqT;
  363.  
  364.     DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
  365.  
  366.     /*
  367.      * If we previously had a list of HMQs to spy on, free the old list
  368.      * now
  369.      */
  370.     if (pahmqSpy != NULL) {
  371.         WinFreeMem(hheapSpyHook, (char *)pahmqSpy, sizeof(HMQ) * chmqSpy);
  372.         pahmqSpy = NULL;
  373.     }
  374.  
  375.     chmqSpy = chmq;
  376.  
  377.     if (chmqSpy > 0) {
  378.         phmqT = pahmqSpy = (HWND *) WinAllocMem(hheapSpyHook, sizeof(HMQ) * chmqSpy);
  379.  
  380.         if (phmqT != NULL) {
  381.             for (i=0; i < chmq; i++) {
  382.                 *phmqT++ = *rghmq++;
  383.             }
  384.         } else
  385.             chmqSpy = 0;
  386.     }
  387.  
  388.     fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
  389.             fProcessAllWindows || fProcessAllFrames;
  390.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  391.  
  392.     return(TRUE);
  393. }
  394.  
  395.  
  396. /***********************************************************************\
  397. * BOOL FAR PASCAL SpyGetQueueList( chmq, rghmq )
  398. *
  399. * Effect:  This routine gets the list of queues whose messages we watch.
  400. *
  401. * Returns value:  TRUE
  402. \***********************************************************************/
  403. SHORT FAR PASCAL SpyGetQueueList( chmq, rghmq )
  404. SHORT       chmq;
  405. HMQ FAR    *rghmq;
  406. {
  407.     SHORT   i;
  408.     HMQ     *phmqT;
  409.  
  410.     DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
  411.  
  412.     if (chmq > chmqSpy)
  413.         chmq = chmqSpy;
  414.  
  415.     phmqT = pahmqSpy;
  416.  
  417.     for (i=0; i < chmq; i++) {
  418.         *rghmq++ = *phmqT++;
  419.     }
  420.  
  421.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  422.  
  423.     return(chmq);
  424. }
  425.  
  426.  
  427. /***********************************************************************\
  428. * BOOL FAR PASCAL SpySetMessageList(UCHAR FAR *prgNewMsgFilter,
  429. *                   BOOL fNewDispMsgsNotInList)
  430. *
  431. * Effect:  This routine sets the list of windows that whose message we watch.
  432. *
  433. * Returns value:  TRUE
  434. \***********************************************************************/
  435. BOOL FAR PASCAL SpySetMessageList(prgNewMsgFilter, fNewDispMsgsNotInList)
  436. UCHAR FAR           *prgNewMsgFilter;
  437. BOOL                fNewDispMsgsNotInList;
  438. {
  439.     SHORT           i;
  440.     unsigned char   *prgb;
  441.  
  442.     DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
  443.  
  444.     prgb = rgMessageFilter;
  445.  
  446.  
  447.     fDispMsgsNotInList = fNewDispMsgsNotInList;
  448.  
  449.     for (i=0; i < MAXMSGFILTERBYTES; i++) {
  450.         *prgb++ = *prgNewMsgFilter++;
  451.     }
  452.  
  453.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  454.  
  455.     return(TRUE);
  456. }
  457.  
  458.  
  459. /***********************************************************************\
  460. * BOOL FAR PASCAL SpyFWindowInList (hwnd, fInWindowListOnly)
  461. *
  462. * Effect:  This function checks our current list of windows, and returns
  463. *          TRUE if the window is in the list, else returns FALSE.
  464. *
  465. * Returns value:  TRUE if window is in list.  Also, if we are in the special
  466. *           state we will pass through all frame windows.
  467. \***********************************************************************/
  468. BOOL FAR PASCAL SpyFWindowInList (hwnd, fInWindowListOnly)
  469. register HWND  hwnd;
  470. BOOL            fInWindowListOnly;
  471. {
  472.     register int    i;
  473.     char            szClassName[10];    /* Class name of window */
  474.     CLASSINFO       classinfo;          /* Information about class */
  475.     HMQ             hmqWindow;          /* HMQ of window        */
  476.     HMQ             *phmqT;             /* Temporary pointer in hmq list */
  477.     HWND            *phwndT;            /* Temporary pointer to HWND list */
  478.  
  479.     phwndT = pahwndSpy;
  480.     for (i=0; i < chwndSpy; i++) {
  481.         if (hwnd == *phwndT++)
  482.             return (TRUE);
  483.     }
  484.  
  485.     /* See if we are restricting to only windows in list */
  486.     if (fInWindowListOnly)
  487.         return (FALSE);
  488.  
  489.     if (fProcessAllWindows)
  490.         return (TRUE);      /* All windows pass through */
  491.  
  492.     /*
  493.      * See if we are watching any message queues
  494.      */
  495.     if (phmqT = pahmqSpy) {
  496.         hmqWindow = (HMQ)WinQueryWindowULong(hwnd, QWL_HMQ);
  497.         for (i=0; i < chmqSpy; i++) {
  498.             if (*phmqT++ == hmqWindow)
  499.                 return (TRUE);
  500.         }
  501.     }
  502.  
  503.     if (fProcessAllFrames) {
  504.         /* See if frame class */
  505.         if (hwnd == NULL)
  506.             return (TRUE);      /* pass queue messages through */
  507.         WinQueryClassName(hwnd, sizeof(szClassName),
  508.             (PSZ)szClassName);
  509.         WinQueryClassInfo((HAB)NULL, (PSZ)szClassName,
  510.             &classinfo);
  511.         if (classinfo.flClassStyle & CS_FRAME)
  512.             return (TRUE);
  513.     }
  514.  
  515.     return (FALSE);
  516. }
  517.  
  518.  
  519. /***********************************************************************\
  520. * BOOL FAR PASCAL SpyReleaseHook(fZeroQueue)
  521. *
  522. * Effect:  This routine releases the input hook, if it is installed.
  523. *
  524. * Returns value: TRUE if hook is released, FALSE otherwise.
  525. \***********************************************************************/
  526. BOOL FAR PASCAL SpyReleaseHook(fZeroQueue)
  527. BOOL    fZeroQueue;
  528. {
  529.     BOOL fRet;
  530.  
  531.     DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L );
  532.  
  533.     if ( habOwner ) {
  534.         if (SpybHooks & SPYH_INPUT)
  535.                 fRet = WinReleaseHook( habOwner, (HMQ)0, HK_INPUT,
  536.                     (PFN)SpyInputHook, hmodSpy );
  537.  
  538.         if (SpybHooks & SPYH_SENDMSG)
  539.                 fRet = WinReleaseHook( habOwner, (HMQ)0, HK_SENDMSG,
  540.                     (PFN)SpySendMsgHook, hmodSpy );
  541.             if ( fRet ) {
  542.                 habOwner = (HAB)0;
  543.                 hmqOwner = (HMQ)0;
  544.         }
  545.     }
  546.  
  547.     /*
  548.      * When the hook is freed, we want to clear message count out,
  549.      * make sure any process waiting will abort
  550.      * Only do this if the Zeroqueu flag was passed
  551.      */
  552.     if (fZeroQueue) {
  553.         cmsgSpy = 0;
  554.         imsgWrite = 0;
  555.         imsgRead = 0;
  556.         if (pahwndSpy != NULL)
  557.             WinFreeMem(hheapSpyHook, (char *)pahwndSpy,
  558.                     sizeof(HWND) * chwndSpy);
  559.         pahwndSpy = NULL;
  560.         chwndSpy = 0;           /* Max windows to spy */
  561.         fRecording = FALSE;     /* Set recording to off */
  562.         if (pahmqSpy != NULL)
  563.             WinFreeMem(hheapSpyHook, (char *)pahmqSpy, sizeof(HMQ) * chmqSpy);
  564.  
  565.         pahmqSpy = NULL;
  566.         chmqSpy = 0;
  567.         fAnythingToWatch = FALSE;
  568.         DosSemClear((HSEM)(PULONG)&spyMsgSem);    /* Free any process */
  569.     }
  570.     DosSemClear((HSEM)(PULONG)&spyhookSem);
  571.  
  572.     return fRet;
  573. }
  574.  
  575.  
  576. /***********************************************************************\
  577. * BOOL FAR PASCAL SpyHookOnOrOff( fOn)
  578. *
  579. * Effect:  This routine allows the application to turn the hook
  580. *   processing on or off.
  581. *
  582. * Returns:    TRUE
  583. \***********************************************************************/
  584. BOOL FAR PASCAL SpyHookOnOrOff(fOn)
  585. BOOL fOn;
  586. {
  587.     DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L);
  588.  
  589.     fRecording = fOn;
  590.  
  591.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  592.     return (TRUE);
  593. }
  594.  
  595.  
  596.  
  597. /***********************************************************************\
  598. * BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames)
  599. *
  600. * Effect:  Special state if TRUE will cause the window filter to pass
  601. *       all frame windows through.  This is useful when debugging
  602. *       interactions between frame windows, when the windows are
  603. *       net yet created.
  604. *
  605. * Returns:    TRUE
  606. \***********************************************************************/
  607. BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames)
  608. BOOL fAllFrames;
  609. {
  610.     fProcessAllFrames = fAllFrames;
  611.     fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
  612.             fProcessAllWindows || fProcessAllFrames;
  613.     return (TRUE);
  614. }
  615.  
  616. /***********************************************************************\
  617. * BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows)
  618. *
  619. * Effect:  Special state if TRUE will cause the window filter to pass
  620. *       all windows through.  This is useful when debugging
  621. *       interactions between all of the windows.
  622. *
  623. * Returns:    TRUE
  624. \***********************************************************************/
  625. BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows)
  626. BOOL fAllWindows;
  627. {
  628.     fProcessAllWindows = fAllWindows;
  629.     fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
  630.             fProcessAllWindows || fProcessAllFrames;
  631.     return (TRUE);
  632. }
  633.  
  634.  
  635. /***********************************************************************\
  636. * BOOL FAR PASCAL SpySetLNSymbolPID(PID pid, SELECTOR sel);
  637. *
  638. *
  639. * Effect:  Tell the hook to be on the lookout for a specific PID.
  640. *       If found running in the context of the specified process, we
  641. *       will get the selector information for the specified selector.
  642. \***********************************************************************/
  643. BOOL FAR PASCAL SpySetLNSymbolPID(pid, selector)
  644. PID     pid;
  645. USHORT  selector;
  646. {
  647.     if (pidLNSpy == 0xffff) {
  648.         selectorLNSpy = selector;
  649.         rcLNSpy = -1;               /* Assume error for now */
  650.         pidLNSpy = pid;             /* Save PID to look for */
  651.         return (TRUE);
  652.     } else
  653.         return (FALSE);
  654. }
  655.  
  656.  
  657.  
  658. /***********************************************************************\
  659. * VOID SpyCheckPIDForSymbol(VOID)
  660. *
  661. * Effect:  Only called when we are looking for a symbol
  662. *
  663. \***********************************************************************/
  664. VOID SpyCheckPIDForSymbol()
  665. {
  666.     PIDINFO         pidinfo;
  667.  
  668.     /*
  669.      * Get the spy semaphore to serialize access and see if we are the
  670.      * correct PID;
  671.      */
  672.     DosGetPID(&pidinfo);
  673.     if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0)
  674.         return;
  675.  
  676.     if (pidinfo.pid == pidLNSpy) {
  677.         /*
  678.          * We are the correct process, so continue to try go get the
  679.          * symbol information.
  680.          */
  681.         pidLNSpy = 0xffff;       /* reset to not enter again */
  682.         rcLNSpy = IdentifyCodeSelector( selectorLNSpy,
  683.             (PWHOISINFO)&whoIsLNSpy);
  684.     }
  685.  
  686.     DosSemClear( (HSEM)(PULONG)&spyhookSem );
  687. }
  688.  
  689.  
  690.  
  691. /***********************************************************************\
  692. * int FAR PASCAL SpyGetLNSymbolSelector(pwhoinfo)
  693. *
  694. * Effect:  Get the information about the specified selector.
  695. *       If the specified process has not been executed since the
  696. *       function SpySetLNSymbolPID has been called, it will return -1,
  697. *       else it will return what was returned from IdentifyCodeSelector.
  698. \***********************************************************************/
  699. int FAR PASCAL SpyGetLNSymbolSelector(pwhoIsinfo)
  700. PWHOISINFO    pwhoIsinfo;
  701. {
  702.     *pwhoIsinfo = whoIsLNSpy;
  703.     return (rcLNSpy);
  704. }
  705.  
  706.  
  707.  
  708.  
  709. /**********************************************************************\
  710. * VOID GrabMsgDataWords (SHORT imsg, UCHAR bMPType)
  711. *
  712. * Effect:  Gets the next message from the list.
  713. *
  714. *    if timeout != 0 on message processing threads, problems may occur.
  715. *    if lpqmsg==NULL, this function acts like a query or wait function.
  716. \***********************************************************************/
  717. VOID GrabMsgDataWords(imsg, bMPType)
  718. SHORT       imsg;
  719. UCHAR       bMPType;
  720. {
  721.     UCHAR   bMP1Type;
  722.     UCHAR   bMP2Type;
  723.     SHORT   cbMPs;
  724.     SHORT   cbMP1;
  725.     SHORT   cbMP2;
  726.     UCHAR   *rgBuf;
  727.  
  728.     /*
  729.      * This function will use the MPType data to know if MP1 and/or MP2
  730.      * are pointers to any known data, that we want to extract off
  731.      * and save for spy to display later
  732.      */
  733.     rgqmsgSpy[imsg].bMPType = bMPType;
  734.     bMP1Type = (UCHAR)(bMPType & MP_MASK);
  735.     cbMPs = cbMP1 = rgqmsgSpy[imsg].cbDataMP1 = acbMPTypes[bMP1Type];
  736.  
  737.     bMP2Type = (UCHAR)((bMPType >> 3) & MP_MASK);
  738.     cbMPs += (cbMP2 = rgqmsgSpy[imsg].cbDataMP2 = acbMPTypes[bMP2Type]);
  739.  
  740.     if (cbMPs > 0) {
  741.         /* Allocate memory to save the data into */
  742.         rgBuf = rgqmsgSpy[imsg].rgData = WinAllocMem(hheapSpyHook, cbMPs);
  743.  
  744.         if (rgBuf != NULL) {
  745.             /* Copy the data down, Note: if count is 0 will NOP */
  746.             if (cbMP1) {
  747.                 CopyStruct((CHAR FAR *)rgqmsgSpy[imsg].qmsg.mp1,
  748.                         rgBuf, cbMP1);
  749.                 rgBuf += cbMP1;
  750.             }
  751.  
  752.             if (cbMP2) {
  753.                 CopyStruct((CHAR FAR *)rgqmsgSpy[imsg].qmsg.mp2,
  754.                         rgBuf, cbMP2);
  755.             }
  756.         }
  757.  
  758.     } else {
  759.         rgqmsgSpy[imsg].rgData = NULL;
  760.     }
  761. }
  762.  
  763. /**********************************************************************\
  764. * SpyGetNextMessage (lpqmsg, lpBuf, cbBuf, lTimeOut)
  765. *
  766. * Effect:  Get the next message from the list.
  767. *     if timeout != 0 on message processing threads, problems may occur.
  768. *    if lpqmsg==NULL, this function acts like a query or wait function.
  769. *
  770. * Returns:    Whether SpyGetNextMessage succeeds or not.
  771. \***********************************************************************/
  772. BOOL FAR PASCAL SpyGetNextMessage(lpqmsg, lpBuf, cbBuf, lTimeOut)
  773. PQMSGSPY   lpqmsg;      /* Pointer where the user wants the message stored */
  774. PSZ        lpBuf;       /* pointer to buffer */
  775. SHORT      cbBuf;       /* size of buffer in bytes */
  776. LONG    lTimeOut;       /* Timeout value */
  777. {
  778.  
  779.     SHORT       cbMsg;  /* Count of bytes associated with message */
  780.  
  781.     /* Quick escape hatch */
  782.     if ((lTimeOut == 0) && (cmsgSpy == 0))
  783.         return (FALSE);     /* Don't Wait */
  784.  
  785.     /*
  786.      * Now let's possibly wait for a message
  787.      */
  788.     if (cmsgSpy == 0) {
  789.         if (DosSemWait((HSEM)(PULONG)&spyMsgSem, lTimeOut) != 0)
  790.             return (FALSE); /* No messages after timeout */
  791.         if (cmsgSpy == 0)
  792.             return (FALSE); /* Still no messages, return condition */
  793.     }
  794.  
  795.     /*
  796.      * If the lpqmsg is NULL, the user is simply asking if there is
  797.      * a message and/or waiting for the message, so don't extract
  798.      * the message, but simply return the status.
  799.      */
  800.     if (lpqmsg != NULL) {
  801.         if (DosSemRequest((HSEM)(PULONG)&spyhookSem, lTimeOut) == 0) {
  802.             *lpqmsg = rgqmsgSpy[imsgRead];   /* Extract the message */
  803.  
  804.             cbMsg = rgqmsgSpy[imsgRead].cbDataMP1
  805.                     + rgqmsgSpy[imsgRead].cbDataMP2;
  806.  
  807.             if ((cbMsg > 0) && (lpBuf != NULL)) {
  808.                 if (cbMsg < cbBuf)
  809.                     cbBuf = cbMsg;  /* Number of bytes to copy */
  810.                 CopyStruct(rgqmsgSpy[imsgRead].rgData, lpBuf, cbBuf);
  811.             }
  812.  
  813.             if (cbMsg > 0)
  814.                 WinFreeMem(hheapSpyHook, rgqmsgSpy[imsgRead].rgData, cbMsg);
  815.  
  816.             /* Also give the caller any additional information on message */
  817.  
  818.             imsgRead++;
  819.             if (imsgRead == MAXMSGCNT)
  820.                 imsgRead = 0;  /* Wrap around */
  821.  
  822.             /*
  823.              * Decrement count of messages, if we go to zero, set
  824.              * the semaphore, so that the next read will suspend until
  825.              * the next message
  826.              */
  827.             cmsgSpy--;
  828.             if (cmsgSpy == 0)
  829.                 DosSemSet((HSEM)(PULONG)&spyMsgSem);
  830.  
  831.             DosSemClear( (HSEM)(PULONG)&spyhookSem );
  832.         }
  833.     }
  834.  
  835.     return (TRUE);
  836. }
  837.  
  838. /***********************************************************************\
  839. * VOID PASCAL Init( hmod )
  840. * Effect:    Saves the Spy module handle
  841. \***********************************************************************/
  842. VOID PASCAL Init( hmod )
  843. HMODULE hmod;
  844. {
  845.     /* Save the module handle */
  846.     hmodSpy = hmod;
  847. }
  848.  
  849. /***********************************************************************\
  850. * UCHAR GMsgEnableAndType (USHORT msg)
  851. *
  852. * Effect:
  853. *   Should the message be processed?
  854. *
  855. *   If the message is out of range 
  856. *    or bit is set in message bitmask then return TRUE;
  857. \***********************************************************************/
  858. UCHAR GMsgEnableAndType(msg)
  859. USHORT  msg;
  860. {
  861.     if (msg > MAXMSGFILTER)
  862.         return ((UCHAR)(fDispMsgsNotInList? MP_ENABLED : 0));
  863.  
  864.     return (rgMessageFilter[msg]);   /* One byte per message */
  865. }
  866.