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

How to call a function in a DLL file in Intel Visual Fortran?

Intel_C_Intel
Employee
1,200 Views
I want to use thefunctions in a dll file. It was written and compiled in Microsoft VC++, but I don't know the source code.
I can successfully call this function in VC++:
Code:
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 BOOL WINAPI GetId(LPTSTR lpOutBuffer, int Mode);

 #ifdef __cplusplus
 }
 #endif
 
 ... 

 char Id[50];
 memset(Id, '�', 50);
 
 BOOL result = GetId(Id, 0); 
 if(result)
 {
     CString IdStr;
     IdStr = Id;  
     MessageBox(IdStr);
 }
However, if I try to call it in Visual Fortran in myprogram.f90:
Code:
      CHARACTER*50 Id
      LOGICAL reslt


        INTERFACE
        LOGICAL FUNCTION GetId (Id,nin)
        !DEC$ ATTRIBUTES DLLIMPORT :: GetId
        CHARACTER Id*50
        INTEGER nin
        END FUNCTION GetId
        END INTERFACE 

      ...

      reslt = GetId(Id,0)

And compile it in command line:
Code:
ifort myprogram.f90 mydll.lib
There will be error message:
Compiler output:
-out:myprogram.exe 
-subsystem:console 
-entry:mainCRTStartup 
myprogram.obj 
mydll.lib 
myprogram.obj : error LNK2019: unresolved external symbol __imp__GETID referenced in function _MAIN__
myprogram.exe : fatal error LNK1120: 1 unresolved externals

How to call the functions inthis dll file from IntelVisual Fortran?
0 Kudos
18 Replies
Steven_L_Intel1
Employee
1,201 Views
You need to deal with the mixed case issue, and also argument passing conventions are a bit different. Try this:

INTERFACE
LOGICAL FUNCTION GetId (Id,nin)
!DEC$ ATTRIBUTES C,DLLIMPORT,ALIAS:"GetID" :: GetId
CHARACTER Id*50
!DEC$ ATTRIBUTES REFERENCE :: Id
INTEGER nin
END FUNCTION GetId
END INTERFACE

Oh, and change that LOGICAL to INTEGER. Fortran LOGICAL is not the same as C BOOL.
0 Kudos
Intel_C_Intel
Employee
1,201 Views
Thank you, Steve. I tried it per your suggestion:
Code:
INTERFACE
INTEGER FUNCTION GetId (Id,nin)
!DEC$ ATTRIBUTES C,DLLIMPORT,ALIAS:"GetID" :: GetId
CHARACTER Id*50
!DEC$ ATTRIBUTES REFERENCE :: Id
INTEGER nin
END FUNCTION GetId
END INTERFACE 
But still there is problem:
Compiler output:
error LNK2019: unresolved external symbol __imp_GetId referenced in function _MAIN__
The difference between this message and the previous message is "__imp_GetId" and "__imp__GETID".
0 Kudos
Steven_L_Intel1
Employee
1,201 Views
You need to link against the "export library" created when the DLL was built.
0 Kudos
Intel_C_Intel
Employee
1,201 Views
The dll provider provides mydll.dll and mydll.lib. I compiled my Fortran file together with mydll.lib:
ifort myprogram.f90 mydll.lib
It doesn't work.
How could I know if mydll.lib is the "export libary" or not, if I cannot know it from the provider?
0 Kudos
Steven_L_Intel1
Employee
1,201 Views
Do this. Start a command prompt session through Start..Programs..Intel Software Development Tools..Intel Fortran Compiler 9.0 (or 8.1)..Build Environment for IA-32 Applications.

Set default (cd) to the folder containing mydll.lib and type:

dumpbin -exports mydll.lib

Post the results.
0 Kudos
Intel_C_Intel
Employee
1,201 Views
dumpbin -exports mydll.lib
Microsoft  COFF/PE Dumper Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved. 

Dump of file mydll.lib

File Type: LIBRARY
     Exports
       ordinal       name
            18      _FunctionOne@12
            17      _FunctionTwo@12
             4      _FunctionThree@16
           ...      ...
             1      _GetId@8
           ...      ...
Summary
          BA .debug$S
          14 .idata$2
          14 .idata$3
           4 .idata$4
           4 .idata$5
           8 .idata$6
0 Kudos
aliho
Beginner
1,201 Views
The default function type in your C source has been set to STDCALL (for windows developement I presume).

So replace
!DEC$ ATTRIBUTES C,DLLIMPORT,ALIAS:"GetID" :: GetId
by
!DEC$ ATTRIBUTES STDCALL,DLLIMPORT,ALIAS:"GetID" :: GetId

