contents   index   previous   next



Passing Variants

 

Variant arguments can be passed by value or reference. When a Visual Basic program calls a procedure declared to receive a Variant by reference, the calling program passes a pointer to the Variant variable. If the procedure is declared to receive a Variant argument by value, then the calling program passes the complete Variant structure (sixteen bytes) in the stack. This is an important consideration, because not all Fortran compilers are able to handle arguments passed by value.

 

 

 

 

 

Example 4.5

 

In this example, you will create a Fortran function that computes the trigonometric sine of the provided argument. The argument can be of any type (i.e. an integer, a BString, etc.), except a Safe Array. The result of the function is also returned as a Variant containing a double precision value. Below is the listing of function SineX [23]:

 

function SineX(Value)

 

    !Compute the Sine of the argument in Variant VarVal

 

    !if Value contains a base type (VT_I4, VT_R8, etc.)

    !SineX returns the computed value in a variant of type

    !double precision. If an error occurs, the return

    !value of SineX is an empty variant

    !Note: Value can be a reference to a string,

    !in which case SineX attempts to cast the variant

    !into a numeric value. If the Value cannot be 

    !cast, SineX will return an empty variant

    !Note: This function cannot handle Safe Arrays

 

    use f90VBDefs

    use f90VBVariants

    implicit none

 

    !Function arguments

    type(VARIANT)::SineX

    type(VARIANT),intent(in)::Value

 

    !Internal variables

    type(VARIANT)::varTmp

    integer(HRESULT_KIND)::iRet

 

    !Initialize varTmp to an empty variant

    varTmp = VariantCreate(iRet)

 

    !Check that Value is not a Safe Array

    if (iand(Value%varVal%vt,VT_ARRAY).eq.0) then

    

        !cast the variant into a double precision real

        call VariantChangeType(Value, varTmp, VT_R8, iRet)

        !check for errors in the casting operation

        if (iRet.eq.0) then

            !compute the sine

            varTmp%varVal%dblVal = sin(varTmp%varVal%dblVal)

        endif

 

    endif

 

    !Set return values for the function

    SineX = varTmp

 

end function SineX

 

As you can see in the code above, function SineX returns a Variant of type VT_R8. The function also receives a single Variant argument, containing the value for which the sine function is to be computed. The first step of the function is to create an empty temporal variant (varTmp):

 

!Initialize varTmp to an empty variant
varTmp = VariantCreate(iRet)

 

The function then tests that the passed Variant argument (Value) does not contain a Safe Array, in which case it proceeds to cast the argument into a Variant containing a double precision real:

 

!cast the variant into a double precision real
call VariantChangeType(Value, varTmp, VT_R8, iRet)

 

If the casting is successful, then the function computes the sine of the cast Variant, which is later returned as the result of the function.

 

Using your Fortran compiler, you can export function SineX into Example45.dll. You may have to add some compiler-dependent directives to the function (see Chapter 5 for details on how to do this with the compiler you are using).

 

To call function SineX from Visual Basic or Visual Basic for Applications, you need to declare the function as an external procedure, and provide the location of the DLL file that contains the procedure. Start by creating a new Visual Basic project, and add a module file with the following declaration:

 

Declare Function SineX Lib "Example45.dll" (ByRef Value As Variant) As Variant

 

As in previous examples, we assume that Example45.dll and the Visual Basic executable reside in the same directory. You can now build a simple form that requests a value from the user and shows the result of the function (Figure 4.7).

 

The Visual Basic code associated to the form in Figure 4.7 is shown below:

 

Option Explicit

Private Sub cmdGo_Click()
    Text2.Text = SineX(Text1.Text)
End Sub

 

 

As you can see, the code is extremely simple. When you click the button cmdGo, the program calls SineX, passing as argument the contents of the text control Text1. The return value of SineX is placed directly into the text control Text2.

 

Creating Fortran Subroutines Callable From Visual Basic