contents   index   previous   next



Writing a test main Fortran application

 

We need to write the Fortran code to instantiate ActiveX object CMain and handle its events. Let’s start with the function to handle the events, which as with all other procedures in this program is contained in module f90VBGUI (Sample Code 13). Note that we have called this event handler CMainTestEventsHandler. We used this name because this is not the final event handler for our program, but rather a test handler. At this point, all we want is a skeleton of an event handler, so we can concentrate on how things work. We’ll write the real event handler later.

 

CMainTestEventsHandler is a very simple subroutine. We won’t discuss the declaration or arguments passed to this subroutine because they are fully described in the f90VB User and Reference Manuals. The important part of the code is located inside the subroutine’s select statement. The statement discriminates among different values of variable DispID and prints a message on the console window of the main program. DispID is the dispatch ID number of the events fired by class CMain. Each event fired by an outgoing interface has a unique DispID that can be used to identify the event. You can obtain the DispID of each event in an interface by checking the Attributes tab for the event with TLView. For example, Figure 17 shows that event OnFactorialTableClick has a DispID of 3.

 

As you might have inferred, subroutine CMainTestEventsHandler will be called by class CMain each time the class fires an event. Remember that most of the events in CMain are fired when the user selects options from the main menu. So when the user selects menu option Tools/Factorials Table…, class CMain fires event OnFactorialTableClick, subroutine CMainTestEventsHandler is called with a DispID of 3, and we print a message on the main program console window saying that this menu option was selected. Likewise, when the user selects About f90VB Demo (DispID=4) from the main menu, rather than print a message we show the About dialog box exposed by class CAbout.

 

In addition to subroutine CMainTestEventsHandler, you might have noticed that we also added some variables in the declaration section of module f90VBGUI. The reason for this will become obvious later, when we start working on the real event handler subroutine for our program.

 

Ok, now we have simple function to handle the events fired by object CMain, and we are ready to write a test main application program (program TestCMain). The main application has some compiler-dependent code, so you can select the links below for the compiler of your preference:

 

Program TestCMain for Absoft Pro Fortran (Sample Code 14a)

Program TestCMain for Compaq Visual fortran (Sample Code 14b)

Program TestCMain for Lahey Fortran 95 (Sample Code 14c)

 

Let’s dissect the main application program and see what it does. First, we initialize OLE, create an instance of the CMain object and store it in variable CMain:

 

!Initialize Ole

iRet = OleInitialize()

 

!Create an instance of the CMain object

CMain = CreateOleObject('f90VBGUI.CMain',iRet)

!Create an instance of the CInput object

CInput = CreateOleObject('f90VBGUI.CInput',iRet)

 

We also create an instance of CInput. Although CMainTestEventsHandler doesn’t use it, CInput will be used by the final event handler that we’ll write later. If everything goes well, we create an f90VB sink object and connect the object to the CMain instance we created earlier:

 

    EventSinkHndl = EventSinkCreate(iRet)

    call EventSinkConnect(EventSinkHndl, CMain, NullGUID() ,iRet)

 

Note that we use the handle returned by function EventSinkCreate to refer to the specific instance of the f90VB sink object in all subsequent calls. You may have more than one sink object active at any time. Also note that we pass the result of f90VB function NullGUID() to the connection subroutine, which connects the sink object to the default outgoing interface of CMain, in this case __CMain (you can verify this using TLView).

 

Next, our program registers the events we want to handle. We register the same subroutine CMainTestEventsHandler for all four events we are interested in. Notice that CMain also fires a fifth event (OnQuit), but our program doesn’t need to handle this event.

 

    call EventSinkRegEvnt(EventSinkHndl, 'OnLogTableClick', &

                          loc(CMainTestEventsHandler), iRet)

    call EventSinkRegEvnt(EventSinkHndl, 'OnFactorialTableClick', &

                          loc(CMainTestEventsHandler), iRet)

    call EventSinkRegEvnt(EventSinkHndl, 'OnAboutBoxClick', &

                          loc(CMainTestEventsHandler), iRet)

    call EventSinkRegEvnt(EventSinkHndl, 'OnExcelChartClick', &

                          loc(CMainTestEventsHandler), iRet)

    call EventSinkRegEvnt(EventSinkHndl, 'OnQuit', &

                          loc(CMainTestEventsHandler), iRet)

 

As you can see, we register events by name rather than by DispID. If you pass the name of an event that doesn’t exist, subroutine EventSinkRegEvnt will return constant DISP_E_UNKNOWNNAME in argument iRet. Also you should be aware that although we prefer to have a single subroutine handle all of the events fired by an ActiveX object, there’s nothing to stop you from handling each event with a different subroutine (à la Visual Basic).

 

Once events have been registered, the program calls method Show of CMain. As you already know, this method shows the main window for our program. The form shown by CMain is modeless, so we need a way to put the program in stand-by mode while the events fired by the form (and bubble-up through CMain) are processed. We achieve this with a Windows message loop:

 

    !enter a fake message loop, so application can process events

    do while(.not. QuitApplication)

        iret=GetMessage (mesg, 0, 0, 0) 

        iret=DispatchMessage( mesg )

    enddo

 

Note that this loop exists when variable QuitApplication is set to .true.. You can see that this is done in the event handler when object CMain fires the OnQuit event. In other words, when the form shown by CMain is closed (either by clicking the Close Window icon or by selecting File/Exit from the menu), the execution of the main program resumes after the loop. At this point we prepare to shut down the application; un-register the events that have been registered, disconnect and destroy the sink object:

 

    call EventSinkUnregEvnt(EventSinkHndl, 'OnLogTableClick', iRet)

    call EventSinkUnregEvnt(EventSinkHndl, 'OnFactorialTableClick', iRet)

    call EventSinkUnregEvnt(EventSinkHndl, 'OnAboutBoxClick', iRet)

    call EventSinkUnregEvnt(EventSinkHndl, 'OnExcelChartClick', iRet)

    call EventSinkUnregEvnt(EventSinkHndl, 'OnQuit', iRet)

    call EventSinkDisconnect(EventSinkHndl)

    call EventSinkDestroy(EventSinkHndl)

 

Finally we release the CMain and CInput objects, do some additional clean-up, and uninitialize the OLE environment:

 

    !Release the instance of IE

    call Release(CInput)

    call Release(CMain)

    call VariantClear(VarTmp)

 

!Uninitialize Ole

call OLEUninitialize()

 

Now that you understand the basics of how to write a main program and an event handler subroutine for your GUI, you can compile and link your program to see it in action. The links below explain how to do this with several compilers:

 

Instructions to compile TestCMain with Absoft Pro Fortran

 

Instructions to compile TestCMain with Compaq Visual Fortran

 

Instructions to compile TestCMain with Lahey Fortran 95

 

Figure 18 shows a screen shot of the running program after we have made a few selections from the main menu.


Writing the real event handler for CMain