Fortran/C/C++ Compilers & Debugging Tools

Resources

Windows | Macintosh | 32-bit Linux | 64-bit Linux | Debug | Sales

      Buy now, contact Sales,
      Questions about your order,
      
Resellers, Partners,
      
Partial customer list

      Compilers
, Debuggers,
      Tools and Libraries,
      Cluster Software

      Commercial, Academic,
      Cluster Software, Upgrades
      Multi-platform Bundles

      Contact, FAQs, User Forum         Downloads, Registration

Product Information

IMSL math/stat libraries
VAST-F/Parallel
VAST-F/Vector
Fx & Fx2 debuggers
Cluster products
Documentation
Companion Products
   

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
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.

graphic

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
 

 

© 1996-2004 ABSOFT  Corporation 2781 Bond Street Rochester Hills Michigan 48309   Voice: 248-853-0050   Fax: 248-853-0108 

            Contact | Newsletter | Career | Legal | Terms of Use | Privacy