Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
New Contributor II
1 View

Calling Fortran from VB with Type argument

I've been happily using a VB Type as an argument to a Fortran subroutine in a DLL.  This Type was made up of a number of Doubles.  I wanted to add a Boolean member (logical in the Fortran derived type), but the program was crashing (on the third call to the subroutine).  I concluded that VB Boolean isn't quite the same as Fortran logical, and changed to using a VB Long and Fortran integer.  To my surprise this also crashed.  In desperation I am now using a Double for the flag, with +1/-1 for true/false.  This works.  It appears that the VB Type is interoperable with a Fortran derived type only if all members are the same type.  I haven't seen this written anywhere - is it true?

0 Kudos
29 Replies
Highlighted
Black Belt
1 View

I suspect the issue is not

I suspect the issue is not what you describe. Can you provide a small test case?

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran
0 Kudos
Highlighted
New Contributor II
1 View

Hi Steve,

Hi Steve,

I have created a small test case.

I build metab-dll.dll 32-bit, and use 32-bit Excel.  If you have 64-bit Excel you'll need to build the DLL 64-bit and rename it as metab-dll64.dll.

The DLL subroutine mp_execute doesn't really do anything, so when you click the 'Solve metabolism' button in Excel mp_execute is called but leaves no trace.  If the Type member 'recalcable' is changed to Boolean and real(REAL_KIND) in the VB and the Fortran, the program crashes.

(By the way, I misdescribed the situation in my original post.  What I was observing, in the real program, was the crash occurred when the loop in mp_execute was traversed three times.)

Gib

0 Kudos
Highlighted
Black Belt
1 View

I can't reproduce an error.

I can't reproduce an error. With either double or boolean as the last member (and associated change made in the DLL), the DLL function runs to completion.

What is the "crash"? Do you know how to debug your DLL in this environment?

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran
0 Kudos
Highlighted
New Contributor II
1 View

Interesting.  I'm not very

Interesting.  I'm not very familiar with the debugger.  It's hard to see how this simple fragment of code could produce an error, but I'll remind you that I'm using a very old version of the compiler - 11.0.075 - on this machine.  It may have problem with VBA.

The crash is Excel stopping, as in the attached pic.  By the way, commenting out the line

mpArr(i) = metab
stops the crash, but commenting out the line above it does not.

Are you using the 32-bit or the 64-bit DLL?  Some time (since I'm pursuing this out of curiosity, not out of need) I'll test on my machine at work, where I have a more recent compiler that supports 64-bit compilation.

0 Kudos
Highlighted
Black Belt
1 View

I used a 32-bit DLL and the

I used a 32-bit DLL and the 19.0.5 compiler. Unfortunately your PNG omitted the details of the crash.

I don't recall issues with VBA calling Fortran in 11.0 - an Excel sample had been part of the product back into the DVF days.

Here's how to debug a DLL that is called by some non-Visual Studio language. In the DLL project properties, go to Debugging. Set "Command" to the full path to the executable (Excel.exe in this case.) For command arguments, give the path to your .xls file.

Set a breakpoint on the first executable statement in your DLL routine, and then press F5 to start debugging. You may want to go into the VBA debugger in Excel and step through it there, stepping into the DLL routine.

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran
0 Kudos
Highlighted
New Contributor II
1 View

Here are the crash details

Here are the crash details (might mean something to you):

Problem signature:
  Problem Event Name:    APPCRASH
  Application Name:    EXCEL.EXE
  Application Version:    14.0.4756.1000
  Application Timestamp:    4b9c08e8
  Fault Module Name:    StackHash_6798
  Fault Module Version:    6.1.7601.24520
  Fault Module Timestamp:    5d673df5
  Exception Code:    c0000374
  Exception Offset:    000ce9a3
  OS Version:    6.1.7601.2.1.0.256.48
  Locale ID:    1033
  Additional Information 1:    6798
  Additional Information 2:    6798a49cb55fcaa1deb02c15eb9ba081
  Additional Information 3:    ffe8
  Additional Information 4:    ffe877722da68f4c779c7ba0c0797622
 

0 Kudos
Highlighted
Black Belt
1 View

Gib, apart from all the

Gib, apart from all the issues that you and Steve have discussed, I see this problem with your Fortran subroutine in the test example: the local variable metab, which is a derived type, is used without having any value assigned to it.

I am not a user of Excel or VB; please check whether you need the SEQUENCE attribute for the derived type in order to make the VB actual argument and the Fortran dummy argument mpArr compatible.

0 Kudos
Highlighted
Valued Contributor II
1 View

The comment of mecej4 on

The comment of mecej4 on SEQUENCE is a good one. Having the type with BIND(C) would also achieve that.  In the VBA your derived type has DOUBLE items which are 8 byte but the BOOLEAN is 2 bytes it would seem!!!  I also note that: "In VBA, data elements in user-defined data types are packed to 4-byte boundaries". There seem quite a few potential pitfalls !

0 Kudos
Highlighted
Black Belt
1 View

Yes, that's an interesting

Yes, that's an interesting aspect that did not occur to me. While SEQUENCE isn't going to matter here, if VBA chooses a different length for the type than Fortran, the effect will be running off the end of the array and this could cause an access violation or other error. 

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran
0 Kudos
Highlighted
New Contributor II
1 View

Regarding the size of BOOLEAN

Regarding the size of BOOLEAN vs LOGICAL, which shows promise, note that the crash doesn't happen for Steve.  For me, the crash also happens with recalcable declared as integer, which is 4 bytes on the Fortran side, not sure about the VBA.  I will test declaring recalcable as logical(2) ...

that didn't help.

0 Kudos
Highlighted
Valued Contributor II
1 View

You maybe need to check the

You maybe need to check the size of the struct in VBA to see if it is different from the Fortran. There is the possibility of padding for example. 

0 Kudos
Highlighted
New Contributor II
1 View

The sizes of the struct in

The sizes of the struct in VBA and Fortran make it unclear how to proceed using Boolean and logical(2).

When recalcable is Double the sizes are the same, both 144 - 8 bytes per double, as expected.

When recalcable is Boolean and logical(2), the VBA size is 140, while the Fortran size is still 144.

In other words, in VBA 4 bytes are added for the 2 bytes of Boolean, implying 2 bytes of padding.  In Fortran 8 bytes are added for the 2 bytes of logical(2), implying 6 bytes of padding.  I'm not surprised by VBA making the length a multiple of 4, but I don't understand what Fortran is doing.

0 Kudos
Highlighted
New Contributor I
1 View

One solution is to copy the

One solution is to copy the VB type (you know its length) to an integer/real vector and pass the vector with its length to the DLL.

In Fortran you can do the reverse by copying the vector into a vector EQUIVALENCEd with a user type. 
So you can inspect each byte of storage.

In the end, and for any language, a variable has an address and a length. 

0 Kudos
Highlighted
Valued Contributor II
1 View

You could add a junk variable

You could add a junk variable  at the end  to pad in VB so the Fortran and vb have the same size.

You could also pass the size in your call so you can error check for  if something changes in the future. I would avoid doing anything with the obsolete EQUIVALENCE. 

 

0 Kudos
Highlighted
Valued Contributor II
1 View

Quote:gib wrote:.... but I

gib wrote:
.... but I don't understand what Fortran is doing.

The value of the /align compiler option will have a bearing on the matter.

0 Kudos
Highlighted
Black Belt
1 View

Gib, please post an Excel

Gib, please post an Excel file that invokes the DLL with meaningful values of the arguments, and modify the DLL source file such that all variables are defined before being used. As of now, the only input argument passed with a meaningful value is ng, and I can see that the value of ng is passed correctly. 

0 Kudos
Highlighted
Black Belt
1 View

I will also point out that

I will also point out that VBA Boolean isn't the same as Fortran LOGICAL - at least by default in Intel Fortran. It is more likely to be compatible if you use the /standard-semantics (Language > Assume F2003 Semantics) option.

Steve (aka "Doctor Fortran") - https://stevelionel.com/drfortran
0 Kudos
Highlighted
1 View

RE Boolian vs LOGICAL

RE Boolian vs LOGICAL

I would suggest NOT using either in inter-operational data. IOW use an agreed upon type that is inter-operational. e.g. integer or character (kind ASCII), and who's value (for true/false) is defined in the applications. VBA and Fortran can define compatible test/set/reset functions (and/or converter functions).

Jim Dempsey

0 Kudos