and it will work.
0 Kudos
Steven_L_Intel1
Employee
1,201 Views
Oh, I should have noticed the WINAPI in the C declaration. Removing that is an alternative.
0 Kudos
Intel_C_Intel
Employee
1,201 Views
I changed it to STDCALL, it still doesn't work. Thank you anyway.
In VC++, to call the function GetId, it includes "mydll.h", which includes the code segment in my first post. We don't include this in Visual Fortran. Does this head file matter?
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,201 Views
The offending line should read either

!DEC$ATTRIBUTES DLLIMPORT, DECORATE, STDCALL, ALIAS: "GetId":: GetId

or

!DEC$ATTRIBUTES DLLIMPORT, STDCALL, ALIAS: "_GetId@8":: GetId

Jugoslav
0 Kudos
Intel_C_Intel
Employee
1,201 Views
Thank you! It works this time!
The key is the alias name, it must be the same as the output of dumpbin /exports. Here I must set:
!DEC$ ATTRIBUTES DLLIMPORT, ALIAS:"_GetId@8" :: GetId
Whenever I put C, STDCALL it will work.
ALIAS:"_GetId@8" is the most important part I ignored.
0 Kudos
Steven_L_Intel1
Employee
1,201 Views
You don't want both C and STDCALL. Choose STDCALL if you're not changing the C code.
0 Kudos
jjfait
Beginner
1,201 Views

i'm trying to follow this example and am getting an error, i simply put in dll, on command when i type dumbpin -export mydll.dll promp it comes up ERSET_WRAPPER, then in the main project i copy over the dll and gives me the error _imp_ERSET_WRAPPER, do you need to have the name of the dll library somewhere like how C uses ("mydll.dll"), also tried putting in a module instead of a subroutine and i get a different error, if i take out call ERSET_WRAP(1,2,3) it compiles.

I just noticed i didnt do this thing with a .def, i tried link /dll mydll.dll mydef.def, but it says there isnt a mydef.def, is this thing necessary,thanks Jeremy

subroutine ERSET_WRAPPER(x,y,z)

!DEC$ ATTRIBUTES DLLEXPORT, ALIAS: "ERSET_WRAPPER" :: ERSET_WRAPPER

implicit none

integer

, intent(in) :: x,y,z

end subroutine

subroutine

CALLERSET

implicit none

INTERFACE

subroutine ERSET_WRAP(x,y,z)

!DEC$ ATTRIBUTES DLLIMPORT, ALIAS: "ERSET_WRAPPER" :: ERSET_WRAP

integer x,y,z

!DEC$ ATTRIBUTES REFERENCE :: x,y,z

end subroutine

END INTERFACE

call ERSET_WRAP(1,2,3)

end subroutine

0 Kudos
Steven_L_Intel1
Employee
1,201 Views
If you're going to use DLLIMPORT, then link against the export library (.lib) created when the DLL was linked. That will resolve the __imp symbols. I recommend this rather than .def files.
0 Kudos
jjfait
Beginner
1,201 Views

im confused on how to link the export library, do i put into the directory of executible or the path of the library directory through the properties of theexecutible, also why does the .lib get deleted from executible directory when it is rebuilt if it is put there, thanks Jeremy

OK, i got it. You put the dll in the directory of the executible and in the properties you tell it to look for the .lib

0 Kudos
Steven_L_Intel1
Employee
1,201 Views
That's certainly one way. You can also make the DLL project a "dependent" of the executable project and Visual Studio will link in the library automatically.
0 Kudos
jjfait
Beginner
1,201 Views

I guess I still have two questions:

1. Why does the .lib file get deleted and the .dll doesnt,when placed in the executible directory, whenthe executible is rebuilt.

2. If I keep the .dll and .lib in the original directory of the library, i can tell it to find the lib in the command file of the linker by mylib.lib, but when i run it says the dll file was not found. Under additional library directories, I placed the link to where the lib and dll files are placed. Also, I went to project dependencies and placed: "Main depends on Library" and it doesnt seem to link. I had to place the dll in the exe. directory manually.

Thanks for your help, Jeremy

0 Kudos
Steven_L_Intel1
Employee
1,201 Views
When you rebuild a project, Visual Studio deletes all obj, lib and mod files in the project's "output directory" A dll or exe will remain due to incremental linking (though that's not supported for Fortran.) You should never copy files into that directory. Reference the .lib from the DLL project's directory, or use some other folder to hold it.

You do have to copy the DLL - best place is into the project directory (with the .vfproj file) of the executable project. I do this in a "Post-build step" rule in the DLL project.
0 Kudos
Reply