home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l430 / 1.ddi / SOURCE.ZIP / CALLFUNC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-09  |  15.5 KB  |  586 lines

  1. /*
  2.     CALLFUNC.C -- Windows Dynlink Function-Call Interpreter
  3.  
  4.     Copyright (c) Andrew Schulman & Dave Maxey, 1992. All Rights Reserved.
  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 CALLFUNC HANDLES (for Borland C++ v3.00)
  12.                  WINIOMS CALLFUNC HANDLES (for Microsoft C/SDK)
  13.     Note: Ensure that HANDLES.H and HANDLES.C are present
  14. */
  15.  
  16. #include <windows.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <dos.h>
  21. #include "toolhelp.h"
  22. #include "winio.h"
  23. #include "handles.h"
  24.  
  25. typedef WORD (far *FN)();
  26. typedef LPSTR (far *STRFN)();
  27. typedef BYTE (far *BYTEFN)();
  28. typedef WORD (far *WORDFN)();
  29. typedef DWORD (far *LONGFN)();
  30. typedef double (far pascal *FLOATFN)();
  31.  
  32. #ifdef __BORLANDC__
  33. #define _asm asm
  34. #endif
  35.  
  36. #ifndef FALSE
  37. #define FALSE 0
  38. #define TRUE 1
  39. #endif
  40.  
  41. #define ID_HELP 1
  42.  
  43.  
  44. HANDLE modhandle(LPSTR modname)
  45.     {
  46.     HANDLE handle;
  47.     if ((handle = GetModuleHandle(modname)) != NULL)
  48.         return handle;
  49.     else
  50.         return LoadLibrary(modname);
  51.     }
  52.  
  53. DWORD axtol(char *s)
  54.     {
  55.     DWORD x, xx;
  56.     int radix;
  57.     int c;
  58.     BOOL neg = FALSE;
  59.     
  60.     if (! s)
  61.         return 0;
  62.     
  63.     if (*s == '-')
  64.         {
  65.         neg = TRUE;
  66.         s++;
  67.         }
  68.     
  69.     if (s[0] == '0' && s[1] == 'x')
  70.         {
  71.         radix = 16;
  72.         s += 2;
  73.         }
  74.     else if (strchr(s, ':'))    // seg:ofs
  75.         radix = 16;
  76.     else
  77.         radix = 10;
  78.     
  79.     x = xx = 0;
  80.     while (c = *s++)
  81.         {
  82.         if (c == ':')
  83.             {
  84.             xx = x << 16;
  85.             x = 0;
  86.             }
  87.         else
  88.             x *= radix;
  89.         if (c >= '0' && c <= '9')
  90.             x += (c - '0');
  91.         else if (radix == 16)
  92.             {
  93.             if (c >= 'A' && c <= 'F')
  94.                 x += (10 + (c - 'A'));
  95.             else if (c >= 'a' && c <= 'f')
  96.                 x += (10 + (c - 'a'));
  97.             else if (c != ':')
  98.                 break;
  99.             }   
  100.         else
  101.             break;
  102.         }
  103.     
  104.     return (x | xx) * (neg ? -1L : 1L);
  105.     }
  106.  
  107. typedef enum { typ_string, typ_byte, typ_word, typ_long, typ_float,
  108.     typ_buffer } TYPE;
  109.  
  110. TYPE type(char *arg);
  111. TYPE retval_type(char *s);
  112.  
  113. /* push(): a trick that relies on pascal calling convention */
  114. void pascal push() { }
  115.  
  116. // push args on stack, count # of words
  117. #define PUSH_ARG(arg)   \
  118.     {   \
  119.     switch (type(arg))  \
  120.         {   \
  121.         case typ_string:    push((LPSTR) arg);              c += 2; break;  \
  122.         case typ_byte:      push(arg[1]);                   c += 1; break;  \
  123.         case typ_word:      push((WORD) axtol(arg));        c += 1; break;  \
  124.         case typ_long:      push(axtol(arg));               c += 2; break;  \
  125.         case typ_float:     push(atof(arg));                c += 4; break;  \
  126.         }   \
  127.     }
  128.  
  129. int split(char *s, char *arr[], int max, char *splitchars)
  130.     {
  131.     char *tok;
  132.     char *eos;
  133.     int argc = 1;       // argv[0] unused
  134.     int inQuotes = 0;
  135.     
  136.     if (! s)
  137.         goto done;
  138.     eos = s + strlen(s);
  139.     while (tok = strtok(s, splitchars))
  140.         {
  141.         s = 0;
  142.         if (! inQuotes)
  143.             {
  144.             if (*tok == '\"')
  145.                 {
  146.                 inQuotes = 1;
  147.                 tok++;
  148.                 if ((s = tok + strlen(tok)) != eos)
  149.                     *s = ' ';
  150.                 }
  151.             arr[argc++] = tok;
  152.             if (argc == max)
  153.                 break;
  154.             }
  155.         if (inQuotes)
  156.             if ((s = strchr(tok, '\"')) != NULL)
  157.                 {
  158.                 *s++ = 0;
  159.                 inQuotes = 0;
  160.                 }
  161.             else
  162.                 if ((s = tok + strlen(tok)) != eos)
  163.                     *s++ = ' ';
  164.         }
  165.     done:   
  166.         return argc;
  167.     }
  168.  
  169.  
  170. #define ARG_MAX 24
  171.  
  172. static CATCHBUF catchbuf = {0} ;
  173. static char *err_msg = 0;
  174. static BOOL in_dynlink = 0; 
  175. static unsigned callfunc_ss = 0;
  176.  
  177. #if 1
  178. #define error(s)    do { err_msg = s; Throw(catchbuf, 1); } while (0)
  179. #else
  180. #define error(s)    do { puts(s); return; } while (0)
  181. #endif
  182.  
  183. #define SAVE_ES()       _asm push es
  184. #define RESTORE_ES()    _asm pop es
  185.  
  186. void dynlink(int argc, char *argv[])
  187.     {
  188.     FN f;
  189.     TYPE retval_typ = typ_word;
  190.     char *mask = "0x%04x";
  191.     HANDLE module;
  192.     WORD save_ax, save_bx, save_cx, save_dx;
  193.     WORD save_si, save_di, save_ds, save_es;
  194.     BOOL is_cdecl = FALSE;
  195.     BOOL is_reg_based = FALSE;
  196.     BOOL show_regs = FALSE;
  197.     int start_arg = 3;
  198.     int i, c;
  199.     
  200.     if (argc < 3)
  201.         error("usage: <dllname> <func name> [args...] [%mask] [!]");
  202.     
  203.     /* see if cdecl */
  204.     if (argv[argc-1][0] == '!')
  205.         {
  206.         is_cdecl = TRUE;
  207.         argc--;
  208.         }
  209.     else if (argv[argc-1][0] == '?')
  210.         {
  211.         show_regs = TRUE;
  212.         argc--;
  213.         }
  214.     else if ((argc > 2) && (strcmp(argv[3], "regs") == 0))
  215.         {
  216.         is_reg_based = TRUE;
  217.         start_arg++;
  218.         }
  219.     
  220.     /* handle optional printf mask */
  221.     if (strchr(argv[argc-1], '%'))
  222.         retval_typ = retval_type(mask = argv[--argc]);
  223.     
  224.     if ((module = modhandle(argv[1])) == 0)
  225.         error("can't load dll");
  226.     
  227.     /* pass ASCIIZ string or ordinal number */
  228.     if (isdigit(argv[2][0]))
  229.         f = (FN) GetProcAddress(module, (LPSTR) atol(argv[2]));  // ord#
  230.         else if (strchr(argv[2], ':'))
  231.             f = (FN) axtol(argv[2]);
  232.     else    
  233.         f = (FN) GetProcAddress(module, argv[2]);
  234.     if (! f)
  235.         error("can't find function");
  236.     
  237.     if (show_regs)
  238.         {
  239.         _asm mov save_ax, ax;
  240.         _asm mov save_bx, bx;
  241.         _asm mov save_cx, cx;
  242.         _asm mov save_dx, dx;
  243.         _asm mov save_si, si;
  244.         _asm mov save_di, di;
  245.         _asm mov save_ds, ds;
  246.         _asm mov save_es, es;
  247.  
  248.         printf("AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x "
  249.                 "DS=%04x ES=%04x\n", save_ax, save_bx, save_cx, save_dx,
  250.                 save_si, save_di, save_ds, save_es);
  251.         }
  252.     else if (is_cdecl)
  253.         {
  254.         /* push in reverse order for cdecl */
  255.         for (i=argc-1, c=0; i>=start_arg; i--)
  256.             PUSH_ARG(argv[i]);
  257.         }
  258.     else
  259.         {
  260.         for (i=start_arg, c=0; i<argc; i++)
  261.             PUSH_ARG(argv[i]);
  262.         }   
  263.     
  264.     if (is_reg_based)
  265.         {
  266.         save_dx = (WORD) axtol(argv[7]);
  267.         save_cx = (WORD) axtol(argv[6]);
  268.         save_bx = (WORD) axtol(argv[5]);
  269.         save_ax = (WORD) axtol(argv[4]);
  270.         _asm mov ax, save_ax;
  271.         _asm mov bx, save_bx;
  272.         _asm mov cx, save_cx;
  273.         _asm mov dx, save_dx;
  274.         }
  275.  
  276.     in_dynlink++;
  277.  
  278.     /* args are on the stack : call (*f)() and print retval */
  279.     switch (retval_typ)
  280.         {
  281.         case typ_string: printf(mask, ((STRFN) f)()); break;
  282.         case typ_byte:   printf(mask, ((BYTEFN) f)()); break;
  283.         case typ_word:   printf(mask, f()); break;
  284.         case typ_long:   printf(mask, ((LONGFN) f)()); break;
  285.         case typ_float:  printf(mask, ((FLOATFN) f)()); break;
  286.         }
  287.  
  288.     in_dynlink--;
  289.  
  290.     if (is_cdecl)
  291.         {
  292.         c <<= 1;
  293.         _asm add sp, word ptr c;
  294.         }
  295.     
  296.     if (show_regs)
  297.         {
  298.         _asm mov save_ax, ax;
  299.         _asm mov save_bx, bx;
  300.         _asm mov save_cx, cx;
  301.         _asm mov save_dx, dx;
  302.         _asm mov save_si, si;
  303.         _asm mov save_di, di;
  304.         _asm mov save_ds, ds;
  305.         _asm mov save_es, es;
  306.  
  307.         printf("AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x "
  308.                 "DS=%04x ES=%04x\n", save_ax, save_bx, save_cx, save_dx,
  309.                 save_si, save_di, save_ds, save_es);
  310.         }
  311.     
  312.     printf("\n");
  313.     }
  314.  
  315. void do_help(HWND hwnd, WORD wID)
  316.     {
  317.     winio_warn(FALSE, "CallFunc HELP",
  318.         "At the > prompt, enter:\n"
  319.         "\tdll-name func-name [REGS] [params] [%mask] [!]\n"
  320.         "\t\tOR\n"
  321.         "\tdll-name ordinal [REGS] [params] [%mask] [!]\n"
  322.         "\t\tOR\n"
  323.         "\tDUMP xxxx:xxxx [bytes]\n"
  324.         "\t\tOR\n"
  325.         "\tSEL xxxx\n"
  326.         "\t\tOR\n"
  327.         "\tINFO or ?\n"
  328.         "\t\tOR\n"
  329.         "\t!exe-name [params]\n"
  330.         "\t\tOR\n"
  331.         "\tEXIT");
  332.     }
  333.  
  334. void info(void)
  335.     {
  336.     extern HANDLE FAR PASCAL GetTaskQueue(HANDLE hTask);
  337.     static WORD hCS;
  338.     HANDLE hTask = GetCurrentTask();
  339.     
  340.     _asm mov word ptr hCS, cs;
  341.  
  342.     printf("hwnd = 0x%04x\n", __hMainWnd);
  343.     printf("task = 0x%04x\n", hTask);
  344.     printf("module = 0x%04x\n", HMODULE_FROM_HTASK(hTask));
  345.     printf("instance (DS) = 0x%04x\n", HINSTANCE_FROM_HTASK(hTask));
  346.     printf("CS = 0x%04x\n", hCS);
  347.     printf("PSP (PDB) = 0x%04x\n", PSP_FROM_HTASK(hTask));
  348.     printf("task q = 0x%04x\n", GetTaskQueue(hTask));
  349.     printf("local heap = 0x%04x\n", *((WORD near *) 6));
  350.     }
  351.     
  352. #define WIDTH       16
  353.  
  354. void dump(LPSTR fp, WORD bytes, char *mask, DWORD addr)
  355.     {
  356.     HWND hwndNew, hwndSav = NULL;
  357.     LPSTR p;
  358.     WORD i, j, c, limit;
  359.     char buf[120];
  360.     
  361.     if (! verr(FP_SEG(fp)))
  362.         {
  363.         printf("%04x not valid for reading\n", FP_SEG(fp));
  364.         return;
  365.         }
  366. //  if (lar(FP_SEG(fp)) & 8)
  367. //      {
  368. //      printf("%04x is a code segment\n", FP_SEG(fp));
  369. //      return;
  370. //      }
  371.     if ((limit = lsl(FP_SEG(fp))) < FP_OFF(fp))
  372.         {
  373.         printf("Start offs %04X is outside selector %04X limit of %04X\n",
  374.             FP_OFF(fp), FP_SEG(fp), limit);
  375.         return;
  376.         }
  377.     if ((limit + 1) < (bytes + FP_OFF(fp)))
  378.         {
  379.         printf("Selector %04X limit is %04X, length of dump adjusted\n",
  380.             FP_SEG(fp), limit);
  381.         bytes = limit - FP_OFF(fp) + 1;
  382.         }
  383.     FP_SEG(fp) &= ~3;
  384.     FP_SEG(fp) |= 1;
  385.     
  386.     if (limit > 63)
  387.         {
  388.         sprintf(buf, "Dump: %Fp for %d bytes", fp, bytes);
  389.         if (! (hwndNew = winio_window(buf, bytes * 5, WW_HASMENU)))
  390.             winio_warn(FALSE, "Dump", "Insufficient resources!");
  391.         hwndSav = winio_setcurrent(hwndNew);
  392.         }
  393.     else
  394.         hwndNew = __hMainWnd;
  395.     
  396.     winio_setpaint(hwndNew, FALSE);
  397.     
  398.     for (i=0; i<bytes; i += WIDTH)
  399.         {
  400.         c = ((bytes-i) > WIDTH) ? WIDTH : bytes-i;
  401.         printf(mask, addr+i);
  402.         putchar(' '); putchar('|'); putchar(' ');
  403.         for (j=c, p=fp+i; j--; p++)
  404.             printf("%02X ", (unsigned char) *p);
  405.         for (j=WIDTH-c; j--; )  // pad out on last line
  406.             printf("   ");
  407.         putchar('|'); putchar(' ');
  408.         for (j=c, p=fp+i; j--; p++)
  409.             putchar( isprint(*p) ? *p : '.' );
  410.         putchar('\n');
  411.         }
  412.     
  413.     winio_setpaint(hwndNew, TRUE);
  414.     if (hwndSav)
  415.         {
  416.         winio_home(hwndNew);
  417.         winio_setcurrent(hwndSav);
  418.         }
  419.     }
  420.  
  421. BOOL builtin(int argc, char *argv[])
  422.     {
  423.     if (argv[1][0] == '?')
  424.         info();
  425.     else if (stricmp(argv[1], "info") == 0)
  426.         info();
  427.     else if (stricmp(argv[1], "cls") == 0)
  428.         winio_clear(__hMainWnd);
  429.     else if (stricmp(argv[1], "dump") == 0)
  430.         {
  431.         static unsigned char far *base = 0;
  432.         static unsigned bytes = 64;
  433.         if (argc < 3)
  434.             {
  435.             if (base) 
  436.                 base += bytes;
  437.             else
  438.                 return 1;
  439.             }
  440.         else
  441.             base = (unsigned char far *) axtol(argv[2]);
  442.         if (argc >= 4)
  443.             bytes = (unsigned) axtol(argv[3]);
  444.         dump(base, bytes, "%Fp", (DWORD) base);
  445.         }
  446.     else if (stricmp(argv[1], "sel") == 0)
  447.         {
  448.         WORD sel = (WORD) axtol(argv[2]);
  449.         BOOL r = verr(sel);
  450.         BOOL w = verw(sel);
  451.         if (r || w)
  452.             printf("sel=0x%04X size=%d %s %s%s%s\n",
  453.             sel, lsl(sel) + 1, lar(sel) & 8 ? "code" : "data",
  454.             r ? "read" : "", r && w ? "/" : "", w ? "write" : "");
  455.         else
  456.             printf("Invalid selector\n");
  457.         }
  458.     else
  459.         return 0;   // no match
  460.     
  461.     return 1;
  462.     }
  463.  
  464. void _export far FaultHandler(void)
  465. {
  466.     static unsigned intnum;
  467.     static unsigned fault_ss;
  468.     
  469.     _asm mov ax, word ptr [bp+8]
  470.     _asm mov intnum, ax
  471.     _asm mov ax, word ptr [bp+14h]
  472.     _asm mov fault_ss, ax
  473.         
  474.     if ((in_dynlink) && (intnum == 13) && (fault_ss == callfunc_ss))
  475.         error("GP fault!");
  476.     else
  477.         return;
  478. }
  479.  
  480. main()
  481.     {
  482.     FARPROC procinst_faulthandler;
  483.     char buf[256];
  484.     char *argv[ARG_MAX];
  485.     int argc;
  486.     
  487.     winio_settitle(__hMainWnd, "CallFunc");
  488.     winio_about(
  489.         "CALLFUNC"
  490.         "\nWindows DynaLink Function Caller"
  491.         "\n\nCopyright (c) Andrew Schulman & Dave Maxey, 1991-1992"
  492.         "\n\nFrom Chapter 4 of"
  493.         "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
  494.         "\nby Andrew Schulman, David Maxey and Matt Pietrek"        
  495.         );
  496.     InsertMenu(winio_hmenuhelp(__hMainWnd),
  497.         0, MF_STRING | MF_ENABLED | MF_BYPOSITION,
  498.         ID_HELP, "&Usage");
  499.     
  500.     DrawMenuBar(__hMainWnd);
  501.     
  502.     winio_setmenufunc(__hMainWnd, ID_HELP, (MENU_FUNC) do_help);
  503.     
  504.     _asm mov callfunc_ss, ss
  505.     procinst_faulthandler = 
  506.         MakeProcInstance((FARPROC) FaultHandler, __hInst);
  507.     if (! InterruptRegister(0, procinst_faulthandler))
  508.         puts("Can't register GP fault handler!");
  509.     
  510.     if (Catch(catchbuf) != 0)
  511.         puts(err_msg);
  512.  
  513.     for (;;)
  514.         {
  515.         putchar('>'); putchar(' ');                 // prompt
  516.         gets(buf);                                  // read
  517.         if (buf[0] == '!')                          // do before split!
  518.             {
  519.             WinExec(&buf[1], SW_SHOWNORMAL);
  520.             continue;
  521.             }
  522.         if (strcmp(buf, "exit") == 0)
  523.             break;
  524.         argc = split(buf, argv, ARG_MAX, " \t");
  525.         if (! builtin(argc, argv))
  526.             dynlink(argc, argv);                // eval-print
  527.         }
  528.  
  529.     FreeProcInstance(procinst_faulthandler);
  530.     puts("done");
  531.     return 0;
  532.     }
  533.  
  534. /*
  535.     type() uses some dumb rules to determine the type of an argument:
  536.         if first character of arg is a digit or '-'
  537.             and if arg contains '.' then it's a floating-point number
  538.             else if last character is an 'L' then it's a long
  539.             else it's a unsigned word
  540.         else if first character is an apostrophe
  541.             it's a single-byte character
  542.         otherwise
  543.             it's a string
  544.             if the first char
  545. */          
  546. TYPE type(char *arg)
  547.     {
  548.     if (isdigit(arg[0]) || (arg[0] == '-' && isdigit(arg[1])))
  549.         {
  550.         char *p = arg;
  551.         while (*p)
  552.             if (*p++ == '.') 
  553.                 return typ_float;
  554.         return (*--p == 'L') ? typ_long : typ_word;
  555.         }
  556.     else if (stricmp(arg, "@buf") == 0)
  557.         return typ_buffer;
  558.     else
  559.         return (arg[0] == '\'') ? typ_byte : typ_string;
  560.     }
  561.  
  562. /*
  563.     retval_type() uses a printf() mask (e.g., %s or %lX) to determine
  564.     type of return value
  565. */
  566. TYPE retval_type(char *s)
  567.     {
  568.     while (*s)
  569.         {
  570.         switch (*s)
  571.             {
  572.             case 's' :  return typ_string; break;
  573.             case 'c' :  return typ_byte; break;
  574.             case 'p' : case 'l' : case 'I' : case 'O' : case 'U' :
  575.                         return typ_long; break;
  576.             case 'e' : case 'E' : case 'f' : case 'g' : case 'G' :
  577.                         return typ_float; break;
  578.             }
  579.         s++;
  580.         }
  581.  
  582.     /* still here */
  583.     return typ_word;
  584.     }
  585.  
  586.