Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Tools

A GUI Environment for Fortran Development


JUN93: A GUI ENVIRONMENT FOR FORTRAN DEVELOPMENT

A GUI ENVIRONMENT FOR FORTRAN DEVELOPMENT

VShell as the bridge between Visual Basic front ends and Fortran DLLs

Vinod Anantharaman

Vinod is a graduate student in the EECS department at the University of Michigan. He can be contacted at 1803 Willowtree Lane, Ann Arbor, MI 48105.


Fortran end users have long put up with primitive command-line user interfaces restricted by READ and WRITE, the only ANSI standard I/O statements provided in the language. While many such users wish to take advantage of modern graphical user interfaces, creating these graphical environments--dialog boxes, command buttons, scroll bars, icons, graphs, pull-down and pop-up menus--can mean considerable work for Fortran programmers. Using the C-based Windows Software Development Kit (SDK), for instance, is often a tedious process that involves looking at all the nitty-gritties of the Windows API straight in the eye.

This is where Microsoft's Visual Basic comes into the picture. For a graphical environment such as Windows, a visual development environment like Visual Basic is not merely a means for interactive interface design--it also makes the complexity of the Windows API transparent to the user. Fortran routines in dynamic link libraries (DLLs) can be called from the Basic code that processes the user's actions. This way, all the real computing can be done in Fortran, with Visual Basic taking care of the GUI front end.

The Fortran Visual Shell (VShell) presented in this article is an icon-based visual tool that simplifies (via drag and drop) the process of creating Fortran DLLs accessible from Visual Basic. VShell is itself developed with Visual Basic and features a Windows-hosted GUI in which objects such as Fortran-related files and project folders are icons. The user executes a task on an object by double-clicking the object or dragging and dropping it on the task icon. A Fortran project complete with a Windows GUI can be developed from scratch under VShell without any complicated interfacing between Fortran and Visual Basic.

The VShell/Fortran Development Cycle

VShell has a set of windows, called "forms," each with a set of controls: icons, menus, buttons, file-system controls, and the like. The VShell Main form (see Figure 1) displays icons for a file browser, command icons, and folder icons. Command icons include Edit, Folder, Compile, DLL-VB Frontend, Run, Programmer's Workbench (PWB), and Visual Basic.

Begin by creating/editing Fortran source files. To create a new file, run an editor by double-clicking the Edit icon on the Main form. To edit an existing file, either select the file from the file browser and drag and drop its icon on Edit or, if the file has a .FOR extension, double-click on it in the browser. Both methods run an editor with the chosen file open. The editor can be selected the first time Edit is used; VShell displays the Editor form with an icon for each available editor; see Figure 2. The selected editor is then used for all editing.

Figure 3 shows the Folder form used to create a Fortran project. On the Main form, double-click on the Folder Command icon to bring up this form. This form has a file browser that lets you explore the file system for Fortran source files (.FOR extension). To select a file and include it in the folder, drag-and-drop its associated icon from the file list box into the folder contents box. The contents box displays files (with full paths) currently selected for the folder's project. To set the compiler flags for the project, use the Fortran Compiler Options entry in the Options menu--this displays the Fortran Compiler Flags form, which has option buttons for various Fortran compiler flags, as seen in Figure 4. Once a folder has been created and given a name, an icon that represents it is added to the set of folder icons on the Main form when the Folder form is closed.

To edit files in an existing project folder, drop the folder's icon on the Edit Command icon, and the File_to_Edit form shown in Figure 5 will pop up with the names of all the Fortran files in that folder. Select one of these files, and the editor window comes up with the selected file open. To examine or change the contents of a folder, either drag-and-drop on the Folder Command icon or double-click on the Folder's icon to bring up the Folder form with the desired folder's contents.

Once a project folder has been created, drop its icon on the Compile Command icon to compile it and produce a QuickWin executable. The compiler flags set for the project, along with some VShell default flags (discussed next) are used. If compilation is successful, the .EXE file created is added to the project's folder, and the folder's icon on the Main form is tagged as an .EXE folder icon.

To run the executable in a compiled folder, drag and drop it on the Run Command icon. The Run form in Figure 6 pops up and prompts for command-line arguments, if any. The executable in the folder is then run inside a window. Executable files dropped directly from the file browser onto the Run Command icon may not be run within a window unless they were originally compiled as QuickWin applications.

