The information below
is taken from the Pro Fortran for Windows User Guide.
USING
THE WIN32 API
This section
describes how to access the routines available in the Win32 API.
For a complete explanation of all the Windows systems routines,
refer to Microsoft Win32 Programmers Reference, Volumes 1-5,
listed in the bibliography. Written by Microsoft, the Programmers
Reference is the definitive resource for Windows programming
and is essential if you plan to use system calls directly.
Program Organization:
FORTRAN VS. WINDOWS
Usually a FORTRAN
program has the following structure: first, it initializes
its variables, possibly reading data from files, then it calculates,
then it outputs the results. Some of these steps may be repeated,
but the basic order of execution is linear (see figure 7-3 below).
Once a program begins, there is typically very little interaction
with the user.
 |
 |
| Typical FORTRAN
Program |
Typical
Windows Program |
Windows, on
the other hand, presents a very different, highly interactive environment
to the user. The interface provided on Windows between the program
and the user allows for control and data selections to be made in
a graphical manner as well as the more traditional textual methods.
Windows communicates user requests to the program through a mechanism
known as an message which describes an action such as making
a menu selection, clicking the mouse button, or typing a key on
the keyboard. After the program receives a message it processes
it, carrying out whatever action is required.
These actions
are usually directed by a message loop, in which the program
requests from Windows any messages pending for the program, carries
out the directed action, and then repeats the process (see figure
7-4). When no messages are pending, the program will carry out whatever
other procedures it was designed to do. Some programs may simply
be idle at this stage if they are designed entirely to react to
user input (such as a drawing program).
Unfortunately,
there is much more to Windows programming than this simple description
implies, and it would be necessary to add a great deal of programming
to even the simplest FORTRAN program to add a Windows look and feel
to it. MRWE can add most of these features to your program without
delving into the details of Windows programming.
Note that MRWE
provides a more than adequate Windows look and feel to the typical
ported FORTRAN program. However, you cannot avoid using the Win32
API to access many of the features of Windows. Given the proper
reference materials (such as the Programmers Reference mentioned
above) programming Windows need not be as difficult as the above
discussion may have led you to believe-you may even find it rewarding.
How Absoft
Fortran 77 Interfaces with Windows
A group of FORTRAN
include files with the extension ".inc" allows Absoft
Fortran 77 to interface with the Win32 API for Windows. These files
contain FORTRAN declarations for every routine and most of the structures,
types, and constants defined in Microsoft Win32 Programmers Reference,
Volumes 1-5;. To include one of these files, use a statement
such as:
INCLUDE
"wingdi.inc"
This INCLUDE
statement will define all the GDI information for a single
program unit. To speed compilation and to define the same information
for all program units within a file, place the INCLUDE
statement in a GLOBAL DEFINE block at the top of the
file:
GLOBAL DEFINE
INCLUDE "wingdi.inc"
END
There are many
dependencies between the include files. As a convenience, all of
the Win32 INCLUDE files can be included by referencing the Windows
master include file: windows.inc:
INCLUDE
"windows.inc"
Note:
To enhance compilation speed, use this declaration only in a GLOBAL
DEFINE block.
Locating
the Interface Files
The ".inc"
files are located in the directory C:\Absoft\FInclude.
This is the default directory for the Absoft FORTRAN 77 system include
files so there is no need to completely specify the full path-the
file name alone is sufficient.
If, for any
reason, you move the system INCLUDE files to another
directory, you must inform the compiler of the new location by using
the -I compiler option (Include File Paths). See Chapter
4, Using the Compiler for more information.
Passing
Arguments
By language
definition, FORTRAN passes all actual arguments and receives all
dummy arguments by reference. Absoft Fortran 77 can also pass arguments
by value using the VAL() function and can receive dummy
arguments by value using the VALUE statement.
Standard FORTRAN
77 passes all arguments by reference. This means that the memory
address containing the argument is sent to the called subprogram,
thereby allowing the subprogram to return information to the calling
program as well as to use the value passed. Other languages, such
as Pascal and C, allow a choice of passing by reference or passing
by value. Passing by value is a one way communication. A copy is
created of the argument and passed to the subprogram. This copy
may be used and modified but the actual argument is not changed.
Absoft Fortran
77 is designed to interface directly to the C programming language
enabling FORTRAN programs to call Win32 API routines with the only
requirement being careful attention to argument data types. You
must be careful to pass the proper kind and type of argument to
the Win32 API routines. Failure to do so can cause incorrect results
or even program crashes. Passing by reference is simple because
it is the standard FORTRAN convention. Passing by value requires
using the FORTRAN VAL function corresponding to the
parameter size (1, 2, or 4 bytes). The VAL function
must be used to pass all pointers and literal values, whether variables
or numeric constants, to any C language argument that is not declared
as a pointer type. See the section Value Parameters for C
later in this chapter for further details. To determine the correct
argument order and type, refer to the Programmer's Reference
and to the ".inc" files containing the routines
you want to call. The following FORTRAN code calls the LineTo
routine with three "pass by value" arguments:
CALL LineTo(val(hdc),val(50),val(50))
! x=50, y=50
The C declaration for
LineTo (from the Microsoft Win32 Programmer's Reference,
Volume 4):
BOOL LineTo(hdc,nXEnd,nYEnd)
HDC hdc; /*
device context handle */
int nXEnd; /*
x-coordinate of line's ending point */
int nYEnd; /*
y-coordinate of line's ending point */
All variables
passed must have the same size as the corresponding routine parameters.
Passing more complex parameter types is discussed later in this
chapter.
All pointers
and handles are 32 bits and must be declared as INTEGER*4
values or as POINTERs and passed as arguments with
the VAL4 function. These calls pass a pointer to the
GetCaretPos routine:
INTEGER*4 p_point
CALL GetCaretPos
(VAL4(p_point))
or
RECORD /POINT/
point
POINTER (p_point,
point)
CALL GetCaretPos
(VAL4(p_point))
or
RECORD /POINT/
point
POINTER (p_point,
point)
CALL GetCaretPos
(point)
CHARACTER
Arguments
The binary interface
to the Windows system functions on computers using Intel processors
does not adhere to the same CALL/RETURN sequence that
FORTRAN and C use. This discrepancy is resolved by the include files
for each compiler which make a special declaration for all of the
Win32 API functions: STDCALL. This declaration directs
the compiler to generate the special code sequences required to
interface to the system.
Normally, you
do not need to be concerned about this difference since proper use
of the include files insures that the calls are made correctly.
However, CHARACTER arguments need special attention
when calling Win32 API functions which require pointers to strings
as parameters. The Absoft Fortran 77 compiler adds extra arguments
to subroutine and function argument lists which specify the length
of CHARACTER arguments. The extra arguments are placed
after the formal parameter list and are used by the called procedure
to determine the size of CHARACTER arguments declared
with the *(*) length specifier. Unfortunately, these
length arguments are not recognized by the Windows functions on
Intel based systems and you cannot pass CHARACTER arguments
in the normal manner. There are two ways to successfully pass pointers
to FORTRAN CHARACTER arguments which are equivalent
to:
CHARACTER*256
WindowName
INTEGER hWnd
.
.
.
call SetWindowText(val(hWnd),WindowName)
but do not pass
the additional hidden length argument.
1) Take the
address of the argument and pass it by value:
CHARACTER*256
WindowName
INTEGER hWnd
.
.
.
call SetWindowText(val(hWnd),VAL(LOC(WindowName)))
2) Create a
pointer to the argument and pass the pointer
CHARACTER*256
WindowName
POINTER (p_WindowName,WindowName)
INTEGER hWnd
.
.
.
call SetWindowText(val(hWnd),VAL(p_WindowName))
IMPLICIT
NONE Statement
Use of the IMPLICIT
NONE statement is strongly recommended when using ".inc"
files. The IMPLICIT NONE statement informs the compiler
to issue warnings for all undeclared variables, thereby forcing
explicit declaration of all variables used. Placing this statement
at the beginning of each program unit is the easiest way to avoid
difficulties due to undeclared or misspelled variable names. The
following code fragment is an example of using IMPLICIT NONE:
GLOBAL DEFINE
INCLUDE "windows.inc"
END
-
SUBROUTINE asub(hdc)
IMPLICIT NONE
INTEGER*4 hdc,x,y
RECORD /POINT/
point
-
x = 175
y = 35
CALL MoveToEx(VAL(hdc),
VAL(x), VAL(y), point)
RETURN
END
More details
about the IMPLICIT statement can be found in the FORTRAN
77 Language Reference Manual.
Using STRUCTUREs
and RECORDs with Win32
Some of the
Win32 routines require structures as parameters. Although standard
FORTRAN 77 does not have structures, Absoft Fortran 77 supports
VAX-compatible structures that may be interchanged with C structures.
Here is an example
of the SYSTEM_INFO structure described in Volume 5
of the Microsoft Win32 Programmers Reference and defined
in the winbase.h C header file:
typedef struct
SYSTEM_INFO {
DWORD dwOemId;
DWORD swPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD dwActiveProcessorMask;
DWORD dwNumberofProcessors;
DWORD dwProcessorType;
DWORD dwReserved1;
DWORD dwReserved2;
} SYSTEM_INFO
*LPSYSTEM_INFO;
The equivalent
FORTRAN structure is in the INCLUDE file winbase.inc:
STRUCTURE /SYSTEM_INFO/
INTEGER*4 dwOemId
INTEGER*4 swPageSize
INTEGER lpMinimumApplicationAddress
INTEGER lpMaximumApplicationAddress
INTEGER*4 dwActiveProcessorMask
INTEGER*4 dwNumberofProcessors
INTEGER*4 dwProcessorType
INTEGER*4 dwReserved1
INTEGER*4 dwReserved2
END STRUCTURE
This sample
program uses the SYSTEM_INFO structure:
GLOBAL DEFINE
INCLUDE "windows.inc"
END
-
PROGRAM ProcessorType
-
CHARACTER*7
processor
RECORD /SYSTEM_INFO/
sinf
-
CALL GetSystemInfo(sinf)
-
IF ((sinf.dwProcessorType
== 386) .OR.
+ (sinf.dwProcessorType
== 486) .OR.
+ (sinf.dwProcessorType
== 586) THEN
processor =
"Intel"
ELSE IF (sinf.dwProcessorType
== 601) THEN
processor =
"IBM"
ELSE
processor =
"Unknown"
END IF
-
PRINT *,processor,sinf.dwProcessorType
-
END
The CALL
to the routine GetSystemInfo passes the address of the record.
Passing Procedure
Pointers to Win32 Routines
The binary interface
to the operating system functions on Intel based Windows systems
does not conform to the procedure interface used by FORTRAN and
C. The Absoft Fortran 77 compiler must be informed when these Windows
routines are referenced so that it can set up the CALL/RETURN
sequence properly for the operating system. This is accomplished
with the STDCALL declaration statement. For example:
INTEGER Ellipse
STDCALL EXTERNAL
Ellipse
When you use
the INCLUDE files supplied with the compiler, these
functions are all declared correctly for you. However, certain Win32
API routines require pointers to other routines as parameters. These
may be routines that you write to customize a standard feature or
they may be handlers for messages that you want to act on. When
you write a routine that will be called by the operating system
you must always use the STDCALL specification statement.
For example, a dialog handler might start with:
stdcall function
AboutDlgProc (hDlg, message, wParam, lParam)
-
implicit none
-
logical AboutDlgProc
-
integer hDlg;
value hDlg
integer message;
value message
integer wParam;
value wParam
integer lParam;
value lParam
For this function,
the parameters are passed by value and are declared accordingly.
Note:
Although the STDCALL mechanism is not required for
PowerPC based systems, the compiler ignores it making it easier
to move programs between the two systems.
Handles
The Windows
memory manager can move certain blocks of memory at any time to
a new location and pointers referencing data in those blocks will
be left "dangling", or pointing to an incorrect address.
To avoid this, a data type called a handle is used. Handles use
one level of indirection to access the data they reference. The
indirection is via a master pointer which exists for each moveable
block. When the block is moved, the memory manager properly updates
its master pointer and all handles are still valid because the master
pointer has not moved. In other words, handles are pointers to pointers.

A handle
points to a pointer to a memory block
Handles are
dealt with in much the same manner as pointers. You will rarely
need to dereference handles to access the pointer to the data directly.
If you do need to, you should use the Win32 API GlobalLock
and GlobalUnlock functions to return a safe pointer.
The following example copies up to 1024 bytes of text from the Clipboard:
INTEGER*1 text(1024)
INTEGER*1 memory(1)
POINTER (p_memory,memory)
-
INTEGER i, h_memory
-
IF (.NOT.IsClipboardFormatAvailable(val(CF_TEXT)))
RETURN
IF (.NOT.OpenClipboard(val(0)))
RETURN
-
h_memory = GetClipboardData(val(CF_TEXT))
IF (h_memory
== 0) RETURN
-
p_memory = GlobalLock(val(h_memory))
-
DO i=1,1024
if (memory(i)
== 0) EXIT
text(i) = memory(i)
END DO
-
CALL GlobalUnlock(val(h_memory))
-
END
-
-
|