Software Archive
Read-only legacy content
17060 Discussions

External variables??

Intel_C_Intel
Employee
325 Views
I need to solve the Fortran problem described below. My Fortran books are
not really good on this.

1. I have a Fortran subroutine that is called from Visual Basic. The Fortran subroutine
has the following essential structure:

subroutine iofortran(... ..., VBcallback)

integer, external :: VBcallback
integer flag
real T

call numericsolver( ......)

return
end

2. I can call-back from the iofortran routine, e.g. as follows:

...
flag = VBcallback(T)
call numericsolver(......)
...

This works, and the commands in the relevant Visual Basic routine is run.

3. However, I don't really want to call-back from routine iofortran, I want
to call-back from routine numericsolver. To transfer information about VBcallback
to routine numericsolver, this can be achieved in at least two ways:
* By putting a copy of VBcallback into a common block that is included in
both iofortran and numericsolver, e.g. inserting the following code into
"iofortran":

integer cVBcallback
common/callback/ cVBcallback

cVBcallback = VBcallback

and the following code into "numericsolver":

integer cVBcallback
integer, external VBcallback
common/callback/cVBcallback

VBcallback = cVBcallback

NOTE: I don't know if these Fortran statements/structures are legal Fortran
code!!!

* By transferring the callback reference as an argument in the call to
"numericsolver":

call numericsolver(......, VBcallback)

and in numericsolver:

subroutine numericsolver(......, VBcallback)

integer, external :: VBcallback
integer flag
real T

flag = VBcallback(T)
-----------------------------
In the real Fortran code, the call to VBcallback will take place after
going through *several layers of subroutine calls*. That means that if I use
the second method, I need to add the VBcallback argument in each layer of
subroutine calls, but if I use the common block approach, I only need to
define the common block in the iofortran routine and in the actual
routine/layer where the callback is performed.
-------------------

QUESTION: Does anyone have an idea about the correct Fortran syntax for doing
what I indicate here? Is it easier to do this using modules?

-Bernt
0 Kudos
4 Replies
Jugoslav_Dujic
Valued Contributor II
325 Views
There are several solutions to the problem; the most portable and standard is indeed passing EXTERNAL through arg-lists. However, since it's inconvenient, (and since portablity probably doesn't matter). We had a similar problem and solved it using Compaq's extension of cray pointers to functions:
 
module m_dmsapp 
... 
interface 
   logical function DMS_EnumProc(pStruct, nType, lParam) 
   !DEC$ATTRIBUTES STDCALL::  DMS_EnumProc 
   integer::         pStruct 
   integer::         nType 
   integer::         lParam 
   end function 
end interface 
pointer(pEnumProc, DMS_EnumProc) 
... 
end module 
!=Entry procedure====== 
integer function DMS_Enumerate(...pfnCallback...) 
use m_dmsapp 
external pfnCallback 
pEnumProc = loc(pfnCallback) 
!=Procedure that calls callback====== 
use m_dmsapp 
... 
if (pEnumProc.NE.0) ist=DMS_EnumProc(loc(tLossR), STR_LOSSES, lgParam) 

The INTERFACE block specifies the prototype of callback; POINTER statement declares that this function is "target", i.e. that its address is not constant, but is determined by value of pEnumProc variable. Assignment to pEnumProc in entry procedure causes the function to be "associated" with that address and it can be called under the name specified in INTERFACE block. MODULE ensures that this declaration is global, i.e. available by all procedures that USE the module. See "Integer pointers" in programmer's guide.

HTH

Jugoslav
0 Kudos
Intel_C_Intel
Employee
325 Views
Some follow up questions to Jugoslav's possible solution:

I take it that the m_dmsapp module can be put in a separate file?,
and that the name of the module is arbitrary. (Is it standard to use
m_something for module?)

Regarding the module:
* Would it in my case be:

module m_VBcallback

interface
integer function VBcallback(T)
real :: T
end function
end interface
pointer(pVBcallback, VBcallback)

end module
---------
My subroutine which is called from VB, would it be:

subroutine iofortran(..., VBcallback)
use m_VBcallback
external VBcallback
pVBcallback = loc(VBcallback)

...
----------
The subroutine down the layers that use the callback function, would that be:

subroutine something(...)
...
use m_VBcallback
...

flag = VBcallback(T)

...
end
-------------

Jugoslav suggests:

> !=Procedure that calls callback======
> use m_dmsapp
> ...
> if (pEnumProc.NE.0) ist=DMS_EnumProc(loc(tLossR), STR_LOSSES, lgParam)

Why the test for whether the pointer pEnumProc differs from zero?

-Bernt
0 Kudos
Jugoslav_Dujic
Valued Contributor II
325 Views
Nothing special -- just an excercise in "paranoic" style of programming. If VB caller passes a NULL address of te callback, your code would try to call a routine at adress 0... kaboom. Also, this provides that the callback can be "optional".
0 Kudos
Intel_C_Intel
Employee
325 Views
Jugoslav partially answers my questions. Right now, I'm trying the following:

I have created the following module code in file VBcallbackModule.for, which I have
placed as a Source Files file in Visual Fortran:

----------------------

module m_VBcallback
integer, external :: VBCALLBACK
end module m_VBcallback

----------------------

In my main Fortran soubroutine (in Source Files file IOFORTRAN.FOR), i.e. the subroutine
which is called from Visual Basic, I insert the following:

-------------------------------------------

SUBROUTINE IOFORTRAN(T, P, X, VBcallback)

use m_VBcallback

DOUBLE PRECISION T, P
DOUBLE PRECISION X(*) ! X is a one dimensional array of varying size

DOUBLE PRECISION PHI(*) ! same comment as for X
INTEGER ICB

ICB = VBCALLBACK(T, P, X, PHI)

END IOFORTRAN

--------------------------------

When I try to Rebuild All, I get the following error message:

Error: The same named entity from different modules and/or program units cannot be referenced. [VBCALLBACK]
ICB = VBCALLBACK(TRETF, PRETF, XRETF, PHIRETF)

-------------------

Question: What is wrong??

-Bernt
0 Kudos
Reply