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

Calling C in dynamically loaded DLL from Fortran

Adrian_F_1
Beginner
933 Views
I have always been using this method to call functions in a dynamically loaded DLL:

      INTERFACE
        logical function Check_Security_DLL(itype) BIND(C, NAME="Check_Security_DLL")
          integer(4) :: itype [value]
        end function Check_Security_DLL
      END INTERFACE

      pointer (p_CheckSecurity, Check_Security_DLL)

      if(.not. LibLoaded) then
        dll_handle = LoadLibrary('Tec1.dll'//char(0))
        if (dll_Handle /= 0) then
          i_CheckSecurity = GetProcAddress(dll_handle, "Check_Security_DLL"C)
          if (i_CheckSecurity /= 0) then
            p_CheckSecurity = i_CheckSecurity
            LibLoaded = .true.
          endif
        endif
      endif

      if (LibLoaded) then
        result = Check_Security_DLL(type)
      endif

 

However I get these warnings if I switch on F2008 checking:

D:\ToolsetIncs\Check_SecF.F90(23): warning #7028: Integer pointer non-standard
D:\ToolsetIncs\Check_SecF.F90(17): warning #7372: Procedures as pointees is not supported in Fortran 2008 standard.   [CHECK_SECURITY_DLL]

So I guess there is a new method, however the Samples do not have an example for dynamically loading the DLL and how to call a function in the DLL.

0 Kudos
8 Replies
Steven_L_Intel1
Employee
933 Views

Sure the samples have this - DLL\DynamicLoad. In recent versions it's even full F2003 compliant (other than calling Windows API routines.) I've attached it here. But the method you're using also works - you're just using an extension.

0 Kudos
Adrian_F_1
Beginner
933 Views

Ah yes I was looking in MixedLanguage, not DLL.  I see it now thanks.

0 Kudos
Adrian_F_1
Beginner
933 Views

sorry just a followup - is the "abstract" keyword required here?  What if it is not specified?

 

0 Kudos
Steven_L_Intel1
Employee
933 Views

If it isn't specified then the compiler thinks you're declaring an actual external procedure. You should use it here.

0 Kudos
JVanB
Valued Contributor II
933 Views

Now full f2003 compliance...

Can you remove the dependence on the interface specification for GetProcAddress by surrounding its invocation with TRANSFER? I generally write out the result variable as being of type C_PTR for gfortran; TRANSFER would mean that it would work either way.

Also that Arguments argument to FormatMessage: shouldn't it be typed as a pointer to an array of TYPE(T_VA_LIST) rather than a scalar? Or perhaps just TYPE(C_PTR) by value. In the former case, one could use C_F_POINTER to get a pointer to an array addressed from C_NULL_PTR; in the latter case just passing C_NULL_PTR directly would serve instead of the ifort NULL extension.

 

0 Kudos
Steven_L_Intel1
Employee
933 Views

Yes, one could just use the result of GetProcAddress in a TRANSFER directly, but I thought it was clearer this way, especially as one was testing it for NULL.

As for FormatMessage, Arguments is optional (_In_opt_ in MSDN), so passing a NULL is exactly what one would do to omit it in C. Here NULL is just the name of a constant from IFWINTY, not an extension.

0 Kudos
JVanB
Valued Contributor II
933 Views

We are kind of on different wavelengths here, Steve. I was thinking in terms of

p_USERFUNC = TRANSFER(GetProcAddress (hModule=dll_handle, &
lpProcName="USERFUNC"//C_NULL_CHAR),p_USERFUNC)

The point being that this syntax would work even given a 'rationalized' interface for GetProcAddress that defined the result as TYPE(C_PTR). The extensions used in kernel32.f90 are pre-f2003 and were necessitated by the lack of standardized methods for interfacing to C. In code that was intended to only be compiled by ifort the use of TRANSFER above looks nonsensical, but it would be more transportable.

As for FormatMessage::Arguments, MSDN says it's an array of values, but kernel32.f90 specifies it as

!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: Arguments
  TYPE(T_VA_LIST) Arguments ! va_list* Arguments

To be consistent with MSDN documentation, I think Arguments should be DIMENSION(*) rather than a scalar. I hadn't noticed that FormatMessage is expanded as a generic. In this style, NULL as actual argument is, as you say, not an extension. However, don't you need 4 generic flavors given that there are two possible independent interfaces for lpBuffer and Arguments? If lpBuffer and Arguments are both sent NULL, isn't the invocation ambiguous?

 

0 Kudos
Steven_L_Intel1
Employee
933 Views

Point taken about GetProcAddress.

And yes, the interface for FormatMessage in KERNEL32 is questionable. We inherited this one from Microsoft and have refined hundreds of these over the years, but this one doesn't seem to have been looked at closely. I'll add it to my (very long) list of APIs to reconsider.

0 Kudos
Reply