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

Call a 3rd party dll from Fortran

pletzky
Beginner
3,262 Views
It's been years since I used Fortran, but I'm now tasked with doing some maintenance work on an application written in Fortran. I'm using Visual Fortran Composer XE 2011, though that may not be particularly relevant.

I need to call a 3rd party DLL from within the Fortran application. Can someone tell me or point me to some documentation (preferably step-by-step) that explains how to do this? I need help with pretty much all the steps. How do I tell Fortran about the ".lib" file? How do I get the ".lib" file to link in? Do I need to create some kind of interface in order to use the dll? Is there any chance of getting intellisense to work with it? How do I tell the IDE to include a folder in the search path at run/debug time?

Any/all help would be appreciated!

Thanks!
Brad.
0 Kudos
16 Replies
Steven_L_Intel1
Employee
3,262 Views
You can simply add the .lib file as a source file to the project - that's the easiest way. Then you just call the routines. If they don't follow Fortran conventions, you may need to write interface blocks that declare the routine, its external name, and its arguments. The Mixed Language Programming section of the compiler documentation will help with that.

You won't be able to get Intellisense to work for it. As for the search path, you will need to add the path to the DLL to the PATH environment variable before you start the IDE.
0 Kudos
pletzky
Beginner
3,262 Views
Thanks a lot for your reply! Apparently I didn't make it sufficiently clear what a newbie I am to Intel Fortran. :-)

So I tried that: I added the ".lib" file as a source file to the project.If I then add a "use" statement to my source, I get"Error 1 error #7002: Error in opening the compiled module file. Check INCLUDE paths." Alternatively, if I try simply calling the routines (as you suggest) without a "use" statement, I get "Error 1 error LNK2019: unresolved external symbol _ROUTINENAME referenced in function _MAIN__".

What am I doing wrong? Where do I go from here?

Thanks again,
Brad.
0 Kudos
mecej4
Honored Contributor III
3,262 Views
In order for the compiler to compile source code B that contains a USE mymod in it, the source code that defines the module mymod should have been compiled first.

If you have a third party library in DLL form, you also need, in addition, i) the corresponding import library file (*.lib) or a module definition file (*.def) which can be used to build the import library file, and ii) the module file (*.mod) that contains the definitions of and interfaces to module entities.

Please note that "module" is used in two rather independent senses here. The linker has one concept of the word, going back to IBM mainframes of the 1960s, and the Fortran compiler has another concept of module, which was introduced with Fortran 90.
0 Kudos
pletzky
Beginner
3,262 Views
Unfortunately, whereas I can appreciate what you're saying, it gets me no closer to calling a dll from Fortran. Are you saying it's impossible without the *.mod file? From your description I would think it should be possible to infer or generate that given the *.dll and the *.lib.

Thanks!
Brad.
0 Kudos
mecej4
Honored Contributor III
3,262 Views
> From your description I would think it should be possible to infer or generate that given the *.dll and the *.lib.

No, only the Fortran compiler can produce .mod files and it does so if the source code for the module is available.

Without a .mod file, it is impossible to compile any source that has a USE statement for that module. You may try to obtain the .mod file from the author of the DLL, or fall back to calling the DLL routines with explicit or implicit interfaces that you provide in your source code.
0 Kudos
pletzky
Beginner
3,262 Views
I'm certainly not tied to the .mod file. I know what the interface looks like. How can I define that and make the necessary calls?

Thanks!
Brad.
0 Kudos
mecej4
Honored Contributor III
3,262 Views
> I know what the interface looks like.

In that case, you are in good shape.

There are several include files in the MKL include directory upon which you may model your interface code. The Intel Fortran Reference contains a section called Procedure Interfaces.

You may put the interface body inside the routine that calls the corresponding DLL routine(s).

If you want to avoid having to multiple copies of interfaces, you can create a module that contains nothing but just the interface declarations, and USE that module wherever needed. Once you compile the module source, you will have the hitherto missing .mod file that the author/vendor of the DLL should have provided.
0 Kudos
anthonyrichards
New Contributor III
3,262 Views
If you are starting from scratch, I suggest that you do the following:

1) write your own third-party DLL program by Creating a DLL project containing a single subroutine that takes three real arguments. The first two reals should be the numbers to be added, the routine should add them and return the result in the third variable. This is straightforward Fortran programming.
Write the code for this but remember to include a DLLEXPORT compiler directive to 'export' the name of the subroutine. This means that the non-executable .LIB file that is generated at the same time as the .DLL executable code will then contain a list of all names of all the members members included in the DLL that you have decided to make visible to the outside world. In this case it will a list of one name, that of the routine you hacve written. If you omit the 'DLLEXPORT' of the name, the subroutine will be invisible to the outside world and the linker will not be able to find it in the DLL.

2)Creat a simple 'Hello world' console program to test the DLL. Add code to the default 'Hello World' generated code to define three real variables and assign values to two of them.
Add a compiler directive to IMPORT the name of the subroutine that you want to use from the DLL (there is only one at this stage). Then add a call to the DLL subroutine using the three variables as arguments and get the subroutine to return the sum in the third variable.
The compiler will use the contents of the DLL's .LIB file to get all the information it needs about the DLL and in teh list of symbols it finds it will look for a symbol having the name that you use for the subroutine you want to call. Hopefully, if you have not spelled it wrong, the compiler will find it and the linker will do all the necessary linking to load the DLL and call the subroutine.

P.S. The Fortran compiler comes with a utility called DUMPBIN which, used with a DLL or a DLL's .LIB file as an argument and the appropriate switch will list the names of all the exported symbols present in the DLL. Be warned, that depending on the calling convention specified for use in your interface blocks, the compiler may add a leading underscore to the straight symbol name and may even add a trailing @12 to the name (specifying that the routine expects an argument list of 3 variables supplied by reference, each address reference requiring 4 bytes, making 12 bytes in total.
ALso note that Case is SiGniFicanT in symbol names and that FORTRAN normally forces all routine names referenced in its code to be UPPERCASE unless sternly told not to do so (using the appropriate compiler directive), so if mixed case names occur in your third-party DLL, you need to establish exactly what they are and use the 'ALIAS' directive to tell the Fortran compiler to use that rather than the Upper case name.
0 Kudos
pletzky
Beginner
3,262 Views
I think I'm missing something more basic than the interface code. Regardless of whether or not I have an interface section, I continue to get "Error 1 error LNK2019: unresolved external symbol _ROUTINENAME referenced in function _MAIN__".

How do I get the information in the *.lib file to link into the executable properly? I've included the *.lib file as a "Source File", but that appears to be insufficient.

Thanks again!
Brad.
0 Kudos
pletzky
Beginner
3,262 Views
As I said, I'm a newbie! How do I "add a compiler directive to IMPORT the name of the subroutine..."? I'm wondering if that's the step I'm missing.

Also, the routines definitely used mixed case. Can you provide more details about the "ALIAS" directive?

Thanks!
Brad.
0 Kudos
mecej4
Honored Contributor III
3,262 Views
Did you actually create a routine with the mysterious name ROUTINENAME ? Where and how is it declared and implemented?

It may be worthwhile at this point for you to work with a small example, get the problems taken care of using it (posting here as needed), and then apply the same techniques to your real code.
0 Kudos
anthonyrichards
New Contributor III
3,262 Views
Here are some files which I hope will be of assistance:

MYDLL.F90 contains code to create a DLL called MYDLL.DLL.
The DLL contains two subroutines, both of which take 3 real arguments, adding the first two numbers and equating the total to the third. The wrinkle I have added is to give one of the subroutines an alias which exports a mixed case name for it to the symbol table that is created in the MYDLL.LIB file that is created alongside the MYDLL.DLL.
To show what turns up in the MYDLL.DLL, I attach the output file MYDLL_DUMPBIN_OUTPUT.TXT obtained by running the utility DUMPBIN on MYDLL.DLL using the command (from within the MYDLL.DLL /debug/ or /release/ folder)

>dumpbin /exports /OUT:MYDLL_DUMPBIN_OUTPUT.TXT mydll.dll

As you can see, the linker exports the correct mixed-case name as required and also exports two versions of the default upper-case name for the second routine. The one ending '@12' is referred to as 'decorated'.

To test the DLL, I attach the files TESTMYDLL.F90 and a module file MYINTERFACES.F90. The latter contains interface blocks that tell the compiler what symbols to look for in the external source (in this case MYDLL.DLL), with the 'ALIAS' part of the directive giving the case-preserving symbol name when required. When creating the project, these two files need to be supplemented by the MYDLL.LIB file that you will find in the /MYDLL/debug/ folder (or /release folder if release version being tested) along with MYDLL.DLL once you have built the MYDLL.DLL library. Just use 'Add item' or 'Add to Project' to add the .LIB file to the TESTMYDLL project.

In order to test the DLL, you will need to copy MYDLL.DLL from the folder it was created in to the /debug/ or /release/ folder of the TESTMYDLL project.

Here is what to expect when you run the TESTMYDLL test program:

Hello World, Here is a test of MYDLL that tries to use a mixed-case subroutinename

from Mixed Case Subroutine: X = 2.00000000000000 , Y =3.00000000000000 , SUM = 5.00000000000000

from UPPER CASE Subroutine: X = 5.00000000000000 , Y =10.0000000000000 , SUM = 15.0000000000000

Fortran Pause - Enter command or to continue.

I would recommend the following steps:

1) Creat an empty workspace

2) Create a new project, selecting Dynamic link library, with no files, and add it to the blank workspace

3) Add MYDLL.F90 to the DLL project.

4) compile and build the DLL

5) Create a new empty console project, add it to the same workspace

6) add TESTMYDLL.F90 and MYINTERFACES.F90 to the console project.

7) Add MYDLL.LIB to the console project, using ' Add Item' or ' Add file' and navigating to the /MYDLL/debug/ or /release/ folder where it will be created alongside the DLL.

8) compile and build the TESTMYDLL project

9) Execute the TESTMYDLL.EXE

All this is most easily done using the Visual Studio environment, but others more familiar with the command-line can advise you how to do what I propose from there.

Hope this helps!

0 Kudos
waterresourcesengine
3,262 Views
Hi Brad; I've also been working through similar issues, but I am linking with a 'static library' (.lib file) obtained from a third party; and I'm getting similar 'external' errors.

My .lib was developed by another agency using the Intel compilers; using the Command Line to build it.

About all I presently offer up is 'moral support' but hopefully soon we will both work through this.....

I'm sure glad this Forum is here as I have no other support of use!!!!



0 Kudos
Steven_L_Intel1
Employee
3,262 Views
waterresourceengin, if you have purchased Intel Fortran you have Intel Premier Support available to you. But this forum is the proper place for "how to" questions.
0 Kudos
pletzky
Beginner
3,262 Views
So, despite some interruptions, I've made great progress on this problem. However, I'm now faced with what appears to be a COM problem that may or may not be connected. I do a "COMINITIALIZE" followed by a "COMCreateObjectByProgID". Both of these return a status of zero. However, when I try to use the COM object, I get "Unhandled exception at 0x00000000 in VMG.Fortran.01.exe: 0xC0000005: Access violation."

I realize that this error can mean almost anything, but has anyone got some suggestions of common problems with COM that produce this problem?

Thanks!
Brad.
0 Kudos
pletzky
Beginner
3,262 Views
OK, if you want to see my resolution of the problem, feel free to take a look at http://software.intel.com/en-us/forums/showpost.php?p=188194

Brad.
0 Kudos
Reply