Using Intel® Visual Fortran to Create and Build Windows*-Based Applications

ID 757211
Date 7/23/2021
Public
Document Table of Contents

Coding Requirements for Sharing Data in DLLs

A dynamic-link library (DLL) is an executable file that can be used as a place to share data across processes.

Coding requirements include using the cDEC$ ATTRIBUTES compiler directive DLLIMPORT and DLLEXPORT options. Variables and routines declared in the program and in the DLL are not visible to each another unless you use DLLIMPORT and DLLEXPORT.

When sharing data among multiple threads or processes, do the following:

  • Declare the order, size, and data types of shared data consistently in the DLL and in all procedures importing the DLL exported data.

  • If more than one thread or process can write to the common block simultaneously, use the appropriate features of the Windows* operating system to control access to the shared data. Such features include critical sections (for single process, multiple thread synchronization) and mutex objects (for multi-process synchronization).

This section discusses:

Exporting and Importing Common Block Data

Data and code in a dynamic-link library is loaded into the same address space as the data and code of the program that calls it. However, variables and routines declared in the program and in the DLL are not visible to one another unless you use the cDEC$ ATTRIBUTES compiler directive DLLIMPORT and DLLEXPORT options. These directive options enable the compiler and linker to map to the correct portions of the address space so that the data and routines can be shared, allowing use of common block data across multiple images.

You can use DLLEXPORT to declare that a common block in a DLL is being exported to a program or another DLL. Similarly, you can use DLLIMPORT within a calling routine to tell the compiler that a common block is being imported from the DLL that defines it.

To export and import common block data:

  1. Create a common block in the subprogram that will be built into a Fortran DLL. Export that common block with !DEC$ ATTRIBUTES DLLEXPORT, followed by the COMMON statement, associated data declarations, and any procedure declarations to be exported. For example:

    !DEC$ ATTRIBUTES DLLEXPORT :: /X/
    COMMON /X/ C, B, A
    REAL C, B, A
    END
    ...

    If the Fortran DLL procedure contains only a common block declaration, you can use the BLOCK DATA statement:

    BLOCK DATA T 
    !DEC$ ATTRIBUTES DLLEXPORT :: /X/
    COMMON /X/ C, B, A
    REAL C, B, A
    END

    The Fortran procedure to be linked into a DLL can contain a procedure, such as the following:

      SUBROUTINE SETA(I)
    !DEC$ ATTRIBUTES DLLEXPORT :: SETA, /X/
    COMMON /X/ C, B, A
    REAL C, B, A
    INTEGER I
    A = A + 1.
    I = I + 1
    WRITE (6,*) 'In SETA subroutine, values of A and I:' , A, I
    RETURN
    END SUBROUTINE
  2. Refer to the common block in the main program with !DEC$ ATTRIBUTES DLLIMPORT, followed by the local data declarations and any procedure declarations defined in the exported DLL. For example:

     PROGRAM COMMONX
    !DEC$ ATTRIBUTES DLLIMPORT:: SETA,  /X/
    COMMON /X/ C, B, A
    REAL C, B, A, Q
    EQUIVALENCE (A,Q)
    A = 0.
    I = 0
    WRITE (6,*) 'In Main program before calling SETA...'
    WRITE (6,*) 'values of A and I:' , A, I
    CALL SETA(I)
    WRITE (6,*) 'In Main program after calling SETA...'
    WRITE (6,*) 'values of A and I:' , Q, I     A 
     = A + 1.
    I = I + 1
    WRITE (6,*) 'In Main program after incrementing values'
    END PROGRAM COMMONX
  3. Build the DLL and then build the main program, as described in Building Dynamic-Link Libraries.

Exporting and Importing Data Objects in Modules

You can give data objects in a module the DLLEXPORT property, in which case the object is exported from a DLL.

When a module is used in other program units, through the USE statement, any objects in the module with the DLLEXPORT property are treated in the program using the module as if they were declared with the DLLIMPORT property. So, a main program that uses a module contained in a DLL has the correct import attributes for all objects exported from the DLL.

You can also give some objects in a module the DLLIMPORT property. Only procedure declarations in INTERFACE blocks and objects declared EXTERNAL or with cDEC$ ATTRIBUTES EXTERN can have the DLLIMPORT property. In this case, the objects are imported by any program unit using the module.

If you use a module that is part of a DLL and you use an object from that module that does not have the DLLEXPORT or DLLIMPORT property, the results are undefined.

For more information: