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?
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.)
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?
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.
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.
Here are the crash details (might mean something to you):
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
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.
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 !
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.
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.
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.
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.
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.
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.
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.
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).