Previous: 23 Distributing your application
Next: 25 Departing from the norm
In this section:
This Chapter recaps and summarizes some of the things that we have learnt previously. In essence, there are 8 main elements to ClearWin+, which I will list one by one below. Anecdotally, there are 7 deadly sins. In Fortran, there are many more. In ClearWin+ there are definitely at least 8 classes of things that the programmer needs to master.
You should recognise them all from what we have done earlier in the book.
Probably the easiest way to tell FTN95 to compile your program for a Windows interface is to incorporate the directive WINAPP in your code. I find it convenient to do this at the start of the source code file that contains my PROGRAM routine. You can also compile with the /WINDOWS command line directive. It is as simple as that. Some of the older documentation suggests that WINAPP should be followed by numbers giving sizes for storage areas called the Heap and the Stack, but this was required for a 16-bit Windows environment, and you can forget them if you should see them in an older program (written for FTN77 for example).
Incidentally, it is still possible to run out of stack space, especially if your preferred style of programming has huge local arrays, especially when they are passed from routine to routine, as that uses stack space. That is less likely if you are rejuvenating an old Fortran program than if you are writing one from scratch.
It’s the way that Windows works, at least in 32-bit mode, so that they are the defaults that 32-bit FTN95/ClearWin+ work to. I still like my OPTIONS directive, however. In 64-bit mode, the INTEGERs have to be 8-byte, or INTEGER*8 – at least when used for addressing.
That said, there is no reason not to use different sized INTEGER or REAL variables for particular purposes in your program. Indeed, in many programs, there is very little chance of overflowing INTEGER*2 (nearly 33,000) and even one byte for an INTEGER may well be enough in some situations. Some similar things can be said for LOGICAL, and indeed, as LOGICAL can only have values of .TRUE. or .FALSE. anything more than LOGICAL*0.125 (I made that up!) is wasteful. Sometimes, that’s all we use an INTEGER for (such as grey codes) and that also wastes the extra bits. However, two points are noteworthy. The first of those is that even the 32-bit memory space is vast compared to the mainframes of old, and you can usually be as wasteful as you like. The second point is that REAL*4 arithmetic creates and accumulates roundoff errors very quickly, and it is possible that conversion of an old (DOS) PC program that used REAL*4 by default may give you noticeably different answers when recompiled with REAL*8!
Really, the next 3 sections need to be understood altogether. WINIO@ is an INTEGER FUNCTION with a variable number of arguments. The first argument is always a character string, and the remaining arguments are a mix of constants, variables and INTEGER FUNCTION names. The INTEGER FUNCTIONs are the so-called callback routines. The character string contains the format codes.
An example of a statement involving WINIO@ with just the text string and no other arguments is given here:
IA = WINIO@('%bt[OK]&')
%bt is a format code. What is does is specify that a button is inserted into the Window. This button will have the text label OK on it, and it comes already equipped to respond to mouse clicks (or presses). The final ampersand (&) is a symbol to say that the window isn’t finished, and that there are more WINIO@ function calls to come. Especially in the layout of an application’s main window, there may even be a hundred or more WINIO@ calls. The last WINIO@ call in the series does not have the continuation ampersand. Embedded things like the ‘OK’ are typically surrounded by square brackets.
Format codes are always made up of:
The % and the 2-letter code are always present.
Format codes specify various things in a window:
Arguments following the CHARACTER string relate to numerical values required by the various format codes. For example, if I wanted to define a graphics region 200 pixels wide and 150 pixels high, I would have to give those numerical values somewhere, and I would do it with arguments. A graphics region is a difficult example, because as well as its size, it also needs (at least) a number called its handle, to distinguish it from other graphics areas. The call for this would be:
iHANDLE = 101 iXsize = 200 iYsize = 150 IA=WINIO@('%gr&', iXsize, iYsize, iHANDLE)
The arguments must always come in the right order, and there must be enough of them, and they must be of the right type.
Let us suppose that in a particular window we have a control, such as a button, that is intended to make the program do something. How do we transfer control to the part of the program that acts out that control? There are two ways, and one of them relies on what is known as a callback function. Some controls must always have callback functions, whereas with other controls, they are optional. A menu is an example of a place where there is always a callback function, but in the case of a button, it is optional.
All callback functions must be INTEGER FUNCTIONs. In Fortran-77 style, they are declared as EXTERNAL (which means that their names may be passed as parameters in SUBROUTINE and FUNCTION calls). I find it useful to declare the names INTEGER at the same time using a Fortran 90 construct even if you have used IMPLICIT type:
INTEGER, EXTERNAL :: callback_function_name
But FTN95 doesn’t seem to care about this, and just EXTERNAL will do.
If you prefer the Fortran 90/95 syntax, and you use MODULEs and CONTAINs, then you can declare your callback functions within the module where they are used.
Where a callback is optional, and it is provided, then the special symbol modifier ^ must be put between the % symbol and the 2-letter format code. So, an example might be:
INTEGER, EXTERNAL :: BLEEPER IA = WINIO@('%^bt[Beep]&', BLEEPER)
And later in the program you may find:
INTEGER FUNCTION BLEEPER() C -------------------------- BLEEPER = 1 ! 2 might work even better here INCLUDE <WINDOWS.INS> CALL BEEP@ RETURN; END
Should the user press the Beep button, program control is transferred to the function BLEEPER, which sounds the computer’s buzzer (that is what the BEEP@ subroutine – an FTN95 standard function – does).
All FUNCTIONs have a return code, and the return code in this case is 1, which means “keep the parent window open ready for more commands”. A return code of 0 means “now close the parent window”. A return code of 2 is similar to 1, but does not cause the parent window to refresh itself.
BEEP@ is one of the contents of FTN95’s extensive libraries of standard subroutines and functions. There are really 2 kinds of libraries. One of them relates to very useful functions that were developed for FTN77 when it was a DOS (strictly DOS-extended) product, and the other is specific to ClearWin+. Those useful functions and subroutines that aren’t part of ClearWin+ are described in various places in the online documentation.
The ClearWin+ functions and subroutines are described in the online help files.
If you take the opportunity to look into the .INS files, you will see that they contain nothing more than a mixture of interfaces so that you (and ClearWin+) can call the C routines that are provided as part of Windows, with parameters that are specified by name and their corresponding values. It’s a big job to understand the contents of the INCLUDE files, but the names for routines and parameters are the same as those in MSDN. Most of the time, ClearWin+ provides a Fortran ‘wrapper’ for those files, but it is still better to use the parameters by their Windows’ names, rather than by their strict numerical value. However, there are some functions that don’t have a ClearWin+ wrapper, and those do need to be called by their Windows’ name. Those functions are generally for very advanced use.
Resources are, in the main as far as ClearWin+ is concerned, a collection of bitmap images stored as separate files in a variety of formats that you will bind in to your program. These bitmaps may represent some of the control buttons, pointers or cursors, that you will use. They may also represent textures, backgrounds, logos and other imagery. The exception is that hypertext files are incorporated via the RESOURCES section.
You have 2 ways of listing your resources. Firstly, you can add a RESOURCES section after your program code. Then, when your program is being compiled by FTN95, the separate resource compiler SRC is invoked. Alternatively, you can list all the resources in a file – preferably with a
.RC extension, and compile it yourself using the Silverfrost Resource Compiler SRC.EXE. If you take the second of these routes, an .OBJ file is created that can be linked with SLINK.EXE. (When using PLATO, the resources file is just another file in a project).
The content of the RESOURCES section of file is divided into lines of code, each of which has 3 parts:
TIMER CURSOR “TIMER.CUR”
The valid types are:
CURSOR ICON BITMAP IMAGE HYPERTEXT
All of them are described in the help files.
FORTRAN and the ART of Windows Programming, Copyright © Eddie Bromhead, 2023.