To create a Visual Basic/Fortran mixed-language application, edit Fortran DLL source file(s) and create a folder, as described previously. The DLL code must consist only of functions or subroutines because the Visual Basic side will constitute the main program. Instead of compiling the folder, create a Fortran DLL by dragging and dropping the folder icon on the DLL-VB Frontend icon. VShell prompts you for the name of a Visual Basic declarations-module file into which it writes Basic Declare statements for accessing the Fortran DLL's exported functions and subroutines. The user can then drag and drop this Basic file from the file browser on the Visual Basic Command icon to run Visual Basic and load the declarations file. Now the stage is set for the user to design and implement the Windows user interface using Visual Basic as the front end, calling the Fortran DLL routines as needed by using the Basic Call statement.

This completes a typical project-development cycle under VShell. There is one further Command icon in VShell, the PWB Command used to run Microsoft's PWB. Double-click the icon to run PWB, or drop a project folder icon on the PWB icon to make PWB load the folder's files as well.

VShell Internals

Both the VShell Main form and the Folder form have file browsers that allow the user to explore the file system. Visual Basic's specialized file-system controls--the drive list box, the directory list box, and the file list box--are combined and synchronized to display the system's drives, directories, and files, all with a few mouse clicks.

For folders compiled to produce an executable, we use the /MW option that instructs FL (Microsoft's Fortran 5.1 Compiler is assumed) to compile a Quick-Win application. Also by default, the executable file produced by FL is given the base name of the first file in the folder contents box. The user can override the following default compiler settings: the warning level (set to /W1, to display warning messages), the debug option (set to none), the processor (set to /GO, the 8086/8088 instruction set), floating-point option (set to /FPi, to generate inline instructions and select the emulator math package), and the optimization desired (set to/Ox by default, full optimization). The set of compiler flags assumed for folders used to create DLLs is different and is discussed in the section on accessing Fortran DLLs from Visual Basic.

Every folder has a folder-description file (FDF) with an .FOL extension name and the same base name as the folder name. The FDF is a text file that contains a description of the folder: the files it contains, their paths, and the compiler flags for the project. The folder.vsh file in the VShell directory contains the names of all the project folders in existence and their types: plain (yet uncompiled, with only Fortran source files), executable, or DLL. When VShell is started, the Main form is loaded with folder icons for each of these project folders. The folder.vsh file gets updated on quitting a VShell session.

Both the Compile and DLL-VB Frontend Command icons make use of Microsoft's Program Maintenance Utility (NMAKE) to simplify project management. When these Command icons are run, VShell automatically creates a suitable NMAKE "description file" for the project. The description file has the target, the target's dependents, and the commands to build the target. NMAKE ensures that a project's files are recompiled only if dependents are modified simultaneously with or later than the target. If you attempt to run an outdated executable from a folder, VShell will prompt you to rebuild the folder. An outdated DLL in a folder remains outdated until a new DLL is explicitly created using the DLL-VB Frontend icon.

System commands and other executable programs (like editors, NMAKE, PWB, and so on) are run from Visual Basic using the Shell function. However, when VShell calls Shell to run a program such as NMAKE, the VShell code immediately following the Shell call will normally continue executing even as NMAKE is running. Therefore, VShell requires some way to infer the termination status of NMAKE, and a clean way to branch on the completion of the NMAKE run, depending on the termination status. VShell solves this problem by using a DOS batch file and a Visual Basic timer control, as with the Visual Basic code (available electronically; see "Availability," page 7). As you can see, compile.bat first calls NMAKE using the description file created by VShell. Next, it tests the exit code returned by NMAKE using the DOS batch command IF ERRORLEVEL. The exit code is 0 if NMAKE ran successfully, and higher if it encountered an error. The exitdump program dumps a dummy value (0) into a temporary file (temp1.tmp) if the error level is 0. Next, a dummy value is written into another temporary file (temp2.tmp) whether NMAKE had fatal errors or not. The Shell call runs the batch file. A program information file (PIF), compile.pif, created for this batch file, sets the Display Usage option to Windowed--the batch file is set to run in a window.

The two statements before the Shell call ensure that if either of the temporary files that compile.bat may create are already present, they are deleted. After the Shell call is made, a Visual Basic timer control, Compile_Timer, is enabled, and the VShell Main form, Shellform, is disabled. Compile_Timer is programmed to check, at regular intervals, if the temporary file temp2.tmp has been created; this happens after NMAKE has completed. When Compile_Timer finds the file temp2.tmp, it checks if the file temp1.tmp has been created. If it has, then NMAKE completed successfully, and the Compile_Timer code adds the .EXE file created to the project's folder. If temp1.tmp has not been created, Compile_Timer displays a message box indicating that NMAKE encountered a fatal error. In either case, the timer is disabled and the VShell Main form is enabled again.

Accessing Fortran DLLs from Visual Basic

To create Fortran DLLs accessible from Visual Basic, drag a folder icon (with the Fortran DLL code) and drop it on the DLL-VB Frontend Command icon. VShell takes care of the following: compiling the Fortran code with the appropriate compiler flags; creating the definitions file with the DLL export functions; linking with the appropriate runtime library to produce the DLL; and creating the Visual Basic declarations module containing the declarations for the Fortran DLL routines imported by Visual Basic.

What appears as a simple drag-and-drop event involves the following steps: First, a new form, the DLL form (Figure 7), is loaded. In this form, you're prompted for the name of the Visual Basic declarations file for the front end. Next, the DLL source files are compiled using NMAKE, producing an object file. The /Zi compiler flag, for producing debugging information with the Microsoft Codeview debugger, is specified in the NMAKE description file for reasons that will become apparent later. Because a DLL gets its stack from the caller, the DLL's code cannot assume the stack segment is equal to the data segment; the /Aw option generates code that takes this into account. VShell assumes that all the functions and subroutines in the DLL code may be imported by Visual Basic. Hence, the /Gw option is used for all the source files; this generates appropriate prologue and epilogue code.

For VShell to know whether compilation was successful or not, the DOS interface is implemented along the same lines as in Listing One. A timer control, Object_Timer, runs code that checks for temporary files created by the batch file that calls NMAKE and determines if NMAKE ran successfully or not. If it was unsuccessful, VShell displays a message box indicating that NMAKE encountered a fatal error, and terminates the DLL creation process; otherwise, NMAKE produces a .OBJ file from the DLL source files.

For the rest of the DLL creation process to proceed without user input, symbolic information regarding the names of all the DLL subroutines and functions and their parameter and function-return types is required. This is why compilation used the /Zi flag--the .OBJ file has symbolic debugging information, and Microsoft's Object/Library Decoder is used to extract it. The output from the Decoder is directed to a file with the same base name as the .OBJ file, but with the extension .OMF (for Object Module Format). VShell makes one pass through this .OMF file to extract the names of all the information it requires about the DLL subroutines and functions. With this information, VShell constructs two files: the definitions file (.DEF), which has all the names of all subroutines and functions in the DLL in the EXPORT section, along with the default WEP DLL termination routine; and the Visual Basic declarations file, which has a Declare statement with the special keyword Lib and the full path to the .DLL file for each of the DLL functions and subroutines. The parameter types extracted from the .OMF file are converted to their Basic equivalents in the Visual Basic declarations module. Since the default calling protocols in Fortran and Visual Basic are similar (almost everything is passed as a far pointer), interfacing Visual Basic with Fortran is straightforward. Owing to a limitation in the version of Decode used by VShell, passing arrays and structures as parameters between Visual Basic and Fortran is not permitted at this point.

Once the .OBJ and the .DEF files have been created, run the linker to create the .DLL file using the runtime library LDLLFEW.LIB. The interface with DOS for calling the linker is implemented the usual way: The link command is part of a batch file that Visual Basic runs using a Shell call, and a timer control, Complete_Timer, checks if the DLL creation process completed successfully or not. If unsuccessful, the .DLL file gets added to the folder, and the folder's icon on the Main form is tagged as a DLL folder. This completes the DLL creation process. If the linker encountered any fatal errors, Complete_Timer detects this, and displays a "linker error" message.

Once the DLL and the Visual Basic declarations file have been created, dropping the declarations file (from the browser) on the Visual Basic Command icon runs Visual Basic and loads the declarations file. With this, the user can proceed with designing Visual Basic forms and controls, writing code to handle user-interface events, and calling the Fortran routines as needed.

A Monte Carlo Integrator

Among other projects, I used VShell to develop a Visual Basic/Fortran mixed-language program for Monte Carlo integration. To integrate a real-value function over an interval, this method takes a rectangular region that includes the interval, plus a method of determining whether a random point in the rectangular region is inside or outside the function. Monte Carlo integration evaluates the function at a random sample of points. It estimates the integral as the ratio of the points in random sample that were inside the function to the total number of random points, multiplied by the area of the rectangular region.

The program offers a choice of five different functions to integrate (including linear, polynomial and trigonometric functions). The Fortran DLL side (available electronically; see "Availability," page 7) has the following routines:

  • Subroutine RANDOMXY generates random points within a specified rectangular boundary.
  • Functions F1 to F5, one for each of the five mathematical functions, return the value of that mathematical function at a specified point, given the values of the function's coefficients.
  • Subroutine MCARLO, given the mathematical function selected, its coefficients, and a random point (generated by RANDOMXY) determines whether or not that point was within the function.
The main components of the Windows user interface (designed and implemented on the Visual Basic side) are: option buttons to select the function to integrate; a picture box to draw the graph of the selected function; scroll bars to adjust the X-coordinate boundaries of the integration; option buttons to choose the number of random points for the integration; a menu option that enables the user to adjust the function's coefficients; another option for turning the display of the random points on or off; and various command buttons. The user interface is shown in
Figure 8 and Figure 9 .

The VShell-created Visual Basic declarations file for accessing the DLL and the main Visual Basic code that calls the DLL routines are both available electronically; see "Availability," page 7.

Conclusions

Using VShell, programmers can preserve their investment in useful Fortran code and make it part of a GUI application. Under VShell, the entire cycle of Fortran program development--from editing files to running compiled projects--is fully "visual," making it very easy to use and intuitive for all Fortran development.



_A GUI ENVIRONMENT FOR FORTRAN DEVELOPERS_
by Vinod Ananthraraman


[LISTING ONE]
<a name="0190_000a">
Branching based on the termination status of an executable program run via a Shell call.]

 batfile% = OpenFile("\vshell\bat\compile.bat", FILEWR)                  'Open batch file.
 If batfile% Then
      <Code to create MakeFile, the NMAKE description file for the Folder>

      Print #batfile%, "NMAKE /F " + MakeFile                               'Batch file runs NMAKE.
      Print #batfile%, "IF NOT ERRORLEVEL 1 exitdump temp1.tmp  0"
    'If NMAKE runs successfully
                                                                                                         'then write to temp1.tmp.
      Print #batfile%, "exitdump temp2.tmp 0"                                     'Write to temp2.tmp.
      Close batfile%

      If Len(Dir$("temp1.tmp")) > 0 Then Kill "temp1.tmp"             'If temporary files temp1.tmp
      If Len(Dir$("temp2.tmp")) > 0 Then Kill "temp2.tmp"            'or temp2.tmp exist, delete.
      x = Shell("c:\vshell\bat\compile.bat", 1)                     'Now run the batch file.

      Compile_Timer.Enabled = TRUE                            'Enable Compile_Timer.
      Shellform.Enabled = FALSE                           'Disable the Main form.
 End If


