home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 3 Comm
/
03-Comm.zip
/
fax067.zip
/
dll.doc
< prev
next >
Wrap
Text File
|
1997-04-14
|
11KB
|
315 lines
First preliminary description of calling convention for
ANSW.DLL
FREC.DLL
FSEND.DLL
1) OVERVIEW
All three DLLs are in behavior identical to their EXE counterparts.
While EXE is called with commandline parameters (or switches respectively
options), DLL assumes a call to its internal (exported) entry function. This
entryfunction (DllHandler) has two arguments and returns one value:
APIRET APIENTRY DllHandler(TXPARAM *txp,void *dummy);
The argument 'dummy' MUST BE NULL (a null pointer) otherwise, DllHandler
assumes an other calling convention as described here!
The pointer 'txp' points to a structure of pointers to some optional and
mandatory values or functions:
typedef struct {
BOOL (* APIENTRY Deb_Bin)(UCHAR *,int,int);
void (* APIENTRY Status)(CHAR *,USHORT);
void (* APIENTRY Update)(void *,int);
void **Extra;
char *Cmd;
} TXPARAM, *PTXPARAM;
Status and Cmd are mandatory values, if not supplied (null), DllHandler quits
and returns (APIRET) 255.
Deb_Bin, Update and Extra are optional values and if not supplied, internal
replacements will be used.
2) DESCRIPTION of arguments of DllHandler
void APIENTRY Status(CHAR *line,USHORT sign);
'line' is a zero limited string, its length can be maximal 2048 characters, but
normally it is not more than 128 characters (as much as needed).
'sign' is an ordinal number from 0 to 9 and has the following meaning:
0 ... Received
1 ... Send
2 ... Wait
5 ... Info
6 ... Action
8 ... Error
9 ... Debug (only supplied if 'Debug' is set in applications CFG)
There are some RESTRICTIONS for this function!
It is recommended, to do not write directly to screen or to file system. It
it recommended, to use an extra thread for all displaying and storing of
Status. Communication between Status() and thread should be done via
message queue.
Status flagged by 8 is normally not timecritical. If Status writes directly
to screen, a redirection to a disk file should be avoided!
Please keep also in mind, that ANY thread of the DLL can call Status!
char *Cmd;
This is in fact the commandline, which would be supplied to the EXE.
This commandline MUST have valid entry for a configuration file
(e.g. -cFREC.CFG) and the HANDLE of an already opened COM port (e.g. -p6).
It is also recommended, to supply a task number (e.g. -task1) to synchronize
calling application with called DLL.
The supplied pointer MUST point to free space (max. 128 character) which will
be filled by called DLL when finishing. Caller MUST save the value of the
supplied pointer, because it may be replaced by NULL to signal certain
condition!
BOOL APIENTRY Deb_Bin(UCHAR *content,int count,int sign);
This function is optional, and if not supplied (NULL), DLL will create its own
Debug_Thread and write to it.
If calling application supplies this function, than it MUST handle calls to
it via message queue to a dedicated thread, which is running under priority
IDLETIME !!!
'content' is a 'string' of bytes (0 - 255) of length 'count'. It MAY NOT be
assumed that only printable characters are in this 'string'!
'sign' has identical meaning as above, with the exception that also 9 is
passed in each case!
Please keep in mind, that this function can deliver a huge amount of data
(nearly ALL activities of DLL are 'logged' here).
void APIENTRY Update(void *value,int meaning);
This function may be only supplied if caller knows internals of DLL. AT this
time, there exists no real 'standard', how this function acts (but it is
called from DLL more often than Status).
The author is willing to accept a transparent handling of this function, but
keep in mind, that 'handling' of this function needs also a dedicated thread,
to which message queue (or WinPostMsg) is reporting.
The primary indention of this function is, to supply any kind of 'windows' of
calling application with more or less meaningful information like:
time of transmission, byte count and length of receiving/sending files, some
additional status information about session and much more.
It is recommended to supply NULL.
void **Extra;
This is a 'backdoor' for future expansions. Only one feature is implemented
at this time;
void *MyExtra[2];
char keyboardstatus;
MyExtra[0] = (void *) &keyboardstatus;
MyExtra[1] = NULL;
Extra = MyExtra;
In fact, the DLL is supplied with a pointer to an array of (void) pointers,
where the first one is a pointer to a character, which can transmit
keyboardentries (or 0) to the called DLL. The DLL reacts for:
0 .... no reaction
27 ... ESC, the string 'ERROR' is supplied to internal routines, as if it
comes from modem, also a global variable 'break_request' is set to TRUE
30 ... the string 'RING' is supplied to internal routines, as if it comes
from modem. Can be used to manually initiate a call.
DLL itself uses this pointer to that character! If 27 or 30 is read, DLL sets
the character to 0. Also (if value of character is 0) DLL may set it to any
value to signalize internal.
DLL internal does absolutely NO CHECK to users keyboard or mouse activities.
Therefore DLL can be used for textmode AND PM application!
In case of unusable (internal) function Deb_Bin, message is redirected to
'stderr' which should in any case be redirected (by '2>error.log') to a file
to avoid damage of screen layout. Normally, 'stderr' is not used, but the only
way for IMGPROC.DLL (which is called from FREC.DLL and FSEND.DLL) to
report errors.
3) DESCRIPTION of return of DllHandler
DllHandler simply returns the same value, as EXE will do by ErrorLevel.
But there is one additional feature, the EXE never can do:
The supplied pointer txp->Cmd is treated in dependence of what has happened.
If termination of DLL was incorrect or any error has occurred, txp->Cmd is
set to NULL. Caller should cancel all further actions on this call.
If termination of DLL was in a state, where caller should continue, txp->Cmd
is set to "" (empty string). Caller must continue, is if DLL never was called.
If DLL has done all its jobs and a special entry in CFG (MessageOk or PageOk)
was found, the arguments of it are copied to txp->Cmd. As a result of the next
described option, it is only meaningful to use a numerical value (e.g. for an
errorlevel exit) here.
If DLL has detected a situation, where it had to do some job of caller, the
last response of modem is supplied as a copy in txp->Cmd. Caller must act, as
if this response was received by itself.
4) EXAMPLE of implementing call to DllHandler
Assuming, we have a main 'listening' function, which has detected a certain
modem response, on which it has decided, to call DllHandler.
Where 'modul' is the module name of the DLL (ANSW or FREC or FSEND) and 'cmd'
some elsewhere supplied commandline parameters ...
HFILE hTTY; // the REAL handle for COM
USHORT TaskNumber;
APIRET FeatureDLL(UCHAR *cmd, UCHAR *modul)
{
APIRET ret,rc;
CHAR LoadError[100],cmdline[256];
HMODULE ModuleHandle;
ULONG ProcType;
TXPARAM txp;
void *Extra[2];
APIRET (* APIENTRY DllHandler)(TXPARAM *,VOID *);
// clear it
memset(&txp,0,sizeof(txp));
#ifdef MAXCOMM
hTTY = ComGetFH(hcModem);
ComPause(hcModem);
#endif
// add porthandle to commandline
sprintf(cmdline,"%s -p%u",cmd,hTTY);
// if other than zero, add task#
if (TaskNumber)
sprintf(&cmdline[strlen(cmdline)]," -task%hu",TaskNumber);
txp.Status = status; // supply our function
txp.Cmd = cmdline; // supply this local buffer
ret = (APIRET) -1;
rc = DosLoadModule(LoadError,sizeof(LoadError),module,&ModuleHandle);
if (rc == 0)
{
rc = DosQueryProcType(ModuleHandle,1L,NULL,&ProcType);
if (rc == 0 && ProcType == PT_32BIT)
{
rc = DosQueryProcAddr(ModuleHandle,1L,NULL,
(PFN *) &DllHandler);
if (rc == 0)
{
ret = DllHandler(&txp,NULL);
}
}
DosFreeModule(ModuleHandle);
}
#ifdef MAXCOMM
ComResume(hcModem);
#endif
If (txp.Cmd) strcpy(cmd,txp.Cmd);
else ret = (APIRET) -1; // in this case, ignore cmd
return(ret);
}
5) CONCEPTIONAL Hints
The usefulness of a FeatureDLL is enormous. Not only (as described here)
fax receive and transmission and answering machine are possible applications.
A FREECALL.DLL is already created by third party, and CALLERID.DLL is also
an imaginable purpose.
If well implemented to front-end's modem listening routine, DllHandler can be
called at incoming calls and at outgoing calls. Multiple calls to different
modules are possible:
Modem response RING calls ANSW.DLL to distinguish between fax/dat/voice calls.
If voice call, ANSW.DLL do all the necessary job and returns with
txp->Cmd = NULL to signalize, all over and out.
If fax calling tone is detected by ANSW, it can call FREC.DLL by itself or
simply return with txp->Cmd = "", which signals to front-end to 'collect'
further more modem responses. If front-end detects FAX or +FCO or +FCON it
calls FREC.DLL which do all the fax job and even if a remote fax wants to poll
FREC calls by itself FSEND.DLL to satisfy poll.
FREC returns normally with txp->Cmd = "" or txp->Cmd = "<number>".
ANSW also can return with txp->Cmd = "<number>" to signalize, front-end should
act (e.g. by errorlevel exit) appropriate.
There is a special situation, if using modems from USR in conjunction with
fax class 1 (which must be selected if modem should work as a fax receiver AND
pollserver):
If front-end detects RING, it calls FREC (or even ANSW) with '-sWAIT_FCON'.
FREC (or even ANSW) will issue the necessary
'AT+FCLASS=1<cr>AT+FAA=1<cr>AT+FCR=1<cr>ATA<cr>' to force adaptive autoanswer
for class 1.
If a fax call arrives, FAX is detected and FREC will do its job and set
txp->Cmd = NULL. If a datacall arrives, modem sends DATA to FREC, which
'knows' (by 'USRobotics' in CFG) that it should send 'ATO<cr>' to modem.
From this point on, two conditions are possible:
Negotiation of data call is so fast, that FREC will receive the
'CONNECT 28800/ARQ' response (txp->Cmd = "CONNECT 28800/ARQ"), or if not,
FREC will terminate and signalize wait for response (txp->Cmd = "").
There is no known front-end (mailer) which can do it, but it is worth to
think about:
Front-end (mailer) dials a certain number and gets the response FAX or +FCO or
+FCON (has in fact called a fax machine). Very simple to act on this:
Call FSEND.DLL and send. If called station has also a fax 'on hold', FSEND will
recognize it and call FREC.DLL by itself.
Other situation (modem must be clever enough to detect VOICE):
Front-end (mailer) has called a human and should send a voice message, by
calling ANSW.DLL. If 'human' is clever and switches his modem on-line, ANSW
detects 'CONNECT XXXXX/Any' and simply returns with
txp->Cmd = "CONNECT XXXX/Any" to signal front-end about the successful data
connection .....
Same mechanism could be used, to implement FREEPOLL also for a caller (for
called front-end there still exists a FREEPOLL.DLL).
Detection and solution of CallerID are also possible, and all the ISDN goodies.
Simply construct a FeatureDLL for the purpose you want ...
Harald Pollack
Fido: 2:310/14.59
I-Net: Harald.Pollack@omv.co.at
Bernhard Seidl
Fido: 2:310/14.5