home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 January / Chip_1997-01_cd.bin / ms95 / disk19 / dir01 / f014050.re_ / f014050.re
Text File  |  1996-04-02  |  49KB  |  1,043 lines

  1. Feature:
  2.  
  3.   Dynamic Link Modules
  4.   
  5. Description:
  6.  
  7.   Dynamic Link Modules - Introduction
  8.   
  9.   Following are definitions of some of the terms and phrases used in the
  10.   description of Dynamic Link Modules:
  11.   
  12.       built-ins - variables and functions that are actually part of
  13.      MicroStation, but are accessible to MDL applications. They are also
  14.      available to Dynamic Link Modules.
  15.      
  16.       Dynamic Link Modules (DLM) - modules that can be loaded and linked
  17.      by MicroStation at runtime. These modules are compiled into native
  18.      machine code. Dynamic Link Modules are created using the host
  19.      operating system's tools such as the compiler and linker. The MDL
  20.      tools are not used to create a Dynamic Link Module.
  21.      
  22.       Dynamic Link Specification (DLS) - used to specify what symbols
  23.      can be resolved from a specific Dynamic Link Module. A Dynamic Link
  24.      Specification source file is compiled using the program "dlmspec"
  25.      (supplied by Bentley Systems) to create a Dynamic Link
  26.      Specification object file. A Dynamic Link Specification object file
  27.      is used when linking an MDL application to tell mlink what symbols
  28.      will be resolved from the Dynamic Link Module.
  29.      
  30.       native code - code created by using standard compilers and
  31.      linkers. The keyword nativeCode in a declaration tells the MDL
  32.      compiler that the function or variable being declared is part of
  33.      MicroStation or a DLM. The function or variable being declared is
  34.      not part of the MDL application but is accessible from the MDL
  35.      application.
  36.      
  37.       pseudo-code instructions - instructions generated by the MDL
  38.      compiler and understood by MicroStation's MDL interpreter.
  39.      
  40.       task ID - the name used for an MDL or MicroCSL application. This
  41.      name appears in MicroStation input queue elements. It also is used
  42.      in MicroStation commands that refer to MDL applications. For
  43.      example, in the command "MDL UNLOAD QDIM", QDIM is the task ID. It
  44.      is also displayed in the MDL Applications dialog box.
  45.      
  46.       resources - in this document, resource does not refer to the kind
  47.      of resources that are managed by the MicroStation Resource Manager.
  48.      It refers to anything a DLM or MicroStation may allocate and
  49.      release for an MDL application. Examples are memory and file
  50.      handles.
  51.      
  52.       user hooks - MDL functions called by native code functions. Both
  53.      MicroStation and DLM's can call MDL user hooks.
  54.      
  55.   Dynamic linking addresses a number of developer concerns. These are:
  56.   
  57.       performance of MDL.
  58.      
  59.       shared libraries for their MDL applications to use. Developers
  60.      often have multiple applications with common code.
  61.      
  62.       access to object-code libraries (with some limitations).
  63.      
  64.       ability to use the MDL builtin functions from native machine code.
  65.      
  66.   The main concerns with Dynamic Link Modules:
  67.   
  68.       printf may be the best debugging tool. The Clipper is the only
  69.      platform with source level debugging for DLM's.  On the PC, the
  70.      PharLap debugger takes the symbols from the DLM.
  71.      
  72.       The features of dynamic linking are not guaranteed to be available
  73.      on all platforms.  In fact, it still is not known if it will be
  74.      available on the Macintosh.
  75.      
  76.       Applications share the stack with MicroStation. On some platforms
  77.      including the PC, the applications are limited by the size of
  78.      MicroStation's stack.  This is not a problem on any of the Unix
  79.      platforms.
  80.      
  81.       DLM's may be restricted to position independent code. When this is
  82.      necessary, it does not seem to create any problems. This is
  83.      achieved through compiler flags.
  84.      
  85.       There might be problems when different Dynamic Link Modules define
  86.      symbols of the same name. On both the HP and Sparc, if 2 DLM's define
  87.      the global data with the same name, then both applications share the
  88.      same data.  DLM's generally should be coded with as few globals as 
  89.      possible, and all of the globals named so that the names are likely
  90.      to be unique across applications.
  91.      
  92.       In general, it is dangerous to have a DLM that needs to be linked with
  93.      any system libraries. When linking with a system library, it is very
  94.      difficult to link in the desired modules from the library without
  95.      bringing in extra modules. For example, the link step may bring in a
  96.      new copy of heap management but may not have any of the heap
  97.      management data structures initialized.
  98.  
  99.      There are 2 known limitiations with the Sparc dynamic linking. First, all 
  100.      data must be initialized because the SunOS utility ld.so does not correctly
  101.      initialize the BSS segment. Second, if a function in a DLM tries to call 
  102.      another function in same DLM but from a different source module, and 
  103.      MicroStation has a function with the same name as the called function, then 
  104.      MicroStation's function is called instead of the one in the same DLM.
  105.  
  106.   When Should a DLM Be Used
  107.  
  108.   A DLM should not be the key component of an application's architecture. If
  109.   the bulk of an application must be in native code, the application should
  110.   use the external program interface.
  111.  
  112.   A DLM is ideal when an MDL application or group of applications need 
  113.   functions that must be compiled in native code either due to performance
  114.   considerations, or because the functions must access some system features
  115.   that are not available through MDL. These functions can be packaged 
  116.   together in a DLM to be used by these applications.
  117.  
  118.   Use of System Libraries
  119.  
  120.   Whenver possible, use MicroStation's built-in functions instead of
  121.   functions from system libraries.  The set of MicroStation's built-in
  122.   functions includes nearly the entire ANSI C library.
  123.  
  124.   Using system libraries can sometimes become quite complicated.  It
  125.   can be very difficult to figure out how to build the DLM.  It increases
  126.   the risks that it will be more difficult to move the application to
  127.   MicroStation upgrades, operating system upgrades, or other operating 
  128.   systems.  It also increases the risk of problems resulting from 
  129.   interaction with other applications.
  130.  
  131.   Examples of functions that must not be resolved from system libraries
  132.   are malloc and fopen. If a DLM brings in its own copy of malloc, then
  133.   the MicroStation process will have 2 copies of malloc.  Each copy of
  134.   malloc will operate as if it has exclusive control of controlling 
  135.   MicroStation's heap.  This generally works for a while, and then 
  136.   eventually leads to heap problems and a crash. This problem occurs
  137.   even if malloc is resolved from the C shared library. When malloc is
  138.   resolved from the C shared library, it also causes the linker to bind in
  139.   the static data structures used in tracking heap management.  Having this
  140.   data structure duplicated leads to the heap management problems.
  141.  
  142.   Typically, it should be safe to use library functions that that do not
  143.   save any state information in global data structures.  fopen and malloc
  144.   are dangerous because they save state information in global data structures.
  145.   fopen saves state information in the iob.  malloc saves state information 
  146.   in the heap management data structures.  kill is okay because is does
  147.   not save state information.  It just sends a signal to another process 
  148.   and returns.
  149.  
  150.   It is okay to use the shared libraries that MicroStation uses.  The 
  151.   XWindows versions of MicroStation use the X shared libraries and the 
  152.   C shared libraries.  The Environ V version of MicroStation uses the 
  153.   libtools2 shared library and the C shared library.  Howver, on the 
  154.   Intergraph workstation, the DLM should not use functions that require 
  155.   global data structures.
  156.  
  157.   On the Intergraph workstation, MicroStation version 4.4 generates an
  158.   error messages and refuses to load a DLM if the DLM redefines malloc,
  159.   calloc, free, fopen, brk, sbrk, or iob.
  160.   
  161.   Dynamic Link Modules - Changes to MDL Source
  162.   
  163.   The MDL compiler generates special instructions for accessing
  164.   functions and variables that are not part of the MDL program.
  165.   Therefore, it is necessary to identify for the compiler the symbols
  166.   that refer to functions and variables that are not in the MDL
  167.   application.  To indicate that these symbols refer to code or data
  168.   implemented in native code rather than MDL, declare them using a
  169.   storage class of nativeCode.  The following declarations tell the MDL
  170.   compiler that "exampleFunc" is a function that was compiled to machine
  171.   code, and that "exampleVar" is a variable defined in a native module.
  172.   
  173.       nativeCode int exampleFunc (int firstParam);
  174.       nativeCode long exampleVar;
  175.   
  176.   When the MDL compiler compiles code that uses a function pointer, it
  177.   must know whether that pointer points to an MDL function or a
  178.   nativeCode function.  By default, function pointers in MDL refer to
  179.   MDL functions.  A typedef or variable can be designated as a pointer
  180.   to a native-code function through use of the pointerToNative pragma.  The
  181.   following lines would be used to create a typedef for pointing to a
  182.   native code function.
  183.   
  184.       typedef int (*FuncP)();
  185.       #pragma pointerToNative funcP
  186.   
  187.   The syntax for the pointerToNative pragma is:
  188.   
  189.       #pragma pointerToNative <object-name> [,] ....
  190.   
  191.   where object-name refers to a variable or typedef name.  The
  192.   pointerToNative pragma accepts a comma-separated list of object-names.
  193.   Each object-name must be a typedef name or variable name. The object
  194.   must have type pointer-to-function.
  195.   
  196.   Dynamic Link Modules - Access to MicroStation's Built-ins
  197.   
  198.   On some platforms, DLM source files must include the file "dloadlib.h"
  199.   to be able to access built-in functions using the same names MDL
  200.   programs use. Dloadlib.h contains define statements that cause the C
  201.   preprocessor to replace references to MDL built-ins with references to
  202.   the internal names for the built-in functions and variables.
  203.   
  204.   Dloadlib.h is platform specific.  On both the Intergraph platform and
  205.   PC's, it does not do anything.  Because of the way dynamic linking is
  206.   implemented on these platforms, it is not necessary to translate any
  207.   of the names.  The versions for the HP and SPARC contain a lot of
  208.   defines because there are a lot names to translate.
  209.   
  210.   If a source file includes dloadlib.h, then it should be possible to
  211.   use that source file unchanged on all platforms both as MDL source and
  212.   as DLM source. All of the differences should be handled by dloadlib.h.
  213.   
  214.   Dynamic Link Modules - Linking an MDL Program with a DLM
  215.   
  216.   The MDL linker "mlink" must know how to resolve the symbols for the
  217.   DLM. It must know what symbols can be resolved at runtime. Since the
  218.   DLM itself cannot be linked with the MDL program, a Dynamic Link
  219.   Specification (DLS) object file is used. The DLS object file specifies
  220.   the name of the dynamic link module, the list of symbols to be
  221.   resolved from the dynamic link module, and the version number of the
  222.   library. All of this information can be linked with the MDL program so
  223.   that MicroStation can use it at runtime to dynamically load and link
  224.   the DLM.
  225.   
  226.   The syntax for Dynamic Link Specification files is described in the
  227.   section "Dynamic Link Modules - Dynamic Link Specification Source
  228.   Files"..
  229.   
  230.   "mlink" treats DLS object files like libraries. It does not make the
  231.   DLS object file part of the program unless the DLS object file
  232.   resolves symbols required by the mdl object files. Since it is treated
  233.   like a library, the DLS object file must appear in the link step after
  234.   any MDL object files that use functions or variables from the
  235.   corresponding DLM.
  236.   
  237.   The Dynamic Link Specification object file must be specified for every
  238.   link step that may resolve symbols from that file. To simplify this,
  239.   mlink now uses the environment variable MLINK_STDLIB.  MLINK_STDLIB
  240.   specifies a list of object files to be included in a link step. This
  241.   list may be up to 400 characters. The entries in the list are blank
  242.   separated. After processing the command line, mlink gets the value of
  243.   MLINK_STDLIB. If the environment variable MLINK_STDLIB is defined,
  244.   mlink interprets it as a list of files. This list is appended to the
  245.   list of input files specified in the command line.
  246.   
  247.   Dynamic Link Modules - Runtime Concerns
  248.   
  249.   MicroStation's DLM's are modeled after standard dynamically linked
  250.   shared libraries. MicroStation does not create a process (does not
  251.   allocate a process descriptor or MDL descriptor) for a DLM. A DLM is
  252.   primarily a set of functions that can be called by MDL programs. A DLM
  253.   is loaded only if it is required by an MDL program. The DLM is
  254.   required by an MDL program if "mlink" resolved references for the
  255.   program from a corresponding Dynamic Link Specification object file.
  256.   
  257.   Generally, a DLM executes only when a function in the DLM is called by
  258.   an MDL program or if MicroStation calls one of the DLM's hook
  259.   functions.
  260.   
  261.   If a DLM is called by an MDL program, then that MDL program is the
  262.   current process while the DLM executes. If the DLM calls any functions
  263.   that allocate resources that must belong to a process, then the
  264.   resources will belong to the MDL program.
  265.   
  266.   It is difficult to predict what the current process will be when
  267.   MicroStation calls a DLM hook function. For example, a DLM can have a
  268.   hook that is called when an MDL program is unloaded, When MicroStation
  269.   calls this hook, the current process is random. It may be the MDL
  270.   program affected by what is going on at the time, or it may be
  271.   MicroStation. If it is important for the DLM to know what MDL program
  272.   is affected, then a pointer to the MDL descriptor is provided as a
  273.   parameter.
  274.   
  275.   MicroStation never loads more than 1 copy of a DLM. If there are
  276.   multiple requests to load the DLM, then MicroStation keeps track of
  277.   the number of requests. Each time there is a request to unload the
  278.   DLM, MicroStation decrements the counter of opens. If the counter goes
  279.   to 0 then the DLM is physically unloaded.
  280.   
  281.   Dynamic Link Modules - Function Pointers as Parameters to
  282.   MicroStation's Built-in Functions
  283.   
  284.   DLM function pointers and MDL function pointers cannot be used
  285.   interchangeably. Using an MDL function pointer where a real function
  286.   pointer is expected would cause a fault.  Also, using a real function
  287.   pointer where an MDL function pointer is expected would cause a fault.
  288.   
  289.   There are a lot of MDL functions for establishing user hooks. These
  290.   functions generally have a form similar to mdlSystem_setFunction
  291.   (<function-type>, <function-pointer>). The <function-pointer> must be
  292.   an offset into the current MDL application. It cannot be a pointer
  293.   into the DLM. Therefore, a DLM can call one of these functions to set
  294.   up a hook for an MDL application, but it cannot use these to set up a
  295.   hook for itself.
  296.   
  297.   In MicroStation's FDF files, all function parameters that are MDL
  298.   function pointers are declared as type MdlFunctionP.  MdlFunctionP is
  299.   declared in mdl.h as:
  300.   
  301.       #if defined (mdl)
  302.       typedef int (*MdlFunctionP)();
  303.   
  304.       #else
  305.       typedef unsigned long   MdlFunctionP;
  306.       #endif
  307.   
  308.   If a source file includes the FDF files, then it should be impossible
  309.   to pass real function pointers where MDL function offsets are
  310.   expected. Declarations such as the one for mdlSystem_setFunction
  311.   should cause the compiler to catch all invalid uses of the these
  312.   functions.
  313.   
  314.       void mdlSystem_setFunction
  315.       (
  316.       int             type,
  317.       MdlFunctionP    function
  318.       );
  319.   
  320.   Dynamic Link Modules - Identifying MDL Applications
  321.   
  322.   It may be important for some DLM's to keep track of certain MDL
  323.   applications, particularly if the DLM is used by more than 1 MDL
  324.   application, and the DLM allocates and frees resources for these
  325.   applications. The DLM should be able to detect when the application is
  326.   removed. It should then free any of the application's resources that
  327.   the application failed to free. MicroStation provides built-in
  328.   functions to let a DLM track an MDL application. MicroStation can
  329.   notify a DLM whenever an MDL application is unloaded.
  330.   
  331.   Internally, MicroStation manages data structures called MDL
  332.   descriptors to track the status of MDL applications. The format of the
  333.   MDL descriptor is not published. However, the pointers to the MDL
  334.   descriptors are still very important. Internally, most of the
  335.   functions used to manage MDL functions require a pointer to an MDL
  336.   descriptor as a parameter.  A DLM can call the function
  337.   mdlSystem_getCurrMdlDesc to get a pointer to the MDL descriptor of the
  338.   MDL application that called it. The task ID associated with an MDL
  339.   descriptor can be determined with the function "mdlSystem_getMdlTaskID
  340.   (mdlDescP)". The MDL descriptor for a task can be determined with
  341.   "mdlSystem_findMdlDesc (taskIdP)" where taskIdP points to the
  342.   application's task ID.  This task ID is not case sensitive.
  343.   
  344.   The MDL descriptor is essentially the internal name, and the task ID
  345.   is the external name. The task ID is also used in MicroStation input
  346.   queue elements.
  347.   
  348.   A DLM can have an unload hook that is called whenever an MDL
  349.   application is unloaded. It can use this hook to free any resources
  350.   allocated by the DLM for the MDL application.
  351.   
  352.   See the section "Dynamic Link Modules - Function Call Specifications"
  353.   for more information on these functions.
  354.   
  355.   Dynamic Link Modules - Calling Custom User Hooks
  356.   
  357.   This section describes how native code can call MDL functions. Many
  358.   names are used for this mechanism. Some of the names are "call backs",
  359.   "user hooks", "asynchronous functions", and "filters". The term "user
  360.   hooks" is used in this document.
  361.   
  362.   The mechanism described here works regardless of whether or not the
  363.   native code was called by an MDL function. The mechanism works even if
  364.   the native code is called by one MDL application and calls a function
  365.   in another MDL application.
  366.   
  367.   A DLM cannot directly call functions in MDL programs. It must use
  368.   dlmSystem_callMdlFunction to call these functions.  This does not
  369.   mean that they cannot call MDL built-in functions.  A DLM must use
  370.   use dlmSystem_callMdlFunction to call functions in MDL programs, but
  371.   can call built-in functions directly.
  372.   
  373.   To call an MDL function, the native code must know the offset for that
  374.   function, and the address of the MDL descriptor for the application
  375.   that contains that function.  An MDL function pointer is not an
  376.   absolute addresses. It is an offset from the start of the
  377.   application's code segment.  The MDL linker forces the offset to be 8
  378.   or greater, so 0 can be used to represent a NULL MDL function pointer.
  379.   
  380.   MicroStation needs a pointer to the MDL descriptor to determine the
  381.   start of the code segment so that it can figure out the absolute
  382.   address of the function.
  383.   
  384.   When MicroStation calls an MDL function, its saves the current value
  385.   of currMdlDesc, and sets it to the valued passed into
  386.   dlmSystem_callMdlFunction. When dlmSystem_callMdlFunction returns,
  387.   MicroStation restores currMdlDesc.
  388.   
  389.   See the section "Dynamic Link Specifications - New Built-in Functions"
  390.   for more information on dlmSystem_callMdlFunction.
  391.   
  392.   Dynamic Link Modules - Determining When an MDL Program is Unloaded
  393.   
  394.   It is often important to know when an MDL application is being
  395.   unloaded. For example, if a DLM calls an MDL application's user hook
  396.   after the application has been unloaded, then something random will
  397.   happen. Also, if the DLM is allocating and tracking resources for an
  398.   MDL application, then it must know to free those resources when the
  399.   application is unloaded.
  400.   
  401.   The DLM can use an unload hook to learn when an MDL application is
  402.   unloaded. To install an unload hook, the DLM must call
  403.   "dlmSystem_setFunction (DLM_SYSTEM_MDL_UNLOAD, <dlmID>,
  404.   <unloadFunctionP>)". When an MDL application is unloaded, MicroStation
  405.   will call the unload hook passing the application's MDL descriptor as
  406.   a parameter.
  407.   
  408.   Each DLM may have an unload hook, but a given DLM may have only 1
  409.   hook. To remove an unload hook, call "dlmSystem_setFunction
  410.   (DLM_SYSTEM_MDL_UNLOAD, <dlmID>, NULL)".See the description of
  411.   userHook_mdlUnload for more information on this user hook.
  412.   
  413.   Dynamic Link Modules - Application-Specific Resources versus System
  414.   Resources
  415.   
  416.   There are a number of functions that allocate resources for an MDL
  417.   program. These resources then belong to the MDL program.  Examples are
  418.   dlmSystem_mdlMalloc and dlmSystem_mdlFopen. These handle malloc and
  419.   fopen calls from MDL programs.
  420.   
  421.   Files opened with dlmSystem_mdlFopen must always be closed with
  422.   dlmSystem_mdlFclose. Otherwise, the FILE pointer returned by
  423.   dlmSystem_mdlFopen may be used just like a FILE pointer returned by
  424.   fopen. In fact, dlmSystem_mdlFopen returns the FILE pointer returned
  425.   to it by fopen.
  426.   
  427.   Memory allocated by dlmSystem_mdlMalloc, dlmSystem_mdlCalloc, or
  428.   dlmSystem_mdlRealloc must be freed by dlmSystem_mdlFree. Memory
  429.   allocated by malloc must be freed by calling free. An MDL application
  430.   cannot free memory that a builtin or DLM function allocated by calling
  431.   malloc directly. Memory allocated by calling dlmSystem_mdlMalloc is
  432.   automatically freed by MicroStation when the MDL application is
  433.   unloaded.
  434.   
  435.   Dynamic Link Modules - Dynamic Link Specification Source Files
  436.   
  437.   This section describes the syntax used for Dynamic Link Specification
  438.   source files. The program dlmspec is used to compile a Dynamic Link
  439.   Specification source file producing a Dynamic Link Specification
  440.   object file. The object file is used at link time to specify
  441.   information on symbols that are to be resolved at runtime.  Normal MDL
  442.   object files (.mo files) that need to have symbols resolved from a
  443.   given Dynamic Link Specification object file must appear in mlink's
  444.   command line prior to the Dynamic Link Specification file.
  445.   
  446.   The statements in a Dynamic Link Specification file can be categorized
  447.   as preprocessor directives and commands. Comments are also supported.
  448.   Comments are bracketed with /* and */.
  449.   
  450.   All preprocessor directives contain "#" at the start of a line.
  451.   "#include" can be used to include other source files. "if", "else",
  452.   "elif", "endif", "ifdef", and "endif" can be used for conditional
  453.   compilation. "define" can be used to define values used for
  454.   conditional compilation. It cannot be used to define macros.  The
  455.   Dynamic Link Specification compiler "dlmspec" defines standard
  456.   constants that can be used for conditional compilation. The defines
  457.   that are built in for the appropriate platforms are msdos, pm386,
  458.   IP32, clipper, unix, sparc, hp700, macintosh, vax, BIG_ENDIAN,
  459.   EnvironV, and XWindow.
  460.   
  461.   The commands all begin with "%". The commands are Version, Functions,
  462.   EndFunctions, Variables, EndVariables, ModuleName, and End.
  463.   
  464.   %Version is followed by a version number. This version number is saved
  465.   in the Dynamic Link Specification object file. It is also saved with
  466.   the application at link time. At load time, this version number is
  467.   provided to the DLM's initialization function.
  468.   
  469.   %Functions tells dlmspec to start processing the subsequent symbols as
  470.   function names. It is used to specify the list of functions that can
  471.   be resolved at runtime. %EndFunctions is used to signal the end of the
  472.   list. Any number of pairs of %Functions %EndFunctions can be used, but
  473.   they cannot be embedded.
  474.   
  475.   %Variables tells dlmspec to start processing the subsequent symbols as
  476.   variable names. It is used to specify the list of variables that can
  477.   be resolved at runtime. %EndVariables is used to signal the end of the
  478.   list. Any number of pairs of %Variables %EndVariables can be used.
  479.   
  480.   %ModuleName is followed by the name of a file. For DLM's, this is used
  481.   at runtime to determine the name of the file containing the DLM. The
  482.   file name suffix usually is not specified. It is system-specific. It
  483.   is provided by MicroStation at runtime. The defaults are ".out"
  484.   (Clipper), ".rex" (PC), ".so" (Sparc), and ".sl" (HP700).  
  485.  
  486.   An application should not use more than one DLM source file to 
  487.   describe one DLM.
  488.   
  489.   The final command in a Dynamic Link Module specification source file
  490.   must be %End.
  491.   
  492.   6. Additional Include Files
  493.   
  494.   The following files are provided:
  495.   
  496.       dloadlib.h - this file contains #defines that map the MDL names
  497.      into the real MicroStation names if the MicroStation names are
  498.      needed to load the DLM. This file is system specific. On platforms
  499.      where the operating system resolves dynamic links, it has a lot of
  500.      entries.  On systems such as the PC and Intergraph platform where
  501.      MicroStation resolves the dynamic links, MicroStation maps the
  502.      names at runtime so this file is not needed. On these platforms, a
  503.      dummy dloadlib.h is provided.
  504.      
  505.       dlmfuncs.h - this contains declarations and definitions that are
  506.      only used by DLM's.
  507.      
  508.       fdf files for all of the MDL builtin's that are not in the
  509.      standard C library. Most of these built-ins are available to both
  510.      DLM's and MDL programs.. Both MDL source and DLM source can use the
  511.      FDF files. The files are provided in the mdl/include directory
  512.      along with all of the MDL header files. The file dlmsys.fdf
  513.      declares functions that are available only to DLM's.  The other FDF
  514.      files declare functions that are available to both DLM's and MDL
  515.      programs.
  516.      
  517.   Dynamic Link Modules - Example
  518.   
  519.   The mdl/examples/dlink directory contains an example that illustrates
  520.   most of the important concepts needed to implement a DLM. This example
  521.   implements the Unix file io functions read, write, open, close, etc.
  522.   To compile and link this example, just run "bmake -I$MS/mdl/include/
  523.   fileio". Doing this will build the application including both the MDL
  524.   program and the DLM. Then load the MDL applications testio1 or testio2.
  525.   MicroStation will see that the application needs the DLM and will
  526.   automatically load it.
  527.   
  528.   The concepts illustrated in the example are:
  529.   
  530.       Dynamic Link Specification source file.
  531.      
  532.       Sample make file.
  533.      
  534.       Associating resources - file handles in this case - with a
  535.      specific MDL application.
  536.      
  537.       Using 2 names for a given function - the name used within the DLM
  538.      and the name used for access from an MDL program.
  539.      
  540.       Support for MDL user hooks called from the DLM.
  541.      
  542.       DLM hook functions.
  543.      
  544.       Use of an initialization function.
  545.      
  546.       Use of the error reporting function.
  547.      
  548.   DLM Example - Dynamic Link Specification Source File
  549.   
  550.   The Dynamic Link Specification source file is fileio.dls. It has
  551.   sections specifying the version number, module name, and function
  552.   names. The %Version command specifies a number that is stored with the
  553.   Dynamic Link Specification object file. It is also stored with any MDL
  554.   application created with this object file. When the DLM is loaded into
  555.   memory, MicroStation calls the DLM's initialization function. The
  556.   version number is passed as one of the parameters. In this example,
  557.   the initialization function initialize in filemain.c verifies that the
  558.   version number is less than 0x500. If it 0x500 or greater, then it
  559.   rejects the load request and displays a message saying that the
  560.   versions are incompatible.
  561.   
  562.   The %ModuleName command specifies the name of the file that contains
  563.   the DLM. In this example it provides the name "fileio" to specify that
  564.   the DLM is in the file "fileio.out" (Clipper), "fileio.rex" (PC),
  565.   "fileio.so" (Sparc), or "fileio.sl" (HP700).
  566.   
  567.   The %Functions section specifies what functions can be accessed from
  568.   an MDL program that is linked with this DLM. For each function, if
  569.   only 1 function name is given then that name is used both within the
  570.   MDL program and within the DLM. If a specification also contains a
  571.   name in parentheses, then the name preceding the parentheses is used
  572.   by the MDL program and the name in the parentheses is the name used by
  573.   the DLM. Consider the case "open (fileio_open)". When the MDL program
  574.   calls the function open, it is calling the DLM's function fileio_open.
  575.   
  576.   This example contains an empty Variables section. This section would
  577.   be used for listing the variables that can be accessed from the MDL
  578.   application. The format is the same as for functions.
  579.   
  580.   DLM Example - Managing Application Resources
  581.   
  582.   When MicroStation allocates resources for an MDL task, it associates
  583.   those resources with that MDL task. If the MDL task is unloaded, then
  584.   MicroStation must free those resources. Since a DLM should appear to
  585.   be part of MDL, it must behave the same way. When an MDL application
  586.   is unloaded, a DLM must also release all resources it allocated for
  587.   that application.
  588.   
  589.   In this example, file handles are allocated by open, create, and dup.
  590.   Therefore, the DLM must intercept all calls to these functions and
  591.   record what MDL application called the function.
  592.   
  593.   The first step in the procedure is to establish different internal and
  594.   external names for these functions. This is done in the Dynamic Link
  595.   Specification file. Note that the specification for open is "open
  596.   (fileio_open)". This specifies that the name "open" can be used in an
  597.   MDL program. When the MDL program calls open, MDL will call the DLM's
  598.   function fileio_open.
  599.   
  600.   The function fileio_open must associate the current MDL application
  601.   and the file handle returned by the real open. To get an identifier
  602.   for the MDL application, it calls mdlSystem_getCurrMdlDesc. Then it
  603.   finds a free entry in the array fileList. It that entry, it records
  604.   both the file handle and the MDL descriptor.
  605.   
  606.   The DLM also intercepts calls to close. When the MDL application calls
  607.   close, the DLM's function fileio_close intercepts the call. It clears
  608.   the data structure where it had established that the handle was
  609.   associated with this MDL application.
  610.   
  611.   The final step in controlling the  file handles is to guarantee that
  612.   when the MDL application is unloaded, all of its open files will be
  613.   closed. To do this, the DLM sets up an MDL unload function
  614.   mdlUnloadHook to be called whenever an MDL application is unloaded.
  615.   MicroStation passes a pointer to the MDL descriptor when it calls the
  616.   unload hooks. The DLM uses this pointer to determine what files are
  617.   owned by the MDL application that is being unloaded. It closes all of
  618.   these files.
  619.   
  620.   DLM Example - Support of MDL User Hooks
  621.   
  622.   This application supports a user hook to be called whenever an MDL
  623.   application opens, creates, or dups a file.
  624.   
  625.   MDL applications set up the user hook by calling fileio_setFunction.
  626.   This function records the offset of the function and the current MDL
  627.   descriptor. Whenever an MDL application opens, creates, or dups a file
  628.   the DLM calls all of the hooks using the function
  629.   dlmSystem_callMdlFunction. The first 2 parameters for this function
  630.   are a pointer to an MDL descriptor and the offset to the MDL function.
  631.   The remaining parameters are variable. These parameters are passed to
  632.   the MDL function.
  633.   
  634.   DLM Example - DLM Hook Functions
  635.   
  636.   The DLM "fileio" sets up a hook function to be called whenever an MDL
  637.   application is unloaded. It does this by calling
  638.   dlmSystem_setFunction. Notice that this function is similar to the
  639.   mdlSystem_setFunction except that the second parameter identifies the
  640.   DLM. When an MDL application sets a user hook it does not have to
  641.   identify itself because MicroStation always knows what MDL application
  642.   is active. However, MicroStation does not have any concept of active
  643.   DLM. Therefore, a DLM must identify itself it the
  644.   dlmSystem_setFunction call. When MicroStation calls the DLM's
  645.   initialization function, it provides the DLM's identifier as one of
  646.   the parameters. The DLM uses this identifier as the second argument in
  647.   calls to dlmSystem_setFunction.
  648.   
  649.   DLM Example - Use of Initialization Function
  650.   
  651.   The DLM fileio contains an initialization function. This function is
  652.   called immediately after the DLM is loaded. Typically, this is used to
  653.   verify that the versions are compatible and to set up any hook
  654.   functions that are required.
  655.   
  656.   The initialization function must always be called initialize.
  657.   
  658.   If the initialization function returns anything other than SUCCESS
  659.   then the load fails and the MDL application is unloaded.
  660.   
  661.   See the section "Dynamic Link Modules - New Built-in Functions" for
  662.   more information on initialize.
  663.   
  664.   DLM Example - Use of Error Reporting Function
  665.   
  666.   Typically, when a load fails a lot of error messages are required to
  667.   completely explain what happened. The message fields in the command
  668.   window are not sufficient for this. Therefore, load errors are
  669.   reported with the function dlmSystem_displayError. The format for this
  670.   is the same as for printf, except that the messages should not have a
  671.   newline. The function dlmSystem_displayError appends a newline to
  672.   every message. The dlmSystem_displayError function is also available
  673.   to DLM's.
  674.   
  675.   DLM Example - Platform Specific Notes
  676.   
  677.   At the time this document was written, the example had been tested on
  678.   a SPARCstation, an Interpro running an Environ V version of
  679.   MicroStation, a PC, and an HP. This section describes some of the
  680.   problems that were encountered.
  681.   
  682.   In general, DLM's should not use system libraries.  This example violates 
  683.   this rule because one purpose of this example is to illustrate how to 
  684.   handle some of the difficult problems that arise in linking DLM's.
  685.   
  686.   On the Intergraph platform, a DLM is a relocatable object file. To
  687.   create a relocatable object file, use the Unix utility ld to combine
  688.   object files. Specify -r in the command line to specify that the
  689.   output is a relocatable object file, not an executable file.  ld must
  690.   be used to start the link.  Neither acc or cc pass the -r flag to the
  691.   ld.
  692.   
  693.   On the Intergraph platform, MicroStation can resolve symbols from a
  694.   shared library only if MicroStation is linked with that shared
  695.   library. Currently, only the tools and C shared libraries are
  696.   supported. The X windows version of ustation32, programs will be able
  697.   to use the X windows shared library.
  698.  
  699.   In this example, the link is performed in 2 steps. First fileresl.out
  700.   is created. This resolves references to symbols that are to be
  701.   resolved from the system libraries instead of from MicroStation. 
  702.   This step resolves as few symbols as possible.  Then fileresl.out
  703.   is linked with the other object files to create fileio.out. There
  704.   are a lot of references unresolved in fileio.out.  These are
  705.   all resolved at runtime when fileio.out is loaded.  If the link
  706.   step only contained 1 step, and the link step that builds fileio.out
  707.   used the libraries, then these references would be resolved from
  708.   the libraries instead of from MicroStation. That could cause some
  709.   important data structures to be duplicated, possibly breaking the
  710.   heap management functions such as malloc and free.
  711.   
  712.   Since nearly all standard C functions are available as built-in
  713.   functions, a portable DLM should not have to use any of the shared
  714.   libraries. In fact, many DLM's will not be linked with any libraries.
  715.   All of the references will be resolved at runtime from MicroStation's
  716.   built-ins. It should be able to have all of the symbols resolved from
  717.   MicroStation's built-ins at runtime.
  718.   
  719.   On the SPARC Station the DLM is a sharable object file. This is done
  720.   automatically. There is nothing unusual in the compilation or link
  721.   steps, except that ".so" is specified as the file suffix for the
  722.   sharable object the link step creates.
  723.   
  724.   On the SPARC, it is necessary for the DLM to provide intermediate
  725.   functions to call functions that are in the shared library. MDL
  726.   applications can not directly call functions from a system shared
  727.   library. The MDL application must call a function in the DLM that in
  728.   turn calls the function in the shared library. The DLM in this example
  729.   has a function fileio_perror that does nothing other than call perror
  730.   with the same parameters. This is needed because the runtime load step
  731.   would fail when MicroStation tried to get the address of perror for
  732.   the MDL application. The system call used for that would fail and
  733.   would terminate MicroStation. On other systems, it is possible to have
  734.   the MDL functions call library functions directly. For example, on the
  735.   Interpro the fileio_perror intermediate function is not required. In
  736.   this example, the intermediate functions are used regardless of
  737.   platform so that the code can be as similar as possible on all
  738.   platforms.
  739.  
  740.   On the SPARC, do not specify the standard libraries in the Dynamic 
  741.   Link Module's link step.  If the link step does not specify the
  742.   standard libraries, the Dynamic Link Module still can use functions
  743.   and variables from those libraries. All of the symbols are resolved at 
  744.   runtime.  Starting with Release 4.1.2 of the SunOS, if
  745.   both MicroStation and the dynamic link module specify the same
  746.   shared library then at runtime the following message occurs:
  747.  
  748.       "ld.so: conflicting usage of dlopen'ed dependents"
  749.   
  750.   On the SPARC, MicroStation never unloads a DLM. There is a bug in the
  751.   SunOS that causes MicroStation to crash when a DLM is reloaded.  To
  752.   get around this problem, MicroStation always keeps the DLM loaded.
  753.   This is most significant to developers who must restart MicroStation
  754.   to use a new version of a DLM.
  755.   
  756.   On the HP700, the DLM is a shared library. All of the object files
  757.   must contain position-independent code. This is achieved by specifying
  758.   "+z" in the compilation step. Specify "-b" in the command line of the
  759.   load step to specify that the output file is a shared library.
  760.   
  761.   On the PC, the DLM is a REX file that is created by the Phar Lap
  762.   linker and then processed by the BSI-supplied utility linkdlm to help
  763.   the runtime code find all references that need to be fixed up.
  764.   
  765.   A REX file is a standard Phar Lap relocatable executable. The REX file
  766.   must be linked with a number of standard BSI-supplied object files and
  767.   libraries. Both  linkdlm and MicroStation's runtime verify that these
  768.   files were included in the link step.
  769.   
  770.   The object file ustnfrst.obj must be the first input file specified in
  771.   the link step.  The library file dlmsyms.lib must be specified after
  772.   all of the object files. This contains definitions for all of the
  773.   symbols that can be resolved from MicroStation. ustnlast.lib must be
  774.   the last file in the link step.
  775.   
  776.   After creating the REX file, run it through linkdlm. The command to
  777.   invoke linkdlm is
  778.   
  779.     "linkdlm -r<rex file> -o<output file>"
  780.   
  781.   where <rex file> specifies a rex file that was created by the Phar Lap
  782.   linker and <output file> specifies the outname of the output file. The
  783.   output will be used as a DLM.
  784.   
  785.   Dynamic Link Modules - Debugging
  786.   
  787.   Source level debugging is only available on the Intergraph platform.
  788.   
  789.   To debug a DLM on an Interpro, just start MicroStation with dbg. After
  790.   the DLM has been loaded, hit ctrl-C to get into the debugger. Then you
  791.   can set breakpoints in the DLM. To invoke the debugger immediately
  792.   after the DLM is loaded but before the initialize function is called,
  793.   set a breakpoint on the function "dlink_debugHook". This MicroStation
  794.   function is called immediately after a DLM is loaded.
  795.   
  796.   Dynamic Link Specifications - New Built-in Functions
  797.   
  798.   This section documents the following built-in functions:
  799.   
  800.   dlmSystem_callMdlFunction, dlmSystem_setFunction, dlmSystem_mdlMalloc,
  801.   dlmSystem_calloc, dlmSystem_mdlFree, dlmSystem_mdlRealloc,
  802.   dlmSystem_mdlFopen, dlmSystem_mdlFclose, dlmSystem_mdlTmpfile,
  803.   dlmSystem_mdlFreopen, mdlSystem_getCurrMdlDesc, mdlSystem_findMdlDesc,
  804.   and mdlSystem_getCurrTaskId
  805.   
  806.   It also documents the following hook functions that can be defined in
  807.   the DLM: initialize, userHook_mdlUnload, userHook_dlmUnload.
  808.   
  809.   The DLM does not need to use the names userHook_mdlUnload and
  810.   userHook_dlmUnload. These hook functions are designated to
  811.   MicroStation by address only using dlmSystem_setFunction.
  812.   
  813.   The name initialize must be used for the initialization function.
  814.   MicroStation uses the DLM's symbol table to find the address of this
  815.   function.
  816.   
  817.   The functions dlmSystem_mdlMalloc, dlmSystem_mdlCalloc,
  818.   dlmSystem_mdlRealloc, and dlmSystem_mdlFree have the same parameters
  819.   and return values as malloc, calloc, realloc, and free. These
  820.   dlmSystem_mdl... functions associate the memory with the current MDL
  821.   application.  When that application is unloaded, the memory is
  822.   automatically freed.  To allocate and free memory without associating
  823.   it with the current MDL application, use malloc, calloc, realloc, and
  824.   free.
  825.   
  826.   The functions dlmSystem_mdlFopen, dlmSystem_mdlFclose,
  827.   dlmSystem_mdlTmpfile, and dlmSystem_mdlFreopen have the same
  828.   parameters and return values as fopen, fclose, tmpfile, and freopen.
  829.   These dlmSystem_mdl... functions associate the file pointer with the
  830.   current MDL application. When the application is unloaded, the file is
  831.   automatically closed. To manipulate files without associating them
  832.   with the MDL application, use the standard functions fopen, fclose,
  833.   tmpfile, and freopen.
  834.   
  835.   Summary
  836.   
  837.   #include "dlmsys.fdf"
  838.   
  839.   int dlmSystem_callMdlFunction
  840.   
  841.   (
  842.   void           *mdlDescP,
  843.   MdlFunctionP    functionOffset,
  844.   ...             /* Parameters for the MDL function */
  845.   )
  846.   
  847.   Description
  848.   
  849.   The dlmSystem_callMdlFunction function is used to call an MDL
  850.   function. The mdlDescP parameter points to the MDL descriptor for the
  851.   function to be called.
  852.   
  853.   The functionOffset parameter is an offset to the function to be
  854.   called. This is an MDL function pointer.
  855.   
  856.   The variable argument list represents the arguments to be passed to
  857.   the MDL function. Up to 15 arguments may be passed. MicroStation
  858.   automatically determines the number and types of arguments expected by
  859.   the function. (It does this by examining the function's header. This
  860.   header is actually part of the MDL program loaded by MDL. It is
  861.   created automatically by the MDL compiler.) Using this information,
  862.   MicroStation moves the arguments from MicroStation's stack to the MDL
  863.   application's stack and dispatches the function.
  864.   
  865.   Return Value
  866.   
  867.   dlmSystem_callMdlFunction returns the value returned by the MDL
  868.   application. It only returns integer values. If
  869.   dlmSystem_callMdlFunction  is not able to call the function, then it
  870.   returns 0. This only happens if the offset is 0, or the pointer to the
  871.   MDL descriptor is NULL.
  872.   
  873.   Summary
  874.   
  875.   #include "dlmsys.fdf"
  876.   
  877.   int dlmSystem_setFunction
  878.   (
  879.   int           functionType,
  880.   void         *dlmID,
  881.   int         (*funcP)()
  882.   )
  883.   
  884.   Description
  885.   
  886.   The dlmSystem_setFunction function is used to designate a DLM user
  887.   hook. The functionType parameter specifies the type of hook. Valid
  888.   values are DLM_SYSTEM_MDL_UNLOAD and DLM_SYSTEM_DLM_UNLOAD.
  889.   
  890.   The dlmID parameter identifies the DLM setting up the hook. This value
  891.   was supplied by MicroStation in the call to the DLM's initialization
  892.   function.
  893.   
  894.   The funcP parameter specifies the function to be called when the
  895.   designated event occurs. A value of NULL cancels the outstanding hook.
  896.   
  897.   Return Value
  898.   
  899.   dlmSystem_setFunction returns SUCCESS if it was able to set up the
  900.   hook. Otherwise, it returns ERROR.
  901.   
  902.   Summary
  903.   
  904.   #include "mssystem.fdf"
  905.   
  906.   void *mdlSystem_getCurrMdlDesc
  907.   (
  908.   void
  909.   )
  910.   
  911.   void *mdlSystem_findMdlDesc
  912.   (
  913.   char       *taskIdP
  914.   )
  915.   
  916.   char *mdlSystem_getMdlTaskId
  917.   (
  918.   void        *mdlDescP
  919.   )
  920.   
  921.   
  922.   
  923.   Description
  924.   
  925.   The mdlSystem_getCurrMdlDesc function is used to retrieve a pointer to
  926.   the MDL descriptor of the currently active MDL application. This
  927.   pointer is used a parameter to a number of functions.
  928.   
  929.   The mdlSystem_findMdlDesc function is used to retrieve a pointer to
  930.   the MDL descriptor of the MDL application specified by taskIdP. The
  931.   string functionType points to is the task ID of an MDL application.
  932.   mdlSystem_findMdlDesc is not case sensitive. It makes a copy of the
  933.   string and converts it to upper case before starting the search.
  934.   
  935.   The mdlSystem_getMdlTaskId function is used to retrieve a pointer to
  936.   the task ID of an MDL application. mdlDescP specifies the MDL
  937.   descriptor of a loaded MDL application.
  938.   
  939.   Return Value
  940.   
  941.   mdlSystem_getCurrMdlDesc and mdlSystem_findMdlDesc both return
  942.   pointers to MDL descriptors. mdlSystem_getCurrMdlDesc always returns a
  943.   non-NULL value. If no MDL application is active, then it returns a
  944.   pointer to MicroStation's MDL descriptor. mdlSystem_findMdlDesc
  945.   returns NULL if the specified task ID does not name a loaded MDL
  946.   application. mdlSystem_getMdlTaskId returns a pointer to the task ID
  947.   of the specified MDL application.
  948.   
  949.   INITIALIZE
  950.   
  951.   int initialize
  952.   (
  953.   char           *fileNameP,
  954.   char           *taskIdP,
  955.   void           *dlmID,
  956.   unsigned long   initParameter
  957.   )
  958.   
  959.   Description
  960.   
  961.   MicroStation calls the initialize function as the final step of
  962.   loading an MDL application that requires DLM. If the DLM is required
  963.   by more than 1 MDL program, then the DLM is only loaded once but the
  964.   initialize function is called for each MDL program.
  965.   
  966.   The parameter fileNameP points to the name of the file that contains
  967.   the DLM. The name includes the entire path.
  968.   
  969.   taskIdP points to the task ID of the MDL program being loaded.
  970.   
  971.   dlmID is a pointer that uniquely identifies the DLM. The DLM should
  972.   use this value if it calls any functions that take a DLM ID as a
  973.   parameter. initParameter is the value specified with the %Version
  974.   command in the Dynamic Link Specification source file.
  975.   
  976.   Return Value
  977.   
  978.   initialize may return 0 to allow the load to continue. If initialize
  979.   returns a non-zero value then the load of the MDL program is aborted.
  980.   If no other MDL programs have the DLM loaded, then the DLM is also
  981.   unloaded.
  982.   
  983.   userHook_mdlUnload, userHook_dlmUnload
  984.   
  985.   void userHook_mdlUnload
  986.   (
  987.   void           *mdlDescP,
  988.   unsigned char  *taskIdP,
  989.   unsigned char  *fileNameP
  990.   )
  991.   
  992.   void userHook_dlmUnload
  993.   (
  994.   void
  995.   )
  996.   
  997.   Description
  998.   
  999.   MicroStation calls the userHook_mdlUnload user hook functions whenever
  1000.   an MDL application is unloaded. Both the mdlDescP and the taskIdP
  1001.   identify the MDL application being unloaded. Either parameter is
  1002.   enough to uniquely identify the application. Both parameters are
  1003.   supplied just as a matter of convenience. mdlDescP may or may not be
  1004.   the same as the current MDL descriptor. Never depend on the value of
  1005.   the current MDL descriptor when this unload hook is called.
  1006.   
  1007.   MicroStation calls the userHook_dlmUnload function prior to unloading
  1008.   the DLM that designated that hook.
  1009.   
  1010.   Return Value
  1011.   
  1012.   Both of these hook functions are type void. MicroStation ignores the
  1013.   return values of both of these functions.
  1014.   
  1015.   
  1016.   
  1017. Feature:
  1018.  
  1019.   MDL Debugger Changes
  1020.   
  1021. Description:
  1022.  
  1023.   If source is compiled using make files similar to those distributed
  1024.   with the MDL examples, then it is no longer necessary to use the
  1025.   environment variable MS_DBGSOURCE to tell the debugger where to find
  1026.   the source.  These make files use the entire path to specify the names
  1027.   of source files.  These complete names are now stored with the object
  1028.   files and MDL programs. The debugger first uses this information to
  1029.   find the source files before trying to use the information in
  1030.   MS_DBGSOURCE.
  1031.   
  1032.   On the Intergraph platform, if the environment variable MS_DBGOUT is
  1033.   set, the MDL debugger then uses the terminal session that started
  1034.   MicroStation for input and output instead of using the MicroStation
  1035.   debugger window. That way, the terminal session can be used for
  1036.   debugging DLM's and an MDL program. The MDL debugger does not work in
  1037.   curses mode. It only supports line mode.  The MDL debugger supports
  1038.   cntl-P for previous line, cntl-N for next line, cntl-B for back 1
  1039.   character, cntl-F for forward 1 character, and backspace.  It also
  1040.   supports ESCAPE to clear the current command line.
  1041.   
  1042.  
  1043.