Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28367 Discussions

Calling Fortran from VB with Type argument

gib
New Contributor II
1,363 Views

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
Steve_Lionel
Honored Contributor III
963 Views

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

0 Kudos
gib
New Contributor II
963 Views

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
Steve_Lionel
Honored Contributor III
963 Views

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?

0 Kudos
gib
New Contributor II
963 Views

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
Steve_Lionel
Honored Contributor III
963 Views

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.

0 Kudos
gib
New Contributor II
963 Views

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
mecej4
Honored Contributor III
963 Views

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
andrew_4619
Honored Contributor II
963 Views

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
Steve_Lionel
Honored Contributor III
963 Views

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. 

0 Kudos
gib
New Contributor II
963 Views

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
andrew_4619
Honored Contributor II
963 Views

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
gib
New Contributor II
963 Views

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
LRaim
New Contributor I
963 Views

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
andrew_4619
Honored Contributor II
963 Views

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
andrew_4619
Honored Contributor II
963 Views

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
mecej4
Honored Contributor III
963 Views

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
Steve_Lionel
Honored Contributor III
963 Views

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.

0 Kudos
jimdempseyatthecove
Honored Contributor III
963 Views

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
gib
New Contributor II
898 Views

@Steve But the program doesn't fail for you.  How is that?

@Jim That's why I am using Double/real(8) in my real program (integer also causes a crash).  I'm pursuing this issue out of interest - it might crop up again in a different context.

@mecej4 The real program where I first observed this behaviour passes values.  It doesn't make any difference whether or not the passed array C is initialised, or if the returned array mp is given values.  It is clear by now that the problem is at least the result of the different sizes given to the elements in the Types, and the difference between VBA Boolean and Fortran logical may also be a problem.

@Andrew I'll try adding a dummy variable to pad the Types to the same length, but without much confidence.

0 Kudos
Reply