<a name="0190_000b">
[LISTING TWO]
<a name="0190_000b">
The file "mcarlo.for" with the Fortran DLL routines for Monte Carlo integration.]


      SUBROUTINE MCARLO(INDF,C1,C2,C3,C4,XVAL,YVAL,ISIN)
c
c   Takes INDF, the index of the function to integrate, its
c   coefficients (C1 to C4), and a random point (XVAL, YVAL) and
c   determines if the random point was inside the
c   function. If the point is inside the function, MCARLO sets ISIN
c   to 1 or -1 according as the point is on the negative or
c   positive side of the abscissa (the X coordinate axis).
      INTEGER   INDF
      REAL*4    C1,C2,C3,C4
      REAL*4    XVAL, YVAL
      INTEGER   ISIN
      REAL*4   TRUEPT
      EXTERNAL  FUNC,F1,F2,F3,F4,F5
            ISIN = 0
            TRUEPT = FUNC(INDF,XVAL,C1,C2,C3,C4)
      IF ((TRUEPT .GE. 0) .AND. (YVAL .LE. TRUEPT)
     +               .AND. (YVAL .GE. 0)) THEN
         ISIN = 1
      ELSE IF ((TRUEPT .LT. 0) .AND. (YVAL .GE. TRUEPT)
     +               .AND. (YVAL .LE. 0)) THEN
         ISIN = -1
      END IF
      RETURN
      END

      REAL*4 FUNCTION FUNC(INDF, X,C1, C2, C3, C4)
