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

Calling functions out of an existing .dll

mhopp
Beginner
2,030 Views

Hello,

my problem is, that i got an existing .dll-File from an old, not Visual Fortran using Project (built with salford), and want to use the functions from this .dll in my new Visual Fortran Project.

I have no idea how to get this file correctly integrated.

Are there any commands in the source code i have to add?

Im using Visual Studio 2008 / Intel Visual Fortran Compiler Professional Edition 11.1 (on Windows XP).

So which steps i have to do?

Manuel

0 Kudos
18 Replies
ZlamalJakub
New Contributor III
2,030 Views

If you have import library file *.lib you can specify it to the linker and use functions from dll as it is your compiled code (be carefull on calling conventions of your dll).

If You do not hae *.lib file you can use dumpbin.exe to create it (google it).

Or you can use routines if you know their names by following code (i get only important parts how to call routine declared as

subroutine ROUTINE(I,Array,length)

integer*4 i,length

real*8 arrray(length)

...

! here is code how to call it

subroutine calldll(Arg1,Arg2,Arg3)
use kernel32
integer*4 Arg1,Arg3
real*8 Arg2(Arg3)
integer(HANDLE) iLib,iProc
interface
recursive subroutine RunDllSub(isub,i1,i2,i3,i4,i5,i6,i7,i8)
OPTIONAL :: i1,i2,i3,i4,i5,i6,i7,i8
end subroutine
end interface

pointer(pi1,Arg1)
pointer(pi2,Arg2)
pointer(pi3,Arg3)

iLib=LoadLibrary("library.dll"C)
iProc=GetProcAddress(iLib,"_ROUTINE@12"C) ! here You must know routine name how it was exported

pi1=LOC(Arg1)
pi2=LOC(Arg2)
pi3=LOC(Arg3)
call RunDllSub(%VAL(iProc),%VAL(pi1),%VAL(pi2),%VAL(pi3))
return
end subroutine


recursive subroutine RunDllSub(sub,i1,i2,i3,i4,i5,i6,i7,i8)
OPTIONAL :: i1,i2,i3,i4,i5,i6,i7,i8
external sub
if (present(i8)) then
call sub(i1,i2,i3,i4,i5,i6,i7,i8)
elseif (present(i7)) then
call sub(i1,i2,i3,i4,i5,i6,i7)
elseif (present(i6)) then
call sub(i1,i2,i3,i4,i5,i6)
elseif (present(i5)) then
call sub(i1,i2,i3,i4,i5)
elseif (present(i4)) then
call sub(i1,i2,i3,i4)
elseif (present(i3)) then
call sub(i1,i2,i3)
elseif (present(i2)) then
call sub(i1,i2)
elseif (present(i1)) then
call sub(i1)
else
call sub()
endif
end subroutine

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

Hi and thanks for the answer,

but if i try to compile it i get the following error messages:

Error 1 error #6406: Conflicting attributes or multiple declaration of name. [ARG2] C:\Dokumente und Einstellungen\hoppm\Eigene Dateien\Visual Studio 2008\Projects\Wasdamta_test\Wasdamta_test\calldll.F90 16
Error 2 error #6406: Conflicting attributes or multiple declaration of name. [ARG3] C:\Dokumente und Einstellungen\hoppm\Eigene Dateien\Visual Studio 2008\Projects\Wasdamta_test\Wasdamta_test\calldll.F90 17
Error 3 error #7098: A dummy argument object cannot be a pointee. [ARG1] C:\Dokumente und Einstellungen\hoppm\Eigene Dateien\Visual Studio 2008\Projects\Wasdamta_test\Wasdamta_test\calldll.F90 4
Error 4 Compilation Aborted (code 1) C:\Dokumente und Einstellungen\hoppm\Eigene Dateien\Visual Studio 2008\Projects\Wasdamta_test\Wasdamta_test\calldll.F90 1

I changed this two lines as follows:

iLib=LoadLibrary("C:/tmp/SE_Wasdamta.dll"C)
iProc=GetProcAddress(iLib,"_FTN_HKRIT@0"C)

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views

I am sorry.

I am adding example of how to do it.

After you build solution please copy compiled dll testdll.dll to directory with exe file (to be found by exe file).

I hope it will work (I put routine calling dll to module because compiler has not problem with interface there.

(in GetProcAddres I used only "ROUTINE"C because intel fortran does not use @..., it depends on compiler)

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

Thank you very much, this example helped me a lot.

But how can i get some resulting values from functions of the .dll?

How can i write/use the results?

Manuel

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views

ivalue=iRunDllFunc(....)

parameters are the same as call RundllSub

IRunDllunc is defined in example

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

Thanks, but the resulting values seem to be huge integer Values but i want (and expected) to get double precision Values.

Is there a clue to get the resulting values transformed or have i to change the source code of the function (iRunDllFunc) in order to get double precision values?!

This is the source code of my function call:

[fortran]    double precision function tp(p)
    use kernel32
    integer(HANDLE) iLib,iProc
    double precision p
    double precision point1
    pointer(pp,point1)
    iLib=LoadLibrary("SE_Wasdamta.dll"C)
    iProc=GetProcAddress(iLib,"FTN_TP"C) ! here You must know routine name how it was exported
    pp=LOC(p)
    tp=iRunDllFunc(%VAL(iProc),%VAL(pp))
    return
    end function[/fortran]

And for tp i always get the value of: 538976288.000000; even for different input values of p.

Is that the position of the value inside the memory? If, how can i get the value of it?

Any suggestion? What did i wrong?

Thanks a lot for your effort.

Manuel

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views

in this case define in rundllsub.f90 function for example

[fortran]recursive real*8 function rRunDllFunc(isub,i1,i2,i3,i4,i5,i6,i7,i8)
		OPTIONAL :: i1,i2,i3,i4,i5,i6,i7,i8
		external isub
		if (present(i8)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5,i6,i7,i8)
		elseif (present(i7)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5,i6,i7)
		elseif (present(i6)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5,i6)
		elseif (present(i5)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5)
		elseif (present(i4)) then
			rRunDllFunc=isub(i1,i2,i3,i4)
		elseif (present(i3)) then
			rRunDllFunc=isub(i1,i2,i3)
		elseif (present(i2)) then
			rRunDllFunc=isub(i1,i2)
		elseif (present(i1)) then
			rRunDllFunc=isub(i1)
		else
			rRunDllFunc=isub()
		endif
	end function
[/fortran]
add interface to this new routine and use this. You can define routines for different returning types.

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

I added a new function as described above and wrote an Interface as follows:

[fortran]recursive real*8 function rRunDllFunc(isub,i1,i2,i3,i4,i5,i6,i7,i8)
		use ifwinty
		integer(HANDLE) isub,i1,i2,i3,i4,i5,i6,i7,i8
		OPTIONAL :: i1,i2,i3,i4,i5,i6,i7,i8
end function[/fortran]

But I still get the same value.

Also tried it with a double precision function:

[fortran]recursive double precision function dRunDllFunc(isub,i1,i2,i3,i4,i5,i6,i7,i8)
...[/fortran]
but again no change of the value!?

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views

I do not know which compiler creates Dll but may be that there is difference how routine returns its value back. I think standard is that value is passed in ST0 registry but IVF assumes different passing procedure.

Are you able to debug dll and look at its return code (in assembler Ctrl+Alt+D)?

If not, display registers Ctrl+Alt+G (then right mouse button on it and select Floating point)and set breakpoint at the end of rRunDllFunc. Look at registers, in ST0 should be return value of your routine (see attachement). If not there is probably problem in routine in your dll.

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

The ST0 value is exactly the value i expected, so i think there is no problem inside the routine, but how can i get this value now?

[bash]EAX = 20202020 EBX = 0012FF6C ECX = 0020001E EDX = 7FFFFFFF ESI = 00000000 EDI = 067AF9D4 EIP = 004015A8 ESP = 0012FD60 EBP = 0012FDA8 EFL = 00000206 

ST0 = +1.5183624387684500e+0002   ST1 = +3.7334949153037572e+0007   ST2 = +4.7443639793396927e+0008   ST3 = +0.0000000000000000e+0000   ST4 = +0.0000000000000000e+0000   
ST5 = +0.0000000000000000e+0000   ST6 = -0.2241176083388291e+4426   ST7 = +5.3758132584073803e+0002   CTRL = 0360 STAT = 2020 TAGS = FCFF EIP = 10001E11 EDO = 0012FD38 

0012FD9C = 41C0101010000000 
[/bash]
It has the same value even within the real and integer version of the function.

Thanks again for your quick answer.

Manuel

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views
[fortran]double precision function tp(p)  
use kernel32  
integer(HANDLE) iLib,iProc  
double precision p  
double precision point1  
pointer(pp,point1)  

real*8 rRunDllFunc ! important !!!!

iLib=LoadLibrary("SE_Wasdamta.dll"C)  
iProc=GetProcAddress(iLib,"FTN_TP"C) ! here You must know routine name how it was exported  
pp=LOC(p)  
tp=rRunDllFunc(%VAL(iProc),%VAL(pp))  
return  
end function  [/fortran]

please use code like this (see line important !!!), i think that you does not use interface block and routine rRunDllRunc is assumed (by default) to have return value of real*4 kind.

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

Adding this line mentioned above results in an Error:

Error 1 error #6637: This actual argument must be the name of an external user function or the name of an intrinsic function. [%%VAL] C:\Dokumente und Einstellungen\hoppm\Eigene Dateien\Visual Studio 2008\Projects\calldll2\Console1\Console1\Source1.F90 42

I also tried (without adding the line above) to change the declaration of all other used "double precision" variables and functions in the source code to: "real*8" but it still returns the wrong value (same as before).

[fortran]    real*8 function tp(p)
    use kernel32
    integer(HANDLE) iLib,iProc
    real*8 p
    real*8 point1
    pointer(pp,point1)
    !real*8 rRunDllFunc
    iLib=LoadLibrary("SE_Wasdamta.dll"C)
    iProc=GetProcAddress(iLib,"FTN_TP"C) ! here You must know routine name how it was exported
    pp=LOC(p)
    tp=rRunDllFunc(%VAL(iProc),%VAL(pp))
    print*,tp
    return
    end function[/fortran]

and:

[fortran]recursive real*8 function rRunDllFunc(isub,i1,i2,i3,i4,i5,i6,i7,i8)
		OPTIONAL :: i1,i2,i3,i4,i5,i6,i7,i8
		external isub
		if (present(i8)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5,i6,i7,i8)
		elseif (present(i7)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5,i6,i7)
		elseif (present(i6)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5,i6)
		elseif (present(i5)) then
			rRunDllFunc=isub(i1,i2,i3,i4,i5)
		elseif (present(i4)) then
			rRunDllFunc=isub(i1,i2,i3,i4)
		elseif (present(i3)) then
			rRunDllFunc=isub(i1,i2,i3)
		elseif (present(i2)) then
			rRunDllFunc=isub(i1,i2)
		elseif (present(i1)) then
			rRunDllFunc=isub(i1)
		else
			rRunDllFunc=isub()
		endif
	end function[/fortran]

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views

I missed that function tp is declared in module and there is interface to rRunDllfunc above it before contains. It was bad guess.

I do not precisely know what is happening. Can you put your code (and dll) to forum to test it? At least source file which calls rRunDllFunc?

Jakub

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views

I missed that function tp is declared in module and there is interface to rRunDllfunc above it before contains. It was bad guess.

But I still think the problem is in type mismatch.

I do not precisely know what is happening. Can you put your code (and dll) to forum to test it? At least source file which calls rRunDllFunc?

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

Here you get my solution folder.

The .dll-file is in the debug-folder (SE_Wasdamta.dll).

Manuel

0 Kudos
anthonyrichards
New Contributor III
2,030 Views

If you are getting the same value back when you apparently send a different value to the DLL function, perhaps you are actually sending the same value each time?

I note you are always sending the location of a value. Since this location will not change whatever value you send, unless it is a different location, perhaps this explains it. Maybe you should send the VALUE itself. Then perhaps you will get a different value back when you change the VALUE sent?

Test bysupplying the function withtwo different values stored in different locations?

0 Kudos
ZlamalJakub
New Contributor III
2,030 Views

I must apologize, it is my problem. Routine rRunDllFunc should start like ...

[bash]	recursive real*8 function rRunDllFunc(isub,i1,i2,i3,i4,i5,i6,i7,i8)
OPTIONAL :: i1,i2,i3,i4,i5,i6,i7,i8
external isub
real*8 isub
[/bash]

isub was assumed to be integer*4 (by default) not real*8 and it produces problem with value conversion

Jakub

0 Kudos
mhopp
Beginner
2,030 Views

Thanks! Now it runs!

You dont have to apologize, you did a great job and helped me alot!

Manuel

0 Kudos
Reply