- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello, dear fellow developers!
Well, I have kind of a weird problem. I have a Module in FORTRAN with several subroutines, some of which are called from a Main and others that are called from other subroutines within the module. That worked really fine (amazing, I would say :) ). But I transformed my main into a subroutine and complied the project into a .dll so that I could call it from an Excel VBA macro... There isn't any problem with this part, until a subroutine calls another subroutine. More or less, the subroutines are:
SUBROUTINE FirstOne(VarX, VarY)
REAL(DP), INTENT(IN), DIMENSION(:) :: VarX
REAL(DP) :: Var1[ALLOCATABLE](:),Var2[ALLOCATABLE](:)
REAL(DP) ::Var3[ALLOCATABLE](:)
INTEGER (KIND(1)) :: i
ALLOCATE (VAR1(N), STAT=R)
IF(R.NE.0) CALL some-other-subroutine
ALLOCATE (VAR2(N) , STAT=R)
IF(R.NE.0) CALL some-other-subroutine
ALLOCATE (VAR3(N) , STAT=IERROR)
IF(IERROR.NE.0) CALL some-other-subroutine
!N is a global variable in the module, that indicates the length of the arrays troughout the program
DO i=1,NC
Var1(i)=0.D0
Var2(i)=0.D0
Var3(i)=0.D0
END DO
CALL SecondOne(Var1,Var2,Var3)
DEALLOCATE(Var1 , STAT=R)
IF(R.NE.0) CALL some-other-subroutine
DEALLOCATE(Var2 , STAT=R)
IF(R.NE.0) CALL some-other-subroutine
DEALLOCATE(Var3 , STAT=R)
IF(R.NE.0) CALL some-other-subroutine
RETURN
END SUBROUTINE
SUBROUTINE SecondOne(Var1,Var2,Var3)
REAL (DP), INTENT(OUT), DIMENSION(:) :: Var1,Var2,Var3
DO i=1,N
Var1(i)=Some Arithmetic Operation <-----------------------Here is the problem... allegedly
Var2(i)=Some Arithmetic Operation
Var3(i)=Some Arithmetic Operation
END DO
RETURN
END SUBROUTINE
And then I get "fortl: severe(408): fort: (2): Subscript #1 of the array Var1 has value 1 which is greater than the upper bound of 0"
I already tried writing Intent(inout), changing to dimension(N), transferring to other variables (Var12, Var22, Var32) and several combinations. As far as I know, I can't make it allocatable, but I'm not sure wether it's going to solve my problem
Please, my friends... Any suggestions? It worked before I linked it to Excel VBA
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's always a risk when we don't see the whole code, or worse, paraphrases and snippets of code. Two things come to mind. First, I don't see that the caller of SecondOne has a visible external interface to SecondOne. This is required because of the DIMENSION(:). If these two subroutines are together in a module, then that is sufficient, otherwise you need to add an interface (ideally by putting the routine in a module and USEing the module, or putting them together in a module.
Second, when calling from VBA, you need to have !DEC$ ATTRIBUTES STDCALL for the routine called from VBA. For example:
!DEC$ ATTRIBUTES STDCALL,REFERENCE,ALIAS:"FirstOne" :: FirstOne
This assumes you declare the routine as "FirstOne" exactly like that in VBA. However you spell it in VBA is exactly what you should put in the ALIAS value. Of course, it's obvious here that FIrstOne is not the one you're calling from VBA, since it also has a DIMENSION(:) argument and that can't be used from VBA, but you should get the idea.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks a lot, Steve.
Yes. What I do, is calling from VBA a subroutine "Commander" from a .f90 file, which USEs the module in which i have the FirstOne and the SecondOne (the module is in another .f90 file).
"Commander" does have the
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, DECORATE :: Commander
!DEC$ ATTRIBUTES REFERENCE :: Some Set of dummy variables that are not used in the module but are used in some logic operations.
Actually the variable that isn't working is declared within the module and is a local variable that is used only in the module in order to give some other return variables in VBA.
----
Maybe I forgot to say that the references I send to FORTRAN from VBA are actually getting in. I did some simple operation and I get a return value. When I proved the subroutine is working, I called the subroutine from the module... That worked fine too. But everything fails as soon as the first routine calls the second routine within the module. Then FORTRAN doesn't know or doesn't want to know the length of the array I'm working with. And if I give explicitly Dimension(N), my computer freezes and I have to reboot Excel.
Thanks in advance
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
With only paraphrased snippets, I don't think there's more we can tell you. Probably the next step I'd take is to run this in the debugger. For a DLL project the way you do this is set the property Debugging > Command to be the path to Excel.exe. Make sure that Excel is loading your Debug configuration DLL. Set a breakpoint in Commander in your DLL and then start execution. When Excel calls your DLL, the debugger will break in and you can step through it.
Sometimes, odd errors like this are due to stack corruption, which is why I mentioned STDCALL, but you say you have that covered. The next thing I can suggest is to start cutting out pieces of the Fortran code until you get the minimum that shows the problem. If cutting out something else makes the problem go away, look at that more closely.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
you may want to look at these code snippets and compare them with yours (and a couple of other posts I have made, including an example to download):
-------------------------------------
I think in VBA, ByRef is assumed as default, and is not required. In VB, however, it is (just to make life more interesting).
To allow for the different versions of Excel, I need to now use declarations like this one. The VBA7 section is for Excel 2010 - it needs the addition of the PtrSafe keyword.
#If VBA7 Then
Private Declare PtrSafe Sub WaterDensity_F Lib "AWAProps.dll" _
(TempC As Double, Value As Double, ByVal Units As String)
#Else
Private Declare Sub WaterDensity_F Lib "AWAProps.dll" _
(TempC As Double, Value As Double, ByVal Units As String)
#End If
on the Fortran Side, I have:
Subroutine WaterDensity_F(TempC, Value, Units)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS:'WaterDensity_F' :: WaterDensity_F
!DEC$ ATTRIBUTES REFERENCE :: Units
Hope this is helpful. (note the apparent inconsistency in keywords for passing back strings - on the VB side ByVal vs using the Reference attribute on the Fortran side)
David
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page