×
INTELLIGENT WORK FORUMS
FOR ENGINEERING PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you an
Engineering professional?
Join Eng-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Eng-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Have I missed something in FORTRAN?

Have I missed something in FORTRAN?

Have I missed something in FORTRAN?

(OP)
I have been programming in FORTRAN for 47 years, from FORTRAN II up to Compaq Visual Fortran (CVF) and IVF, but recently came up against this simple thing I wanted to do, which I cannot solve either in FORTRAN or Assembler.

I have the address of a routine that I want to call (it's in a .DLL provided by somebody else).
I have the address as a 32 bit value in a Fortran Integer SUBNAM.

But you cannot write CALL SUBNAM( argument list )

This is because I actually want an indirect call, not to the address of SUBNAM, but to the address it contains.

So I went into assembler and passed SUBNAM in as an argument, and tried to JMP to that address after saving a return address on the stack. I also tried pushing it on the stack and just doing a RET.

No dice. ACCESS VIOLATION!!

One reason may be that the assembly code may be trying to jump to an absolute address, but this is not allowed. You are only allowed to touch virtual addresses. And user ring programs are not allowed to have access to the mapping from one to the other.

Does anyone know how to solve this?

Of course this is all Microsoft and Intel's fault for making such a dog's breakfast of the PC programming model.

RE: Have I missed something in FORTRAN?

You didn't say whether you're using F77 or F90 or later. Anyway, this works on F77. If you need F90, you need to mess with interface definitions. F90 etc may be the latest greatest stuff but it is what Chinese call luan.

CODE

! A sample subroutine
	subroutine subsub (x)
         real x
         print *, "subsub called ", x
      end subroutine subsub

	! A sample function
      integer function funcfunc (single)
         integer single
         funcfunc = single + single
      end function funcfunc

	! Calling a subroutine indirectly
      subroutine callsub (subname, param)
         external subname
	   real param
         call subname (param)
      end subroutine callsub

	! Calling a function indirectly
      subroutine callfunc(funcname, param)
         integer funcname
         external funcname
         integer ires

         ires = funcname(param)
         print *, "funcname(param) returned ", ires
      end subroutine callfunc

      ! Usage
      program funcs
         integer funcfunc
         external subsub, funcfunc
      
         call callsub (subsub, 3.14)
         call callfunc (funcfunc, 100)
         stop
      end 

RE: Have I missed something in FORTRAN?

Just in case you want the hippy method of doing things

CODE

subroutine subsub (x)
   real, intent(in):: x
   print *, "subsub called ", x
end subroutine subsub

integer function funcfunc (single)
   integer, intent(in):: single
   funcfunc = single + single
end function funcfunc

subroutine callsub (subname, param)
   interface
      subroutine subname(rr)
         real, intent(in):: rr
      end subroutine subname
   end interface
   real, intent(in):: param
   call subname (param)
end subroutine callsub


subroutine callfunc(funcname, param)
   interface
      integer function funcname(ii)
         integer, intent(in):: ii
      end function funcname
   end interface
   integer, intent(in):: param
   integer:: ires

   ires = funcname (param)
    print *, "funcname(param) returned ", ires
end subroutine callfunc

program funcs
   integer funcfunc
   external subsub, funcfunc

   call callsub (subsub, 3.1415)
   call callfunc (funcfunc, 30)

   stop
end 

Both GNU and PS4/DVF/CVF/IVF have a function called LOC which gets the address of the function, similar to what comes back from GetProcAddress which is used with LoadLibrary which you can use for late loading DLLs.

RE: Have I missed something in FORTRAN?

(OP)
I tried passing the subroutine name in an argument list, but that only works if the subroutine is linked into your program. It doesn't work if SUBNAM is a variable with an address in it. However, I have now found the solution, in an obscure part of CVF that I had never had to use before. Here is the solution:

(1) in the IDE, do "Add to Project". "files" amd locate the .dll you want to use. Alternatively copy the .dll to the program's workspace.

(2) put
USE kernel32
at the start of the main program to provide access to Windows APIs.

(3) For each subroutine or function that the .dll provides that you want to use, provide an INTERFACE block like

INTERFACE
SUBROUTINE NAME1(...argument list...)
...declare the types of the arguments....
If the .dll routines use C calling conventions, add
!DEC$ ATTRIBUTES CALLER
(this means that it is the calling program that will clean up the stack)
I have not found it necessary in the interface to specify whether arguments are
passed by value or address. This happens in the call, later.)
END SUBROUTINE NAME1
END INTERFACE

