- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I need to pass an array of strings from VB to FORTRAN (but not back). I have perused the supplied example of using safearrays to do this but wondered if, in my case, there is an easier way. Since I am doing the code on both sides of the call, I can use fixed length strings and I know the dimensions of thearray (1) and its bounds. In this case is there an easier way than using the full mechanism of safearrays as shown in the example project.
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
I have someexperienceswith C# we had to use an array of integers that every elements of this array show number ofcharacters in string. I think it is also possible in VB.
Subroutine Initialize(IntOfText, nChar, IntOfTextDLL, nCharDLL)
! Expose Subroutine Initialize to users of this DLL
!DEC$ If DEFINED (_DLL)
!DEC$ ATTRIBUTES DLLEXPORT::Initialize
!DEC$ End If
INTEGER(4),INTENT(in) :: nChar , nCharDLL
INTEGER(2),INTENT(in) :: IntOfText(1024) , IntOfTextDLL(1024)
Character*1024 :: prjPath , DLLPath
integer :: nPath , nDLLPath
DLLPath = '' ; nDLLPath = 0
PrjPath = '' ; nPath = 0
CALL FindPath(nChar,INTOFTEXT,PrjPath,nPath, *999)
CALL FindPath(nCharDLL,IntOfTextDLL,DLLPath,nDLLPath, *999)
.
.
.
SUBROUTINE FindPath(nChar,INTOFTEXT,prjPath,nPath, *)
CHARACTER*1024 :: prjPath
INTEGER(4) :: nChar
INTEGER(2) :: INTOFTEXT(1024)
LOGICAL(1) :: isTextToInt
DO i0 = nChar , 1 , -1
IF (CHAR(INTOFTEXT(i0)) == '') Exit
END DO
nPath =i0
DO i=1 , nPath
prjPath(i:i) = CHAR(INTOFTEXT(i))
END DO
prjPath = TRIM(prjPath)
RETURN
999 RETURN 1 ! RETURN Error
END
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sorry, but I don't think that thissolves my problem. As I understand it, what you have is an array of characters, i.e. a string, and not an array of strings. What you are doing in your program is pretty easy in VB, its when you want to pass an array of string that things get complicated.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here is a way to do it.
Create a VB .NET executable containing a form (Form1) with a single button, Button1. Add the following code:
Imports System.Runtime.InteropServices
Public Class Form1
Private Declare Sub PASSSTRINGSTOFORTRAN Lib "c:\YOURPATHGOESHERE\test_VBstrings.dll" _
(ByRef nelements As Long, ByVal str() As String)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim STRARRAY(0 To 9) As String
Dim str As System.String
Dim nelements As Long
str = "This is string 1 "
STRARRAY(0) = str
STRARRAY(1) = "This is string 2 "
STRARRAY(2) = "This is string 3 "
STRARRAY(3) = "This is string 4 "
STRARRAY(4) = "This is string 5 "
STRARRAY(5) = "This is string 6 "
STRARRAY(6) = "This is string 7 "
STRARRAY(7) = "This is string 8 "
STRARRAY(8) = "This is string 9 "
STRARRAY(9) = "This is string 10"
nelements = 10
MsgBox("Passing string array...", MsgBoxStyle.OkOnly, "Button clicked")
PASSSTRINGSTOFORTRAN(nelements, STRARRAY)
End Sub
End Class
Note the UPPERCASE symbol PASSSTRINGSTOFORTRAN.
The above assumes Fortran code exists in a DLL called 'test_VBstrings.dll'.
Create a Fortran DLL project and add this code:
! test_vbstrings.f90
!
! FUNCTIONS/SUBROUTINES exported from test_vbstrings.dll:
! PassStringsToFortran - subroutine called from VB .NET to pass a
! Safearray of strings
!
subroutine PassStringsToFortran(nelements, ptr_Array)
! Expose subroutine PassStringsToFortran to users of this DLL
!
!DEC$ ATTRIBUTES value::Ptr_Array
!DEC$ ATTRIBUTES DLLEXPORT::PassStringsToFortran
!(N.B. The symbol exported will be un UPPERCASE!)
USE OLEAUT32
USE DFNLS
USE DFWIN
! ptr_array is a pointer to a SafeArray of bit-strings
! nelements is the number of strings in the array
integer(4) ptr_array, nelements
! variables
integer(4) i,j, iret, mret
!
character(3) cj, ce
! define an array of 2-byte integers to receive the converted unicode string
integer(2) istring(18)
! define a character string to store the converted string (make sure it is long enough to store the longest
! string, similarly for the variable ISTRING )
character(18) string
POINTER(lptrstr, istring)
!
! Lock the pointer
ilock=SafeArrayLock( ptr_array)
if(ilock.eq.S_OK) then
!
! Get the array upper bound, store it in variable J
! (becuase we have access to the VB .NET code, we know it only has one dimension...modify accordingly if more than one)
!
iret=SafeArrayGetUbound(ptr_array,1,J)
! Upper bound should be one less than 'nelements'
write(cj,'(i3)') j
mret=MessageBox(0,"The SafeArray Upper bound = "//cj//char(0), &
"PassStringsToFortran"c,IOR(MB_TOPMOST,MB_OK) )
write(ce,'(i3)') nelements
mret=MessageBox(0,"The SafeArray contains "//ce//" strings"//char(0), &
"PassStringsToFortran"c,IOR(MB_TOPMOST,MB_OK) )
! Go through the Safe array elements, one by one
do i=1,nelements
! Recover the contents of i'th string (zero-based) as an integer array in ISTRING
jret=SafeArrayGetElement(ptr_array,i-1,Loc(lptrstr))
! Convert the recovered wide-character Unicode integers in ISTRING to an Ansi string
iret=MBConvertUnicodeToMB (istring, string )
! Display the recovered string
mret=MessageBox(0,string//char(0),"SafeArray strings from VB .NET"c,MB_OK)
end do
!
! Unlock the pointer
ilock=SafeArrayUnLock( ptr_array)
if(ilock.ne.S_OK) then
mret=MessageBox(0,"Failed to unlock SafeArray pointer"c,"SafeArrayUnLock"c,MB_OK)
endif
else
mret=MessageBox(0,"Failed to lock SafeArray pointer"c,"SafeArrayLock"c,MB_OK)
endif
return
end subroutine PassStringsToFortran
Hope this helps!
P.S. Note being a VB .NET expert, I did a google search using the string "VB .NET SAFEARRAY
"and got my main clue from here:
http://objectmix.com/dotnet/102931-safearray-returned-vc6-interface-object-vb-net.html
P.P.S. If you want to ensure that you make your string buffers large enough to cope with unknown length Bit-strings, utilize the fact that the BSTR wide character string is preceded in memory by its length as an integer occupying 4 bytes, retrieve that length then allocate the appropriate buffer size(s) to cope. e.g.
integer(4) lstring
...
! Point to the string length buffer LSTRING and to the string buffer ISTRING
POINTER(lptrstr, istring)
POINTER(lptrstr4, lstring)
...
! Recover the contents of i'th string (zero-based) as an integer array in ISTRING
jret=SafeArrayGetElement(ptr_array,i-1,Loc(lptrstr))
! set a pointer 4 bytes earlier in memory to access the string length
lptrstr4=lptrstr-4
write(ce,'(i3)') lstring
if(SIZEOF(istring).gt. lstring) then
mret=MessageBox(0,"The string size = "//ce//" is < or = to the 36-byte buffer"//char(0),&
"PassStringsToFortran"c,IOR(MB_TOPMOST,MB_OK) )
......
etc.
Create a VB .NET executable containing a form (Form1) with a single button, Button1. Add the following code:
Imports System.Runtime.InteropServices
Public Class Form1
Private Declare Sub PASSSTRINGSTOFORTRAN Lib "c:\YOURPATHGOESHERE\test_VBstrings.dll" _
(ByRef nelements As Long,
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim STRARRAY(0 To 9) As String
Dim str As System.String
Dim nelements As Long
str = "This is string 1 "
STRARRAY(0) = str
STRARRAY(1) = "This is string 2 "
STRARRAY(2) = "This is string 3 "
STRARRAY(3) = "This is string 4 "
STRARRAY(4) = "This is string 5 "
STRARRAY(5) = "This is string 6 "
STRARRAY(6) = "This is string 7 "
STRARRAY(7) = "This is string 8 "
STRARRAY(8) = "This is string 9 "
STRARRAY(9) = "This is string 10"
nelements = 10
MsgBox("Passing string array...", MsgBoxStyle.OkOnly, "Button clicked")
PASSSTRINGSTOFORTRAN(nelements, STRARRAY)
End Sub
End Class
Note the UPPERCASE symbol PASSSTRINGSTOFORTRAN.
The above assumes Fortran code exists in a DLL called 'test_VBstrings.dll'.
Create a Fortran DLL project and add this code:
! test_vbstrings.f90
!
! FUNCTIONS/SUBROUTINES exported from test_vbstrings.dll:
! PassStringsToFortran - subroutine called from VB .NET to pass a
! Safearray of strings
!
subroutine PassStringsToFortran(nelements, ptr_Array)
! Expose subroutine PassStringsToFortran to users of this DLL
!
!DEC$ ATTRIBUTES value::Ptr_Array
!DEC$ ATTRIBUTES DLLEXPORT::PassStringsToFortran
!(N.B. The symbol exported will be un UPPERCASE!)
USE OLEAUT32
USE DFNLS
USE DFWIN
! ptr_array is a pointer to a SafeArray of bit-strings
! nelements is the number of strings in the array
integer(4) ptr_array, nelements
! variables
integer(4) i,j, iret, mret
!
character(3) cj, ce
! define an array of 2-byte integers to receive the converted unicode string
integer(2) istring(18)
! define a character string to store the converted string (make sure it is long enough to store the longest
! string, similarly for the variable ISTRING )
character(18) string
POINTER(lptrstr, istring)
!
! Lock the pointer
ilock=SafeArrayLock( ptr_array)
if(ilock.eq.S_OK) then
!
! Get the array upper bound, store it in variable J
! (becuase we have access to the VB .NET code, we know it only has one dimension...modify accordingly if more than one)
!
iret=SafeArrayGetUbound(ptr_array,1,J)
! Upper bound should be one less than 'nelements'
write(cj,'(i3)') j
mret=MessageBox(0,"The SafeArray Upper bound = "//cj//char(0), &
"PassStringsToFortran"c,IOR(MB_TOPMOST,MB_OK) )
write(ce,'(i3)') nelements
mret=MessageBox(0,"The SafeArray contains "//ce//" strings"//char(0), &
"PassStringsToFortran"c,IOR(MB_TOPMOST,MB_OK) )
! Go through the Safe array elements, one by one
do i=1,nelements
! Recover the contents of i'th string (zero-based) as an integer array in ISTRING
jret=SafeArrayGetElement(ptr_array,i-1,Loc(lptrstr))
! Convert the recovered wide-character Unicode integers in ISTRING to an Ansi string
iret=MBConvertUnicodeToMB (istring, string )
! Display the recovered string
mret=MessageBox(0,string//char(0),"SafeArray strings from VB .NET"c,MB_OK)
end do
!
! Unlock the pointer
ilock=SafeArrayUnLock( ptr_array)
if(ilock.ne.S_OK) then
mret=MessageBox(0,"Failed to unlock SafeArray pointer"c,"SafeArrayUnLock"c,MB_OK)
endif
else
mret=MessageBox(0,"Failed to lock SafeArray pointer"c,"SafeArrayLock"c,MB_OK)
endif
return
end subroutine PassStringsToFortran
Hope this helps!
P.S. Note being a VB .NET expert, I did a google search using the string "VB .NET SAFEARRAY
"and got my main clue from here:
http://objectmix.com/dotnet/102931-safearray-returned-vc6-interface-object-vb-net.html
P.P.S. If you want to ensure that you make your string buffers large enough to cope with unknown length Bit-strings, utilize the fact that the BSTR wide character string is preceded in memory by its length as an integer occupying 4 bytes, retrieve that length then allocate the appropriate buffer size(s) to cope. e.g.
integer(4) lstring
...
! Point to the string length buffer LSTRING and to the string buffer ISTRING
POINTER(lptrstr, istring)
POINTER(lptrstr4, lstring)
...
! Recover the contents of i'th string (zero-based) as an integer array in ISTRING
jret=SafeArrayGetElement(ptr_array,i-1,Loc(lptrstr))
! set a pointer 4 bytes earlier in memory to access the string length
lptrstr4=lptrstr-4
write(ce,'(i3)') lstring
if(SIZEOF(istring).gt. lstring) then
mret=MessageBox(0,"The string size = "//ce//" is < or = to the 36-byte buffer"//char(0),&
"PassStringsToFortran"c,IOR(MB_TOPMOST,MB_OK) )
......
etc.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The "VB.NET-Safearrays" sample provided by the compiler illustrates use of these features.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, the solution presented above is basically the same as that shown in the included example from the installation, just specific to a one dimensional array. I would not call this a "simple" method, I mean its not like passing an array of anything numeric, which is trivial by comparison. But if this is the only way then I guess thats the answer.
I did find one really easy method that is a total cludge, but it works. Just write a file from VB and then read it back in with FORTRAN. A couple lines of code on each side of the mixed language subroutine call, no "use" files or system calls.
I did find one really easy method that is a total cludge, but it works. Just write a file from VB and then read it back in with FORTRAN. A couple lines of code on each side of the mixed language subroutine call, no "use" files or system calls.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
When building the Fortran project for this example I get 2 unresolved externals (MBCONVERTMBTOUNICODE and MBCONVERTUNICODETOMB). It appears there is another libraay I need to link to.
I am working on a 64-bit machine with XP x-64 sp2 using VB9 with IVF 12.0 on IA-32.
Mike
When building the Fortran project for this example I get 2 unresolved externals (MBCONVERTMBTOUNICODE and MBCONVERTUNICODETOMB). It appears there is another libraay I need to link to.
I am working on a 64-bit machine with XP x-64 sp2 using VB9 with IVF 12.0 on IA-32.
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
When building the Fortran project for this example I get 2 unresolved externals (MBCONVERTMBTOUNICODE and MBCONVERTUNICODETOMB). It appears there is another libraay I need to link to.
I am working on a 64-bit machine with XP x-64 sp2 using VB9 with IVF 12.0 on IA-32.
Mike
When building the Fortran project for this example I get 2 unresolved externals (MBCONVERTMBTOUNICODE and MBCONVERTUNICODETOMB). It appears there is another libraay I need to link to.
I am working on a 64-bit machine with XP x-64 sp2 using VB9 with IVF 12.0 on IA-32.
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
These are defined in the "Portability Library", libifport.lib, which is linked in by default. Did you disable linking the portability library?
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page