home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol11n16.zip / DYNLINK.C < prev    next >
C/C++ Source or Header  |  1992-08-14  |  9KB  |  351 lines

  1. /* 
  2. DYNLINK.C -- run-time dynamic linking functions for CLIPSERV
  3.  
  4. Copyright (c) 1992 Ziff Davis Communications
  5. PC Magazine * Andrew Schulman (June 1992)
  6. */
  7.  
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <malloc.h>
  11. #include "windows.h"
  12. #include "toolhelp.h"
  13. #include "objwnd.h"
  14. #include "clipserv.h"
  15.  
  16. static BOOL in_dynlink = 0; 
  17.  
  18. /* 1k buffer to bang on; used via @buf */
  19. static char the_buffer[1024] = {0} ;
  20.  
  21. typedef enum { typ_string, typ_byte, typ_word, typ_long, typ_float,
  22.     typ_buffer, typ_hwnd } TYPE;
  23.  
  24. /* push(): a trick that relies on pascal calling convention */
  25. void pascal push() { }
  26.  
  27. // push args on stack, count # of words
  28. #define PUSH_ARG(arg)   \
  29. {   \
  30.     switch (type(arg))  \
  31.     {   \
  32.         case typ_buffer:    push((char far *) the_buffer); c += 2; break; \
  33.         case typ_hwnd:      push(hwnd);                   c += 1; break; \
  34.         case typ_string:    push((char far *) arg);       c += 2; break;  \
  35.         case typ_byte:      push(arg[1]);                 c += 1; break;  \
  36.         case typ_word:      push((unsigned) axtol(arg));  c += 1; break;  \
  37.         case typ_long:      push(axtol(arg));             c += 2; break;  \
  38.         case typ_float:     push(atof(arg));              c += 4; break;  \
  39.     }   \
  40. }
  41.  
  42. /*
  43.     type() uses some dumb rules to determine the type of an argument:
  44.         if first character of arg is a digit or '-'
  45.             and if arg contains '.' then it's a floating-point number
  46.             else if last character is an 'L' then it's a long
  47.             else it's a unsigned word
  48.         else if first character is an apostrophe
  49.             it's a single-byte character
  50.         otherwise
  51.             it's a string
  52.             if the first char
  53. */          
  54. TYPE type(char *arg)
  55. {
  56.     if (isdigit(arg[0]) || (arg[0] == '-' && isdigit(arg[1])))
  57.     {
  58.         char *p = arg;
  59.         while (*p)
  60.             if (*p++ == '.') 
  61.                 return typ_float;
  62.         return (*--p == 'L') ? typ_long : typ_word;
  63.     }
  64.     else if (strcmp(arg, "@buf") == 0)
  65.         return typ_buffer;  // push far ptr to 1k buffer
  66.     else if (strcmp(arg, "@hwnd") == 0)
  67.         return typ_hwnd;    // push caller's HWND
  68.     else
  69.         return (arg[0] == '\'') ? typ_byte : typ_string;
  70. }
  71.  
  72. /*
  73.     retval_type() uses a printf() mask (e.g., %s or %lX) to determine
  74.     type of return value
  75. */
  76. TYPE retval_type(char *s)
  77. {
  78.     while (*s)
  79.     {
  80.         switch (*s)
  81.         {
  82.             case 's' :  return typ_string; break;
  83.             case 'c' :  return typ_byte; break;
  84.             case 'p' : case 'l' : case 'I' : case 'O' : case 'U' :
  85.                         return typ_long; break;
  86.             case 'e' : case 'E' : case 'f' : case 'g' : case 'G' :
  87.                         return typ_float; break;
  88.         }
  89.         s++;
  90.     }
  91.  
  92.     /* still here */
  93.     return typ_word;
  94. }
  95.  
  96. int split(char *s, char *arr[], int max, char *splitchars)
  97. {
  98.     char *tok;
  99.     char *eos;
  100.     int argc = 1;       // argv[0] unused
  101.     int in_quotes = 0;
  102.     
  103.     if (! s)
  104.         goto done;
  105.     eos = s + strlen(s);
  106.     while (tok = strtok(s, splitchars))
  107.         {
  108.         s = 0;
  109.         if (! in_quotes)
  110.             {
  111.             if (*tok == '\"')
  112.                 {
  113.                 in_quotes = 1;
  114.                 tok++;
  115.                 if ((s = tok + strlen(tok)) != eos)
  116.                     *s = ' ';
  117.                 }
  118.             arr[argc++] = tok;
  119.             if (argc == max)
  120.                 break;
  121.             }
  122.         if (in_quotes)
  123.             if (s = strchr(tok, '\"'))
  124.                 {
  125.                 *s++ = 0;
  126.                 in_quotes = 0;
  127.                 }
  128.             else
  129.                 if ((s = tok + strlen(tok)) != eos)
  130.                     *s++ = ' ';
  131.         }
  132. done:   
  133.     return argc;
  134. }
  135.  
  136. typedef unsigned (far *FN)();
  137. typedef char far * (far *STRFN)();
  138. typedef char (far *BYTEFN)();
  139. typedef unsigned (far *WORDFN)();
  140. typedef unsigned long (far *LONGFN)();
  141. typedef double (far pascal *FLOATFN)();
  142.  
  143. unsigned loadmod(char far *modname)
  144. {
  145.     unsigned handle = LoadLibrary(modname);
  146.     return handle? handle : LoadLibrary(strupr(modname));
  147. }
  148.  
  149. void far *procaddr(unsigned modhand, char far *funcname)
  150. {
  151.     void far *fn = GetProcAddress(modhand, funcname);
  152.     return fn? fn : GetProcAddress(modhand, strupr(funcname));
  153. }
  154.  
  155. unsigned modhandle(char far *modname)
  156. {
  157.     unsigned handle;
  158.     if ((handle = GetModuleHandle(modname)) != 0)
  159.         return handle;
  160.     else
  161.         return loadmod(modname);
  162. }
  163.  
  164. /* Convert a string to a long number:  accepts decimal, hex,
  165.    or seg:ofs far pointer */
  166. unsigned long axtol(char *s)
  167. {
  168.     unsigned long ret;
  169.     if (s[0]=='0' && s[1]=='x')
  170.     {
  171.         sscanf(s+2, "%lx", &ret);
  172.         return ret;
  173.     }
  174.     else if (strchr(s, ':'))
  175.     {
  176.         sscanf(s, "%Fp", &ret);
  177.         return ret;
  178.     }
  179.     else
  180.         return atol(s);
  181. }
  182.  
  183. BOOL dynlink(HWND hwnd, int argc, char *argv[])
  184. {
  185.     static char buf[128];
  186.     FN f;
  187.     TYPE retval_typ = typ_word;
  188.     char *modname;
  189.     char far *funcname;
  190.     char *mask = "0x%04x";
  191.     unsigned module;
  192.     WORD save_es;
  193.     BOOL is_cdecl = FALSE;
  194.     int start_arg = 2;
  195.     int i, c;
  196.     
  197.     if (argc < 2)
  198.     {
  199.         put_clip_str("CLIPREPLY DYNLINK ERROR ARGS");
  200.         return FALSE;       // wrong usage
  201.     }
  202.     
  203.     /* see if cdecl */
  204.     if (argv[argc-1][0] == '!')
  205.     {
  206.         is_cdecl = TRUE;
  207.         argc--;
  208.     }
  209.  
  210.     /* handle optional printf mask */
  211.     if (strchr(argv[argc-1], '%'))
  212.         retval_typ = retval_type(mask = argv[--argc]);
  213.  
  214.     /* see if explicitly specifying module name with mod!func */
  215.     if (strchr(argv[1], '!'))
  216.     {
  217.         modname = strtok(argv[1], "!");
  218.         funcname = (char far *) (modname + strlen(modname) + 1);
  219.     }
  220.     else
  221.     {
  222.         modname = (char *) 0;
  223.         funcname = (char far *) argv[1];
  224.     }
  225.     
  226.     /* func can be ASCIIZ string or ordinal number or s:o func ptr */
  227.     if (strchr(funcname, ':'))
  228.     {
  229.         f = axtol(funcname);    // passed in seg:ofs func ptr
  230.         goto got_func;
  231.     }
  232.     else if (isdigit(funcname[0]))
  233.         funcname = (char far *) atol(funcname); // ordinal number
  234.     
  235.     /* get function pointer */
  236.     if (modname)
  237.     {
  238.         // the module name was explicitly supplied
  239.         if ((module = modhandle(modname)) == 0)
  240.         {
  241.             put_clip_str("CLIPREPLY DYNLINK ERROR MOD");
  242.             return FALSE;   // can't load DLL
  243.         }
  244.         
  245.         f = (FN) procaddr(module, funcname);
  246.     }
  247.     else
  248.     {
  249.         // automatically try the three main Windows DLLs
  250.         static HANDLE hUser = 0;
  251.         static HANDLE hKernel = 0;
  252.         static HANDLE hGDI = 0;
  253.         if (! hUser)    // one-time initialization
  254.         {
  255.             hUser = GetModuleHandle("USER");
  256.             hKernel = GetModuleHandle("KERNEL");
  257.             hGDI = GetModuleHandle("GDI");
  258.         }
  259.         if (! (f = (FN) procaddr(hUser, funcname)))
  260.             if (! (f = (FN) procaddr(hKernel, funcname)))
  261.                 f = (FN) procaddr(hGDI, funcname);
  262.     }
  263.     
  264.     if (! f)
  265.     {
  266.         put_clip_str("CLIPREPLY DYNLINK ERROR FUNC");
  267.         return FALSE;   // can't find function
  268.     }
  269.         
  270. got_func:       
  271.     in_dynlink++;
  272.     
  273.     if (is_cdecl)
  274.     {
  275.         /* push in reverse order for cdecl */
  276.         for (i=argc-1, c=0; i>=start_arg; i--)
  277.             PUSH_ARG(argv[i]);
  278.     }
  279.     else
  280.     {
  281.         for (i=start_arg, c=0; i<argc; i++)
  282.             PUSH_ARG(argv[i]);
  283.     }
  284.     
  285.     save_es = _ES;
  286.     
  287.     /* args are on the stack : call (*f)() and print retval */
  288.     switch (retval_typ)
  289.     {
  290.         case typ_string: wsprintf(buf, mask, ((STRFN) f)()); break;
  291.         case typ_byte:   wsprintf(buf, mask, ((BYTEFN) f)()); break;
  292.         case typ_word:   wsprintf(buf, mask, f()); break;
  293.         case typ_long:   wsprintf(buf, mask, ((LONGFN) f)()); break;
  294.         case typ_float:  wsprintf(buf, mask, ((FLOATFN) f)()); break;
  295.     }
  296.     
  297.     in_dynlink--;
  298.     
  299.     _ES = save_es;
  300.     
  301.     /* if cdecl, have to restore stack based on value of c ? */
  302.     
  303.     put_clip_str(buf);
  304.     return TRUE;
  305. }
  306.  
  307. static FARPROC procinst_faulthandler;
  308. static CATCHBUF catchbuf = {0} ;
  309. static HANDLE clipserv_task = 0;
  310.  
  311. BOOL dynlink_error(void)
  312. {
  313.     if (Catch(catchbuf) == 0)
  314.         return FALSE;
  315.     else
  316.     {
  317.         put_clip_str("CLIPREPLY DYNLINK ERROR GPFAULT");
  318.         return TRUE;
  319.     }
  320. }
  321.  
  322. void _export far FaultHandler(void)
  323. {
  324.     static unsigned intnum;
  325.     
  326.     _asm mov ax, word ptr [bp+8]
  327.     _asm mov intnum, ax
  328.         
  329.     if ((in_dynlink) && (intnum == 13) && (GetCurrentTask() == clipserv_task))
  330.         Throw(catchbuf, 1);
  331.     else
  332.         return;
  333. }
  334.  
  335. void init_dynlink(HANDLE hInstance)
  336. {
  337.     /* use TOOLHELP to install GP fault handler for DYNLINK */
  338.     clipserv_task = GetCurrentTask();
  339.     procinst_faulthandler = 
  340.         MakeProcInstance((FARPROC) FaultHandler, hInstance);
  341.     if (! InterruptRegister(0, procinst_faulthandler))
  342.         fail("Can't register GP fault handler!");
  343. }
  344.  
  345. void fini_dynlink(void)
  346. {
  347.     FreeProcInstance(procinst_faulthandler);
  348.     InterruptUnRegister(0);
  349. }
  350.  
  351.