Building a DLL application
The DLL application may consist of multiple source modules. Some of the source modules may contain references to imported functions, imported variables, or both.
To use a load-on-call DLL in your DLL application, perform the following steps:
- Write the DLL application code. Write it as you would if the functions were statically bound. Assembler code that will access imported functions and/or imported variables must use the Language Environment macros.
- Compile the DLL application code.
- Compile the C source files with the following compiler options:
LP64RENTLONGNAME
These options instruct the compiler to generate special code when calling functions and referencing external variables.
- Compile your C source files with the following compiler options:
- Compile your C++ source files with the
LP64compiler option. - Assembler DLL application source files must be assembled with
the
GOFFoption.
- Compile the C source files with the following compiler options:
- Bind the DLL application code.
- The binder option
CASE(MIXED)is required when binding DLL applications that use mixed-case exported names. - The binder options
RENT,DYNAM(DLL), andCOMPAT(PM4)orCOMPAT(CURRENT)are required.
Include the definition sidedeck from the DLL provider in the set of object modules to bind. The binder uses the definition sidedeck 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 theINCLUDEstatement. - The binder option
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_WSA64 during
program execution.
TRIANGLE DLL described previously (see Writing your C++ DLL code). Compile normally and bind with
the definition sidedeck provided
with the TRIANGLE DLL. extern int getarea(); /* function prototype */
main () {
...
getarea(); /* imported function reference */
...
}
DLLAPPL CELQPRLG PSECT=ADLA6IFP
*
R3 EQU 3 RETURN VALUE
R5 EQU 5 ENVIRONMENT
R6 EQU 6 ENTRY POINT ADDRESS
R7 EQU 7 RETURN POINT ADDRESS
R8 EQU 8 WORK REGISTER
R9 EQU 9 WORK REGISTER
*
WTO 'ADLA6IV4: Calling imported function dllfunc64',ROUTCDE=11
*
CELQCALL dllfunc64,WORKREG=10
*
WTO 'ADLA6IV4: Getting address of imported var DllVar64', X
ROUTCDE=11
*
CEEPLDA DllVar64,REG=9
*
* Set value of imported variable to 789
*
LA R8,789
ST R8,0(,R9)
*
WTO 'ADLA6IV4: Done.',ROUTCDE=11
*
SR R3,R3
RETURN DS 0H
CELQEPLG
*
CEEPDDA DllVar64,SCOPE=IMPORT
LTORG
CEEDSAHP CEEDSA SECTYPE=XPLINK
CEECAA
*
END DLLAPPL
See Figure 1 for a summary of the processing steps required for the application (and related DLLs).