Error Calling DLL

Error Calling DLL

I am trying to load a Fortran DLL at runtime, using this code:

INTEGER :: p
pointer (q,AWAPROPS_SUB)
p = loadlibrary("AWAProps.dll"C)
NAME = "AWAPropsLicense_F"
q = getprocaddress(p, TRIM(NAME)//""C)
CALL AWAPROPS_SUB(IResult, CopyR)

(I am also checking that p and q are non-zero)

When I call this, I get the following error:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

I suspect this is because the DLL has been set up for calling from VBA, and the DLLEXPORTS are like:

Subroutine AWAPropsLicense_F(IResult, CopyR)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS:'AWAPropsLicense_F' :: AWAPropsLicense_F
!DEC$ ATTRIBUTES REFERENCE :: CopyR
IMPLICIT NONE
INTEGER, INTENT(OUT) :: IResult(1)
CHARACTER(LEN=33), INTENT(OUT) :: CopyR

What do I need to add to my Fortran calling program to allow for this different calling convention?

Also, within the same run, can I reuse the pointer q to call different routines (with different numbers of arguments), or do need a separate pointer for each?

Thanks,

David

4 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

You need to tell the compiler that the procedure pointer is to be called with STDCALL. The way I would recommend this is to adopt the method shown in the provided example DLL\Dynamic_Load.

First, it declares an abstract interface for the procedure:

abstract interface
  function USERFUNC_int (arg)
  integer USERFUNC_int
  integer, intent(IN) :: arg
  end function USERFUNC_int
end interface

In your case, you'd want to add:

!DEC$ ATTRIBUTES STDCALL, REFERENCE :: USERFUNC_int

Then it uses the Fortran 2003 procedure pointer feature (ISO_C_BINDING needed):

procedure(USERFUNC_int), pointer :: USERFUNC
integer(C_INTPTR_T) :: p_USERFUNC
...
p_USERFUNC = GetProcAddress (hModule=dll_handle, lpProcName="USERFUNC"//C_NULL_CHAR)
call C_F_PROCPOINTER (TRANSFER(p_USERFUNC, C_NULL_FUNPTR), USERFUNC)

Yes, with a STDCALL routine, you need a different interface for each set of arguments.

It might also work with your existing code if you added an EXTERNAL declaration for AWAPROPS_sub and then added an ATTRIBUTES STDCALL for the same name. I'm not 100% sure of this. You could use the same pointer for different numbers of arguments, but you had better be sure that you're passing the correct number to each routine.

Steve - Intel Developer Support

Steve,

When I looked at the Dynamic_Load example before I wasn't sure how to use the abstract interface for my case where all my entry points are subroutines.  In addition, I have 130 or so different entry points, so setting up 130 interface blocks isn't trivial.

thanks,

David

You don't need 130 different interface blocks, just one for each combination of argument number/types. If that is still daunting, you can probably make it work with EXTERNAL and ATTRIBUTES STDCALL.

Steve - Intel Developer Support

Leave a Comment

Please sign in to add a comment. Not a member? Join today