- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello, I've been tasked with coming up with a way to expose some Fortran subroutines in a dll to both other Fortran projects and COM.
First of all: I do not know Fortran. You may wonder about the wisdom of choosing me to accomplish this task - I know I do ;) It is what it is!
I've spent considerable time researching this and I think it's time to ask for some direct help. Thesubroutines are:
sub1(real8a, real8b, char256c, char80d)
sub2 has 19 real(8) parameters
sub3 has 22 real(8) parameters
Here's what I've tried so far:
Put DLLExport statements in the dllto expose the subroutines, and DLLIMPORT statements in the project.
Created a generic console app that calls into the dll, using the .lib file. Result: Unresolved external.
I've used the /gen-interfaces switch to get a whole mess o' .mod and f90 files. I've linked to those individual mod files. Result: corrupt file or can't open file.
It would seem that I just don't get what needs to be done. It seems so simple...
I'm sure that I've left out crucial bits of information - I'm sorry, I just don't know what to provide. I'm happy to add anything that you need!
Thanks in advance,
Mike
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mike,
It sounds like you need to expose your code as a COM Server. Then it can be called from Fortran or a multitude of other clients.
From what I've heard on this Forum the COM Server wizard should be making a return in Intel Visual Fortran 10.0 which is due in the next month. It was a very useful feature in CVF 6.6, that has been sorely missed. The COM Server wizard lets you easily build COM Servers in Fortran.
Also see the book "Developing Statistical Software in Fortran 95" by Lemmon & Schafer ISBN 0-387-23817-4.(which advocates and provides techniques for wrapping Fortran code as COM Servers).
http://methodology.psu.edu/newbooks/fortranbook/index.html
Peter P.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mbrengartner@pyrix.com:
Put DLLExport statements in the dllto expose the subroutines, and DLLIMPORT statements in the project.
I have a hunch that COM is a red herring here; as I get it, you want to call the Dll from a COM server written in another language, yes? If so, it shouldn't matter which language it is, as long as you correctly declare and call the dll routines.
For the start, download Dependency Walker and check if you're really exporting those routines properly (it's neat to have it associated with dll's by default). DLLIMPORT is not essential.mbrengartner@pyrix.com:
I've used the /gen-interfaces switch to get a whole mess o' .mod and f90 files. I've linked to those individual mod files. Result: corrupt file or can't open file.
Exactly. /gen-interfaces does not do what you think (it cross-checks the validity of calls within Fortran code if explicit interfaces are not provided). In addition, .mod files are not intended for the linker, but for compiler: they're sort of equivalent to C++ .pch (precompiled headers).
mbrengartner@pyrix.com:
I'm sure that I've left out crucial bits of information - I'm sorry, I just don't know what to provide. I'm happy to add anything that you need!
Exact wording of the linker error would be helpful; you can also post the DLL's .lib file so that we can examine it. Are you sure you're linking with it?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, this is great - thanks everybody! I'll try to address everyone's questions here. I think the COM part is working - I ran the COM export wizard, wich generated a module that I included in my dll. Now I can call out to that dll, and everything seems to work.
That function is declared as follows:
subroutine
eval(evalflag,itire,var1,Alpha,Gamma,SlipRatio,P, V,MuRoad,Fx,Fy, Fxc, Fyc, Mx, Mz, Fxbest, SRbest,Fybest,SAbest,KT,var2,Re) !DEC$ ATTRIBUTES DLLEXPORT :: eval !DEC$ ATTRIBUTES STDCALL, REFERENCE :: eval !DEC$ ATTRIBUTES REFERENCE :: evalflag,itire, var1,Alpha,Gamma,SlipRatio,P,V, MuRoad, Fx, Fy, Fxc, Fyc, Mx, Mz, Fxbest,SRbest,Fybest,SAbest,KT,var2,Re
Even thoughthis is marked as STDCALL, can I still call this from Fortran? Or, what do I need to do to call it from Fortran? Here's the sample project I've been using to test:
program
dllTest call testcontains
subroutine testimplicit
real(8) (a-z)iTire = 1
RL = 13.5
!inAlpha = 2
!degGamma = -1
!degSlipRatio = 0.08
!unitlessP = 0
!psiV = 150
!mphMuRoad = 1
!unitlessFZ = -2000
!lbdblFlag = 1
dblSlipAngle = 2.0
call eval (dblFlag, iTire, FZ, dblSlipAngle, Gamma, SlipRatio, P, V, MuRoad, Fx, Fy, Fxc, Fyc, Mx, Mz, Fxbest, SRbest, Fybest, SAbest, KT, RL, Re) end subroutineend
programIn VS2005, I've set Project Properties->Linker->Input->Additional Dependencies to the dll I'm trying to call (the one that has eval). I've copied the dll to the project path locally.
Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There are multiple ways to achieve such "explicit interface" but, long story short, you can write INTERFACE blocks for the dll routine and make sure they're visible in the calling routine(s) via declaration, INCLUDEing or USEing:
interface
subroutine eval(evalflag,itire,var1,Alpha,Gamma,SlipRatio,P, &
V, MuRoad, Fx, Fy, Fxc, Fyc, &
Mx, Mz, Fxbest, SRbest,Fybest,SAbest,KT,var2,Re)
!DEC$ ATTRIBUTES STDCALL, REFERENCE :: eval
end subroutine
end interface
(Btw, if none of the arguments is a CHARACTER(*), your longish second REFERENCE declaration is redundant, as the one with STDCALL implies it for all arguments).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, so does the interface go in the dll? or the calling program? And I thought the INCLUDE or USE function was to import .mod files?
I'll remove the other reference attribute; you're right, they're all real(8) variables.
Thanks again,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
INCLUDE performs just the text substitution (its argument is a file name); USE makes the compiler search and process the .mod file (which is binary), and its argument is the module name (which is the same as the .mod file name without .mod extension).
Alternatively, if you do have the .mod file coming from the dll compilation (by means of /gen-interfaces), you can skip writing the interface and USE that mod file. It's not exactly the method I would use, as it depends on the compiler settings for the dll, but it should work. (I'd prefer the third method, explicitly putting MODULE...CONTAINS...END MODULE around dll routines, and as result a proper .mod file will be always generated)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, so now I get "error LNK2019: unresolved external symbol _FRTTIRE_EVAL referenced in function _DLLTEST._TEST"
I did a depends on the dll, and got these two entries: frttire_eval and _frttire_eval@88, both with the same entry point. Do I need an alias in my interface like this:
!DEC$ ATTRIBUTES ALIAS : _frttire_eval@88 :: frttire_evalThanks!
program dllTest
call test
contains
subroutine testimplicit
real(8) (a-z)interface
subroutine frttire_eval(evalflag,itire,var1,Alpha,Gamma,SlipRatio,P, &V, MuRoad, Fx, Fy, Fxc, Fyc, &
Mx, Mz, Fxbest, SRbest,Fybest,SAbest,KT,var2,Re)
!DEC$ ATTRIBUTES STDCALL, REFERENCE :: frttire_eval end subroutineend interface
iTire = 1
RL = 13.5
!inAlpha = 2
!degGamma = -1
!degSlipRatio = 0.08
!unitlessP = 0
!psiV = 150
!mphMuRoad = 1
!unitlessFZ = -2000
!lbdblFlag = 1
dblSlipAngle = 2.0
call frttire_eval (dblFlag, iTire, FZ, dblSlipAngle, Gamma, SlipRatio, P, V, MuRoad, Fx, Fy, Fxc, Fyc, Mx, Mz, Fxbest, SRbest, Fybest, SAbest, KT, RL, Re) end subroutineend
program- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
error LNK2019: unresolved external symbol _frttire_eval@88 referenced in function _DLLTEST._test
note that the name decoration is correct and matches your dll export (and I get the link error because I don't have the dll library). I vaguely recall someone mentioned a VF bug regarding STDCALL, REFERENCE, but sorry, I don't know which version is affected... searching... see here, but it was back in June 2006; the workaround allegedly was to spell out the REFERENCE atribute for individual arguments.
In addition, you have to add at least implicit real(8) again within the interface statement (after !DEC$ATTRIBUTES), in order to declare the arguments -- the one outside doesn't "leak" into interface block.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
C:Program FilesIntelCompilerFortran9.1IA32Bin>ifort
Intel Fortran Compiler for 32-bit applications, Version 9.1 Build 20070109
Z Package ID: W_FC_C_9.1.034
Copyright (C) 1985-2007 Intel Corporation. All rights reserved.
I've added the implicit real(8) (a-z) and still get the linker error. Is my alias statement right? It won't work if I use it as typed above.
Thanks,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
!DEC$ATTRIBUTES ALIAS: "_whatever@88":: whatever
But it should work without the alias statement... I'm not sure what's going on.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, hmmm.. still no luck. So the only thing I need to set in the project properties is the "additional dependencies" set to the .lib file of the dll? Nothing else needs to be set?
Thanks,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Could you zip and attach all relevant project and source files? Alternatively, you can ask for Intel Premier support.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, I got it! I had a small typo in the interface code that caused the differences (frttire_eval vs _frttire_eval@88) once that was fixed, everything fell into place quickly.
Ok, so now how do I get this interface out? Can I put it into a .f90 file or compile it into a .mod? Then would I just include that into the subroutine that needs to call it?
Thanks to everybody for their help, and especially big thanks to JugoslavDujic for staying with me on this ;)
Thanks,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The easiest way to do this is not to expose your main routine in the DLL.
Then write TWO wrapper routines for the two ways you want to call the routine, one with a Fortran export (no STDCALL) and the other with using STDCALL.
Otherwise, you risk corrupting the arguments, especially if strings are involved.
I have successfully done this with DLL's callable from Excel VBA and from other Fortran projects.
Regards,
David
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, so here's a weird one (to me anyways) - With a release build of the dll I'm trying to access, the debug version of my test program (see above) works fine, but the release build doesn't work! I put some write statements in to see the results and it's acting like I'm not passing in the correct values or that I'm not allowed to call that function (we have code that checks to see if you're authorized). Again, the debug version OF THE TEST PROGRAM works fine!
Any ideas on why that would be? I've checked, and there are no obvious compiler switch differences between the two builds...
Any help would be appreciated!
Thanks,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, here's a little tidbit I just ran across - if I set my Config Properties->Fortran->General->Debug Information Format to anything other than "None", it works as expected. If it's set to "None", I get the funky output.
Here's the Command Line text:
/nologo /Zi /module:"$(INTDIR)/" /object:"$(INTDIR)/" /libs:static /threads /c
Thanks,
Mike
- 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
Changing that switch seemed to actually help: it works when the switch is there at all.If I set it to "Custom" and then seteverything to "no" I get the error. Setting any one to "Yes" or "All" I got no warnings.
It seems to be limited to the Charachter(256) variable - if I pull that out of the call and interface, replace it with a real(8) dummy variable and change the dll to hard code the string, everything works great.
I can even add a variable 'filelength' to the end of the frttire_init call in the dll, NOT specify it in the interface, and it works... but I can't then access the filelength variable (access violation) I think a buffer overrun isthe likely cause.
Any ideas?
Thanks,
Mike
I also changed the parameter order to put the string variable last...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you are passing Character arguments, it is best not to have variable length arguments, and if you are using the STDCALL protocol, pad the argument in the calling routine to its full length.
This seems to be because in addition to the string itself, the length of the string is passed as a hidden argument. If your string is not the correct length in the caller, then you may not be able to pass back the 256 characters that you want.
If you don't get this right, you will find that some of the arguments point to the wrong memory location and/or are overwritten, resulting in strange values, and unrepeatable execution.
Hope this helps,
Regards,
David White
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for that tip - but I thought that by declaring the variable asa Character(256) that it pads the rest for you? In debug mode, if I hover over the variable, it looks like it is already padded. But perhaps it's not. Is there an easy way to pad it, or do you have to just hit the space bar 200 times? :)
Thanks,
Mike

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page