c
c   Calls one of the functions F1-F5, depending on the value of the
c   index INDF.

      INTEGER   INDF
      REAL*4   X, C1, C2,C3, C4
      SELECT CASE (INDF)
         CASE (1)
            FUNC = F1(X,C1,C2)
         CASE (2)
            FUNC = F2(X,C1,C2)
         CASE (3)
            FUNC = F3(X,C1,C2,C3)
         CASE (4)
            FUNC = F4(X,C1,C2,C3,C4)
         CASE (5)
            FUNC = F5(X,C1,C2,C3)
         CASE DEFAULT
            FUNC = -999
         END SELECT
      RETURN
      END

      REAL*4 FUNCTION F1(X,C1,C2)
c
c   Linear function

      REAL*4 X, C1, C2
      F1 = (C1*X) + C2
      RETURN
      END

      REAL*4 FUNCTION F2(X,C1,C2)
c
c   Square root function

      REAL*4 X, C1, C2
      F2 = C1*SQRT(X) + C2
      RETURN
      END

      REAL*4 FUNCTION F3(X,C1,C2,C3)
c
c   Quadratic function

      REAL*4 X, C1, C2, C3
      F3 = C1*X**2 + C2*X + C3
      RETURN
      END

      REAL*4 FUNCTION F4(X,C1,C2,C3,C4)
