QDLL
----

  QLIB now offers a new way to manage large amounts of code/data.  Now you
can keep fragments of your program in DLLs and call apon them at anytime.
These DLLs can also access the main programs rountines (thru the use
of extensive tables).

To build a DLL simply create a C or ASM file as follows:
  - must have dll_main(dword hnd) which is called after the DLL is loaded
  - link with the /x option to create a DLL instead of an EXE.

Exports:
  QLIB offers two functions inside a DLL to export functions from the DLL to
  the main program stream.  Each export has a 'name' and an 'offset'.

Structures for export tables:
  struct DLL_EXPORT {
    char *obj;   //"name" of resource
    void *off;   //offset of resource
  }
  Usually this should be a table of entries (an array).
  Example:
    struct DLL_EXPORT my_exports[]= { {"func1",&func1} , {"func2",&func2} };

Functions user must provide in DLLs:
  sdword dll_main(dword hnd)
    - must be defined by user in a DLL source file.
    - hnd is a handle to the DLL itself (provided by the DLL loader)
    - return value:
        ERROR (-1) = on error
        anything else = successful

Functions provided for DLLs:
  sbyte dll_export(dword hnd,char *name,void *addr);
    Desc: Exports one function/data element.
    Input:
      hnd - DLL handle that was given to dll_main()
      name - export name (case sensative)
      addr - offset of func/data/etc. to be assigned to 'name'
    Output:
      On error   : ERROR (-1)
        Cause(s) : not enough memory to add to export table
      On success : 0
    Notes:
      - this func does not use the DLL_EXPORT struct
      - Should be called during dll_main() but may be called at anytime
        during DLLs execution.

  sbyte dll_export_table(dword hnd,void *table, dword num_eles);
    Desc: Exports a table of function/data elements.
    Input:
      hnd - DLL handle that was given to dll_main()
      table - pointer to an array of DLL_EXPORT structures.
      num_eles - number of definitions within the table.
    Output:
      On error   : ERROR (-1)
        Cause(s) : not enough memory to add to export table
      On success : 0
    Notes:
      - this func uses an array of the DLL_EXPORT struct
      - Should be called during dll_main() but may be called at anytime
        during DLLs execution.
  
Functions for main program stream:
  sdword dll_load(char *filename)
    Desc: Loads a DLL file (QDL.*)
    Input:
      filename - DLL filename
    Output:
      On error   : ERROR (-1)
        Cause(s) : not enough memory to load DLL
      On success : DLL handle

  sdword dll_unload(sdword hnd)
    Desc: Unloads a DLL file from memory
    Input:
      hnd - a DLL handle returned from dll_load()
    Output:
      On error   : ERROR (-1)
        Cause(s) : Invalid handle
      On success : 0

  void *dll_import(sdword hnd,char *name,dword idx);
    Desc: Returns a pointer of an export
    Input:
      hnd - a DLL handle returned from dll_load()
      name - export name (case sensative)
      idx - index #
    Output:
      On error   : ERROR (-1)
        Cause(s) : 'name' not found in DLL export table
      On success : pointer

  sdword dll_call(sdword hnd,char *name,dword idx,...);
    Desc: Calls a function(pointer) of export 'name'
    Input:
      hnd - a DLL handle returned from dll_load()
      name - export name (case sensative)
      ... - arguments to pass to function
    Output:
      On error   : ERROR (-1)
        Cause(s) : 'name' not found in DLL export table
      On success : 0
    Notes:
      - Because the export table can contain function and data pointers
        you must be sure that you only call functions with dll_call()

  sdword dll_import_idx(sdword hnd,dword idx);
    Desc: Returns a pointer of an export
    Input:
      hnd - a DLL handle returned from dll_load()
      idx - # of export to return, where the 1st export = 0, etc.
    Output:
      On error   : ERROR (-1)
        Cause(s) : idx is beyond export table
      On success : pointer
    Notes:
      - This method of importing exports is faster than dll_import_nam() but
        it more error-prone.  If you use this method, keep a header file
        to define your export #s.

  sdword dll_call_idx(sdword hnd,dword idx,...);
    Desc: Calls a function(pointer) of an export
    Input:
      hnd - a DLL handle returned from dll_load()
      idx - # of export to return, where the 1st export = 0, etc.
      ... - arguments to pass to function
    Output:
      On error   : ERROR (-1)
        Cause(s) : idx is beyond export table
      On success : 0
    Notes:
      - This method of importing exports is faster than dll_import() but
        it more error-prone.  If you use this method, keep a header file
        to define your export #s.
      - Because the export table can contain function and data pointers
        you must be sure that you only call functions with dll_callidx()

  sdword dll_import(sdword hnd,char *name,dword idx);
    Desc: Returns a pointer of an export
    Input:
      hnd - a DLL handle returned from dll_load()
      name - export name (case sensative)
      idx - # of export to return, where the 1st export = 0, etc.
    Output:
      On error   : ERROR (-1)
        Cause(s) : idx is beyond export table
      On success : pointer
    Notes:
      - This method uses both a number and the name.  In order for this
        function to succeed the number must match with the export name
        exported by the DLL.  This can avoid more errors and is faster
        than dll_import().

  sdword dll_call(sdword hnd,char *name,dword idx,...);
    Desc: Calls a function(pointer) of an export
    Input:
      hnd - a DLL handle returned from dll_load()
      idx - # of export to return, where the 1st export = 0, etc.
      ... - arguments to pass to function
    Output:
      On error   : ERROR (-1)
        Cause(s) : idx is beyond export table
      On success : 0
    Notes:
      - This method uses both a number and the name.  In order for this
        function to succeed the number must match with the export name
        exported by the DLL.  This can avoid more errors and is faster
        than dll_import().
      - Because the export table can contain function and data pointers
        you must be sure that you only call functions with dll_call2()

General DLL Notes :
 - *.SET files are not used during QDLLs linking since DLLs do not need to be
   configured in any way.
 - available memory is the only limitation to the number of DLLs you can
   load/use.
 - DLLs can not access global data in your main program stream (unless
   you provide it's address to a function)
 - QLIB defines some tables that allow DLLs to access some code/data in
   the main stream code (only functions/data within QLIB).  The code may
   be used in C or ASM but the data can only be done directly in 'C' langauge.
   These DLL table hold 'pointers' to the real data variables (such as stdin,
   stdout,selcode,etc.)
   and inside DLL.H are macros to use these pointers from within a DLL.
   See \h\dll.h for an example.
   If you use these variables from ASM code remember that they are pointers,
   and not the real data.
   These table have a limited number of resources (functions/data) that will
   allow DLLs to access in the main program stream.  If you attempt to
   link a DLL and get 'unresolved references' then you are attempted to
   use something not found in the DLL tables.
 - See \inc\src\dlltab.inc - for a list of main stream resources that a DLL
   may use.
   If you add/change this table you must increment DLL_VERSION in \inc\dll.inc
   and \h\dll.h and then re-compile \src\dll\c0dll.obj and \src\qlib\dll.asm
   and re-lib the QLIB.LIB file (just run MAKE.BAT in each directory).

EOF
