Building a simple DLL application

A simple DLL application contains object modules that are made up of only DLL-code. The application may consist of multiple source modules. Some of the source modules may contain references to imported functions, imported variables, or both.

It is not necessary for DLL applications to be reentrant. However, for some compilers it is necessary to compile code that references DLLs with the RENT option in order to provide support for the DLL call mechanism.

To use a load-on-call DLL in your simple DLL application, perform the following steps:
  • Writing your DLL application code

    Write your code as you would if the functions were statically bound. Assembler code that will access imported functions and imported variables must use the Language Environment macros.

  • Compiling your DLL application code
    • Compile your C source files with the following compiler options:
      • DLL (not necessary if the XPLINK compiler option is specified)
      • RENT
      • LONGNAME
      These options instruct the compiler to generate special code when calling functions and referencing external variables.
    • Compile your C++ source files normally. A C++ application is always DLL code.
    • Compile your COBOL source files with the following compiler options:
      • DLL
      • RENT
      • NOEXPORTALL
    • Compile your Enterprise PL/I source files with the RENT option.
    • Assembler DLL Application source files must be assembled using the GOFF option.
  • Binding your DLL application code
    • The binder option CASE(MIXED) is required when binding DLLs applications that use mixed-case exported names.
    • The binder options RENT, DYNAM(DLL), and COMPAT(PM3) or COMPAT(CURRENT) are required.
    Include the definition side-deck from the DLL provider in the set of object modules to bind. The binder uses the definition side-deck to resolve references to functions and variables defined in the DLL. If you are referencing multiple DLLs, you must include multiple definition side decks.
    Note: Because definition side decks in automatic library call (autocall) processing will not be resolved, you must use the INCLUDE statement.

After final autocall processing of DD SYSLIB is complete, all DLL-type references that are not statically resolved are compared to IMPORT control statements. Symbols on IMPORT control statements are treated as definitions, and cause a matching unresolved symbol to be considered dynamically rather than statically resolved. A dynamically resolved symbol causes an entry in the binder B_IMPEXP to be created. If the symbol is unresolved at the end of DLL processing, it is not accessible at run time.

Addresses of statically bound symbols are known at application load time, but addresses of dynamically bound symbols are not. Instead, the runtime library that loads the DLL that exports those symbols finds their addresses at application run time. The runtime library also fixes up the importer's linkage blocks (descriptors) in C_WSA during program execution.

The following code fragment illustrates how a C++ application can use the TRIANGLE DLL described inWriting your C++ DLL code. Compile normally and bind with the definition side-deck provided with the TRIANGLE DLL.

   extern int getarea(); /* function prototype */
   main() {
         ...
         getarea();      /* imported function reference */
         ...
   }

The following COBOL code sample illustrates how a simple COBOL-only DLL application (A1C4DL01) calls a COBOL DLL (A1C4DL02):

Figure 1. COBOL DLL application calling a COBOL DLL
       CBL PGMNAME(LONGMIXED),DLL,RENT
       IDENTIFICATION DIVISION.
       PROGRAM-ID. 'A1C4DL01'.
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
       DATA DIVISION.
       FILE SECTION.
       WORKING-STORAGE SECTION.
       01 TODAYS-DATE-YYYYMMDD         PIC 9(8).
       PROCEDURE DIVISION.
           Display 'A1C4DL01: Entered'
           MOVE FUNCTION CURRENT-DATE(1:8) TO TODAYS-DATE-YYYYMMDD
           Call 'A1C4DL02' using todays-date-yyyymmdd
           Display 'A1C4DL01: All done'
           GOBACK
           .

       CBL PGMNAME(LONGMIXED),DLL,EXPORTALL,RENT
       IDENTIFICATION DIVISION.
       PROGRAM-ID. 'A1C4DL02'.
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
       DATA DIVISION.
       FILE SECTION.
       WORKING-STORAGE SECTION.
       LINKAGE SECTION.
       01 TODAYS-DATE-YYYYMMDD         PIC 9(8).
       PROCEDURE DIVISION using todays-date-yyyymmdd.
           Display 'A1C4DL02: Todays date is ' todays-date-yyyymmdd
           GOBACK
           .
The following code fragment illustrates how an Assembler routine can use the ADLLBEV2 DLL described in Writing your Language Environment-conforming assembler DLL code. Assemble and bind with the definition side-deck provided with the ADLLBEV2 DLL.
Figure 2. Assembler DLL application calling an assembler DLL
DLLAPPL  CEEENTRY MAIN=YES,PPA=DLLPPA
*        Symbolic Register Definitions and Usage
R8       EQU   8             Work register
R9       EQU   9             Work register
R15      EQU   15            Entry point address
*
         WTO   'ADLABIV4: Calling imported function dllfunc',ROUTCDE=11
*
         CEEPCALL dllfunc,MF=(E,)
*
         WTO   'ADLABIV4: Getting address of imported var DllVar',     X
               ROUTCDE=11
*
         CEEPLDA DllVar,REG=9
*
* Set value of imported variable to 789
*
         LA    R8,789
         ST    R8,0(,R9)
*
         WTO   'ADLABIV4: Done.',ROUTCDE=11
*
         SR    R15,R15
RETURN   DS   0H
         CEETERM  RC=(R15),MODIFIER=0
*
*
         CEEPDDA DllVar,SCOPE=IMPORT
DLLPPA   CEEPPA
         LTORG
         CEEDSA
         CEECAA
         END      DLLAPPL

See Figure 1 for a summary of the processing steps required for the application and related DLLs.