Declaring array arguments
Visual Basic array arguments must be declared as Safe Array handles passed by reference in your Fortran subroutines. Example 4.4 (Chapter 4), already discussed some of the basic considerations to write Fortran subroutines that can be called from Visual Basic and Visual Basic for Applications. In this section, you will see the compiler-specific changes that need to be done on Example 4.4 to make it into a DLL that can be used from Visual Basic.
After the discussion of changes necessary in the code of Example 4.4, this section will discuss another example (Example 5.2) in which you create a Fortran subroutine that handles arrays of string values created in Visual Basic.
Absoft Pro Fortran
Changes to MatrixProduct
To indicate that MatrixProduct should conform to the standard calling convention you need to add the qualifier STDCALL in front of the subroutine declaration.
After this change, the code for MatrixProduct should be as follows (changes appear in bold):
stdcall subroutine MatrixProduct(SAHndlA, SAHndlB, SAHndlR, iError)
is subroutine receives two arrays (SAHndlA and SAHndlB)
!multiplies them and returns the result in SAHndlR
!If the operation is successful, iError contains 0,
!otherwise it contains a negative value
use f90VBDefs
use f90VBSafeArrays
implicit none
!subroutine arguments
integer(SAFEARRAY_KIND),intent(in)::SAHndlA, SAHndlB
integer(SAFEARRAY_KIND),intent(inout)::SAHndlR
integer(SHORT_KIND),intent(inout)::iError
(the rest of the code stays the same)
end subroutine MatrixProduct
Compiling MatrixProduct
By default, Absoft Pro Fortran does not initialize declared variables. Un-initialized handles can have spurious values, which would be interpreted by Window's Safe Array services as addresses of allocated Safe Arrays. The initialization problem can be approached in two ways:
Explicitly initialize to zero all declared Safe Array handles: In MatrixProduct you can do this by adding the following statement at the beginning of the source code:
SAHndlR =0
Use the –s compiler switch, which forces the compiler to treat internal variables as static and initialized to zero.
For simplicity, you can use the second approach to compile MatrixProduct using the following command-line instruction:
f90 –c –s Example44.f90 -p "%f90VBAPFModDir%"
Which produces the object file Example44.obj. The –p compiler switch is used to indicate the path of the f90VB modules. This path is stored in environment variable f90VBAPFModDir, created when you installed f90VB.
Linking MatrixProduct
Absoft Pro Fortran will mangle the name of subroutines with the STDCALL qualifier. To solve this problem, you need to create an accessory file (Example44.als) for the linker containing aliases for the mangled names. In this case, the file contains a single line:
_MatrixProduct@16 MatrixProduct
This file is used later to tell the linker that subroutine _MatrixProduct@16 will be known externally as MatrixProduct.
You also need another file (Example44.xps) to indicate the name of the Fortran procedures that will be exported to the DLL. In this case, the exports file contains only one line:
MatrixProduct
Use the following command-line instruction to link the library:
lnk /dll Example44.obj /exports:Example44.xps /aliases:Example44.als absRT0.lib fmath.lib f90math.lib "%f90VBAPFLibDir%\f90VBSafeArrays.lib"
The /dll switch instructs Absoft's linker to create Example44.dll. The /exports switch loads the file with the list of procedures to export into Example44.dll. The /aliases switch loads the aliases file with the external name of the subroutine. Note that you link against the f90VBSafeArrays library. The path of this library is stored in environment variable f90VBAPFLibDir, which was created by the f90VB installation program.
Example44.dll and MatrixProduct are now ready to be called from your Visual Basic program.
Compaq (Digital) Visual Fortran
Changes to MatrixProduct
To indicate that MatrixProduct should conform to the standard calling convention, you need to add a DEC$ATTRIBUTE STDCALL compiler directive to the declaration of the subroutine:
!DEC$ATTRIBUTES STDCALL:: MatrixProduct
The STDCALL attribute also changes the default method used to pass arguments, so you need to tell the compiler that arguments to subroutine MatrixProduct are passed by reference. You can do this using the DEC$ATTRIBUTE REFERENCE directive:
!DEC$ATTRIBUTES REFERENCE:: SAHndlA, SAHndlB, SAHndlR, iError
To indicate that the subroutine must be exported to the DLL as a public procedure, you add the DEC$ATTRIBUTES DLLEXPORT compiler directive to the subroutine declaration:
!DEC$ATTRIBUTES DLLEXPORT:: MatrixProduct
Compaq Visual Fortran will mangle the name of subroutines with the STDCALL attribute. You can use another compiler directive to indicate an alias for the mangled name of the exported subroutine:
!DEC$ATTRIBUTES ALIAS: 'MatrixProduct'::MatrixProduct
The first argument is the alias (i.e. the name by which the subroutine would be available to external programs using the DLL), the second argument is the Fortran name of the subroutine.
After these changes, the code for MatrixProduct should be as follows (changes appear in bold):
subroutine MatrixProduct(SAHndlA, SAHndlB, SAHndlR, iError)
!This subroutine receives two arrays (SAHndlA and SAHndlB)
!multiplies them and returns the result in SAHndlR
!If the operation is successful, iError contains 0,
!otherwise it contains a negative value
!DEC$ATTRIBUTES STDCALL:: MatrixProduct
!DEC$ATTRIBUTES DLLEXPORT:: MatrixProduct
!DEC$ATTRIBUTES ALIAS: 'MatrixProduct':: MatrixProduct
!DEC$ATTRIBUTES REFERENCE:: SAHndlA, SAHndlB, SAHndlR, iError
use f90VBDefs
use f90VBSafeArrays
implicit none
!subroutine arguments
integer(SAFEARRAY_KIND),intent(in)::SAHndlA, SAHndlB
integer(SAFEARRAY_KIND),intent(inout)::SAHndlR
integer(SHORT_KIND),intent(inout)::iError
(the rest of the code stays the same)
end subroutine MatrixProduct
Compiling and Linking MatrixProduct
You can compile and link MatrixProduct in a single operation, using the following command-line instruction:
f90 Example44.f90 /dll /out:Example44.dll /module:"%f90VBDVFModDir%" "%f90VBDVFLibDir%\f90VBSafeArrays.lib"
The /dll switch instructs CVF's linker to create a dynamic link library whose name is provided by the /out switch. The /mod compiler switch is used to indicate the path of the f90VB modules. This path is stored in environment variable f90VBDVFModDir, created when you installed f90VB. Note that you link against the f90VBSafeArrays library. The path of this library is stored in environment variable f90VBDVFLibDir, also created by the f90VB installation program.
Example44.dll and MatrixProduct are now ready to be called from your Visual Basic program.
Lahey/Fujitsu Fortran 95
Changes to MatrixProduct
The only change you need to do to compile subroutine MatrixProduct with Lahey’s compiler is to add the DLL_EXPORT directive to indicate that the subroutine should be exported to a DLL. After this change, the code for MatrixProduct should be as follows (changes appear in bold):
subroutine MatrixProduct(SAHndlA, SAHndlB, SAHndlR, iError)
!This subroutine receives two arrays (SAHndlA and SAHndlB)
!multiplies them and returns the result in SAHndlR
!If the operation is successful, iError contains 0,
!otherwise it contains a negative value
use f90VBDefs
use f90VBSafeArrays
implicit none
DLL_EXPORT MatrixProduct
!subroutine arguments
integer(SAFEARRAY_KIND),intent(in)::SAHndlA, SAHndlB
integer(SAFEARRAY_KIND),intent(inout)::SAHndlR
integer(SHORT_KIND),intent(inout)::iError
(the rest of the code stays the same)
end subroutine
The compiler directive DLL_EXPORT also indicates the external name of the procedure, so the subroutine becomes publicly available with the name that follows DLL_EXPORT.
Compiling and Linking MatrixProduct
To compile MatrixProduct with Lahey/Fujitsu Fortran 95 you need to use the special switch –ml msvb to indicate to the compiler/linker the appropriate name-mangling and calling convention. The command
lf95 Example44.f90 -dll -win -ml msvb -mod "%f90VBLF95ModDir%" -lib "%f90VBLF95LibDir%\f90VBSafeArrays.lib"
creates Example44.dll containing subroutine MatrixProduct, which is ready to be called from Visual Basic. The -mod compiler switch is used to indicate the path of the f90VB modules. This path is stored in environment variable f90VBLF95ModDir, created when you installed f90VB. Note that you link against the f90VBSafeArrays library. The path of this library is stored in environment variable f90VBLF95LibDir, also created by the f90VB installation program.