home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
pcmag
/
vol11n16.zip
/
DYNLINK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-14
|
9KB
|
351 lines
/*
DYNLINK.C -- run-time dynamic linking functions for CLIPSERV
Copyright (c) 1992 Ziff Davis Communications
PC Magazine * Andrew Schulman (June 1992)
*/
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "windows.h"
#include "toolhelp.h"
#include "objwnd.h"
#include "clipserv.h"
static BOOL in_dynlink = 0;
/* 1k buffer to bang on; used via @buf */
static char the_buffer[1024] = {0} ;
typedef enum { typ_string, typ_byte, typ_word, typ_long, typ_float,
typ_buffer, typ_hwnd } TYPE;
/* push(): a trick that relies on pascal calling convention */
void pascal push() { }
// push args on stack, count # of words
#define PUSH_ARG(arg) \
{ \
switch (type(arg)) \
{ \
case typ_buffer: push((char far *) the_buffer); c += 2; break; \
case typ_hwnd: push(hwnd); c += 1; break; \
case typ_string: push((char far *) arg); c += 2; break; \
case typ_byte: push(arg[1]); c += 1; break; \
case typ_word: push((unsigned) axtol(arg)); c += 1; break; \
case typ_long: push(axtol(arg)); c += 2; break; \
case typ_float: push(atof(arg)); c += 4; break; \
} \
}
/*
type() uses some dumb rules to determine the type of an argument:
if first character of arg is a digit or '-'
and if arg contains '.' then it's a floating-point number
else if last character is an 'L' then it's a long
else it's a unsigned word
else if first character is an apostrophe
it's a single-byte character
otherwise
it's a string
if the first char
*/
TYPE type(char *arg)
{
if (isdigit(arg[0]) || (arg[0] == '-' && isdigit(arg[1])))
{
char *p = arg;
while (*p)
if (*p++ == '.')
return typ_float;
return (*--p == 'L') ? typ_long : typ_word;
}
else if (strcmp(arg, "@buf") == 0)
return typ_buffer; // push far ptr to 1k buffer
else if (strcmp(arg, "@hwnd") == 0)
return typ_hwnd; // push caller's HWND
else
return (arg[0] == '\'') ? typ_byte : typ_string;
}
/*
retval_type() uses a printf() mask (e.g., %s or %lX) to determine
type of return value
*/
TYPE retval_type(char *s)
{
while (*s)
{
switch (*s)
{
case 's' : return typ_string; break;
case 'c' : return typ_byte; break;
case 'p' : case 'l' : case 'I' : case 'O' : case 'U' :
return typ_long; break;
case 'e' : case 'E' : case 'f' : case 'g' : case 'G' :
return typ_float; break;
}
s++;
}
/* still here */
return typ_word;
}
int split(char *s, char *arr[], int max, char *splitchars)
{
char *tok;
char *eos;
int argc = 1; // argv[0] unused
int in_quotes = 0;
if (! s)
goto done;
eos = s + strlen(s);
while (tok = strtok(s, splitchars))
{
s = 0;
if (! in_quotes)
{
if (*tok == '\"')
{
in_quotes = 1;
tok++;
if ((s = tok + strlen(tok)) != eos)
*s = ' ';
}
arr[argc++] = tok;
if (argc == max)
break;
}
if (in_quotes)
if (s = strchr(tok, '\"'))
{
*s++ = 0;
in_quotes = 0;
}
else
if ((s = tok + strlen(tok)) != eos)
*s++ = ' ';
}
done:
return argc;
}
typedef unsigned (far *FN)();
typedef char far * (far *STRFN)();
typedef char (far *BYTEFN)();
typedef unsigned (far *WORDFN)();
typedef unsigned long (far *LONGFN)();
typedef double (far pascal *FLOATFN)();
unsigned loadmod(char far *modname)
{
unsigned handle = LoadLibrary(modname);
return handle? handle : LoadLibrary(strupr(modname));
}
void far *procaddr(unsigned modhand, char far *funcname)
{
void far *fn = GetProcAddress(modhand, funcname);
return fn? fn : GetProcAddress(modhand, strupr(funcname));
}
unsigned modhandle(char far *modname)
{
unsigned handle;
if ((handle = GetModuleHandle(modname)) != 0)
return handle;
else
return loadmod(modname);
}
/* Convert a string to a long number: accepts decimal, hex,
or seg:ofs far pointer */
unsigned long axtol(char *s)
{
unsigned long ret;
if (s[0]=='0' && s[1]=='x')
{
sscanf(s+2, "%lx", &ret);
return ret;
}
else if (strchr(s, ':'))
{
sscanf(s, "%Fp", &ret);
return ret;
}
else
return atol(s);
}
BOOL dynlink(HWND hwnd, int argc, char *argv[])
{
static char buf[128];
FN f;
TYPE retval_typ = typ_word;
char *modname;
char far *funcname;
char *mask = "0x%04x";
unsigned module;
WORD save_es;
BOOL is_cdecl = FALSE;
int start_arg = 2;
int i, c;
if (argc < 2)
{
put_clip_str("CLIPREPLY DYNLINK ERROR ARGS");
return FALSE; // wrong usage
}
/* see if cdecl */
if (argv[argc-1][0] == '!')
{
is_cdecl = TRUE;
argc--;
}
/* handle optional printf mask */
if (strchr(argv[argc-1], '%'))
retval_typ = retval_type(mask = argv[--argc]);
/* see if explicitly specifying module name with mod!func */
if (strchr(argv[1], '!'))
{
modname = strtok(argv[1], "!");
funcname = (char far *) (modname + strlen(modname) + 1);
}
else
{
modname = (char *) 0;
funcname = (char far *) argv[1];
}
/* func can be ASCIIZ string or ordinal number or s:o func ptr */
if (strchr(funcname, ':'))
{
f = axtol(funcname); // passed in seg:ofs func ptr
goto got_func;
}
else if (isdigit(funcname[0]))
funcname = (char far *) atol(funcname); // ordinal number
/* get function pointer */
if (modname)
{
// the module name was explicitly supplied
if ((module = modhandle(modname)) == 0)
{
put_clip_str("CLIPREPLY DYNLINK ERROR MOD");
return FALSE; // can't load DLL
}
f = (FN) procaddr(module, funcname);
}
else
{
// automatically try the three main Windows DLLs
static HANDLE hUser = 0;
static HANDLE hKernel = 0;
static HANDLE hGDI = 0;
if (! hUser) // one-time initialization
{
hUser = GetModuleHandle("USER");
hKernel = GetModuleHandle("KERNEL");
hGDI = GetModuleHandle("GDI");
}
if (! (f = (FN) procaddr(hUser, funcname)))
if (! (f = (FN) procaddr(hKernel, funcname)))
f = (FN) procaddr(hGDI, funcname);
}
if (! f)
{
put_clip_str("CLIPREPLY DYNLINK ERROR FUNC");
return FALSE; // can't find function
}
got_func:
in_dynlink++;
if (is_cdecl)
{
/* push in reverse order for cdecl */
for (i=argc-1, c=0; i>=start_arg; i--)
PUSH_ARG(argv[i]);
}
else
{
for (i=start_arg, c=0; i<argc; i++)
PUSH_ARG(argv[i]);
}
save_es = _ES;
/* args are on the stack : call (*f)() and print retval */
switch (retval_typ)
{
case typ_string: wsprintf(buf, mask, ((STRFN) f)()); break;
case typ_byte: wsprintf(buf, mask, ((BYTEFN) f)()); break;
case typ_word: wsprintf(buf, mask, f()); break;
case typ_long: wsprintf(buf, mask, ((LONGFN) f)()); break;
case typ_float: wsprintf(buf, mask, ((FLOATFN) f)()); break;
}
in_dynlink--;
_ES = save_es;
/* if cdecl, have to restore stack based on value of c ? */
put_clip_str(buf);
return TRUE;
}
static FARPROC procinst_faulthandler;
static CATCHBUF catchbuf = {0} ;
static HANDLE clipserv_task = 0;
BOOL dynlink_error(void)
{
if (Catch(catchbuf) == 0)
return FALSE;
else
{
put_clip_str("CLIPREPLY DYNLINK ERROR GPFAULT");
return TRUE;
}
}
void _export far FaultHandler(void)
{
static unsigned intnum;
_asm mov ax, word ptr [bp+8]
_asm mov intnum, ax
if ((in_dynlink) && (intnum == 13) && (GetCurrentTask() == clipserv_task))
Throw(catchbuf, 1);
else
return;
}
void init_dynlink(HANDLE hInstance)
{
/* use TOOLHELP to install GP fault handler for DYNLINK */
clipserv_task = GetCurrentTask();
procinst_faulthandler =
MakeProcInstance((FARPROC) FaultHandler, hInstance);
if (! InterruptRegister(0, procinst_faulthandler))
fail("Can't register GP fault handler!");
}
void fini_dynlink(void)
{
FreeProcInstance(procinst_faulthandler);
InterruptUnRegister(0);
}