Calling Visual Fortran from Visual Basic

When calling a Visual Fortran DLL from Visual Basic, important argument passing and data type considerations are:

This section discusses the following topics:

Declaring the Fortran Routine in Visual Basic

When you declare a Fortran routine in Basic the routine name is exported in exactly the same case as you declared it. Optionally, you can specify a directory path to the Fortran DLL in the declaration.

The following Visual Basic example declares a Fortran subroutine named FortranCall that takes two single-precision arguments:
 Declare Sub FortranCall Lib "d:\MyProjects\FCall.dll" (A1 as Single,
 						       A2 as Single)
The following example declares a Fortran function named FortranFunc that takes two integer (32-bit) arguments and returns a single precision value:
 Declare Function FortranFunc Lib "d:\MyProject\FFun.dll" (A1 as Long,
							 A2 as Long)
                                                         As Single

Exporting the Routine from the Fortran DLL

When you create the Fortran DLL, you need to add two additional attributes to the function or subroutine declaration so that it can be accessed from outside the DLL.

The Fortran routine name must be exported from the DLL, and it must be aliased to match exactly the name expected by Basic. The ATTRIBUTES (cDEC$ ATTRIBUTES compiler directive) and ALIAS declarations export the name and alias, as shown below for a Fortran subroutine:
     SUBROUTINE FortranCall
  !DEC$ ATTRIBUTES DLLEXPORT :: FortranCall             ! This exports the name
  !DEC$ ATTRIBUTES ALIAS : "FortranCall" :: FortranCall !This sets it

This is also true for Fortran functions, which must be exported and aliased to match exactly the name expected by Basic:
     REAL Function FortranFunc
  !DEC$ ATTRIBUTES DLLEXPORT :: FortranFunc
  !DEC$ ATTRIBUTES ALIAS : "FortranFunc" :: FortranFunc

Data Type Considerations

When you pass data between Visual Basic and Visual Fortran, you need to keep in mind the calling standard used by the two languages, the size of the data, and the on-disk format of the data.

The following table summaries the calling considerations for the data types:

Data Type Calling Considerations
Integer By default, both Visual Basic and Visual Fortran pass integers by reference. The default integer size in Basic is 2 bytes, equivalent to INTEGER(2) in Fortran. No extra action is required by either language to access integer arguments.
Floating point By default, both Visual Basic and Visual Fortran pass single- and double-precision floating point numbers by reference. The size of a single-precision floating point number is 4 bytes in both languages. The size of a double-precision floating point number is 8 bytes in both languages. No extra action is required by either language to access floating point arguments.
Logical By default, both Basic and Fortran pass logical data by reference. The default logical size in Basic is two bytes, equivalent to LOGICAL(2) in Fortran. No extra action is required by either language to access logical arguments.
Strings By default, Basic passes strings in a structure called a BSTR. By default, Fortran passes strings in two arguments: the string's address and a hidden argument containing the string's length. These defaults can be easily overridden by making changes in the Basic declaration, and sometimes in the Fortran declaration too.

Whenever you pass a string from Basic to Fortran, the passing mechanism should be declared as ByVal. See the String Passing Examples.

Arrays By default, Basic arrays are 0-based. Fortran arrays are 1-based by default. When you declare a Basic array to be of size n, n+1 elements are allocated, including the 0th element. This can be overridden, as show in the Array Passing Examples.

To pass arrays of numbers from Basic to Fortran, whether they are integer or floating-point numbers, pass the first element. In the Fortran code declare the argument to be an array. Usually the Basic code will pass the number of elements in the array.

To pass arrays of strings or types from Basic to Fortran requires the use of COM utilities to read the structures created by Basic. The arrays are passed as is from Basic, and then extracted in the Fortran code using SafeArrayxx utilities. For more detail, please refer to the Visual Fortran Samples found in the MixLang\VB\arrays and MixLang\VB\typearrays folders.

Types Basic-declared types can be passed from Basic to Fortran. The Basic-declared type will also have to be declared in Fortran; care should be taken to keep the two structures the same. In Fortran, the TYPE should be declared to be packed, usually PACK:2. You should be aware of the default sizes of the TYPE elements in the two languages, and adjust the defaults accordingly.

Note that strings in Basic-declared types are stored as Unicode, which can be declared in Fortran as an array of Integer*2. To access these strings from Fortran, use the Natural Language System (NLS) API calls. For information, see Using National Language Support Routines and the Visual Fortran Samples found in the MixLang\VB\typearrays folder.

String Passing Examples

The following example shows passing strings using the usual case, where the string will have varying length, and the length must also be passed to Fortran ByVal:

Visual Basic code:

  Declare Sub FortString1 Lib "forttest" (ByVal S1 as String,
					  ByVal L1 as Long)
  Dim S1 as String * 12
  Call FortString1(S1, Len(S1))

Visual Fortran code:

  Subroutine FortString1 (mystring)
  !DEC$ ATTRIBUTES DLLEXPORT, ALIAS : "FortString1" :: FortString1
  CHARACTER*(*) mystring

The following example shows shows passing strings where the length of the string will be constant and known by both the Basic and Fortran code, so you do not need to pass the length to Fortran, but you need to tell Fortran not to expect its length:

Visual Basic code:

  Declare Sub FortString2 Lib "forttest" (ByVal S2 as String)
  Dim S2 as String * 25

Visual Fortran code:

  Subroutine FortString2 (mystring)
  !DEC$ ATTRIBUTES DLLEXPORT, ALIAS : "FortString2" :: FortString2
  !DEC$ ATTRIBUTES REFERENCE :: mystring
  CHARACTER*25 mystring

Array Passing Examples

The following example shows shows passing arrays:

Visual Basic code:

 Basic declaration:
    Declare Sub FortArray1 Lib "forttest" (A1 as Long, NumElem as long)
    Dim A1(1:3) as Long
    Call FortArray1(A1(1), 3)

Visual Fortran code:

 Subroutine FortArray1 (Array1, N)
    !DEC$ ATTRIBUTES DLLEXPORT, ALIAS : "FortArray1" :: FortArray1
    Integer array1(N)