(replace SUBROUTINE by FUNCTION if it returns a value, as most C is written to do)

The names such as NAME1 above are your choice.

(3) In the program declarations,include statements like
POINTER(P1,NAME1)
for every subroutine or function that the .dll provides that you want to use. "NAME1" is the same name as you chose for the associated INTERFACE block

Also include a declaration
POINTER(PLIB,ILIB)

(4) in the program, load the .dll by including the windows API statement
PLIB-LOADLIBRARY("dllname.dll")
the logical variable STATUS will come back true of the .dll was loaded corrctly.

(5) For each subroutine or function you want to use, include a windws API statement like
P1=GETPROCADDRESS(PLIB,"subnam1"C)
"subnam1" is what the routine is called (case sensitive) in the .dll, not your name choice. They can be the same however, but FORTRAN will ignore the case. The suffix C passes the string as a C string, that is null-terminated, and no length passed. This sets up the subroutine or function you chose to call by the FORTRAN name NAME1.

(6) Now you can call the subroutine NAME1 in your program by writing

CALL NAME1(....argument list...). where for every scalar variable that is an input argument such as "N" you write %VAL(N) to make FORRTAN pass it by value if the .dll requires it. Output variables that are returned as well as strings and arrays are passed by address so do not need %VAL()

For a function you can write STATUS=NAME1(....argument list...) likewise

(7) Now, if you want to call such a subroutine or function inside another subroutine other than the program in which the above initialization was done, you have to repeat the declarations like:

POINTER(P1,NAME1)
in the subroutine in which you want to use NAME1 and you have to pass the pointers P1 in in the argumant list or better, by declaring a NAMED COMMON to hold them, thus avoiding encumbering the argument list

RE: Have I missed something in FORTRAN?

(OP)
Correction of typo in last post:

Step 4 should read

(4) in the program, load the .dll by including the windows API statement
PLIB=LOADLIBRARY("dllname.dll")

PLIB comes back as zero if the .dll failed to load.

RE: Have I missed something in FORTRAN?

Yes, I forgot about the Cray pointers. It isn't really obscure: it is just that not many Fortran programmers use it. C/C++ programmers use that all the time. Late loading is one of the banes of my life. You don't know the dependencies until that part of the code runs so you don't know that you have to supply particular DLLs with the executable for the system to run. Then you get a call from site that says a DLL is missing and you have to send them a hot fix. This happens all the time in C#.

RE: Have I missed something in FORTRAN?

Just for completeness, add step (8)

(8) FreeLibrary(PLIB) to unload the DLL

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Eng-Tips Forums free from inappropriate posts.
The Eng-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Eng-Tips forums is a member-only feature.

Click Here to join Eng-Tips and talk with other members! Already a Member? Login


Resources

Low-Volume Rapid Injection Molding With 3D Printed Molds
Learn methods and guidelines for using stereolithography (SLA) 3D printed molds in the injection molding process to lower costs and lead time. Discover how this hybrid manufacturing process enables on-demand mold fabrication to quickly produce small batches of thermoplastic parts. Download Now
Design for Additive Manufacturing (DfAM)
Examine how the principles of DfAM upend many of the long-standing rules around manufacturability - allowing engineers and designers to place a part’s function at the center of their design considerations. Download Now
Taking Control of Engineering Documents
This ebook covers tips for creating and managing workflows, security best practices and protection of intellectual property, Cloud vs. on-premise software solutions, CAD file management, compliance, and more. Download Now

Close Box

Join Eng-Tips® Today!

Join your peers on the Internet's largest technical engineering professional community.
It's easy to join and it's free.

Here's Why Members Love Eng-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close