c
c   Third degree polynomial function

      REAL*4 X, C1, C2, C3, C4
      F4 = C1*X**3 + C2*X**2 + C3*X + C4
      RETURN
      END

      REAL*4 FUNCTION F5(X,C1,C2,C3)
c
c   Trigonometric function

      REAL*4 X, C1, C2, C3
      F5 = C1*SIN(X) + C2*COS(X) + C3
      RETURN
      END

SUBROUTINE RANDOMXY(XS,XE,YS,YE,RANX, RANY)
c
c   Given the end points of a rectangular region, returns a random point
c   (RANX,RANY) within that region.

      REAL*4   XS,XE,YS,YE
      REAL*4   RVAL, RANX, RANY
      CALL RANDOM(RVAL)
      RANX = (XE - XS)*RVAL + XS
      CALL RANDOM(RVAL)
      RANY = (YE - YS)*RVAL + YS
      RETURN
      END



<a name="0190_000c">
[LISTING THREE]
<a name="0190_000c">
The Visual Basic declarations file "mcarlo.bas" created by VShell to access the routines in the Fortran DLL "mcarlo.dll". This DLL was itself created by VShell from the Fortran source code in "mcarlo.for" shown in Listing 2.]



Declare Sub MCARLO Lib "c:\vb\mcarlo.dll" (Var1 As Long, Var2 As Single, Var3 As Single, Var4 As          Single, Var5 As Single, Var6 As Single, Var7 As Single, Var8 As Long, Var9 As Long)
Declare Function FUNC Lib "c:\vb\mcarlo.dll" (Var1 As Long, Var2 As Single, Var3 As Single, Var4          As Single, Var5 As Single, Var6 As Single) As Single
Declare Function F1 Lib "c:\vb\mcarlo.dll" (Var1 As Single, Var2 As Single, Var3 As Single) As Single
Declare Function F2 Lib "c:\vb\mcarlo.dll" (Var1 As Single, Var2 As Single, Var3 As Single) As Single
Declare Function F3 Lib "c:\vb\mcarlo.dll" (Var1 As Single, Var2 As Single, Var3 As Single, Var4 As          Single) As Single
Declare Function F4 Lib "c:\vb\mcarlo.dll" (Var1 As Single, Var2 As Single, Var3 As Single, Var4 As          Single, Var5 As Single) As Single
Declare Function F5 Lib "c:\vb\mcarlo.dll" (Var1 As Single, Var2 As Single, Var3 As Single, Var4 As          Single) As Single
Declare Sub RANDOMXY Lib "c:\vb\mcarlo.dll" (Var1 As Single, Var2 As Single, Var3 As Single,          Var4 As Single, Var5 As Single, Var6 As Single)


<a name="0190_000d">
[LISTING FOUR]
<a name="0190_000d">
Visual Basic front end code that calls  routines in "mcarlo.dll" and displays the result of the Monte Carlo integration.]


  NumIn = 0         'NumIn is the effective number of random points inside the function.                'Points in the negative side of the function have a weight of -1.
  For j% = 1 To Nr      'Nr is the number of random points used for the integration.

       Call RANDOMXY(Xstart,Xend,Ystart,Yend,Xvalue!,Yvalue!)
            'This DLL routine returns (Xvalue!,Yvalue!), a random point in the                'rectangular region between (Xstart,Ystart) and (Xend,Yend).
       Call MCARLO(FnIndex,Coeff1,Coeff2,Coeff3,Coeff4,Xvalue!,Yvalue!,IsIn&)
            'The DLL routine to determine if the random point is inside the                'function. The index of the function being integrated and its                   'coefficients are parameters.
       NumIn = NumIn + IsIn&
  Next j%

  TotalAreaLabel.Visible = TRUE
  IntegralLabel.Visible = TRUE
  Integral# = (NumIn / Nr) * (Xend - Xstart) * (Yend - Ystart)
            'The integral value estimated by Monte Carlo integration.
  TotalAreaLabel.Caption = "Sampled area: " + Str$((Xend - Xstart) * (Yend - Ystart))
            'Display the total area sampled for random points.
  IntegralLabel.Caption = "Value of integral (colored): " + Str$(Integral#)
            'Display the estimated integral value.












Copyright © 1993, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.