- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
vb form code:
Call TestSSdll(Phi0, RLambda0, NWinTimStps, _ gridfile, gridfile.Length)
fortran dll code:Code:
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')
I have tried passing the strings by value and reference. With the current configuration above, the fortran code does not seem to recognize the string "gridfile" as a string.When added to the Watch window, the value for gridfile shows "Invalid Debug Information". I am able to successfully pass integers and real variables. I currently have the compiler option set to pass string length after all arguments (although I have tried both). I would appreciate any help.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- 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(*)).
- 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.
HTH,
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm not familiar with VB.NET enough; offhand, it seems that
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.
In the meantime, I'd check LOC(gridfile) in the debugger and take a look at what's in Memory window around it (on VB side too).
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What happens if you delete other arguments, leaving only gridfile in the argument-list?
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
On the VB side, the string gets declared as "ByVal stringname as string". You also need to add the string length to the end of the argument list as "ByVal stringlen as Integer". I also changed the numeric args to ByRef, especially as one of them is written. For example:
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
You will need to pass the length of the string explicitly using this arrangement.
On the Fortran side, the routine needs to have the STDCALL and REFERENCE attributes, the string argument should not have the REFERENCE attribute, assuming you want the length passed. For example:
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
Note that the string length is not explicitly specified in the Fortran, as the compiler will look for it, passed by value.
An alternative which I tested that works is to have the length passed from VB ByRef, and having the Fortran look like this:
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
See how this works for you. The key seems to be the REFERENCE on the routine, as otherwise you get VALUE by default and for character arguments that is a bit strange. I tried just REFERENCE on the character arg and that didn't work - not sure why.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My Lord! I could have sworn that VF never does that, i.e. that characters are always passed by reference (with or without length), and I was about to argue your statement above. However, when I did some checking on both CVF and IVF, I verified that you're right...
I'm not sure why that semantics was adopted, i.e. I don't see why would anyone ever wanted to pass a string by value; besides, the name of
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
I beg for a change; I don't see how can this ever be useful (and if needed user can still spell out VALUE attrigute), and it obviously leads to problems such as David's.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'll take a look at the decoration issue.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page