Module Module1 Declare Sub TestSSdll _ Lib "C:Documents and Settings . . . TestSSdll.dll" _ (ByVal Phi0 As Double, ByVal RLambda0 As Double, _ ByVal NWinTimStps As Long, ByVal gridfile As String, _ ByRef len_gridfile As Integer) End Module
Call TestSSdll(Phi0, RLambda0, NWinTimStps, _ gridfile, gridfile.Length)
subroutine TestSSdll (phi0, rlambda0, lgridfile, nWinTimStps, & gridfile, gridfile_lng) implicit none !DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: TestSSdll !DEC$ ATTRIBUTES ALIAS: "TestSSdll" :: TestSSdll !DEC$ ATTRIBUTES REFERENCE :: gridfile, gridfile_lng real(8), intent(in) :: phi0, rlambda0 integer(4), intent(in) :: gridfile_lng integer(8) :: nWinTimStps character(gridfile_lng), intent(in) :: gridfile open(unit=14,file=gridfile,status='old')
Link Copied
Okay, first of all a huge disclaimer; I did NOT try any of this, I just observed some things that were wrong.
First obvious thing - your routine signatures didn't match.
This is the VB code:
Call TestSSdll(Phi0, RLambda0, NWinTimStps, _ gridfile, gridfile.Length)
This is the Fortran code:
subroutine TestSSdll (phi0, rlambda0, lgridfile, nWinTimStps, & gridfile, gridfile_lng)
Before we even talk about the character string, please note that you have an extra "lgridfile"
in the Fortran signature.
That aside, Fortran passes the length of strings as a hidden argument, passed by value.
You explicitly listed "gridfile_lng" as the length. That is not necessary - the Fortran compiler
"knows" that length is there and generates code to deal with it.
So - remove lgridfile and gridfile_lng from your Fortran program. Make the declaration of gridfile
to be CHARACTER(*)
Back to the VB one - you need to make the fifth argument "pass by value".
I think this should work for you.
- Lorri
Thanks very much for your help, Lorri. I apologize for the extra argument -- I was piecing together an example with less arguments than my actual code and left too many in one statement. I believe I tried what you suggested:
Code:
VB module: Declare Sub TestSSdll _ Lib "C:Documents and Settings . . . TestSSdll.dll" _ (ByVal Phi0 As Double, ByVal RLambda0 As Double, _ ByVal NWinTimStps As Long, ByVal gridfile As String, _ ByVal len_gridfile As Integer) VB Call: Call TestSSdll(Phi0, RLambda0, NWinTimStps, gridfile, _ gridfile.Length) FORTRAN dll: subroutine TestSSdll (phi0, rlambda0, nWinTimStps, gridfile) implicit none !DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: TestSSdll !DEC$ ATTRIBUTES ALIAS: "TestSSdll" :: TestSSdll !DEC$ ATTRIBUTES REFERENCE :: gridfile real(8) :: phi0, rlambda0 integer(8) :: nWinTimStps character(*) :: gridfile open(unit=14,file=gridfile,status='old')
When building I get the following error referring to line 1 of the FORTRAN code:
Error: This passed length character name has been used in an invalid context. [GRIDFILE]
Also, I actually need to pass several (3 in this case) strings. Do you list the string lengths for every included string at the end of the argument list in the calling statement?Again, I'm using the compiler option to pass string length after all arguments.
Jugoslav, thanks for the help. It's quite possible I missed something or don't understand, but here's what I get:
- If you declare !DEC$ATTRIBUTES REFERENCE for a string argument, the length is not expected, nor should be passed. However, in that case, you have to hard-code the string length on Fortran side or determine it in other way (but it mustn't be a character(*)).
Code:
VB Module: Declare Sub TestSSdll _ Lib "C:Documents and Settings. . .TestSSdll.dll" _ (ByVal Phi0 As Double, ByVal RLambda0 As Double, _ ByVal NWinTimStps As Long, ByVal gridfile As String) (I tried both ByVal and ByRef for the string) VB Call: Call TestSSdll(Phi0, RLambda0, NWinTimStps, _ gridfile) FORTRAN: subroutine TestSSdll (phi0, rlambda0, nWinTimStps, gridfile) implicit none !DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: TestSSdll !DEC$ ATTRIBUTES ALIAS: "TestSSdll" :: TestSSdll !DEC$ ATTRIBUTES REFERENCE :: gridfilereal(8) :: phi0, rlambda0
integer(8) :: nWinTimStps
character(99) :: gridfile
open(unit=14,file=gridfile,status='old')
Result: gridfile value is incorrect (two symbols and two letters)
I'm not sure how this first method would work practically with VB.NET since, as I understand, fixed length strings are not allowed. I am passing file paths which would be variable lengths. Length of gridfile for this example is 99.
2nd Option:
- If you don't declare REFERENCE, you can use character(*) but you have to pass the length (by value) in the caller for every string argument you have.
Code:
VB Module: Declare Sub TestSSdll _ Lib "C:Documents and Settings. . . TestSSdll.dll" _ (ByVal Phi0 As Double, ByVal RLambda0 As Double, _ ByVal NWinTimStps As Long, ByVal gridfile As String, _ ByVal len_gridfile As Integer) VB Call: Call TestSSdll(Phi0, RLambda0, NWinTimStps, _ gridfile, gridfile.Length) FORTRAN: subroutine TestSSdll (phi0, rlambda0, nWinTimStps, gridfile) implicit none !DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: TestSSdll !DEC$ ATTRIBUTES ALIAS: "TestSSdll" :: TestSSdll real(8) :: phi0, rlambda0 integer(8) :: nWinTimStps character(*) :: gridfile open(unit=14,file=gridfile,status='old')
Result: gridfile value in the watch window is listed as Invalid Debug Information
Did I miss something or misunderstand?
David Coggin
ByVal gridfile As Stringis not the correct declaration for a plain vanilla array of character(1), but I don't know which one is right. I'm sure someone else could help.
Module Module1
Declare Sub TestSSdll _
Lib "C:Documents and Settings . . . TestSSdll.dll" _
(ByRef Phi0 As Double, ByRef RLambda0 As Double, _
ByRef NWinTimStps As Long, ByVal gridfile As String, _
ByVal len_gridfile As Integer)
End Module
subroutine TestSSdll (phi0, rlambda0, lgridfile, nWinTimStps, &
gridfile)
implicit none
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE :: TestSSdll
!DEC$ ATTRIBUTES ALIAS: "TestSSdll" :: TestSSdll
real(8), intent(in) :: phi0, rlambda0
integer(8) :: nWinTimStps
character(*), intent(in) :: gridfile
subroutine TestSSdll (phi0, rlambda0, lgridfile, nWinTimStps, &
gridfile,gridfile_lng)
implicit none
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE :: TestSSdll
!DEC$ ATTRIBUTES ALIAS: "TestSSdll" :: TestSSdll
real(8), intent(in) :: phi0, rlambda0
integer(8) :: nWinTimStps
integer(4), intent(in) :: gridfile_lng
character(gridfile_lng), intent(in) :: gridfile
If I delete all other arguments, I get the exact same results. I'm not sure how to use the LOC but the call stack window shows (gridfile=).When I have the longer list of arguments, theother parameters indicate correct values in the call stack and watch windows. Thanks again.
David
subroutine StrTest(s)still gets mangled as _strtest@8, meaning that you can pass only characters shorter than 4 bytes (if at all).
!DEC$ATTRIBUTES STDCALL:: StrTest
character(10) s
For more complete information about compiler optimizations, see our Optimization Notice.