Hello,
I'm trying to modify the Safearray example for passing multi-dimensional string arrays from VB.Net to Fortran. I want to be able to pass large REAL*8 arrays using Safearray. I have a program that exceeds the stack storage to due large array sizes and I want to pass them using Safearrays. I modified the example but I can't seem to get SafeArrayGetElement statement to retrieve values from the passed in array. The code below shows the VB calling routine with the FORTRAN routine below. SafeArrayGetElement returns 0 for the array index provided. I intend to use a pointer to CurElem to get the value and work on it.
Any help would be appreciated.
Imports System.Runtime.InteropServices ' Required for using MarshalAs Public Class Form1' Declare the Fortran routine. The name of the routine is case-sensitive' and the path to the DLL is explicit. When run from Visual Studio, the DLL' is looked for in the BIN subfolder of the VB.NET project'' By default, VB.NET would simply pass the data to the DLL without any bounds' information (and no chance of rewriting the strings). So we use the MarshalAs' attribute to tell it to pass a SafeArray. If you were passing numeric types,' you could just pass the data and access it as a normal array.' Private Declare Sub ForCall Lib "SafeArrayFORTRAN.dll" _ (<MarshalAs(UnmanagedType.SafeArray)> ByRef array1(,) As Double) Private myarray(2, 3) As Double Private Sub _cmdRun_Click(sender As Object, e As EventArgs) Handles _cmdRun.Click myarray(0, 0) = 12 myarray(0, 1) = 11 myarray(0, 2) = 10 myarray(0, 3) = 9 myarray(1, 0) = 8 myarray(1, 1) = 7 myarray(1, 2) = 6 myarray(1, 3) = 5 myarray(2, 0) = 4 myarray(2, 1) = 3 myarray(2, 2) = 2 myarray(2, 3) = 1 Call ForCall(myarray) End Sub End Class Subroutine ForCall(VBArray) !DEC$ ATTRIBUTES DLLEXPORT,REFERENCE,STDCALL::ForCall !DEC$ ATTRIBUTES ALIAS: 'ForCall'::ForCall !DEC$ ATTRIBUTES REFERENCE :: VBArray use ifcom ! Declare SafeArray and BSTR interfaces implicit none integer(int_ptr_kind()), intent(inout) :: VBArray !Pointer to a SafeArray structure INTEGER(INT_PTR_KIND()) :: ptrElem REAL*8,TARGET :: CurElem POINTER(ptrElem, CurElem) ! This says that ptrElem holds the address of CurElem. !> Array in which we will keep track of array bounds type bounds_type integer lb ! Lower Bound integer ub ! Upper Bound end type bounds_type !< integer nbounds ! Number of bounds type(bounds_type), allocatable :: bounds(:) integer, allocatable :: indexes(:) ! Array to hold current element indexes integer :: i, j, iRes nbounds = SafeArrayGetDim (VBArray) allocate (bounds(nbounds), indexes(nbounds)) do i=1,nbounds ires = SafeArrayGetLbound (VBArray, i, bounds(i)%lb) ires = SafeArrayGetUbound (VBArray, i, bounds(i)%ub) end do DO j=bounds(1)%lb,bounds(1)%ub DO i=bounds(2)%lb,bounds(2)%ub indexes(1)=i+1 indexes(2)=j+1 ires = SafeArrayGetElement (VBArray, indexes(1), loc(ptrElem)) !OUTPUT CurElem HERE end do end do deallocate (bounds) deallocate (indexes) return end subroutine ForCall