- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Fortran gurus,
I was wondering if there was an easy way for a main program to associate procedure pointers that are present in a dynamically-loaded DLL. So, for example, say the DLL contained the following module:
module dll_module abstract interface subroutine blah_( a,b,c ) integer :: a,b,c end subroutine blah_ end interface procedure(blah_),pointer,public,protected :: blah => null() end module dll_module
This DLL is loaded using LoadLibrary() by the main program (which is also Fortran). What I want is for the main program to then associate "blah" to a function present in the main program that the DLL would then have access to.
Now, I have a way to do this that involves adding a setter function to the DLL like so:
subroutine set_blah_pointer(p) !DEC$ ATTRIBUTES DEFAULT, DLLEXPORT, ALIAS:"set_blah_pointer" :: set_blah_pointer type(c_funptr), intent(in) :: p procedure(blah_),pointer :: fp call c_f_procpointer(p, fp) blah => fp end subroutine set_blah_pointer
The main program then calls this setter, passing in the c_funloc of the function, which then gets associated. This does work, but my question is, is there way to do this that is "cleaner" on the DLL side? (that doesn't involve adding this extra function for each of the pointers). If I could DLLEXPORT the procedure pointer, then how would I access it in the main program?
Jacob
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You would put the procedure pointer in a module that is built as part of the DLL project. Then USE that module in the main program. For example:
module dll_mod procedure(), pointer :: dll_proc_ptr !DEC$ ATTRIBUTES DLLEXPORT :: dll_proc_ptr end module dll_mod
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is it possible to USE a module from a DLL that is loaded at runtime via LoadLibrary? In my case, the DLLs (there could be many of them) optionally contain this module to allow them to call some functions in the main program. The idea being that the DLLs are created by users of the tool, but who don't otherwise have access to the sourcecode.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I see two possible solutions. If you want to retain the PROTECTED attribute for the procedure pointers, you are really promising that you won't point them at anything except via a procedure defined within the module that defines the procedure pointers. But we could write a single subroutine that does all the pointing, relying on OPTIONAL arguments to figure out which ones to point at. I wish it were possible to make the first argument to a procedure of a PRIVATE type and OPTIONAL to force keywords for all actual arguments, but this seems to be not allowed in Fortran. Anyhow, here is pointdll1.f90
! pointdll1.f90 module M implicit none private public sub_,blah_,blalalala_,set_pointers,callme abstract interface subroutine sub_(x) implicit none integer x end subroutine sub_ subroutine blah_(x) implicit none real x end subroutine blah_ subroutine blalalala_(x) implicit none character(*) x end subroutine blalalala_ end interface procedure(sub_),pointer,public,protected :: sub => null() procedure(blah_),pointer,public,protected :: blah => null() procedure(blalalala_),pointer,public,protected :: blalalala => null() contains subroutine set_pointers(point_at_sub,point_at_blah,point_at_blalalala) !DEC$ ATTRIBUTES DLLEXPORT :: set_pointers procedure(sub_),optional :: point_at_sub procedure(blah_),optional :: point_at_blah procedure(blalalala_),optional :: point_at_blalalala if(present(point_at_sub)) then sub => point_at_sub end if if(present(point_at_blah)) then blah => point_at_blah end if if(present(point_at_blalalala)) then blalalala => point_at_blalalala end if end subroutine set_pointers subroutine callme() !DEC$ ATTRIBUTES DLLEXPORT :: callme if(associated(sub)) then call sub(1) end if if(associated(blah)) then call blah(1.0) end if if(associated(blalalala)) then call blalalala('hana') end if end subroutine callme end module M
And main1.f90
! main1.f90 module N implicit none contains subroutine mysub(x) integer x write(*,'(*(g0))') 'Greetings from mysub. x = ',x end subroutine mysub subroutine myblalalala(x) character(*) x write(*,'(*(g0))') 'Greetings from myblalalala. x = ',x end subroutine myblalalala end module N program P use M use N implicit none call set_pointers(point_at_sub = mysub, point_at_blalalala = myblalalala) call callme end program P
Build instructions for main1.exe:
rem makedll1.bat ifort /dll pointdll1.f90 ifort main1.f90 pointdll1.lib
Output of main1.exe:
reetings from mysub. x = 1 reetings from myblalalala. x = hana
You can always cheat your way around a restriction like this but is you are going to do it anyway, why make them PROTECTED in the first place? Get rid of that and you can just point in your main program. I see that while I was composing these examples Steve suggested this approach. Here is pointdll2.f90:
! pointdll2.f90 module M implicit none private public sub_,blah_,blalalala_,callme abstract interface subroutine sub_(x) implicit none integer x end subroutine sub_ subroutine blah_(x) implicit none real x end subroutine blah_ subroutine blalalala_(x) implicit none character(*) x end subroutine blalalala_ end interface !DEC$ ATTRIBUTES DLLEXPORT :: sub, blah, blalalala procedure(sub_),pointer,public :: sub => null() procedure(blah_),pointer,public :: blah => null() procedure(blalalala_),pointer,public :: blalalala => null() contains subroutine callme() !DEC$ ATTRIBUTES DLLEXPORT :: callme if(associated(sub)) then call sub(1) end if if(associated(blah)) then call blah(1.0) end if if(associated(blalalala)) then call blalalala('hana') end if end subroutine callme end module M
And main2.f90:
! main2.f90 module N implicit none contains subroutine mysub(x) integer x write(*,'(*(g0))') 'Greetings from mysub. x = ',x end subroutine mysub subroutine myblalalala(x) character(*) x write(*,'(*(g0))') 'Greetings from myblalalala. x = ',x end subroutine myblalalala end module N program P use M use N implicit none sub => mysub blalalala => myblalalala call callme end program P
Build instructions for main2.exe:
rem makedll2.bat ifort /dll pointdll2.f90 ifort main2.f90 pointdll2.lib
Output of main2.exe:
Greetings from mysub. x = 1 Greetings from myblalalala. x = hana
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
See my response to Steve above. In my case, the 2nd solution won't work because the main program doesn't have access to module M at compile time (keeping in mind that there can be more than one DLL, each with its own module M). If I export sub, blah, blalalala
from the DLL, then how do I access them in the main program at runtime?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I forgot you said you were using LoadLibrary. There are solutions to this but, to be honest, the "setter" procedure is probably the best option.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You use GetProcAddress to query the address of something in a DLL, even if that something isn't a "Proc".
But I very much agree with Steve in #6.
! Compile to a DLL MODULE m20171111 USE, INTRINSIC :: ISO_C_BINDING IMPLICIT NONE TYPE(C_FUNPTR), BIND(C, NAME='proc_ptr') :: proc_ptr !DEC$ ATTRIBUTES DLLEXPORT :: proc_ptr CONTAINS SUBROUTINE test() BIND(C, NAME='test') !DEC$ ATTRIBUTES DLLEXPORT :: test ABSTRACT INTERFACE SUBROUTINE s() BIND(C) IMPLICIT NONE END SUBROUTINE s END INTERFACE PROCEDURE(s), POINTER :: p CALL C_F_PROCPOINTER(proc_ptr, p) CALL p END SUBROUTINE test END MODULE m20171111 ! Compile to an exe PROGRAM p20171111 USE, INTRINSIC :: ISO_C_BINDING USE KERNEL32 IMPLICIT NONE INTEGER(HANDLE) :: dll_handle TYPE(C_PTR) :: proc_ptr_cptr TYPE(C_FUNPTR), POINTER :: proc_ptr TYPE(C_FUNPTR) :: test_cptr ABSTRACT INTERFACE SUBROUTINE test_intf() BIND(C) IMPLICIT NONE END SUBROUTINE test_intf END INTERFACE PROCEDURE(test_intf), POINTER :: test dll_handle = LoadLibrary('m20171111.dll' // ACHAR(0)) IF (dll_handle == 0) ERROR STOP 'dll_handle was zero' proc_ptr_cptr = TRANSFER( & GetProcAddress(dll_handle, 'proc_ptr' // ACHAR(0)), & proc_ptr_cptr ) IF (.NOT. C_ASSOCIATED(proc_ptr_cptr)) & ERROR STOP 'proc_ptr_cptr not associated' CALL C_F_POINTER(proc_ptr_cptr, proc_ptr) proc_ptr = C_FUNLOC(my_s) test_cptr = TRANSFER( & GetProcAddress(dll_handle, 'test' // ACHAR(0)), & test_cptr ) IF (.NOT. C_ASSOCIATED(test_cptr)) & ERROR STOP 'test_cptr not associated' CALL C_F_PROCPOINTER(test_cptr, test) CALL test() CONTAINS SUBROUTINE my_s() BIND(C) PRINT "('Hello!')" END SUBROUTINE my_s END PROGRAM p20171111
>ifort /check:all /warn:all /standard-semantics /dll m20171111.f90 Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 18.0.0.124 Build 20170811 Copyright (C) 1985-2017 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 14.00.24215.1 Copyright (C) Microsoft Corporation. All rights reserved. -out:m20171111.dll -dll -implib:m20171111.lib m20171111.obj Creating library m20171111.lib and object m20171111.exp >ifort /check:all /warn:all /standard-semantics p20171111.f90 Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 18.0.0.124 Build 20170811 Copyright (C) 1985-2017 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 14.00.24215.1 Copyright (C) Microsoft Corporation. All rights reserved. -out:p20171111.exe -subsystem:console p20171111.obj >p20171111 Hello!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Whoa, Quote #3 happened while I was preparing Quote #4. You can USE such a module, but the data and procedures won't work, just stuff like type definitions, interfaces, and named constants. At least I think that you will need GetProcAddress and then C_F_PROCPOINTER to access procedures and C_F_POINTER to access data. OK, here is an example of this. Note that there is a problem that you can't USE the interface for subroutine callme directly here because the DLLEXPORT attribute in there just mungs up a procedure pointer that you try to point at it. I think that's a bug in ifort and maybe it's even fix in the latest version. Also there is the issue that procedure pointers aren't first-class objects in Fortran so you have to wrap them in a structure if you want to point at them. Here is pointdll3.f90:
! pointdll3.f90 module M implicit none private public sub_,blah_,blalalala_,callme abstract interface subroutine sub_(x) implicit none integer x end subroutine sub_ subroutine blah_(x) implicit none real x end subroutine blah_ subroutine blalalala_(x) implicit none character(*) x end subroutine blalalala_ end interface procedure(sub_),pointer,public :: sub => null() !DEC$ ATTRIBUTES DLLEXPORT, ALIAS: 'sub' :: sub procedure(blah_),pointer,public :: blah => null() !DEC$ ATTRIBUTES DLLEXPORT, ALIAS: 'blah' :: blah procedure(blalalala_),pointer,public :: blalalala => null() !DEC$ ATTRIBUTES DLLEXPORT, ALIAS: 'blalalala' :: blalalala contains subroutine callme() !DEC$ ATTRIBUTES DLLEXPORT, ALIAS: 'callme' :: callme if(associated(sub)) then call sub(1) end if if(associated(blah)) then call blah(1.0) end if if(associated(blalalala)) then call blalalala('hana') end if end subroutine callme end module M
And main3.f90:
! main3.f90 module N use ISO_C_BINDING implicit none integer, parameter :: HANDLE = C_INTPTR_T integer, parameter :: DWORD = C_LONG interface function LoadLibrary(lpFileName) bind(C,name='LoadLibraryA') import implicit none !DEC$ ATTRIBUTES STDCALL :: LoadLibrary integer(HANDLE) LoadLibrary character(KIND=C_CHAR) lpFileName(*) end function LoadLibrary function GetProcAddress(hModule,lpProcName) bind(C,name='GetProcAddress') import implicit none !DEC$ ATTRIBUTES STDCALL :: GetProcAddress type(C_FUNPTR) GetProcAddress integer(HANDLE), value :: hModule character(KIND=C_CHAR) lpProcName(*) end function GetProcAddress function GetDataAddress(hModule,lpDataName) bind(C,name='GetProcAddress') import implicit none !DEC$ ATTRIBUTES STDCALL :: GetDataAddress type(C_PTR) GetDataAddress integer(HANDLE), value :: hModule character(KIND=C_CHAR) lpDataName(*) end function GetDataAddress function GetLastError() bind(C,name='GetLastError') import implicit none !DEC$ ATTRIBUTES STDCALL :: GetLastError integer(DWORD) GetLastError end function GetLastError end interface contains subroutine mysub(x) integer x write(*,'(*(g0))') 'Greetings from mysub. x = ',x end subroutine mysub subroutine myblalalala(x) character(*) x write(*,'(*(g0))') 'Greetings from myblalalala. x = ',x end subroutine myblalalala end module N program P use M, invalid => callme use N implicit none integer(HANDLE) hModule interface subroutine callme() end subroutine callme end interface procedure(callme), pointer :: pcallme type has_sub procedure(sub_), nopass, pointer :: sub end type has_sub type(has_sub), pointer :: subtype type has_blalalala procedure(blalalala_), nopass, pointer :: blalalala end type has_blalalala type(has_blalalala), pointer :: blalalalatype type(C_PTR) dptr type(C_FUNPTR) fptr hModule = LoadLibrary('pointdll3.dll'//achar(0)) fptr = GetProcAddress(hModule,'callme'//achar(0)) call C_F_PROCPOINTER(fptr,pcallme) dptr = GetDataAddress(hModule,'sub'//achar(0)) call C_F_POINTER(dptr,subtype) subtype%sub => mysub dptr = GetDataAddress(hModule,'blalalala'//achar(0)) call C_F_POINTER(dptr,blalalalatype) blalalalatype%blalalala => myblalalala call pcallme() end program P
Build instructions for main3.exe:
rem makedll3.bat ifort /dll pointdll3.f90 ifort main3.f90
Output of main3.exe:
Greetings from mysub. x = 1 Greetings from myblalalala. x = hana
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The pace of posts to this thread sees to be outstripping my own posting speed. But I think my example in Quote #8 is roughly what you are asking for. Do the module names actually conflict or are they different for the Fortran that compiles to each *.dll. If they conflict, you won't be able to use type definitions, interfaces and named constants from any of the modules, so you will have to rewrite them from scratch or via INCLUDE in programs that USE the modules. As it is ifort, through bugs in my opinion, forces you to rewrite the interface for any module procedures in the *.dll that you want to invoke directly from your main program.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Typically you would put the shared declarations of types and the like into a single,separate module, that was then used in program units that comprise the various DLLs and EXE.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My sense of the use case is that the *.dll projects may come from sufficiently disparate groups that a single MODULE with everybody's declarations is not feasible. But is everyone names their module M instead of giving it a unique name, then that will be a problem. If everybody gives their module different names but uses the same names for entities within their modules, that's not a problem because Fortran can resolve these issues via the renaming clause of the USE statement. Giving procedures the same name is never a problem because GetProcAddress needed the handle to the appropriate *.dll to get a handle to the procedure anyway.
But it occurred to me that one could simplify the Fortran code if a *.def file were permitted in the build process. I showed in a post yesterday https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/748133#comment-1914738 how it might be possible to generate a *.def file automatically, although one slight modification would have to be made to the parser for this problem. But given a *.def file the Fortran code for the *.dll projects would not have to be marked up with all of those DLLEXPORT statements and the Fortran code for the main program would not have to rewrite the interface for procedures in the modules that it needs to invoke through a procedure pointer. Here's what I mean. pointdll4.f90:
! pointdll4.f90 module M implicit none private public sub_,blah_,blalalala_,callme abstract interface subroutine sub_(x) implicit none integer x end subroutine sub_ subroutine blah_(x) implicit none real x end subroutine blah_ subroutine blalalala_(x) implicit none character(*) x end subroutine blalalala_ end interface procedure(sub_),pointer,public :: sub => null() procedure(blah_),pointer,public :: blah => null() procedure(blalalala_),pointer,public :: blalalala => null() contains subroutine callme() if(associated(sub)) then call sub(1) end if if(associated(blah)) then call blah(1.0) end if if(associated(blalalala)) then call blalalala('hana') end if end subroutine callme end module M
pointdll4.def:
; pointdll4.def EXPORTS callme = M_mp_CALLME sub = M_mp_SUB DATA blah = M_mp_BLAH DATA blalalala = M_mp_BLALALALA DATA
main4.f90:
! main4.f90 module N use ISO_C_BINDING implicit none integer, parameter :: HANDLE = C_INTPTR_T integer, parameter :: DWORD = C_LONG interface function LoadLibrary(lpFileName) bind(C,name='LoadLibraryA') import implicit none !DEC$ ATTRIBUTES STDCALL :: LoadLibrary integer(HANDLE) LoadLibrary character(KIND=C_CHAR) lpFileName(*) end function LoadLibrary function GetProcAddress(hModule,lpProcName) bind(C,name='GetProcAddress') import implicit none !DEC$ ATTRIBUTES STDCALL :: GetProcAddress type(C_FUNPTR) GetProcAddress integer(HANDLE), value :: hModule character(KIND=C_CHAR) lpProcName(*) end function GetProcAddress function GetDataAddress(hModule,lpDataName) bind(C,name='GetProcAddress') import implicit none !DEC$ ATTRIBUTES STDCALL :: GetDataAddress type(C_PTR) GetDataAddress integer(HANDLE), value :: hModule character(KIND=C_CHAR) lpDataName(*) end function GetDataAddress function GetLastError() bind(C,name='GetLastError') import implicit none !DEC$ ATTRIBUTES STDCALL :: GetLastError integer(DWORD) GetLastError end function GetLastError end interface contains subroutine mysub(x) integer x write(*,'(*(g0))') 'Greetings from mysub. x = ',x end subroutine mysub subroutine myblalalala(x) character(*) x write(*,'(*(g0))') 'Greetings from myblalalala. x = ',x end subroutine myblalalala end module N program P use M use N implicit none integer(HANDLE) hModule procedure(callme), pointer :: pcallme type has_sub procedure(sub_), nopass, pointer :: sub end type has_sub type(has_sub), pointer :: subtype type has_blalalala procedure(blalalala_), nopass, pointer :: blalalala end type has_blalalala type(has_blalalala), pointer :: blalalalatype type(C_PTR) dptr type(C_FUNPTR) fptr hModule = LoadLibrary('pointdll3.dll'//achar(0)) fptr = GetProcAddress(hModule,'callme'//achar(0)) call C_F_PROCPOINTER(fptr,pcallme) dptr = GetDataAddress(hModule,'sub'//achar(0)) call C_F_POINTER(dptr,subtype) subtype%sub => mysub dptr = GetDataAddress(hModule,'blalalala'//achar(0)) call C_F_POINTER(dptr,blalalalatype) blalalalatype%blalalala => myblalalala call pcallme() end program P
Build instructions for main4.exe:
rem makedll4.bat ifort /dll pointdll4.f90 pointdll4.def ifort main4.f90
Output of main4.exe:
Greetings from mysub. x = 1 Greetings from myblalalala. x = hana
Sorry for the explosion of code, but I wanted to give complete examples of my ideas so they would be easier to understand.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jacob Williams wrote:
Is it possible to USE a module from a DLL that is loaded at runtime via LoadLibrary? In my case, the DLLs (there could be many of them) optionally contain this module to allow them to call some functions in the main program. The idea being that the DLLs are created by users of the tool, but who don't otherwise have access to the sourcecode.
@Jacob Williams,
What exactly are you interested in? Is it really a call-back system, meaning you have a Fortran main program for which users introduce their own libraries (DLLs) with methods to be called by the main program but where the user code calls subprograms (procedures) that are part of the main program? Why not then simply pass the procedure pointers as part of the argument list itself for the DLL methods that are called by the main program, thus avoiding the extra setter methods? That seems a lot 'cleaner' than any of the alternatives.
That is, you can indeed do as shown upthread in Quotes 10 , 8, etc. (and a simpler version is shown below), but you will be violating the spirit of the PROTECTED attribute of your procedure pointer by setting their targets by means other than module procedures. It doesn't appear any 'cleaner' of an option then. Depending on how the main program is structured and what the user DLLs need to do, I might even consider object-oriented design of a wrapper 'class' i,.e., a derived type with type components are procedure pointers to methods in the main program and (some of) the bound procedures of said type are 'implemented' by users via DLLs; the main program only then deals with the wrapper 'class' and its methods but not the user methods directly and all the wiring is connected up in this 'class' by means of Fortran.
So a simpler variation of what was interpreted by Repeat Offender and IanH of your description in the original post might be the following, but note I won't recommend this:
User code:
module i abstract interface subroutine Isub( s ) character(len=*), intent(in) :: s end subroutine end interface end module module m use i, only : Isub implicit none private procedure(Isub), pointer, save, public, protected :: psub => null() contains subroutine foo() character(len=:), allocatable :: msg msg = "Hello World!" call psub( msg ) return end subroutine end module m
Module definition file for user DLL - by the way, I do strongly recommend such DEF files over DLLEXPORT directives which clutter Fortran code:
LIBRARY m EXPORTS M_mp_PSUB @1 DATA M_mp_FOO @2
Main program - note the main program knows nothing about interfaces of stuff in user DLL since it does not 'USE' user MOD file as you indicated - this is not ideal:
module cb_m ! Call back module implicit none contains subroutine sub( s ) ! A call back procedure character(len=*), intent(in) :: s print *, "sub: message is ", s end subroutine end module program p use, intrinsic :: iso_c_binding, only : c_funloc, c_char, NUL => c_null_char, c_ptr, c_funptr, & c_intptr_t, c_f_pointer, c_f_procpointer use IWin_m, only : LoadLibrary, GetProcAddress, GetDataAddress use cb_m, only : sub procedure(), pointer :: foo blk_dll_load: block integer(c_intptr_t) :: m_handle character(kind=c_char, len=*), parameter :: DllName = c_char_"m.dll" // NUL character(kind=c_char, len=*), parameter :: DataName = c_char_"M_mp_PSUB" // NUL character(kind=c_char, len=*), parameter :: ProcName = c_char_"M_mp_FOO" // NUL type(c_funptr) :: cfp_foo type(c_funptr) :: cfp_sub_main type(c_ptr) :: cfp_sub_dll integer(c_intptr_t), pointer :: add_sub m_handle = LoadLibrary( DllName ) ! Set procedure pointer to user DLL method cfp_foo = GetProcAddress( m_handle, ProcName ) call c_f_procpointer( cfp_foo, foo ) ! Set procedure pointer in the user DLL!! cfp_sub_main = c_funloc( sub ) ! Get address of callback procedure cfp_sub_dll = GetDataAddress( m_handle, DataName ) call c_f_pointer( cfp_sub_dll, add_sub ) ! Transfer the address of callback procedure to DLL pointer via an ! intermediary of integer(c_intptr_t) type add_sub = transfer( cfp_sub_main, mold=add_sub ) ! Clean up add_sub => null() end block blk_dll_load call foo() ! Call user DLL method stop end program
Upon execution using Intel Fortran 18.0,
sub: message is Hello World!
Just fyi, the module with interfaces for Windows DLL management APIs that I used are:
module IWin_m use, intrinsic :: iso_c_binding, only : c_char, c_int, c_intptr_t, c_ptr, c_funptr implicit none interface function LoadLibrary(lpLibName) bind(C, NAME='LoadLibraryA') result(RetVal) !DIR$ ATTRIBUTES STDCALL :: LoadLibrary import :: c_char, c_intptr_t !.. Argument list character(kind=c_char, len=1) :: lpLibName(*) !.. Function result integer(c_intptr_t) :: RetVal end function LoadLibrary function GetProcAddress(lpLibHandle, lpProcName) bind(C, NAME='GetProcAddress') result(RetVal) !DIR$ ATTRIBUTES STDCALL :: GetProcAddress import :: c_intptr_t, c_char, c_funptr !.. Argument list integer(c_intptr_t), value :: lpLibHandle character(kind=c_char) :: lpProcName(*) !.. Function result type(c_funptr) :: RetVal end function GetProcAddress function GetDataAddress(lpLibHandle, lpProcName) bind(C, NAME='GetProcAddress') result(RetVal) !DIR$ ATTRIBUTES STDCALL :: GetDataAddress import :: c_intptr_t, c_char, c_ptr !.. Argument list integer(c_intptr_t), value :: lpLibHandle character(kind=c_char) :: lpProcName(*) !.. Function result type(c_ptr) :: RetVal end function GetDataAddress end interface end module
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page