- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I need help with the following tricky situation.
I have a module called MODULE_ERROR which contains types and subroutines that other subroutines of my main program and DLLs can call (see below).
The idea is to have the user code provide a user-defined, error-handling subroutine, which is passed as an argument to the HANDLE_ERROR_INIT subroutine of MODULE_ERROR. HANDLE_ERROR_INIT then initializes a pointer to the user-provided subroutine.
Now, every subroutine in my code or DLLs just needs to call the module subroutine HANDLE_ERROR, which points to the user-defined subroutine (as long as the code/DLLshave the module MODULE_ERROR in their scopeof course).
This works well when the call to HANDLE_ERROR happens in my main executable; but I get an access violation when the call to HANDLE_ERROR is called from one of my DLLs. I suspect that the DLL doesn't know how to interpret the value of the pointer SUB_ERROR_PTR.
Is there a way to get around this? It seems a bit complicated - I hope I explained it well. I am using IVF 10.
Olivier
MODULE MODULE_ERROR
IMPLICIT NONE
!*******************************************************************************
! PUBLIC PARAMETERS AND VARIABLES
!*******************************************************************************
INTEGER,PARAMETER :: MAX_ERROR_MESSAGE_LENGTH = 800
INTEGER,PARAMETER :: MAX_SYMBOL_NAME_LENGTH = 63
INTEGER,PARAMETER :: NO_ERROR = 0
INTEGER,PARAMETER :: WARNING = 1
INTEGER,PARAMETER :: USER_ERROR = 2
INTEGER,PARAMETER :: INTERNAL_ERROR = 3
!*******************************************************************************
! PUBLIC TYPES
!*******************************************************************************
TYPE T_SUBROUTINE_PATH
CHARACTER(MAX_SYMBOL_NAME_LENGTH),POINTER :: SUBROUTINE_NAME
TYPE(T_SUBROUTINE_PATH),POINTER :: PREVIOUS_SUBROUTINE_PATH
END TYPE T_SUBROUTINE_PATH
!*******************************************************************************
! INTERFACES AND PRIVATE VARIABLES
!*******************************************************************************
INTERFACE
SUBROUTINE HANDLE_ERROR_LOC(ERROR_MESSAGE,SUBROUTINE_NAME, &
ERROR_TYPE,SUBROUTINE_PATH)
IMPORT :: MAX_ERROR_MESSAGE_LENGTH,MAX_SYMBOL_NAME_LENGTH, &
T_SUBROUTINE_PATH
IMPLICIT NONE
CHARACTER(MAX_ERROR_MESSAGE_LENGTH),INTENT(IN) :: ERROR_MESSAGE
CHARACTER(MAX_SYMBOL_NAME_LENGTH),INTENT(IN) :: SUBROUTINE_NAME
INTEGER,INTENT(IN) :: ERROR_TYPE
TYPE(T_SUBROUTINE_PATH),OPTIONAL,INTENT(IN) :: SUBROUTINE_PATH
END SUBROUTINE HANDLE_ERROR_LOC
END INTERFACE
INTEGER(KIND=INT_PTR_KIND()) :: SUB_ERROR_PTR
POINTER(SUB_ERROR_PTR,HANDLE_ERROR_LOC)
LOGICAL :: MODULE_IS_INITIALIZED = .FALSE.
PRIVATE :: SUB_ERROR_PTR,MODULE_IS_INITIALIZED,HANDLE_ERROR_LOC
!*******************************************************************************
! CONTAINED PROCEDURES
!*******************************************************************************
CONTAINS
!_______________________________________________________________________________
SUBROUTINE HANDLE_ERROR_INIT(HANDLE_ERROR_USER,INTERNAL_ERROR_FILE_USER)
USE IFPORT,ONLY: SETENVQQ
USE MODULE_OS_CONSTANTS
IMPLICIT NONE
CHARACTER(LEN=MAX_FILE_NAME_LENGTH),INTENT(IN) :: INTERNAL_ERROR_FILE_USER
INTERFACE
SUBROUTINE HANDLE_ERROR_USER(ERROR_MESSAGE,SUBROUTINE_NAME, &
ERROR_TYPE,SUBROUTINE_PATH)
IMPORT :: MAX_ERROR_MESSAGE_LENGTH,MAX_SYMBOL_NAME_LENGTH, &
T_SUBROUTINE_PATH
IMPLICIT NONE
CHARACTER(MAX_ERROR_MESSAGE_LENGTH),INTENT(IN) :: ERROR_MESSAGE
CHARACTER(MAX_SYMBOL_NAME_LENGTH),INTENT(IN) :: SUBROUTINE_NAME
INTEGER,INTENT(IN) :: ERROR_TYPE
TYPE(T_SUBROUTINE_PATH),OPTIONAL,INTENT(IN) :: SUBROUTINE_PATH
END SUBROUTINE HANDLE_ERROR_USER
END INTERFACE
LOGICAL :: STATUS
SUB_ERROR_PTR = LOC(HANDLE_ERROR_USER)
STATUS = SETENVQQ('FOR_DIAGNOSTIC_LOG_FILE=' // TRIM(INTERNAL_ERROR_FILE_USER))
END SUBROUTINE HANDLE_ERROR_INIT
!_______________________________________________________________________________
SUBROUTINE HANDLE_ERROR(ERROR_MESSAGE,SUBROUTINE_NAME,ERROR_TYPE, &
SUBROUTINE_PATH)
IMPLICIT NONE
CHARACTER(MAX_ERROR_MESSAGE_LENGTH),INTENT(IN) :: ERROR_MESSAGE
CHARACTER(MAX_SYMBOL_NAME_LENGTH),INTENT(IN) :: SUBROUTINE_NAME
INTEGER,INTENT(IN) :: ERROR_TYPE
TYPE(T_SUBROUTINE_PATH),OPTIONAL,INTENT(IN) :: SUBROUTINE_PATH
write(*,*) 'test'
CALL HANDLE_ERROR_LOC(ERROR_MESSAGE,SUBROUTINE_NAME,ERROR_TYPE,SUBROUTINE_PATH)
END SUBROUTINE HANDLE_ERROR
END MODULE MODULE_ERROR
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
1. The main program "MY_PROGRAM.f90" and "MY_SUB.f90"
2.A static library "MY_STATIC_LIB.f90"
3. A DLL "MY_DLL.f90"
The source of these procedures is shown below.
I don't know if this is a bug. It's a bit puzzling.
Thanks in advance for your help!
Olivier
PROGRAM MY_PROGRAM
USE MY_STATIC_LIB
USE MY_DLL
IMPLICIT NONE
INTEGER :: I
EXTERNAL :: MY_SUB
I = 0
CALL MY_STATIC_LIB_INIT(MY_SUB)
CALL MY_STATIC_LIB_SUB(I)
WRITE(*,*) I
! This will trigger an error.
CALL MY_DLL_SUB(I)
END PROGRAM MY_PROGRAM
SUBROUTINE MY_SUB(I)
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: I
I = I+1
END SUBROUTINE MY_SUB
MODULE MY_STATIC_LIB
IMPLICIT NONE
INTERFACE
SUBROUTINE MY_STATIC_LIB_SUB_LOC(I)
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: I
END SUBROUTINE MY_STATIC_LIB_SUB_LOC
END INTERFACE
INTEGER(KIND=INT_PTR_KIND()) :: MY_STATIC_LIB_SUB_PTR
POINTER(MY_STATIC_LIB_SUB_PTR,MY_STATIC_LIB_SUB_LOC)
PRIVATE :: MY_STATIC_LIB_SUB_PTR,MY_STATIC_LIB_SUB_LOC
CONTAINS
SUBROUTINE MY_STATIC_LIB_INIT(USER_PROVIDED_SUB)
IMPLICIT NONE
INTERFACE
SUBROUTINE USER_PROVIDED_SUB(I)
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: I
END SUBROUTINE USER_PROVIDED_SUB
END INTERFACE
MY_STATIC_LIB_SUB_PTR = LOC(USER_PROVIDED_SUB)
END SUBROUTINE MY_STATIC_LIB_INIT
SUBROUTINE MY_STATIC_LIB_SUB(I)
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: I
CALL MY_STATIC_LIB_SUB_LOC(I)
END SUBROUTINE MY_STATIC_LIB_SUB
END MODULE MY_STATIC_LIB
MODULE MY_DLL
IMPLICIT NONE
CONTAINS
SUBROUTINE MY_DLL_SUB(I)
!DEC$ ATTRIBUTES DLLEXPORT :: MY_DLL_SUB
USE MY_STATIC_LIB
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: I
CALL MY_STATIC_LIB_SUB(I)
END SUBROUTINE MY_DLL_SUB
END MODULE MY_DLL
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
One fix would be to put the code that is in your static library into in a DLL of its own. Then both the exe and other DLLs refer to that single instance. Another option (more complicated) would be to have the exe provide the DLL with an explicit pointer to a callback routine in the (only) instance of the static library that is in the EXE (the DLL would then not be linked against the static library).
This is similar in many respects to the debilitating programming disease known as multiple C library syndrome.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
One fix would be to put the code that is in your static library into in a DLL of its own. Then both the exe and other DLLs refer to that single instance. Another option (more complicated) would be to have the exe provide the DLL with an explicit pointer to a callback routine in the (only) instance of the static library that is in the EXE (the DLL would then not be linked against the static library).
This is similar in many respects to the debilitating programming disease known as multiple C library syndrome.
Thanks a lot IanH. I think you nailed it. I naively assumed that both the DLL and the EXE would share the same module variables of the common static library they are linked with. Your explanation definitely make sense.
This IS debilitating :)
I'll find a workaround - your first suggestion seems the easiest to implement.
Olivier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Olivier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you mean the executable that links to the DLL, then no. If it isn't visible when the DLL is linked, it isn't visible to the DLL. You can share variables from a DLL to an executable, but they are defined by the DLL and accessed by the executable.

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