home *** CD-ROM | disk | FTP | other *** search
/ Software Collection (I) / TOOLS.iso / b11 / 1.img / SOURCE.ZIP / WISPY.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-09  |  23.2 KB  |  793 lines

  1. /*
  2.     WISPY.C -- Windows Interrupt Spy
  3.  
  4.     Copyright (c) Andrew Schulman & Dave Maxey, 1992 
  5.     
  6.     Contact:  Andrew Schulman (CompuServe 76320,302)
  7.     
  8.     From Chapter 4 of "Undocumented Windows" (Addison-Wesley 1992)
  9.     by Andrew Schulman, Dave Maxey and Matt Pietrek
  10.  
  11.     Build using: WINIOBC WISPY (for Borland C++ v3.00)
  12.                  WINIOMS WISPY (for Microsoft C/SDK)
  13.     Note: Ensure that WISPY.DEF is present
  14.  
  15.  
  16. syntax:  wispy [0x]intno [[0x]intno] ...
  17.  
  18. examples: to trap protected-mode INT 21h calls:
  19.     wispy 0x21
  20.         
  21. to trap DPMI calls:
  22.     wispy 0x31
  23.         
  24. to trap INT 2fh calls:
  25.     wispy 0x2f
  26.         
  27. to trap INT 2fh and DPMI calls:
  28.     wispy 0x2f 0x31
  29.         
  30. wispy 0x31 and wispy 0x2f show Windows use of undocumented DPMI calls
  31.  
  32. the undoc 0x31 calls are in old versions of DPMI spec
  33.  
  34. the undoc 0x2f calls are briefly mentioned in DDK int2fapi.inc
  35. */
  36.  
  37. #include "windows.h"
  38. #include <stdlib.h>
  39. #include <dos.h>
  40. #include <string.h>
  41. #include "wmhandlr.h"
  42. #include "winio.h"
  43.  
  44. #pragma pack(1)
  45.  
  46. typedef struct {
  47. #ifdef __BORLANDC__
  48.     unsigned bp,di,si,ds,es,dx,cx,bx,ax;
  49. #else
  50.     unsigned es,ds,di,si,bp,sp,bx,dx,cx,ax;     /* same as PUSHA */
  51. #endif
  52.     unsigned ip,cs,flags;
  53.     } REG_PARAMS;
  54.     
  55. #define BUF_SIZE    512
  56. #define MAX_REQU    (BUF_SIZE-1)
  57.  
  58. #define SET_NEXT()  { if (next==MAX_REQU) next=0; else next++; }
  59.  
  60. typedef struct {
  61.     int type;
  62.     REG_PARAMS r;
  63.     char taskname[9];
  64.     char dsdx[40];
  65.     int iInt;
  66.     } REQUEST, FAR * LPREQUEST;
  67.  
  68. #define REQU_FREE       'f'     /* request block not in use */
  69. #define REQU_USE        'u'     /* in use */
  70.  
  71. #define BEGIN_CRIT_SEC()        _asm cli
  72. #define END_CRIT_SEC()          _asm sti
  73.  
  74. #define IS_REQUEST(buf) \
  75.     (buf[next].type != REQU_FREE)
  76.         
  77. #define BUFFER_FULL(buf) \
  78.     IS_REQUEST(buf)
  79.     
  80. #ifndef MK_FP       
  81. #define MK_FP(a,b)  ((void far *)(((unsigned long)(a) << 16) | (b)))
  82. #endif
  83.  
  84. WORD lsl(WORD sel)
  85.     {
  86.     _asm sub ax, ax
  87.     _asm lsl ax, word ptr sel
  88.     }
  89.  
  90. static REQUEST far *requ;
  91.  
  92. int WRT_REQUEST(REQUEST far *buf, REG_PARAMS far *pr,
  93.     HANDLE task, int iInt)
  94.     {
  95.     WORD l;
  96.     static int next = 0;
  97.     char far *ptask = MK_FP(task, 0);
  98.     
  99.     if (BUFFER_FULL(buf))
  100.         return 0;
  101.     BEGIN_CRIT_SEC();
  102.     _fmemcpy(&buf[next].taskname, &ptask[0xf2], 8);
  103.     buf[next].taskname[8] = '\0';
  104.     _fmemcpy(&buf[next].r, pr, sizeof(REG_PARAMS));
  105.     buf[next].type = REQU_USE;
  106.     buf[next].iInt = iInt;
  107.     // oops!  nice idea, but might cause fault!!!
  108.     _fmemset(&buf[next].dsdx, 0, 40);
  109.     if (((l = lsl(pr->ds)) != 0) && (l > pr->dx))
  110.         {
  111.         l -= pr->dx;
  112.         _fmemcpy(&buf[next].dsdx, MK_FP(pr->ds, pr->dx), l > 39 ? 39 : l);
  113.         }
  114.     //buf[next].task = task;
  115.     SET_NEXT();
  116.     END_CRIT_SEC();
  117.     PostMessage(__hMainWnd, WM_NULL, 0, 0);
  118.     return 1;
  119.     }
  120.  
  121. // int RD_REQUEST(REQUEST far *buf, REG_PARAMS *pr, HANDLE *ptask)
  122. int RD_REQUEST(REQUEST far *buf, REG_PARAMS *pr, LPSTR ptaskname, int *piInt, LPSTR lpdsdx)
  123.     {
  124.     static int next = 0;
  125.     if (! IS_REQUEST(buf))
  126.         return 0;
  127.     BEGIN_CRIT_SEC();
  128.     _fmemcpy(pr, &buf[next].r, sizeof(REG_PARAMS));
  129.     _fmemcpy(ptaskname, &buf[next].taskname, 9);
  130.     _fmemcpy(lpdsdx, &buf[next].dsdx, 40);
  131.     //*ptask = buf[next].task;
  132.     *piInt = buf[next].iInt;
  133.     buf[next].type = REQU_FREE;
  134.     END_CRIT_SEC();
  135.     SET_NEXT();
  136.     return 1;
  137.     }
  138.  
  139. REQUEST far *INIT_REQUBUF(void)
  140.     {
  141.     LPREQUEST buf, p;
  142.     int i;
  143.     if (! (buf =
  144.         (LPREQUEST) GlobalLock(GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, 
  145.         BUF_SIZE * sizeof(REQUEST)))))
  146.         return 0;
  147.     for (i=BUF_SIZE, p=buf; i--; p++)
  148.         p->type = REQU_FREE;
  149.     return buf;
  150.     }
  151.     
  152. FARPROC (FAR PASCAL *GetSetKernelDosProc)(FARPROC DosProc) = 0;
  153.  
  154. typedef void (_interrupt _far *INTRFUNC)(); 
  155.  
  156.  
  157. INTRFUNC _dos_getvect(int intno)
  158.     {
  159.     _asm push es;
  160.     _asm mov ah, 35h;
  161.     _asm mov al, byte ptr [intno];
  162.     _asm int 21h;
  163.     _asm mov dx, es;
  164.     _asm mov ax, bx;
  165.     _asm pop es;
  166.     }
  167.  
  168.  
  169. void _dos_setvect(int intno, INTRFUNC ifunc)
  170.     {
  171.     _asm push ds;
  172.     _asm mov ah, 25h;
  173.     _asm mov al, byte ptr [intno];
  174.     _asm lds dx, [ifunc];
  175.     _asm int 21h;
  176.     _asm pop ds;
  177.     }
  178.  
  179.  
  180. INTRFUNC get_vect(unsigned intno)
  181. {
  182.     if ((intno == 0x21) && GetSetKernelDosProc)
  183.     {
  184.         FARPROC dos = GetSetKernelDosProc(0);
  185.         GetSetKernelDosProc(dos);
  186.         return (INTRFUNC) dos;
  187.     }
  188.     else
  189.     {
  190.         return _dos_getvect(intno);
  191.     }
  192. }
  193.  
  194. int set_vect(unsigned intno, INTRFUNC handler)
  195. {
  196.     if ((intno == 0x21) && GetSetKernelDosProc)
  197.     {
  198.         printf("Using GetSetKernelDosProc\n");
  199.         GetSetKernelDosProc((FARPROC) handler);
  200.         return TRUE;
  201.     }
  202.     else
  203.     {
  204.         _dos_setvect(intno, handler);
  205.         return (get_vect(intno) == handler);
  206.     }
  207. }
  208.  
  209. void _interrupt _far IntHandler(REG_PARAMS r);
  210. FARPROC lpfn_dos;
  211.  
  212. #define MAX_INTS    16
  213.  
  214. static unsigned long calls = 0;
  215. static unsigned long lost = 0;
  216. static unsigned long missed = 0;
  217.  
  218. static HMENU hmenuIntrs = 0;
  219. static HANDLE wispy_task;
  220. static int intno[MAX_INTS] = {0};    // INT 21h default 
  221. static INTRFUNC old[MAX_INTS] = {0};
  222. static BOOL enabled[MAX_INTS] = {FALSE};
  223. static int tmpInt;              // transient to hold iInt from thunk
  224. static int no_idle = 0; 
  225. static unsigned long num_idle = 0;
  226.  
  227. void on_close(HWND hwnd)
  228.     {
  229.     int i;
  230.  
  231. //  DestroyMenu(hmenuIntrs);
  232.     
  233.     winio_warn(FALSE, "WISPY",
  234.         "%lu interrupts were intercepted\n"
  235.         "(of which %lu were dropped"
  236.         " through buffer overruns)\n\n"
  237.         "%lu occurred while "
  238.         "intercepts were disabled", 
  239.         calls, lost, missed);
  240.     
  241.     if (no_idle)
  242.         winio_warn(FALSE, "WISPY",
  243.         "%lu calls to W386_WIN_KERNEL_IDLE (2F/1689)\n"
  244.         "were received", num_idle);
  245.     
  246.     for (i = 0; i < MAX_INTS; i++)
  247.         if (intno[i] && (! set_vect(intno[i], old[i])))
  248.             winio_warn(FALSE, "WISPY",
  249.                 "Couldn't restore Int %02Xh", intno[i]);
  250.     }
  251.  
  252. void set_intr(HWND hwnd, WORD wID)
  253.     {
  254.     enabled[wID - 1] ^= TRUE;
  255.     CheckMenuItem(hmenuIntrs, wID,
  256.         enabled[wID - 1] ? MF_CHECKED : MF_UNCHECKED);
  257.     }
  258.  
  259. unsigned verr(unsigned short sel)
  260.     {
  261.     _asm mov ax, 1
  262.     _asm verr word ptr sel
  263.     _asm je short okay
  264.     _asm dec ax
  265.     okay:;  
  266.     }
  267.  
  268. void display_int(REG_PARAMS *pr)
  269.     {
  270.     printf("AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x SI=%04x DI=%04x "
  271.            "CS:IP=%04x:%04xh\n",
  272.         pr->ax, pr->bx, pr->cx, pr->dx, 
  273.         pr->ds, pr->si, pr->di, pr->cs, pr->ip);
  274.     }
  275.  
  276. void display_dos_int(REG_PARAMS *pr, char *dsdx)
  277.     {
  278.     int ah = pr->ax >> 8;
  279.     printf("(%02x) ", ah);
  280.     switch (ah)     // ICantBelieveIUsedASwitchStatement
  281.         {
  282.         case 0x0e: // set disk
  283.             printf("SET DISK %02xh\n", pr->dx & 0xFF);
  284.             break;
  285.         case 0x19: // get current disk
  286.             puts("GET DISK");
  287.             break;
  288.         case 0x1A:  // set DTA
  289.             printf("SET DTA %Fp\n", MK_FP(pr->ds, pr->dx));
  290.             break;
  291.         case 0x25: // set vect
  292.             printf("SET VECT %02xh %04x:%04x\n", 
  293.                 pr->ax & 0xFF, pr->ds, pr->dx);
  294.             break;
  295.         case 0x2A:  // get date
  296.             puts("GET DATE");
  297.             break;
  298.         case 0x2C:  // get time
  299.             puts("GET TIME");
  300.             break;
  301.         case 0x2F:  // get DTA
  302.             puts("GET DTA");
  303.             break;
  304.         case 0x30: // get vers
  305.             puts("GET DOS VERS");
  306.             break;
  307.         case 0x35: // get vect
  308.             printf("GET VECT %02xh\n", pr->ax & 0xFF);
  309.             break;
  310.         case 0x3B: // set curr dir
  311.             printf("CHDIR %s\n", dsdx);
  312.             break;
  313.         case 0x3d: // open
  314.             printf("OPEN %s\n", dsdx);
  315.             break;
  316.         case 0x3e:  // close
  317.             printf("CLOSE %u\n", pr->bx);
  318.             break;
  319.         case 0x3f:  // read
  320.             printf("READ %u cb=%u %Fp\n",
  321.                 pr->bx, pr->cx, MK_FP(pr->ds, pr->dx));
  322.             break;
  323.         case 0x40:  // write
  324.             printf("WRITE %u cb=%u %Fp\n",
  325.                 pr->bx, pr->cx, MK_FP(pr->ds, pr->dx));
  326.             break;
  327.         case 0x41:  // delete
  328.             printf("DELETE %s\n", dsdx);
  329.             break;
  330.         case 0x42:  // seek
  331.             printf("LSEEK%d %u %04x%04x\n", 
  332.                 pr->ax & 0xFF, pr->bx, pr->cx, pr->dx);
  333.             break;
  334.         case 0x44: // IOCTL
  335.             if ((pr->ax & 0xFF) == 0x00)    // get dev info
  336.                 printf("IOCTL GET DEV INFO %04xh\n", pr->bx);
  337.             else
  338.             {
  339.                 printf("IOCTL "); 
  340.                 display_int(pr);
  341.             }
  342.             break;
  343.         case 0x4b: // exec
  344.             printf("EXEC %s\n", dsdx);
  345.             break;
  346.         case 0x47: // get curr dir
  347.             puts("GET CURR DIR");
  348.             break;
  349.         case 0x4c: // exit
  350.             printf("EXIT %02xh\n", pr->ax & 0xff);
  351.             break;
  352.         case 0x4e: // find first
  353.             printf("FIND FIRST %s\n", dsdx);
  354.             break;
  355.         case 0x4f: // find next
  356.             puts("FIND NEXT");
  357.             break;
  358.         case 0x50:
  359.             printf("SET PSP %04x\n", pr->bx);
  360.             break;
  361.         case 0x51:
  362.             puts("GET PSP");
  363.             break;
  364.         case 0x52:
  365.             puts("(UNDOC) GET LIST OF LISTS (SYSVARS)");
  366.             break;
  367.         case 0x55: // undoc: create PSP
  368.             printf("(UNDOC) MK PSP %04xh size=%04xh\n", pr->dx, pr->si);
  369.             break;
  370.         case 0x59:  // get extended error
  371.             puts("GET EXTENDED ERROR INFO");
  372.             break;
  373.         default:
  374.             display_int(pr);
  375.         }
  376.     }
  377.  
  378. void display_dpmi_int(REG_PARAMS *pr, char *dsdx)
  379.     {
  380.     unsigned bl = pr->bx & 0xFF;
  381.     printf("(%04x) ", pr->ax);
  382.     switch (pr->ax)     // ICantBelieveIUsedASwitchStatement
  383.         {
  384.         case 0x0000: // alloc LDT descriptors
  385.             printf("ALLOC LDT DESC n=%u\n", pr->cx);
  386.             break;
  387.         case 0x0001: // free LDT descriptor
  388.             printf("FREE LDT DESC %04xh\n", pr->bx);
  389.             break;
  390.         case 0x0002: // seg to desc
  391.             printf("SEG TO DESC %04xh\n", pr->bx);
  392.             break;
  393.         case 0x0003: // get next sel incr
  394.             puts("GET NEXT SEL INCR");
  395.             break;
  396.         case 0x0004: // reserved: Lock Selector Memory
  397.             printf("(RESERVED) LOCK SEL %04xh\n", pr->bx);
  398.             break;
  399.         case 0x0005: // reserved
  400.             printf("(RESERVED) UNLOCK SEL %04xh\n", pr->bx);
  401.             break;
  402.         case 0x0009: // set descriptor access rights
  403.             printf("SET DESC ACCRGTS %04xh %04xh\n", pr->bx, pr->cx);
  404.             break;
  405.         case 0x0200: // get rmode intvec
  406.             printf("GET RMODE VEC %02xh\n", bl);
  407.             break;
  408.         case 0x0201: // set rmode intvec
  409.             printf("SET RMODE VEC %02xh %04x:%04xh\n", bl, pr->cx, pr->dx);
  410.             break;
  411.         case 0x0202: // get except vec
  412.             printf("GET EXCEPT VEC %02xh\n", bl);
  413.             break;
  414.         case 0x0203: // set except vec
  415.             printf("SET EXCEPT VEC %02xh %04x:%04xh\n", bl, pr->cx, pr->dx);
  416.             break;
  417.         case 0x0204: // get pmode intvect
  418.             printf("GET PMODE VEC %02xh\n", bl);
  419.             break;
  420.         case 0x0205: // set pmode intvect
  421.             printf("SET PMODE VEC %02xh %04x:%04xh\n", bl, pr->cx, pr->dx);
  422.             break;
  423.         case 0x0300: // simulate rmode intr
  424.             printf("CALL RMODE INTR %02xh\n", bl);
  425.             break;
  426.         case 0x0301: // call rmode proc with far ret frame
  427.             printf("CALL RMODE PROC %04x:%04xh\n", pr->es, pr->di);
  428.             break;
  429.         case 0x0302: // call rmode proc with iret frame
  430.             printf("CALL RMODE PROC (IRET) %04x:%04xh\n", pr->es, pr->di);
  431.             break;
  432.         case 0x0500: // get free memory information
  433.             puts("GET FREE MEM INFO");
  434.             break;
  435.         case 0x0501: // allocate memory block
  436.             printf("ALLOC MEM nbytes=%x%04xh\n", pr->bx, pr->cx);
  437.             break;
  438.         case 0x0502: // free memory block
  439.             printf("FREE MEM %04x%04xh\n", pr->si, pr->di);
  440.             break;
  441.         case 0x0600: // lock linear region
  442.             printf("LOCK LINEAR @%04x%04x nbytes=%x%04xh\n",
  443.                 pr->bx, pr->cx, pr->si, pr->di);
  444.         case 0x0700: // reserved: Mark Paging Candidates
  445.             printf("(RESERVED) MARK PAGING CANDIDATES @%04x%04xh "
  446.                 "npages=%x%04xh\n",
  447.                 pr->bx, pr->cx, pr->si, pr->di);
  448.         case 0x0701: // reserved: Discard Pages
  449.             printf("(RESERVED) DISCARD PAGES @%04x%04xh "
  450.                 "npages=%x%04xh\n",
  451.                 pr->bx, pr->cx, pr->si, pr->di);
  452.             break;
  453.         case 0x0703: // discard page contents
  454.             printf("DISCARD PAGES @%04x%04x nbytes=%x%04xh\n",
  455.                 pr->bx, pr->cx, pr->si, pr->di);
  456.             break;
  457.         case 0xA000:
  458.             printf("GET VENDOR-SPECIFIC DPMI API \"%s\"\n", dsdx);
  459.             break;
  460.         default:
  461.             display_int(pr);
  462.         }
  463.     }
  464.     
  465. void display_2f_int(REG_PARAMS *pr, char *dsdx)
  466.     {
  467.     unsigned ah = pr->ax >> 8;
  468.     unsigned al = pr->ax & 0xFF;
  469.     
  470.     if (no_idle && (pr->ax == 0x1689))
  471.     {
  472.         num_idle++;
  473.         return;
  474.     }
  475.     
  476.     printf("(%04x) ", pr->ax);
  477.     switch (ah)     // ICantBelieveIUsedASwitchStatement
  478.         {
  479.         case 0x16:  // see DDK include/int2fapi.inc
  480.             switch (al)
  481.                 {
  482.                 case 0x00:
  483.                     puts("W386_GETVERSION");
  484.                     break;
  485.                 case 0x02:
  486.                     puts("W386_OLD_GET_VMID_API");
  487.                     break;
  488.                 case 0x05:
  489.                     puts("W386_STARTUP");
  490.                     break;
  491.                 case 0x06:
  492.                     puts("W386_EXIT");
  493.                     break;
  494.                 case 0x07:
  495.                     puts("W386_DEVICE_BROADCAST");
  496.                     break;
  497.                 case 0x08:
  498.                     puts("W386_STARTUP_COMPLETE");
  499.                     break;
  500.                 case 0x09:
  501.                     puts("W386_BEGIN_EXIT");
  502.                     break;
  503.                 case 0x0A:
  504.                     puts("W386_WINDOWS_ID");
  505.                     break;
  506.                 case 0x0B:
  507.                     puts("W386_TSR_IDENTIFY");
  508.                     break;
  509.                 case 0x0C:
  510.                     puts("W386_ROM_DETECT (ROM WINDOWS)");
  511.                     break;
  512.                 case 0x80:
  513.                     puts("W386_RELEASE_TIME");
  514.                     break;
  515.                 case 0x81:
  516.                     puts("W386_BEGIN_CRITICAL");
  517.                     break;
  518.                 case 0x82:
  519.                     puts("W386_END_CRITICAL");
  520.                     break;
  521.                 case 0x83:
  522.                     puts("W386_GET_CUR_VMID");
  523.                     break;
  524.                 case 0x84:
  525.                     printf("W386_GET_DEVICE_API dev=0x%04x\n", pr->bx);
  526.                     break;
  527.                 case 0x85:
  528.                     puts("W386_SWITCH_AND_CALL");
  529.                     break;
  530.                 case 0x86:
  531.                     puts("W386_TEST_INT31_AVAIL (DPMI)");
  532.                     break;
  533.                 case 0x87:
  534.                     puts("W386_GET_PM_SWITCH_ADDR (DPMI)");
  535.                     break;
  536.                 case 0x88:
  537.                     puts("W386_GET_LDT_BASE_SEL");
  538.                     /* KRNL386.ASM: 
  539.                         mov ax, 1688h
  540.                         mov bx, 0BADh (!)
  541.                         int 2Fh
  542.                         or ax, ax
  543.                         jnz ...
  544.                         mov LDT, bx
  545.                     */
  546.                     break;
  547.                 case 0x89:
  548.                     // can turn off with -noidle
  549.                     puts("W386_WIN_KERNEL_IDLE");
  550.                     break;
  551.                 case 0x8A:
  552.                     printf("W386_DPMI_EXTENSION \"%s\"\n", dsdx);
  553.                     break;
  554.                 default:
  555.                     display_int(pr);
  556.                 }
  557.             break;
  558.         case 0x40:  // cf. DDK, pp. 2-16 - 2-18 (also OS/2 DOS box??)
  559.             switch (al)
  560.                 {
  561.                 case 0x00:
  562.                     puts("ENABLE VM-ASSISTED SAVE/RESTORE");
  563.                     break;
  564.                 case 0x01:
  565.                     puts("NOTIFY BACKGROUND SWITCH");
  566.                     break;
  567.                 case 0x02:
  568.                     puts("NOTIFY FOREGROUND SWITCH");
  569.                     break;
  570.                 case 0x03:
  571.                     puts("ENTER CRITICAL SECTION");
  572.                     break;
  573.                 case 0x04:
  574.                     puts("EXIT CRITICAL SECTION");
  575.                     break;
  576.                 case 0x05:
  577.                     puts("SAVE VIDEO REGISTER STATE");
  578.                     break;
  579.                 case 0x06:
  580.                     puts("RESTORE VIDEO REGISTER STATE");
  581.                     break;
  582.                 case 0x07:
  583.                     puts("DISABLE VM-ASSISTED SAVE/RESTORE");
  584.                     break;
  585.                 default:
  586.                     display_int(pr);
  587.                 }
  588.             break;
  589.         case 0x46:
  590.             // Standard mode winoa286.mod calls
  591.             // 0x4680, 0x4601, 0x4602, 0x4604, 0x4603
  592.             display_int(pr);
  593.         default:
  594.             display_int(pr);
  595.         }
  596.     }
  597.         
  598. void display_ints(void)
  599.     {
  600.     REG_PARAMS r;
  601.     //HANDLE task;
  602.     static char modname[16];
  603.     static char dsdx[40];
  604.     static int iInt;
  605.     
  606.     // This loop looks for, extracts, and displays messages queued
  607.     // up by the interrupt handler function. The only way we know to 
  608.     // terminate the function is because the window closes...
  609.     while (winio_openwindows()) 
  610.         { 
  611.         wmhandler_yield(); 
  612.         while (RD_REQUEST(requ, &r, (LPSTR) &modname, &iInt, (LPSTR) &dsdx))
  613.             {
  614.             printf("<%s> Int %02Xh ", modname, intno[iInt]);
  615.             if (intno[iInt] == 0x21)          // DOS
  616.                 display_dos_int(&r, dsdx);
  617.             else if (intno[iInt] == 0x31)     // DPMI
  618.                 display_dpmi_int(&r, dsdx);
  619.             else if (intno[iInt] == 0x2f)       // INT 2Fh
  620.                 display_2f_int(&r, dsdx);       
  621.             else                        // other
  622.                 display_int(&r);        
  623.             }
  624.         }
  625.     }
  626.  
  627. int axtoi(char *s)
  628.     {
  629.     int ret;
  630.     if (s[0]=='0' && s[1]=='x')
  631.         {
  632.         sscanf(s+2, "%x", &ret);
  633.         return ret;
  634.         }
  635.     else
  636.         return atoi(s);
  637.     }
  638.  
  639.  
  640. FARPROC MakeIntrInstance(FARPROC fp, HANDLE h, int iInt, WORD addr)
  641.     {
  642.     BYTE *pthunk;
  643.     static BYTE thunk[] = {
  644.             0x1e,                       // push ds 
  645.             0x50,                       // push ax
  646.             0xb8, 0, 0,                 // mov ax, h
  647.             0x8e, 0xd8,                 // mov ds, ax
  648.             0x58,                       // pop ax
  649.             0xc7, 0x06, 0, 0, 0, 0,     // mov word ptr [addr], iInt
  650.             0x1f,                       // pop ds
  651.             0xea, 0, 0, 0, 0            // jmp far fp
  652.             }; 
  653. #define OFS_H       0x03
  654. #define OFS_ADDR    0x0A
  655. #define OFS_IINT    0x0C
  656. #define OFS_FP      0x10
  657.  
  658.     static WORD hCS = 0; 
  659.     
  660.     if ((! hCS) && (! (hCS = AllocDStoCSAlias(h))))
  661.         return NULL;
  662.  
  663.     if (! (pthunk = malloc(sizeof(thunk))))
  664.         return NULL; 
  665.     
  666.     h &= 0xfffc; 
  667.     h |= 1; 
  668.     *((HANDLE *) &thunk[OFS_H]) = h;
  669.     *((WORD *) &thunk[OFS_ADDR]) = addr; 
  670.     *((int *) &thunk[OFS_IINT]) = iInt; 
  671.     *((FARPROC *) &thunk[OFS_FP]) = fp; 
  672.     
  673.     memcpy(pthunk, &thunk, sizeof(thunk));
  674.     return (FARPROC) MK_FP(hCS, (WORD) pthunk); 
  675.     }
  676.  
  677.  
  678. main(int argc, char *argv[])
  679.     {
  680.     int i;
  681.     char buf[128];
  682.     char num[8];
  683.     
  684.     if (argc < 2)
  685.     {
  686.         winio_close(__hMainWnd);
  687.         fail("To watch interrupts, include them\n"
  688.              "on the command line.\n"
  689.              "Example:  WISPY 0x21 0x2f 0x31");
  690.     }
  691.     
  692.     if (__hPrevInst)
  693.         {
  694.         winio_close(__hMainWnd);
  695.         fail("Only one instance of WISPY\n"
  696.             "can be run at a time. To watch\n"
  697.             "multiple interrupts, include\n"
  698.             "them all on the command line.\n"
  699.             "Example:  WISPY 0x21 0x2f 0x31");
  700.         }
  701.  
  702.     winio_setbufsize(__hMainWnd, (WORD) 32768, TRUE);
  703.     
  704.     strcpy(buf, "WISPY");
  705.  
  706.     if (! (requ = INIT_REQUBUF()))
  707.         fail("INIT_REQUBUF fail...!");
  708.  
  709.     winio_about("WISPY"
  710.         "\nWindows Interrupt Spy"
  711.         "\n\nCopyright (c) Andrew Schulman and Dave Maxey"
  712.         "\n\nFrom Chapter 4 of"
  713.         "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
  714.         "\nby Andrew Schulman, David Maxey and Matt Pietrek"
  715.         );
  716.         
  717.     hmenuIntrs = CreateMenu();
  718.     InsertMenu(winio_hmenumain(__hMainWnd), 1, MF_POPUP | MF_BYPOSITION,
  719.         hmenuIntrs, "&Interrupts");
  720.     
  721.     winio_onclose(__hMainWnd, (DESTROY_FUNC) on_close);
  722.  
  723.     wispy_task = GetCurrentTask();
  724.     
  725.     GetSetKernelDosProc = GetProcAddress(
  726.         GetModuleHandle("KERNEL"), "GETSETKERNELDOSPROC");
  727.  
  728.     for (i = 0; (i < (argc - 1)) && (i < MAX_INTS); i++)
  729.         {
  730.         if ((strcmp(argv[i+1], "-noidle") == 0) ||
  731.             (strcmp(argv[i+1], "-NOIDLE") == 0))
  732.             {
  733.                 no_idle = 1;
  734.                 continue;
  735.             }
  736.         if (! (intno[i] = axtoi(argv[i + 1])))
  737.             {
  738.             winio_warn(FALSE, "WISPY",
  739.                 "'%s' is not a valid interrupt number", argv[i+1]);
  740.             continue;
  741.             }
  742.         if (! (lpfn_dos = MakeIntrInstance((FARPROC) IntHandler,
  743.             __hInst, i, (WORD) &tmpInt)))
  744.             fail("Could not MakeIntrInstance..!");
  745.  
  746.         old[i] = get_vect(intno[i]);
  747.         if (! set_vect(intno[i], (INTRFUNC) lpfn_dos))
  748.             {
  749.             printf("SetVect on Int %02xh failed!\n", intno[i]);
  750.             intno[i] = 0;
  751.             continue;
  752.             }
  753.         enabled[i] = TRUE;
  754.  
  755.         sprintf(num, " %02xh", intno[i]);
  756.         strcat(buf, num);
  757.  
  758.         AppendMenu(hmenuIntrs, MF_STRING | MF_CHECKED | MF_ENABLED,
  759.             (WORD) i + 1, (LPSTR) num);
  760.         winio_setmenufunc(__hMainWnd, (WORD) i + 1, (MENU_FUNC) set_intr);
  761.         }
  762.  
  763.     winio_settitle(__hMainWnd, buf);
  764.     
  765.     DrawMenuBar(__hMainWnd);
  766.  
  767.     display_ints();
  768.     
  769.     return 0;
  770.     }
  771.  
  772. void _interrupt _far IntHandler(REG_PARAMS r)
  773.     {
  774.     HANDLE task = GetCurrentTask();
  775.         
  776.     if (task != wispy_task)     /* don't show my own ints */
  777.         if (enabled[tmpInt])
  778.             {
  779.             /* tmpInt has been set by the MakeIntrInstance thunk */
  780.             if (! WRT_REQUEST(requ, &r, task, tmpInt))
  781.                 lost++;     /* buffer overflow */
  782.             calls++;
  783.             }
  784.         else
  785.             missed++;
  786.         
  787.     _chain_intr(old[tmpInt]);
  788.     
  789.     // need some way to get return regs!
  790.     }
  791.     
  792.  
  793.