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

  1. /***************************************************************************\
  2. * spy.c - Spy application
  3. *
  4. * Created by Microsoft Corporation, 1989
  5. \***************************************************************************/
  6.  
  7. #define INCL_DOSPROCESS
  8. #define    INCL_WINDIALOGS
  9. #define    INCL_WINFRAMEMGR
  10. #define    INCL_WINHEAP
  11. #define    INCL_WININPUT
  12. #define    INCL_WINLISTBOXES
  13. #define    INCL_WINMENUS
  14. #define    INCL_WINMESSAGEMGR
  15. #define    INCL_WINPOINTERS
  16. #define    INCL_WINSHELLDATA
  17. #define    INCL_WINSYS
  18. #define    INCL_WINWINDOWMGR
  19. #include <os2.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include "spyhook.h"
  24. #include <time.h>
  25. #include "spy.h"
  26.  
  27. /* File Local Variables */
  28. HAB         hab;
  29. HMQ         hmqSpy;
  30. HWND        hwndSpy;
  31. HWND        hwndSpyFrame;
  32. HWND        hwndSpyList = NULL;
  33. HWND        hwndWindowLB;
  34. HWND        hwndMessageLB;
  35. HHEAP       hHeap;
  36. SHORT       cxBorder;
  37. SHORT       cyBorder;
  38.  
  39. HPOINTER    hptrArrow;
  40. HPOINTER    hptrSelWin;
  41.  
  42. USHORT      iCurItemFocus;              /* Index to item that has the focus */
  43. BOOL        fSpyActive = MIA_CHECKED;   /* Any non-zero is true */
  44. BOOL        fTrackingListBox = FALSE;   /* Tracking windows active ? */
  45. BOOL        fAllFrames = 0;             /* Are we processing all frames ? */
  46. BOOL        fAllWindows = 0;            /* Are we processing all windows ? */
  47.  
  48.  
  49. HWND        hwndWinDlgDisp = NULL;      /* hwnds info in Window Dialog */
  50.  
  51. SHORT       wDumpCount = 0;             /* Count of which window is being dumped */
  52. SPWD        *pspwd = NULL;
  53.  
  54.  
  55. /* Define memory semaphore to have second thread sleep on */
  56. ULONG       semThread = 0L;             /* Thread to wait on */
  57. int         AboutCount = 0;
  58. UCHAR       rgMsgData[MAXMSGBYTES];     /* Max bytes to extract per message */
  59.  
  60.  
  61. char szSpyClass[] = "Spy";
  62. char szTitle[] = "";
  63.  
  64. /* Function Prototypes */
  65. int    cdecl main(int, char **);
  66. void    FAR ProcHookThread(void);    /* will process the hook messages */
  67. void    ProcessQueueMsg(QMSGSPY *);
  68. void    UpdateMsgBoxCurMsgText(HWND);
  69. void    InitializeOptions(int, char **);    /* initialize Spy initial state */
  70. PSZ     DumpParam(PSZ prgData, MPARAM mp, SHORT cb, UCHAR bMPType);
  71. MRESULT EXPENTRY SpyWndProc(HWND, USHORT, MPARAM, MPARAM);
  72. VOID    SpyPaint(VOID);
  73.  
  74.  
  75. /***************************************************************************\
  76. * int cdecl main (argc, argv)
  77. *
  78. * Spy Main function
  79. \***************************************************************************/
  80. int cdecl main(argc, argv)
  81. int argc;
  82. char **argv;
  83. {
  84.     ULONG   flCreateFlags;
  85.     QMSG    qmsg;
  86.     RECTL   rcl;
  87.     TID     tid;
  88.     char    *prgStack;
  89.  
  90.  
  91.     hab = WinInitialize(0);
  92.  
  93.     hmqSpy = WinCreateMsgQueue(hab, 0);
  94.  
  95.     if (!WinRegisterClass((HAB)NULL, szSpyClass, (PFNWP)SpyWndProc,
  96.             CS_SYNCPAINT, 0)) {
  97.         WinAlarm(HWND_DESKTOP, 0xffff);
  98.         return(0);
  99.     }
  100.  
  101.  
  102.     /*
  103.      * Create a heap for the program
  104.      */
  105.     hHeap = WinCreateHeap(0, 0, 0, 0, 0, 0);
  106.  
  107.     /*
  108.      * Create a stack for the thread - also initialize the stack by zeroing
  109.      * the first 32 bytes, and filling the remainder with a known value
  110.      */
  111.     prgStack = WinAllocMem(hHeap, CBSTACK);
  112.     if (prgStack == NULL)
  113.         goto Abort;
  114.     memset(prgStack, '\0', 32); /* Init first 32 bytes to zero */
  115.     memset(prgStack+32,'\345', CBSTACK-32); /* Remainder to known value */
  116.  
  117.     hptrArrow = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, TRUE);
  118.     cxBorder = (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
  119.     cyBorder = (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
  120.  
  121.     hptrSelWin = WinQuerySysPointer(HWND_DESKTOP, SPTR_MOVE, TRUE);
  122.  
  123.     SpyInstallHook(hab, hmqSpy, spyopt.bHooks);
  124.     SpySetAllWindowOpt (fAllWindows);
  125.     SpySetAllFrameOpt (fAllFrames);
  126.  
  127.     flCreateFlags = FCF_STANDARD;
  128.     hwndSpyFrame = WinCreateStdWindow(HWND_DESKTOP,
  129.             WS_VISIBLE,
  130.             (VOID FAR *)&flCreateFlags,
  131.             szSpyClass, szTitle,
  132.             WS_VISIBLE,
  133.             (HMODULE)NULL, IDR_SPY,
  134.             (HWND FAR *)&hwndSpy);
  135.  
  136.     WinQueryWindowRect(hwndSpy, &rcl);
  137.     hwndSpyList = WinCreateWindow (hwndSpy, WC_LISTBOX, "",
  138.             WS_VISIBLE | LS_NOADJUSTPOS,
  139.             -cxBorder, -cyBorder,
  140.             (SHORT)(rcl.xRight - rcl.xLeft) + 2 * cxBorder,
  141.             (SHORT)(rcl.yTop - rcl.yBottom) + 2 * cyBorder,
  142.             hwndSpy, HWND_TOP, DID_SPYLIST, NULL, NULL);
  143.  
  144.     /*
  145.      * Read the os2.ini information if it exists, and set the menu items
  146.      * to correspond to the initial state read from OS2.INI.
  147.      */
  148.     InitializeOptions(argc, argv);    /* initialize Spy initial state */
  149.  
  150.     /*
  151.      * Set the focus to the list box.  Note: Only call WinSetFocus if
  152.      * our frame is the active window.  As we may have been started in
  153.      * the background.  If this is the case, we want to set the frame's
  154.      * focus save to the listbox, such that it will be the active window
  155.      * when our frame is activated.
  156.      */
  157.     if (WinQueryWindow(HWND_DESKTOP, QW_TOP, FALSE) == hwndSpyFrame)
  158.         WinSetFocus(HWND_DESKTOP, hwndSpyList);
  159.     else
  160.         WinSetWindowULong(hwndSpyFrame, QWL_HWNDFOCUSSAVE,
  161.             (ULONG)hwndSpyList);
  162.  
  163.  
  164.  
  165.     /* Start the thread that will process the messages from the hook */
  166.     DosCreateThread(ProcHookThread, (PTID)&tid,
  167.         (PBYTE)(prgStack + CBSTACK - 1));
  168.  
  169.     UpdateHooksMsgTable();      /* Set Spy's Message Table */
  170.     SpyHookOnOrOff (TRUE);      /* Turn the hook on */
  171.  
  172.  
  173.    /*
  174.     * Now process all of the messages
  175.     */
  176.     while (WinGetMsg(NULL, (PQMSG)&qmsg, NULL, 0, 0)) {
  177.         WinDispatchMsg(NULL, (PQMSG)&qmsg);
  178.     }
  179.  
  180.     SpyReleaseHook (TRUE);      /* Release input hook */
  181.  
  182.     WinDestroyWindow(hwndSpyFrame);
  183.  
  184.     WinDestroyPointer(hptrArrow);
  185.     WinDestroyPointer(hptrSelWin);
  186.  
  187. Abort:
  188.     WinDestroyMsgQueue(hmqSpy);
  189.     WinTerminate(hab);
  190.  
  191.     /* If the spy output file is open, close it now */
  192.     if (spyopt.hfileSpy != NULL)
  193.         DosClose(spyopt.hfileSpy);
  194.  
  195.  
  196.     DosExit(EXIT_PROCESS, 0);
  197. }
  198.  
  199.  
  200.  
  201.  
  202. /***************************************************************************\
  203. * InitializeOptions(argc, argv)
  204. *
  205. * Initialize spy, first from the default options, second from
  206. * OS2.INI file, and override from command switches.
  207. \***************************************************************************/
  208. VOID InitializeOptions(argc, argv)
  209. int argc;
  210. char **argv;
  211. {
  212.     USHORT      cch;
  213.     USHORT      wAction;
  214.     HWND        hwndMenu;
  215.  
  216.  
  217.     /*
  218.      * If the OS2.INI information exists, initialize our options to
  219.      * the stored values.
  220.      */
  221.     if (WinQueryProfileSize (hab, "Spy", "Options", &cch) == 0) {
  222.         cch = sizeof(SPYOPT);
  223.  
  224.         WinQueryProfileData(hab, "Spy", "Options", (PSZ)&spyopt,
  225.                 &cch);
  226.         WinQueryProfileString(hab, "Spy", "FileName", "spy.out",
  227.                 (PSZ)spystr.szFileName, sizeof(spystr.szFileName));
  228.         WinQueryProfileString(hab, "Spy", "SaveFileName", "spy.lis",
  229.                 (PSZ)spystr.szSaveFileName, sizeof(spystr.szSaveFileName));
  230.     }
  231.  
  232.     /*
  233.      * Then check for command line overrides
  234.      */
  235.     while  (argc > 1) {
  236.         argv++; /* get beyond the program name */
  237.  
  238.         /* Test for send message hook flag */
  239.         if (!strcmpi(*argv, "+s"))
  240.             spyopt.bHooks |= SPYH_SENDMSG;
  241.         if (!strcmpi(*argv, "-s"))
  242.             spyopt.bHooks &= ~SPYH_SENDMSG;
  243.  
  244.         /* Test for input hook flag */
  245.         if (!strcmpi(*argv, "+i"))
  246.             spyopt.bHooks |= SPYH_INPUT;
  247.         if (!strcmpi(*argv, "-i"))
  248.             spyopt.bHooks &= ~SPYH_INPUT;
  249.  
  250.         argc--;
  251.     }
  252.  
  253.     /*
  254.      * Now we need to update the menu items to the final
  255.      * state
  256.      */
  257.     hwndMenu = WinWindowFromID(hwndSpyFrame, FID_MENU);
  258.  
  259.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(CMD_INPUTHOOK, TRUE),
  260.             MPFROM2SHORT(MIA_CHECKED,
  261.              (spyopt.bHooks & SPYH_INPUT) ? MIA_CHECKED : 0));
  262.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(CMD_SENDMSGHOOK, TRUE),
  263.              MPFROM2SHORT(MIA_CHECKED,
  264.              (spyopt.bHooks & SPYH_SENDMSG) ? MIA_CHECKED : 0));
  265.  
  266.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(CMD_SENDEXTEND, TRUE),
  267.             MPFROM2SHORT(MIA_CHECKED,
  268.              spyopt.fSendExtend ? MIA_CHECKED : 0));
  269.  
  270.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(CMD_SENDSTACK, TRUE),
  271.             MPFROM2SHORT(MIA_CHECKED,
  272.             spyopt.fSendStack ? MIA_CHECKED : 0));
  273.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(CMD_OUTSCREEN, TRUE),
  274.             MPFROM2SHORT(MIA_CHECKED, spyopt.fWindow ? MIA_CHECKED : 0));
  275.  
  276.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(CMD_OUTFILE, TRUE),
  277.             MPFROM2SHORT(MIA_CHECKED, spyopt.fFile ? MIA_CHECKED : 0));
  278.  
  279.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(CMD_ALPHASORT, TRUE),
  280.             MPFROM2SHORT(MIA_CHECKED,
  281.                     spyopt.fAlphaSortMsgList ? MIA_CHECKED : 0));
  282.  
  283.     /*
  284.      * If the options specify output to file, open the file now
  285.      */
  286.     if (spyopt.fFile) {
  287.         if (DosOpen((PSZ)spystr.szFileName, &spyopt.hfileSpy,
  288.                 (USHORT far *)&wAction, 0L, 0,
  289.                 0x0012, 0x00C1, 0L) != 0)
  290.             spyopt.hfileSpy = NULL; /* Failed on open */
  291.     }
  292. }
  293.  
  294.  
  295. /***************************************************************************\
  296. * MRESULT EXPENTRY SpyWndProc(hwnd, msg, mp1, mp2)
  297. *
  298. * Spy Client window procedure
  299. \***************************************************************************/
  300. MRESULT EXPENTRY SpyWndProc(hwnd, msg, mp1, mp2)
  301. HWND hwnd;
  302. USHORT msg;
  303. MPARAM mp1;
  304. MPARAM mp2;
  305. {
  306.     QMSGSPY qmsgspy;
  307.     SHORT   cBytes;
  308.     USHORT      wAction;
  309.  
  310.     switch (msg) {
  311.     case WM_CREATE:
  312.         /* Set up this global first thing in case we need it elsewhere */
  313.         hwndSpy = hwnd;
  314.         break;
  315.  
  316.     case WM_SEM2:
  317.         /*
  318.          * Other thread told use there are some messages out there.  Loop
  319.          * through and process all of the pending messages, and output
  320.          * the listbox position at the end.  Also make sure to flush
  321.          * the file buffer before we go back to sleep.
  322.          */
  323.         while (SpyGetNextMessage(&qmsgspy, rgMsgData, sizeof(rgMsgData), 0L)) {
  324.             ProcessQueueMsg(&qmsgspy);
  325.         }
  326.  
  327.         if (spyopt.fFile)
  328.             DosBufReset(spyopt.hfileSpy);
  329.  
  330.         DosSemClear((HSEM)(PULONG)&semThread);
  331.  
  332.         break;
  333.  
  334.     case WM_COMMAND:
  335.         switch (SHORT1FROMMP(mp1)) {
  336.         case CMD_ACTIVE:
  337.  
  338.             /*
  339.              * THe active menu item was selected, we will toggle the
  340.              * the selection by setting active to 0 or MIA_CHECKED.
  341.              * Call the hook, and then update the checkmark on the menu
  342.              */
  343.             fSpyActive ^= MIA_CHECKED;  /* Toggle on or off */
  344.             SpyHookOnOrOff (fSpyActive);
  345.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  346.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_ACTIVE, TRUE),
  347.                 MPFROM2SHORT(MIA_CHECKED, fSpyActive));
  348.  
  349.             break;
  350.         case CMD_ABOUT:
  351.             WinDlgBox(HWND_DESKTOP, hwnd, (PFNWP)AboutWndProc, NULL, AboutDlg, (PCH)NULL);
  352.             break;
  353.  
  354.         case CMD_EXIT:
  355.             WinPostMsg(NULL, WM_QUIT, 0L, 0L);
  356.             break;
  357.  
  358.         case CMD_CLRWIN:
  359.             /*
  360.              * Delete all items in the list.  Simply do this
  361.              * By deleting the first item, until the count goes to
  362.              * zero
  363.              */
  364.             WinSendMsg(hwndSpyList, LM_DELETEALL, 0L, 0L);
  365.             break;
  366.  
  367.         case CMD_SAVEWIN:
  368.             SpyHookOnOrOff (FALSE);
  369.             WinDlgBox(HWND_DESKTOP, hwndSpyFrame,
  370.                 (PFNWP)SpySaveListDlgProc, (HMODULE)NULL,
  371.                 SaveListDlg, (PCH)NULL);
  372.             SpyHookOnOrOff (fSpyActive);
  373.             break;
  374.  
  375.         /*
  376.          * This command saves out the current options to OS2.ini
  377.          */
  378.         case CMD_SAVEOPT:
  379.             WinWriteProfileData(hab, "Spy", "Options", (PSZ)&spyopt,
  380.                     sizeof(SPYOPT));
  381.             WinWriteProfileString(hab, "Spy", "FileName",
  382.                     (PSZ)spystr.szFileName);
  383.             WinWriteProfileString(hab, "Spy", "SaveFileName",
  384.                     (PSZ)spystr.szSaveFileName);
  385.  
  386.             break;
  387.  
  388.         case CMD_LISTNEAR:
  389.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  390.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_LISTNEAR, TRUE),
  391.                 MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  392.             WinLoadDlg(HWND_DESKTOP, hwndSpyFrame,
  393.                 (PFNWP)ListNearDlgProc, (HMODULE)NULL,
  394.                 ListNearDlg, (PCH)NULL);
  395.             break;
  396.  
  397.         case CMD_WINDOWS:
  398.             SpyHookOnOrOff (FALSE);
  399.             hwndWindowLB = NULL;
  400.             iCurItemFocus = (USHORT)-1;
  401.             WinDlgBox(HWND_DESKTOP, hwndSpyFrame,
  402.                 (PFNWP)SpyWindowsDlgProc, (HMODULE)NULL,
  403.                 WindowsDlg, (PCH)NULL);
  404.  
  405.             SpyHookOnOrOff (fSpyActive);
  406.             break;
  407.  
  408.         case CMD_QUEUES:
  409.             SpyHookOnOrOff (FALSE);
  410.             hwndWindowLB = NULL;
  411.             iCurItemFocus = (USHORT)-1;
  412.             WinDlgBox(HWND_DESKTOP, hwndSpyFrame,
  413.                 (PFNWP)SpyQueuesDlgProc, (HMODULE)NULL,
  414.                 MsgQueueDlg, (PCH)NULL);
  415.  
  416.             SpyHookOnOrOff (fSpyActive);
  417.             break;
  418.  
  419.         case CMD_WNMSSEL:
  420.         case CMD_WNMSDSL:
  421.             SpyHookOnOrOff (FALSE);
  422.             SelOrDeselWithMouse(SHORT1FROMMP(mp1) == CMD_WNMSSEL);
  423.             SpyHookOnOrOff (fSpyActive);
  424.             break;
  425.  
  426.         case CMD_ALLWNDWS:
  427.  
  428.             /*
  429.              * The user selected the ALLFRAMES, toggle the state, and
  430.              * update the menu and the hook state.
  431.              */
  432.             fAllWindows ^= MIA_CHECKED;  /* Toggle on or off */
  433.             SpySetAllWindowOpt (fAllWindows);
  434.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  435.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_ALLWNDWS, TRUE),
  436.                 MPFROM2SHORT(MIA_CHECKED, fAllWindows));
  437.             break;
  438.  
  439.         case CMD_ALLFRAMES:
  440.  
  441.             /*
  442.              * The user selected the ALLFRAMES, toggle the state, and
  443.              * update the menu and the hook state.
  444.              */
  445.             fAllFrames ^= MIA_CHECKED;  /* Toggle on or off */
  446.             SpySetAllFrameOpt (fAllFrames);
  447.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  448.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_ALLFRAMES, TRUE),
  449.                 MPFROM2SHORT(MIA_CHECKED, fAllFrames));
  450.             break;
  451.  
  452.         case CMD_WNDPWIN:
  453.             wDumpCount = 0;
  454.             DumpOneWindowInfo();
  455.             break;
  456.  
  457.         case CMD_WNDPALL:
  458.             wDumpCount = 0;
  459.             pspwd = (SPWD *)WinAllocMem(hHeap, sizeof(SPWD)* MAXSPYDUMP);
  460.             cBytes = DumpAllWindowsInfo(HWND_DESKTOP, 0);
  461.             cBytes += DumpAllWindowsInfo(HWND_OBJECT, -10);
  462.             DumpWindowIndex(cBytes);
  463.             WinFreeMem(hHeap, (char *)pspwd, sizeof(SPWD)* MAXSPYDUMP);
  464.             break;
  465.  
  466.         case CMD_MESSAGES:
  467.             SpyHookOnOrOff (FALSE);
  468.             WinDlgBox(HWND_DESKTOP, hwndSpyFrame,
  469.                 (PFNWP)SpyMsgDlgProc, (HMODULE)NULL,
  470.                 MessagesDlg, (PCH)NULL);
  471.             SpyHookOnOrOff (fSpyActive);
  472.             break;
  473.  
  474.         case CMD_ALPHASORT:
  475.             spyopt.fAlphaSortMsgList ^= TRUE;
  476.  
  477.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  478.                     MM_SETITEMATTR, MPFROM2SHORT(CMD_ALPHASORT, TRUE),
  479.                     MPFROM2SHORT(MIA_CHECKED,
  480.                             spyopt.fAlphaSortMsgList ? MIA_CHECKED : 0));
  481.             break;
  482.  
  483.         /*
  484.          * The command in this section are defined in the Hooks Menu.
  485.          * All of these items toggle selections on or off.  The first two
  486.          * items must be registered with the input hook.  The last two simply
  487.          * retrict how much information is displayed for send messages.
  488.          */
  489.  
  490.         case CMD_INPUTHOOK:
  491.             spyopt.bHooks ^= SPYH_INPUT;
  492.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  493.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_INPUTHOOK, TRUE),
  494.                 MPFROM2SHORT(MIA_CHECKED,
  495.                      (spyopt.bHooks & SPYH_INPUT) ? MIA_CHECKED : 0));
  496.                 SpyReleaseHook (FALSE);     /* Dont clear queue */
  497.                 SpyInstallHook(hab, hmqSpy, spyopt.bHooks);
  498.             break;
  499.  
  500.         case CMD_SENDMSGHOOK:
  501.             spyopt.bHooks ^= SPYH_SENDMSG;
  502.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  503.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_SENDMSGHOOK, TRUE),
  504.                 MPFROM2SHORT(MIA_CHECKED,
  505.                      (spyopt.bHooks & SPYH_SENDMSG) ? MIA_CHECKED : 0));
  506.                 SpyReleaseHook (FALSE);     /* Dont clear queue */
  507.                 SpyInstallHook(hab, hmqSpy, spyopt.bHooks);
  508.             break;
  509.  
  510.         case CMD_SENDEXTEND:
  511.             spyopt.fSendExtend ^= 1;  /* Toggle on or off */
  512.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  513.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_SENDEXTEND, TRUE),
  514.                 MPFROM2SHORT(MIA_CHECKED,
  515.                      spyopt.fSendExtend ? MIA_CHECKED : 0));
  516.             break;
  517.  
  518.         case CMD_SENDSTACK:
  519.             spyopt.fSendStack ^= 1;  /* Toggle on or off */
  520.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  521.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_SENDSTACK, TRUE),
  522.                 MPFROM2SHORT(MIA_CHECKED,
  523.                     spyopt.fSendStack ? MIA_CHECKED : 0));
  524.             break;
  525.  
  526.         /*
  527.          * The commands in this section are defined in the Outputs Menu.
  528.          * The first 3 items simply toggle outputs on or off, where the
  529.          * last item allows the user to change all of the output options.
  530.          */
  531.         case CMD_OUTSCREEN:
  532.             spyopt.fWindow ^= 1;  /* Toggle on or off */
  533.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  534.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_OUTSCREEN, TRUE),
  535.                 MPFROM2SHORT(MIA_CHECKED, spyopt.fWindow ? MIA_CHECKED : 0));
  536.             break;
  537.  
  538.         case CMD_OUTFILE:
  539.             spyopt.fFile ^= 1;  /* Toggle on or off */
  540.             WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
  541.                 MM_SETITEMATTR, MPFROM2SHORT(CMD_OUTFILE, TRUE),
  542.                 MPFROM2SHORT(MIA_CHECKED, spyopt.fFile ? MIA_CHECKED : 0));
  543.             /*
  544.              * Open or close the output file
  545.              */
  546.             if (spyopt.fFile) {
  547.                  if (spyopt.hfileSpy == NULL)
  548.                     if (DosOpen((PSZ)spystr.szFileName, &spyopt.hfileSpy,
  549.                             (USHORT far *)&wAction, 0L, 0,
  550.                             0x0012, 0x00C1, 0L) != 0)
  551.                         spyopt.hfileSpy = NULL; /* Failed on open */
  552.             } else {
  553.                 if (spyopt.hfileSpy != NULL) {
  554.                     /* file open, not outputing, close it now */
  555.                     DosClose (spyopt.hfileSpy);
  556.                     spyopt.hfileSpy = NULL;
  557.                 }
  558.             }
  559.             break;
  560.  
  561.         case CMD_OUTPUTS:
  562.             SpyHookOnOrOff (FALSE);
  563.             WinDlgBox(HWND_DESKTOP, hwndSpyFrame,
  564.                 (PFNWP)SpyOutputsDlgProc, (HMODULE)NULL,
  565.                 OutputsDlg, (PCH)NULL);
  566.             SpyHookOnOrOff (fSpyActive);
  567.             break;
  568.  
  569.         case CMD_MGDABLE:
  570.         case CMD_MGEABLE:
  571.             EnableOrDisableMsg(SHORT1FROMMP(mp1) == CMD_MGEABLE);
  572.             break;
  573.         }
  574.  
  575.         break;
  576.  
  577.     case WM_SIZE:
  578.         /* We need to resize the listbox, if it exists */
  579.         if (hwndSpyList != NULL) {
  580.             WinSetWindowPos(hwndSpyList, HWND_TOP, -cxBorder, -cyBorder,
  581.                 SHORT1FROMMP(mp2) + 2 * cxBorder,
  582.                 SHORT2FROMMP(mp2) + 2 * cyBorder, SWP_MOVE | SWP_SIZE);
  583.         }
  584.  
  585.         /* Now fall through to process the message */
  586.     default:
  587.         return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  588.         break;
  589.     }
  590.     return(0L);
  591. }
  592.  
  593.  
  594.  
  595.  
  596. /***************************************************************************\
  597. * USHORT UConvertStringToNum(psz)
  598. *
  599. * Converts the passed string to a number 0xffff if not number
  600. \***************************************************************************/
  601. USHORT  UConvertStringToNum(psz)
  602. register char   *psz;
  603. {
  604.     register USHORT uNum;
  605.  
  606.     /*
  607.      * If the first few chars are 0x, we assume the user typed in a
  608.      * HEX number, else if 0-9, we assume decimal, else we use the string.
  609.      */
  610.     /* First see if digit in first position */
  611.     if ((*psz >= '0') && (*psz <= '9')) {
  612.         /* Assume numbers now */
  613.         if ((*psz == '0') && (*(psz+1) == 'x')) {
  614.  
  615.             /* We are in hex mode */
  616.             psz += 2;
  617.             uNum = 0;
  618.             for (;;) {
  619.                 if ((*psz >= '0') && (*psz <= '9'))
  620.                     uNum = uNum * 16 + (USHORT)(*psz - '0');
  621.                 else if ((*psz >= 'a') && (*psz <= 'f'))
  622.                     uNum = uNum * 16 + (USHORT)(*psz - 'a');
  623.                 else if ((*psz >= 'F') && (*psz <= 'F'))
  624.                     uNum = uNum * 16 + (USHORT)(*psz - 'A');
  625.                 else
  626.                     break;
  627.                 psz++;
  628.             }
  629.  
  630.         } else {
  631.             /* Decimal mode */
  632.             uNum = (USHORT)(*psz++ - '0');
  633.             while ((*psz >= '0') && (*psz <= '9')) {
  634.                 uNum = uNum * 10 + (USHORT)(*psz++ - '0');
  635.             }
  636.         }
  637.  
  638.         return (uNum);
  639.     } else
  640.         /* Not num, return 0xffff */
  641.         return (0xffff);
  642. }
  643.  
  644.  
  645.  
  646.  
  647.  
  648. /***************************************************************************\
  649. * void ProcHookThread()
  650. *
  651. *   This function will wait for the hook to have messages,  when it
  652. *   does, it will set a memory semaphore, post a WM_SEM1 message to the other
  653. *   thread, and wait for the other thread has processed all of the messages.
  654. \***************************************************************************/
  655.  
  656. void FAR ProcHookThread()
  657. {
  658.     while (TRUE) {
  659.         /*
  660.          * Wait for a message to become available.
  661.          */
  662.         if (!SpyGetNextMessage(NULL, NULL, 0, -1L))
  663.             break;
  664.  
  665.         /*
  666.          * Now we have a message, set our semaphore, Post a WM_SEM2
  667.          * message to the Client window, and wait for the client to
  668.          * clear the semaphore.
  669.          */
  670.         DosSemSet((HSEM)(PULONG)&semThread);
  671.         WinPostMsg(hwndSpy, WM_SEM2, (MPARAM)1, (MPARAM)1);
  672.         DosSemWait((HSEM)(PULONG)&semThread, -1L);
  673.     }
  674.  
  675.     DosExit(EXIT_THREAD, 0);
  676. }
  677.  
  678.  
  679.  
  680.  
  681. /***************************************************************************\
  682. * void ProcessQueueMsg(pqmsg)
  683. *
  684. *   This function will process the hook, by calling the hooks which get
  685. *   messages.  We will than post the message to the current output destinations.
  686. \***************************************************************************/
  687.  
  688. void ProcessQueueMsg(pqmsgspy)
  689.     QMSGSPY    *pqmsgspy;
  690. {
  691.     MSGI    *pmsgi;
  692.     SHORT   item;
  693.     CHAR    cSource;
  694.     CHAR    cThread;
  695.     char    szNextMessage[100];
  696.     char    szTime[12];
  697.     SHORT   cch;
  698.     CHAR    bAscii;
  699.     PSZ     prgData;
  700.  
  701.  
  702.  
  703.     /*
  704.      * Now let's build the message to output
  705.      */
  706.     if (WinIsWindow(hab, pqmsgspy->qmsg.hwnd)) {
  707.         if (WinIsChild(pqmsgspy->qmsg.hwnd, hwndSpy))
  708.             return;     /* don't want endless loops */
  709.     }
  710.  
  711.     cThread = ':';
  712.     if (pqmsgspy->qmsg.time == (ULONG)-1) {
  713.         /* Sent message */
  714.         szTime[0] = '\0';
  715.         cSource = 'S';
  716.         if (pqmsgspy->fs)
  717.             cThread = '*';
  718.     } else {
  719.         cSource = 'I';
  720.         if (pqmsgspy->fs != PM_REMOVE)
  721.             cThread = '-';  /* Show different for non-remove */
  722.  
  723.         sprintf (szTime, "%-08lx", pqmsgspy->qmsg.time);
  724.     }
  725.  
  726.     if ((pmsgi = PmsgiFromMsg(pqmsgspy->qmsg.msg)) == NULL) {
  727.         /*
  728.          * Message not in list, use default
  729.          */
  730.         cch = sprintf(szNextMessage,
  731.             "%c%cMSG:0x%04x            H:%04x 1:%08lx 2:%08lx T:%s",
  732.             cSource, cThread, (SHORT)pqmsgspy->qmsg.msg, (SHORT)(ULONG)pqmsgspy->qmsg.hwnd,
  733.             pqmsgspy->qmsg.mp1, pqmsgspy->qmsg.mp2, szTime);
  734.     } else if (pmsgi->wOptions & MSGI_MOUSE) {
  735.         /*
  736.          * Mouse message, decode to mouse types
  737.          */
  738.         cch = sprintf(szNextMessage,
  739.             "%c%c%-20s H:%04x X:%-4d Y:%-4d HT:%04x T:%s",
  740.             cSource, cThread, pmsgi->szMsg, (SHORT)(LONG)pqmsgspy->qmsg.hwnd,
  741.             SHORT1FROMMP(pqmsgspy->qmsg.mp1), SHORT2FROMMP(pqmsgspy->qmsg.mp1),
  742.             SHORT1FROMMP(pqmsgspy->qmsg.mp2), szTime);
  743.     } else if (pmsgi->wOptions & MSGI_KEY) {
  744.         /*
  745.          * Key messages, output special
  746.          */
  747.         bAscii = (CHAR)SHORT1FROMMP(pqmsgspy->qmsg.mp2);
  748.         if ((bAscii < ' ') || (bAscii > '~'))
  749.             bAscii = ' ';
  750.  
  751.         cch = sprintf(szNextMessage,
  752.             "%c%c%-20s H:%04x F:%04x R:%d S:%2x C:%04x(%c) V:%02x T:%s",
  753.             cSource, cThread, pmsgi->szMsg, (SHORT)(LONG)pqmsgspy->qmsg.hwnd,
  754.             SHORT1FROMMP(pqmsgspy->qmsg.mp1),
  755.             CHAR3FROMMP(pqmsgspy->qmsg.mp1),  CHAR4FROMMP(pqmsgspy->qmsg.mp1),
  756.             SHORT1FROMMP(pqmsgspy->qmsg.mp2), bAscii,
  757.             SHORT2FROMMP(pqmsgspy->qmsg.mp2), szTime);
  758.     } else {
  759.         /* No special format */
  760.         cch = sprintf(szNextMessage,
  761.             "%c%c%-20s H:%04x 1:%08lx 2:%08lx T:%s",
  762.             cSource, cThread, pmsgi->szMsg, (SHORT)(ULONG) pqmsgspy->qmsg.hwnd,
  763.             pqmsgspy->qmsg.mp1, pqmsgspy->qmsg.mp2, szTime);
  764.     }
  765.  
  766.     OutputString(szNextMessage, cch);
  767.  
  768.     /*
  769.      * Now dump out any additional information associated with the
  770.      * message.  The processing depends of the type of message on
  771.      * how we are going to process the data.
  772.      */
  773.     if (spyopt.fSendExtend) {
  774.         prgData = DumpParam((PSZ)rgMsgData, pqmsgspy->qmsg.mp1,
  775.                 pqmsgspy->cbDataMP1, pqmsgspy->bMPType);
  776.         DumpParam(prgData, pqmsgspy->qmsg.mp2, pqmsgspy->cbDataMP2,
  777.                 (UCHAR)((pqmsgspy->bMPType) >> 3));
  778.     }
  779.  
  780.     /*
  781.      * If this is a send message, also display the call stack information
  782.      * of who called WinSendMsg
  783.      */
  784.     if (spyopt.fSendStack && (pqmsgspy->qmsg.time == (ULONG)-1)) {
  785.         cch = sprintf(szNextMessage,
  786.             "    PID: %-3d TID: %-2d   Stack:",
  787.             pqmsgspy->pidSend, pqmsgspy->tidSend);
  788.  
  789.         /* Now loop and add the stack info */
  790.         for (item=0; (item < MAXSTRACE) &&
  791.                 (pqmsgspy->pvoidStack[item] != NULL); item++) {
  792.             cch += sprintf(szTime, " %p", pqmsgspy->pvoidStack[item]);
  793.             strcat(szNextMessage, szTime);
  794.         }
  795.  
  796.         OutputString(szNextMessage, cch);
  797.     }
  798.  
  799. }
  800.  
  801.  
  802.  
  803.  
  804. /***************************************************************************\
  805. * PSZ DumpParam(PSZ prgData, MPARAM mp, SHORT cb, UCHAR bMPType)
  806. *
  807. * Dump the additional information that was captured for the message.
  808. *   using the currently defined types.
  809. *
  810. * Returns: PSZ - Pointer to next available byte after process DATA
  811. \***************************************************************************/
  812. PSZ DumpParam(prgData, mp, cb, bMPType)
  813. PSZ         prgData;
  814. MPARAM      mp;
  815. SHORT       cb;
  816. UCHAR       bMPType;
  817. {
  818.     char    szNextMessage[100];
  819.     SHORT   cch;
  820.  
  821.  
  822.     if (FGuessValidPointer((PSZ)mp, cb)) {
  823.         /* Process by type */
  824.         switch (bMPType & 0x07) {
  825.         case MPT_SWP:
  826.             cch = sprintf(szNextMessage,
  827.                 "    SWP:               fs:%04x cx:%d cy:%d y:%d x:%d HB:%04x H:%04x",
  828.                 ((PSWP)prgData)->fs, ((PSWP)prgData)->cy, ((PSWP)prgData)->cx,
  829.                 ((PSWP)prgData)->y, ((PSWP)prgData)->x,
  830.                 (SHORT)(ULONG)((PSWP)prgData)->hwndInsertBehind,
  831.                 (SHORT)(ULONG)((PSWP)prgData)->hwnd);
  832.  
  833.             break;
  834.  
  835.         case MPT_RECTL:
  836.             cch = sprintf(szNextMessage,
  837.                 "    RECTL:             xLeft:%d yBottom:%d xRight:%d yTop:%d",
  838.                 ((PRECTL)prgData)->xLeft, ((PRECTL)prgData)->yBottom,
  839.                 ((PRECTL)prgData)->xRight, ((PRECTL)prgData)->yTop);
  840.             break;
  841.  
  842.         case MPT_QMSG:
  843.             cch = sprintf(szNextMessage,
  844.                 "    QMSG: H:%04x       M:%04x M1:%08lx M2:%08lx T:%08lx (%d, %d)",
  845.                 (SHORT)(ULONG)((PQMSG)prgData)->hwnd, ((PQMSG)prgData)->msg,
  846.                 ((PQMSG)prgData)->mp1,((PQMSG)prgData)->mp2,
  847.                 ((PQMSG)prgData)->time,
  848.                 ((PQMSG)prgData)->ptl.x, ((PQMSG)prgData)->ptl.y);
  849.             break;
  850.  
  851.         default:
  852.             goto NoData;
  853.         }
  854.  
  855.         OutputString(szNextMessage, cch);
  856.     }
  857. NoData:
  858.     return (prgData + cb);
  859. }
  860.  
  861.  
  862.  
  863.  
  864. /***************************************************************************\
  865. * void OutputString(char szOut, SHORT cch);
  866. *
  867. *   This function will output the specified string to the
  868. *   destinations.
  869. \***************************************************************************/
  870.  
  871. void OutputString(szOut, cch)
  872. char        szOut[];
  873. SHORT       cch;
  874. {
  875.     SHORT   item;
  876.     char    *psz;
  877.     USHORT  cchWritten;
  878.  
  879.  
  880.  
  881.     /* Now display the new line on the screen */
  882.     if (spyopt.fWindow) {
  883.         item = SHORT1FROMMR(WinSendMsg(hwndSpyList, LM_INSERTITEM,
  884.             (MPARAM)LIT_END, (MPARAM)(PSZ)szOut));
  885.  
  886.         WinSendMsg(hwndSpyList, LM_SETTOPINDEX, (MPARAM)item, 0L);
  887.  
  888.         /* See if we have too many lines now */
  889.         while (item >= spyopt.cWindowLines)
  890.             item = SHORT1FROMMR(WinSendMsg(hwndSpyList, LM_DELETEITEM,
  891.                     (MPARAM)0, 0L));
  892.     }
  893.  
  894.     /* now for file need cr/lf */
  895.     psz = szOut + cch;    /* point to trailing null */
  896.     *psz++ = '\r';
  897.     *psz++ = '\n';
  898.     *psz = '\0';
  899.  
  900.     if (spyopt.fFile)
  901.         DosWrite(spyopt.hfileSpy, (PSZ)szOut, cch+2,
  902.                 (PUSHORT)&cchWritten);
  903.  
  904. }
  905.  
  906.  
  907. /***************************************************************************\
  908. * MSGI  * PmsgiFromMsg(USHORT msg)
  909. *
  910. * Locate the msg in the array of message items
  911. *
  912. * Returns: pointer to item that has the specified msg, or NULL
  913. \***************************************************************************/
  914. MSGI *PmsgiFromMsg(msg)
  915. USHORT msg;
  916. {
  917.     register MSGI   *pmsgi = rgmsgi;    /* Start at beginning */
  918.     register SHORT i;
  919.  
  920.     /*
  921.      * Currently is a simple linear search, should be made faster
  922.      * probably by using binary search.
  923.      */
  924.     for (i=0; i< cmsgi; i++) {
  925.         if (pmsgi->msg == msg)
  926.             return (pmsgi);
  927.         if (pmsgi->msg > msg)
  928.             return (NULL);
  929.         pmsgi++;
  930.     };
  931.  
  932.     return (NULL);
  933. }
  934.