- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is it possible to pass a function pointer to a dll and use it to call a routine in the .exe?
Or is there a way to do anything similar?
I have a simulator kernal that makes calls to callback routines in a user provided dll. I do not know which variables these callback routines need from the kernal. So, I want to provide a function that the dll can call that is in the simulator kernal to get the data it needs.
Or is there a way to do anything similar?
I have a simulator kernal that makes calls to callback routines in a user provided dll. I do not know which variables these callback routines need from the kernal. So, I want to provide a function that the dll can call that is in the simulator kernal to get the data it needs.
Link Copied
7 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sure, you can do this. Just make sure the DLL uses the correct calling convention (if it's Fortran, that's easy.) The simple approach is to declare the routine EXTERNAL and the dummy argument EXTERNAL.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Steve Lionel (Intel)
Sure, you can do this. Just make sure the DLL uses the correct calling convention (if it's Fortran, that's easy.) The simple approach is to declare the routine EXTERNAL and the dummy argument EXTERNAL.
I tried that and it is insufficient for my needs. I do not simply want to call a function that I pass to the dll through the argument list of the function that would be using it. What I want is to register it to a pointer in the dll and call it from any routine in the dll.
For instance (For logging messages):
MODULE Routine_Registration_m
INTERFACE
SUBROUTINE messenger (message, i_scalar, r_scalar)
CHARACTER(LEN=*), INTENT(IN) :: message ! text, message to be written
INTEGER(KIND=4), OPTIONAL, INTENT(IN) :: i_scalar ! integer one-dimensional array to be written
REAL(KIND=8), OPTIONAL, INTENT(IN):: r_scalar ! real variable to be written
END SUBROUTINE messenger
END INTERFACE
POINTER (p_Messenger, Messenger)
END MODULE Routine_Registration_m
SUBROUTINE Routine_Registration(Msg)
USE Routine_Registration_m
IMPLICIT NONE
INTERFACE
SUBROUTINE Msg (message, i_scalar, r_scalar)
CHARACTER(LEN=*), INTENT(IN) :: message ! text, message to be written
INTEGER(KIND=4), OPTIONAL, INTENT(IN) :: i_scalar ! integer one-dimensional array to be written
REAL(KIND=8), OPTIONAL, INTENT(IN):: r_scalar ! real variable to be written
END SUBROUTINE
END INTERFACE
EXTERNAL :: Msg
p_Messenger = Msg
END SUBROUTINE Routine_Registration
But that doesn't compile because Msg is on the right of an assignment.
Also I am having trouble getting the EXTERNAL statement attached to a subroutine inside a module contains area.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok - I didn't understand everything you wanted.
Here is a complete, working example that demonstrates using Fortran 2003 procedure pointers and abstract interfaces. You'll need 11.0 or later for this. I cheated a bit and made My_Messenger a contained procedure. Fortran 2003 doesn't allow you to pass this as an actual argument, but Fortran 2008 (and Intel Fortran) does. I moved Routine_Registration into the module because I figured this would be part of the DLL. It doesn't HAVE to be, but it makes more sense there.
Let me know if you have further questions.
Here is a complete, working example that demonstrates using Fortran 2003 procedure pointers and abstract interfaces. You'll need 11.0 or later for this. I cheated a bit and made My_Messenger a contained procedure. Fortran 2003 doesn't allow you to pass this as an actual argument, but Fortran 2008 (and Intel Fortran) does. I moved Routine_Registration into the module because I figured this would be part of the DLL. It doesn't HAVE to be, but it makes more sense there.
Let me know if you have further questions.
[plain]MODULE Routine_Registration_m
ABSTRACT INTERFACE
SUBROUTINE messenger (message, i_scalar, r_scalar)
CHARACTER(LEN=*), INTENT(IN) :: message ! text, message to be written
INTEGER(KIND=4), OPTIONAL, INTENT(IN) :: i_scalar ! integer one-dimensional array to be written
REAL(KIND=8), OPTIONAL, INTENT(IN):: r_scalar ! real variable to be written
END SUBROUTINE messenger
END INTERFACE
PROCEDURE(messenger), POINTER :: p_Messenger
CONTAINS
SUBROUTINE Routine_Registration(Msg)
IMPLICIT NONE
PROCEDURE(messenger) :: Msg
p_Messenger => Msg
END SUBROUTINE Routine_Registration
SUBROUTINE Call_Registration
CALL p_messenger ('This is a message', 1, 2.0_8)
END SUBROUTINE Call_Registration
END MODULE Routine_Registration_m
program test
USE Routine_Registration_m
CALL Routine_Registration(My_Messenger)
CALL Call_Registration
CONTAINS
SUBROUTINE My_Messenger (message, i_scalar, r_scalar)
CHARACTER(LEN=*), INTENT(IN) :: message ! text, message to be written
INTEGER(KIND=4), OPTIONAL, INTENT(IN) :: i_scalar ! integer one-dimensional array to be written
REAL(KIND=8), OPTIONAL, INTENT(IN):: r_scalar ! real variable to be written
PRINT *, message, i_scalar, r_scalar
END SUBROUTINE My_Messenger
END PROGRAM TEST[/plain]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Steve Lionel (Intel)
Ok - I didn't understand everything you wanted.
The example uses Fortran 2003 procedure pointers and abstract interfaces. You'll need 11.0 or later for this. I cheated a bit and made My_Messenger a contained procedure. Fortran 2003 doesn't allow you to pass this as an actual argument, but Fortran 2008 (and Intel Fortran) does. I moved Routine_Registration into the module because I figured this would be part of the DLL. It doesn't HAVE to be, but it makes more sense there.
Let me know if you have further questions.
The example uses Fortran 2003 procedure pointers and abstract interfaces. You'll need 11.0 or later for this. I cheated a bit and made My_Messenger a contained procedure. Fortran 2003 doesn't allow you to pass this as an actual argument, but Fortran 2008 (and Intel Fortran) does. I moved Routine_Registration into the module because I figured this would be part of the DLL. It doesn't HAVE to be, but it makes more sense there.
Let me know if you have further questions.
Since the Fortran 2008 Standard is not yet officially approved, Do you have a version that works without the Intel extensions or 2008 Standard features? (My product must be portable to systems that you do not make a compiler for.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just move the callback procedure into a module and USE the module from the main program.
I will warn you that some other compilers may not support procedure pointers, and the "integer pointer" extension you tried to use before is also not widely implemented for procedures.
I will warn you that some other compilers may not support procedure pointers, and the "integer pointer" extension you tried to use before is also not widely implemented for procedures.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks!
I have had problems separating your example into a DLL and a kernal part. The copy of the dll_m module in the kernal will not allow the"PROCEDURE(messenger) :: Msg" in the Routine_Registrationinternfaceto compile.
I have had problems separating your example into a DLL and a kernal part. The copy of the dll_m module in the kernal will not allow the"PROCEDURE(messenger) :: Msg" in the Routine_Registrationinternfaceto compile.
MODULE dll_m
ABSTRACT INTERFACE
SUBROUTINE messenger (message, i_scalar, r_scalar)
CHARACTER(LEN=*), INTENT(IN) :: message ! text, message to be written
INTEGER(KIND=4), OPTIONAL, INTENT(IN) :: i_scalar ! integer one-dimensional array to be written
REAL(KIND=8), OPTIONAL, INTENT(IN):: r_scalar ! real variable to be written
END SUBROUTINE messenger
END INTERFACE
ABSTRACT INTERFACE
SUBROUTINE Routine_Registration(Msg)
PROCEDURE(messenger) :: Msg
END SUBROUTINE Routine_Registration
END INTERFACE
ABSTRACT INTERFACE
SUBROUTINE Call_Test()
END SUBROUTINE Call_Test
END INTERFACE
END MODULE dll_m
error #8169: The specified interface is not declared. [MESSENGER]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
1. Remove "ABSTRACT" from the Routine_Registration and Call_Test declarations. ABSTRACT INTERFACE is when you want to define a procedure interface without an actual corresponding external procedure. I don't think you really want these as INTERFACE blocks at all - they should be module procedures.
2. Add IMPORT following "SUBROUTINE RoutineRegistration(msg)" to make the declaration of messenger visible inside the interface block (assuming you keep it as an interface block.) See Domestic or Imported

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