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

DLLs and Common block

moncef
Beginner
1,532 Views

I used Help files in IVF, "Coding Requirements for Sharing Data in DLLs", "Exporting and Importing Common Block Data", where example of appropriate DLLEXPORT directive is included and described. When I create a dll and I put common blocks that I want to be linked to the same common block in my exe program, the common block information does not pass from the exe to the dll.

How can I declare common block in both the main exe and any dll and having the information passing?

The code source of the DLL is:
subroutine Seta
use user32
use kernel32
!DEC$ ATTRIBUTES STDCALL, REFERENCE,ALIAS :"Seta":: Seta
!DEC$ ATTRIBUTES DLLEXPORT:: Seta, /X/
implicit none
common /X/C,B,A
real C,B,A
A=A+1
B=B+1
return
end subroutine Seta

The subroutine in the main program that uses the DLL is:

subroutine test

use user32

use kernel32

implicit none

pointer (p_seta, seta)

integer(HANDLE) :: dll_handle

integer(BOOL) :: free_status

integer i

real AP

common /X/C,B,A

real C,B,A

Interface

subroutine Seta

!DEC$ ATTRIBUTES DLLIMPORT:: Seta, /X/

implicit none

common /X/C,B,A

real C,B,A

end subroutine Seta

end interface

!==========================================!

dll_handle = LoadLibrary ("DLL_a.dll"C)

! Check for errors

if (dll_handle == NULL) then

! Failure

stop

end if

p_seta = GetProcAddress (dll_handle, "Seta"C)

if (p_Seta == NULL) then

! Failure

stop

end if

! Now call the function

call seta ! the value of A in the DLL is 1

Ap=A ! the value of A in the subroutine test is 0 so Ap=0

free_status = freelibrary(p_seta)

end subroutine Test

If you have a solution, pelase send me a simple example.
thanks in advance

0 Kudos
13 Replies
anthonyrichards
New Contributor III
1,532 Views
Clearly it does not work because, by switching to LoadLibrary and GetProc Address,you have deviated from the recommended method of linking COMMON in a DLL to COMMON in an .EXE. Normally, you would add the DLL_A.LIB file to your .EXE that wants to link to your DLL_A.DLL library. That way, the locations (addresses)of the symbols Seta and X are properly generated and they are propeerly linked.
If you replace

subroutine test
use user32
use kernel32
implicit none
pointer (p_seta, seta)
integer(HANDLE) :: dll_handle
integer(BOOL) :: free_status
integer i
real AP
common /X/C,B,A
real C,B,A
Interface
subroutine Seta
!DEC$ ATTRIBUTES DLLIMPORT:: Seta, /X/
implicit none
common /X/C,B,A
real C,B,A
end subroutine Seta
end interface

with

subroutine test
!DEC$ ATTRIBUTES DLLIMPORT:: /X/
!DEC$ ATTRIBUTES DLLIMPORT,ALIAS :"Seta":: Seta
use user32
use kernel32
implicit none
! pointer (p_seta, seta) ! i.e. forget the pointer, use the location of SETA that the linker generates from the DLL_a.LIB file
integer p_seta
integer(HANDLE) :: dll_handle
integer(BOOL) :: free_status
integer i
real AP
common /X/C,B,A
real C,B,A
Interface
subroutine Seta
end subroutine Seta
end interface
a=1.1111E+00
b=2.2222E+00
C=3.3333E+00


You will find it works. you should add the before and after print commands that you have omitted from thesample codeas well, to confirm what is happening.
0 Kudos
moncef
Beginner
1,532 Views
Quoting - anthonyrichards
Clearly it does not work because, by switching to LoadLibrary and GetProc Address,you have deviated from the recommended method of linking COMMON in a DLL to COMMON in an .EXE. Normally, you would add the DLL_A.LIB file to your .EXE that wants to link to your DLL_A.DLL library. That way, the locations (addresses)of the symbols Seta and X are properly generated and they are propeerly linked.
If you replace

subroutine test
use user32
use kernel32
implicit none
pointer (p_seta, seta)
integer(HANDLE) :: dll_handle
integer(BOOL) :: free_status
integer i
real AP
common /X/C,B,A
real C,B,A
Interface
subroutine Seta
!DEC$ ATTRIBUTES DLLIMPORT:: Seta, /X/
implicit none
common /X/C,B,A
real C,B,A
end subroutine Seta
end interface

with

subroutine test
!DEC$ ATTRIBUTES DLLIMPORT:: /X/
!DEC$ ATTRIBUTES DLLIMPORT,ALIAS :"Seta":: Seta
use user32
use kernel32
implicit none
! pointer (p_seta, seta) ! i.e. forget the pointer, use the location of SETA that the linker generates from the DLL_a.LIB file
integer p_seta
integer(HANDLE) :: dll_handle
integer(BOOL) :: free_status
integer i
real AP
common /X/C,B,A
real C,B,A
Interface
subroutine Seta
end subroutine Seta
end interface
a=1.1111E+00
b=2.2222E+00
C=3.3333E+00


You will find it works. you should add the before and after print commands that you have omitted from thesample codeas well, to confirm what is happening.

0 Kudos
moncef
Beginner
1,532 Views
Quoting - moncef


when icarry out the modifications which you proposed and I compile my main programm I obtains Error LNK2019 : unresolved external symbol seta referenced in function _Test
0 Kudos
anthonyrichards
New Contributor III
1,532 Views
Quoting - moncef

when icarry out the modifications which you proposed and I compile my main programm I obtains Error LNK2019 : unresolved external symbol seta referenced in function _Test

You must add the DLL_A.LIB list of exported functions to your Test project so that it can be used by the Test program to locate the necessary imported symbols. You must also ensure that the DLL can be found by the Test.EXE program, so copy it to the Test.EXE folder.

