I have a FORTRAN DLL that is integrated into third-party software. To do this, it has one entry point routine, the arguments to that routine contain the addresses of all the other interface routines. References to these interface routines are resolved in a C library, which I believe is unneccessary. According to my predecessor (who came up with this scheme), the C library:
"Contains the definition of the addresses of imported functions in the DLL libraries. These addresses
correspond to addresses of functions in whichever executable program calls
the DLL library. To avoid using the DLLIMPORT compiler directive in the
DLL, the addresses are used to call the functions directly. This permits
the building of the DLLs without using any import directives, and thus
does not require a formal exports declaration from the calling executable.
The set of required functions are also defined here. These are called using the
aforementioned addresses."
To improve maintainability, I think I can replace the C with FORTRAN using the POINTER keyword - but I'm not sure exactly how - any one want to help me out?
Cheers,
Dan
"Contains the definition of the addresses of imported functions in the DLL libraries. These addresses
correspond to addresses of functions in whichever executable program calls
the DLL library. To avoid using the DLLIMPORT compiler directive in the
DLL, the addresses are used to call the functions directly. This permits
the building of the DLLs without using any import directives, and thus
does not require a formal exports declaration from the calling executable.
The set of required functions are also defined here. These are called using the
aforementioned addresses."
To improve maintainability, I think I can replace the C with FORTRAN using the POINTER keyword - but I'm not sure exactly how - any one want to help me out?
Cheers,
Dan
链接已复制
10 回复数
Mmh, it's still not so clear what that C library did -- could you post/attach some fragments?
It's the use of word "import" that confuses me -- I'd rather expect "export". On the second reading, it looks as if calling .exe offers some callback functions that are to be called back from the dll, but I'm not sure.
If I got it right, see for example function prototypes and MAPIBind routine in MAPI module. MAPIBind dereferences routine pointers to callable routines. It uses GetProcAddress to obtain the addresses, but they may come through arg-list as well, as (I believe) in your case.
Jugoslav
It's the use of word "import" that confuses me -- I'd rather expect "export". On the second reading, it looks as if calling .exe offers some callback functions that are to be called back from the dll, but I'm not sure.
If I got it right, see for example function prototypes and MAPIBind routine in MAPI module. MAPIBind dereferences routine pointers to callable routines. It uses GetProcAddress to obtain the addresses, but they may come through arg-list as well, as (I believe) in your case.
Jugoslav
Jugo - I think you've hit the nail on the head
In the FORTRAN interface file in the DLL I need something like:
pointer(addr_get_darray, new_get_darray)
pointer(addr_put_darray, new_put_darray)
And I can get rid of set_addresses altogether?
(Sure seems to simplify things....)
In the FORTRAN interface file in the DLL I need something like:
pointer(addr_get_darray, new_get_darray)
pointer(addr_put_darray, new_put_darray)
And I can get rid of set_addresses altogether?
(Sure seems to simplify things....)
I assume extern_get_darray is declared in some .h file (or in the header of .c file) as static void* extern_get_darray, right?
The fortran equivalent of C code would be (for "get" function only):
For example:
HTH
Jugoslav
The fortran equivalent of C code would be (for "get" function only):
MODULE Externs INTEGER, PARAMETER:: LPFUNC=4 !Prototype of the callback (from the exe) INTERFACE SUBROUTINE new_get_darray (name_opt, list, item, field, sub, value) CHARACTER*(*) name_opt CHARACTER*(*) list CHARACTER*(*) item CHARACTER*(*) field INTEGER*4 sub REAL*8 value(*) END SUBROUTINE new_get_darray END INTERFACE !Pointer to the external callback procedure POINTER (lpnew_get_darray, new_get_darray) CONTAINS SUBROUTINE set_addresses(addr_get_darray) !Save address of callback lpnew_get_darray; !new_get_darray is now directly callable from !USErs of the module without resorting to !C wrapper INTEGER(LPFUNC):: addr_get_darray lpnew_get_darray = addr_get_darray END SUBROUTINE set_addresses END MODULE Externs
For example:
subroutine somewhere_deep_in_the_code() use Externs ... call new_get_array(...)
HTH
Jugoslav
Looks as if we posted simultaneously; yes, in my sample set_addresses just does the assignment and can be dropped altogether.
Note that you don't necessarily need pointers. You can use standard Fortran's EXTERNAL or INTERFACE on dummy argument routine but only in case that new_get_darray is passed consistently through all arg-lists where they're needed. However, that can be a PITA if call tree is deep and/or wide. Solution with POINTER in a MODULE as above workarounds for the lack of "global routine pointer" in standard Fortran.
Note that you don't necessarily need pointers. You can use standard Fortran's EXTERNAL or INTERFACE on dummy argument routine but only in case that new_get_darray is passed consistently through all arg-lists where they're needed. However, that can be a PITA if call tree is deep and/or wide. Solution with POINTER in a MODULE as above workarounds for the lack of "global routine pointer" in standard Fortran.
Thanks Jugoslav...I'll get FORTRAN POINTERS into my head eventually! I have managed to do some significant code simplification using it though. Our old code was peppered with cross language links - basically, pre-POINTER, my predecessors were dancing in and out of C every time a pointer was needed.
Then, if you had to change anything, there were umpteen different places you had to remember to do it. PITA.
It's much better with POINTER.
Then, if you had to change anything, there were umpteen different places you had to remember to do it. PITA.
It's much better with POINTER.
Yeah I know it's non-standard - Steve has warned me about that before. But CVF is the only FORTRAN compiler we use, so as long as Steve and the boys don't decide to get rid of POINTER in merging with Intel, I'll stick with it for convenience! ;o)