Also, I have found that with the code I have supplied, if you replace

pointer (p_seta, seta)

with

pointer (p_Otherseta, Otherseta)

and replace p_seta with p_Otherseta in your code, and also replace

dll_handle = LoadLibrary ("DLL_A.dll"C)

with

dll_handle = GetModuleHandle ("DLLA.dll"C)

and replace

call seta

with

call Otherseta

you will find that it works. This is because, having supplied and included the DLL_A.LIB when building the Test.EXE projeect, the .EXE has all the information it needs to to link the DLL_A.DLL at load time and during this process, as a final step after calling the DLL entry point, quote
"Finally, the system modifies the code of the process to provide starting addresses for the referenced DLL functions" unquote. I think that this step is what is missing for the common block /X/ when you use run-time linking using LoadLibrary, so I think that the address of the common block is then not correctly mapped to the process's address space. GetModuleHandle is used to get the handle to a DLL that is already loaded.


0 Kudos
moncef
Beginner
1,532 Views

How Can I add the DLL_A.LIB list of exported functions to my Test project?
0 Kudos
anthonyrichards
New Contributor III
1,532 Views
Quoting - moncef

How Can I add the DLL_A.LIB list of exported functions to my Test project?

Are you using Intel Visual Fortran?
If you are, I think this is what you do:

In your solution,

1. Create two projects, each containing the source files of a single language. The project that contains the main program should be made an executable project and the other astatic or dynamic-linklibrary project.
2. Right-click the executable project and select Dependencies to set the executable project as dependent on the library project.
3.Right-click on the executable project and select Set as Startup Project so that you can build it and debug.
0 Kudos
moncef
Beginner
1,532 Views

Ihave carried out the modifications which you proposed. When I debug the main programm and when I execute the line code : DLL_handle=loadlibrary ("DDL_A") of DLL_handle= GetModuleHandle("DDL_A") Ireceive this error Message :DFORRTD.DLL not Found.
I checked in the repertory C:Windowssystem32: The file is well.
0 Kudos
anthonyrichards
New Contributor III
1,532 Views
Quoting - moncef

Ihave carried out the modifications which you proposed. When I debug the main programm and when I execute the line code : DLL_handle=loadlibrary ("DDL_A") of DLL_handle= GetModuleHandle("DDL_A") Ireceive this error Message :DFORRTD.DLL not Found.
I checked in the repertory C:Windowssystem32: The file is well.

DFORRTD.DLL is a CVF DLL, so you have got hold of the wrong DLL, one that you built with CVF, I think.
0 Kudos
moncef
Beginner
1,532 Views
Quoting - anthonyrichards

DFORRTD.DLL is a CVF DLL, so you have got hold of the wrong DLL, one that you built with CVF, I think.

You can create as many folders as you want. These are for your convenience and are not visible to others.

I found the solution to ovoid this error message. It consists of:


For the DLL :
1.in project setting => FORTRAN=>Librairies => Fortran Libraries=> Reentrancy Support : select threaded
2.in project setting => FORTRAN=>Librairies => Fortran Libraries=>Use-run-timeLibrary :Multi-threaded DLL
3.in project setting => FORTRAN=>Librairies => Other LibraryOptions:Enable Use Common Windows librairies

For theMainproject :
1.in project setting => FORTRAN=>Librairies => Fortran Libraries=> Reentrancy Support : select threaded
2.in project setting => FORTRAN=>Librairies => Fortran Libraries=>Use-run-timeLibrary :Multi-threaded
3.in project setting => FORTRAN=>Librairies => Other LibraryOptions:Enable Use Common Windows librairies

However, the problem persiste : the common block information does not pass from the exe to the dll.

0 Kudos
anthonyrichards
New Contributor III
1,532 Views
I have already posted a solution above that avoids the LoadLibrary and GetProcAddress method that clearly fails to work in your case.

0 Kudos
moncef
Beginner
1,532 Views
Quoting - anthonyrichards
I have already posted a solution above that avoids the LoadLibrary and GetProcAddress method that clearly fails to work in your case.


it is not a problem inherent to use of LoadLibrary instead of GetProcAddress but a problem of compilation option. When one uses a DLLcontaining Dialogswith an MDI project, one should not use directive compilation REFERENCEin the DLL's dialog callback function. Instead of :

!DEC$ ATTRIBUTES STDCALL,REFERENCE, ALIAS :"Function ":: Function

One should use

!DEC$ ATTRIBUTES STDCALL, ALIAS :"Function ":: Function

It was that the solution to my problem. Thanks for having tried to help me.

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,532 Views
Quoting - moncef

When one uses a DLLcontaining Dialogswith an MDI project, one should not use directive compilation REFERENCEin the DLL's dialog callback function.


That's not quite accurate. One should never use reference arguments for a Window procedure or Dialog procedure. You don't have REFERENCE for AboutDlgProc or MainWndProc either.

The callback functions, generally, must have the prototype that is pre-specified by the library in question (for example, in DFLOGM callbacks should be subroutine(Type(Dialog), integer, integer)). Unfortunately, if you miss that, compiler is seldom able to catch the error in compile-time, and you get strange run-time errors.
0 Kudos
moncef
Beginner
1,532 Views
Quoting - Jugoslav Dujic

That's not quite accurate. One should never use reference arguments for a Window procedure or Dialog procedure. You don't have REFERENCE for AboutDlgProc or MainWndProc either.

The callback functions, generally, must have the prototype that is pre-specified by the library in question (for example, in DFLOGM callbacks should be subroutine(Type(Dialog), integer, integer)). Unfortunately, if you miss that, compiler is seldom able to catch the error in compile-time, and you get strange run-time errors.

thanks for having to specify it well.
0 Kudos
Reply