Building Object-Oriented Applications from Existing C Code

From EDM2
Jump to: navigation, search

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

By Gregory Piamonte

This article discusses how the Visual Builder component of VisualAge C++ can extend the usefulness of legacy C code and existing C skills, and provide an elegant migration path from C and procedural programming to C++ and OO development. This process is illustrated step-by-step.


Through computer interaction, users today are enjoying the best of times. This is the age of sophisticated interface controls such as folders, notebooks, and toolbars. Multimedia and graphic-intensive software are becoming standard, making technology easy and intuitive for computer users.

Unfortunately, while software usability improves, software developers have to pay the price for these impressive graphical user interfaces (GUIs). Requirements are more complex, new concepts have to be learned quickly, and competitive markets are forcing reduced time frames.

Fortunately, help has arrived in the form of two emerging technologies, visual programming and software construction from parts. The latter, based mainly upon techniques proven in other industries such as manufacturing, involves building applications from existing, reusable software components called parts. Just as a computer is built from prefabricated components such as the motherboard, power supply, and disk drives, an application can also be assembled from existing software parts. Figure 1 illustrates this construction-from-parts paradigm.

Figure 1. Construction-from-Parts Paradigm

Visual programming hides some of the more complicated concepts involved with graphical user interfaces such as event-driven programming, plus it greatly facilitates the mundane tasks of drawing dialogs and their graphical controls.

These two approaches allow software builders to concentrate on the mission-critical aspects of applications, such as business logic, communications, and data access.

VisualAge C++ to the Rescue!

Does a product exist that effectively exploits the powerful combination of visual programming and the construction-from-parts methodology?

Allow me to present VisualAge C++, IBM's newest member of its C Set family of products (see Figure 2). The VisualAge C++ package includes enhanced versions of components from previous C Set and C Set ++ products, such as WorkFrame, Performance Analyzer, and User Interface Class Library (now called IBM Open Class Library).

Figure 2. VisualAge C++

VisualAge C++ also introduces the Visual Builder component, which builds upon the proven application construction technologies of IBM's VisualAge Smalltalk product. This component allows you to visually develop complete object-oriented applications by providing the tools for building, reusing, and assembling all necessary parts. Standard parts, customized parts, or parts built from scratch can be pieced together to build higher-function parts, subsystems, or entire applications.

The Visual Builder is shipped with its own set of prefabricated parts built from the user interface, application support, data access, and collection classes of the Open Class Library. These classes and parts have been developed for maximum reusability and are the main building blocks for our construction-from-parts approach.

The Visual Builder does not restrict the types of existing parts or usable classes. You can reuse any class library supported by the target platform. You can even bring in procedural code such as C functions to use with Visual Builder parts (see Figure 3), allowing a gradual and elegant transition into the world of objects.

Figure 3. Procedural Code with Object-Oriented Parts

In this article, I attempt to illustrate how software investments can be maximized by recycling procedural functions and leveraging existing C skills. The recommended scenario is to initially exploit Visual Builder's screen-painting and object-oriented code generation facilities for your graphical user interface, but then to call existing procedural code for the application logic.

With this strategy, you can exploit the benefits of object-oriented technology immediately, then learn how to use it at your own pace. Once you've built your object-oriented user interface, you can study the code generated by the Visual Builder and learn, as time permits, how C++ and objects are used in the application.

Visual Builder Fundamentals and Key Concepts

In the Visual Builder world, parts are wrappers around C++ classes or C functions, with their own well-defined interface. A part interface defines how parts communicate with other parts. A part interface comprises three features: attributes, actions, and events. For C parts, only actions are significant. They are defined as the services or operations that a part can perform. Actions correspond to C++ member functions or C functions.

Attributes are the logical data that map to C++ class member data.

Events are signals that a part sends to interested parts whenever a change has occurred or a specific condition has been met. Examples of these changes or conditions include the contents of an entry field being altered and the user clicking on a pushbutton.

Another key concept involves visual connections between parts. These connections are basically the graphical lines of code that implement the logic for the application, and their order dictates the processing flow. A connection is directional, which means it has a source and a target. The direction is determined by the manner in which the connection is drawn. (This will make more sense when we actually start building the sample application.)

The Visual Builder generates C++ code to implement the visual and non-visual parts that have been designed and defined, as well as the connections between these parts. Visual Builder part source code is kept separate from user-defined code to prevent loss of user code if modifications are made. To provide a jump-start, you can generate a code skeleton with stubs for C++ member functions.

All these facilities let you focus on what the application does, rather than how it looks.

Visual Builder Editors

The Visual Builder comes with three editors:

  • Composition Editor, where you design your graphical interface by selecting and laying out prefabricated visual parts on a work space. You add the non-visual parts that provide the application logic, then make the appropriate connections between the parts to define the flow of processing.
  • Part Interface Editor, where you define the features of your parts, specifically their actions, attributes, and events. This editor is normally not applicable for C function parts, but is crucial for C++ parts.
  • Class Editor, where you customize the code generation settings. Here, you provide the specifics of the part to be generated, such as source filenames and file dependencies.

Sample Program Implementation Strategy

This article's sample application will convert temperature units from Fahrenheit to Celsius and vice versa.

There are two techniques for integrating C functions with Visual Builder applications. The first involves calling C functions directly by writing C code using the custom logic facility. The second involves wrapping C functions into Visual Builder parts, allowing other parts to visually call these functions through graphical connections (see Figure 4). Because the second solution offers more flexibility and is in line with object-oriented principles, it is the approach we use here.

Figure 4. Converting C Functions into Visual Builder Parts

The sample application uses pre-built C functions packaged in a dynamic link library (DLL) named CFUNCS.DLL. We will assume that these functions are our legacy C code. For simplicity, we'll keep the implementation of the C functions primitive by limiting the temperature range to between freezing and boiling points. The source code for the two C functions to be used is shown in Figure 5.

/*-------------------------------------------------------------*/ 
/* CFuncs.c Source file for a C DLL                            */ 
/*-------------------------------------------------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "CFuncs.h"

/***************************************************************/
/*  Function Name:  convertFahrenToCelsius	               */
/*  Description:    Convert Fahrenheit temperature to Celsius  */
/*  Parameters	                                               */
/*			                                       */
/***************************************************************/ 
int _Optlink convertFahrenToCelsius(int fahrenheit)
{
   int celsius;
   celsius = ((fahrenheit-32)*5)/9;
   return(celsius);
}

/***************************************************************/ 
/*  Function Name:  convertCelsiusToFahren	               */
/*  Description:    Convert Celsius temperature to Fahrenhei   */
/*  Parameters	                                               */
/*		                      	                       */
/***************************************************************/ 
int _Optlink convertCelsiusToFahren(int celsius)
{
   int fahrenheit;
   fahrenheit = ((celsius*9)/5)+32;
   return(fahrenheit);
}

Figure 5. CFUNCS.C

Creating Our WorkFrame Project

To jump-start the initial project creation, we use another new VisualAge C++ component called Project Smarts. This component helps us create a development project specifically tailored for Visual Builder applications. The generated project will already have the Build, Compile, and Link options properly customized.

To generate our project using Project Smarts:

  1. Open "Project Smarts" in the VisualAge C++ folder to display the Project Smarts catalog, shown in Figure 6.
  2. Select "Visual Builder Application" from the list of available projects, then click on the Create pushbutton.
  3. During the installation, a Location window appears. Input the directory where the source files will be installed, then select the folder where the project will be created.
  4. When the installation is complete, open the project in the specified folder. The Project window will appear, similar to the one in Figure 7.
  5. Because we are not using any of the generated files, delete all files within the project by highlighting the files and selecting "Delete..." from the context or pop-up menu.
Figure 6. VisualAge C++ Project Smarts Catalog
Figure 7. Project Window

Building the C Functions Non-Visual Part

To wrap C functions as Visual Builder parts, we must create a part information file to define how other parts can communicate or interface with this part. At first glance, a part information file may seem cryptic, but it is not complicated and only requires familiarity with the different statement tags.

Part information files normally have a file extension of .VBE. To create our own file, select "Project->Edit" to display the VisualAge C++ Editor. Type in the statements shown in Figure 8, then save the file as CFUNCS.VBE.

//VBBeginPartInfo: CFunctions, "C functions"
//VBIncludes: "cfuncs.h" cfuncs_h
//VBPartDataFile: 'cfuncs.vbb'
//VBComposerInfo: functions, 701, dde4vr30
//VBAction: convertFahrenToCelsius, "Converts Fahrenheit to Celsius",
//VB:         int, int convertFahrenToCelsius(int fahrenheit)
//VBAction: convertCelsiusToFahren, "Converts Celsius to Fahrenheit", 
//VB:         int, int convertCelsiusToFahren(int celsius)
//VBPreferredFeatures: convertFahrenToCelsius, convertCelsiusToFahren
//VBEndPartInfo: CFunctions

Figure 8. Part Information File for C Functions

By importing this file into our sample Visual Builder application, we define the different features of our C part, such as the part name, the include files, the function names as they will be used by other parts, the C function declarations, and the return types.

For more information about the tags and syntax of part information files, refer to the Visual Builder User's Guide and the Building VisualAge C++ Parts for Fun and Profit documentation. (These are shipped with the product as online documentation.)

After creating the CFUNCS.VBE file with the statements outlined in Figure 8, close the editor and switch to the Project window.

Importing the CFuncs Non-Visual Part

To import the CFuncs non-visual part:

  1. From the Project window menu bar, select "Project->Visual" to display the Visual Builder main window, shown in Figure 9.
  2. From the main Visual Builder window menu, select "File->Import part information..." to display a file dialog.
  3. Select CFUNCS.VBE from the list, then click on the OK pushbutton. If the part information file or VBE was created properly, a confirmation dialog should appear, stating that there are no errors or warnings.
  4. Close the confirmation dialog. You should see CFUNCS.VBB in the list of loaded part files. Our non-visual part is now ready to use.
Figure 9. Visual Builder Main Window

Building the Main Window Visual Part

To build the main window visual part:

  1. From the main Visual Builder window menu, select "Part->New" to display the Part-New dialog.
  2. Input Sample as the class name. By default, "Visual part" should be the selected part type. The file name will default to the class name. Click on the Open pushbutton.
  3. Because we are constructing a visual part, the Composition Editor window will initially appear. You should see only an empty frame window on top of a white space called the free-form surface area. We need to lay out the necessary visual parts on that free-form surface area and build the empty window to look like Figure 10.

This is a good point to become better acquainted with different facilities Composition Editor provides. The parts palette on the left side of the Composition Editor has two columns of icons. Icons in the left column represent different part categories. Icons in the right column represent parts within the category selected in the left column. These are prefabricated software components that you can use to build your application. The parts palette typically contains the most frequently used visual and non-visual parts. You can customize it to define new categories and include your own parts.

To add parts to the frame window or the free-form surface area, select the appropriate part from the parts palette. At this point, the mouse pointer is loaded and will turn into a crosshair when moved across an area or part where it can be placed. The information area at the bottom of the Composition Editor will indicate the category or part currently selected, and will also provide other valuable information when we begin working with connections.

To help you properly position, align, and size the parts being used, tools are provided on the toolbar below the menu bar. There are also special canvasses, or containers of parts, that help make life easier. Refer to the online documentation suggested earlier for more detail. For our simple sample, you should have sufficient information to build the window shown in Figure 10.

Our sample application uses only static text controls, numeric spinbuttons, pushbuttons, and entry fields. We will be able to use default settings for all controls except numeric spinbuttons. To alter the settings for the Fahrenheit spinbutton, display its settings notebook by double-clicking on the control or selecting "Open Settings" from its context menu. (Access the context menu through the right mouse button.) Change the lower limit of the numeric range to 32 and the upper limit to 212, then click on the OK pushbutton. Now, do the same for the Celsius spinbutton, except keep the lower limit at 0 and change the upper limit to 100. This restricts temperature values to those between freezing and boiling points.

To modify the title on the main window, access its settings notebook by double-clicking on the title bar. At this point, your window should look like Figure 10.

Figure 10. Composition Editor Window

Providing Application Logic Through Connections

Now we need to furnish the logic for the temperature conversions. For this, we will use C functions contained in CFUNCS.DLL through the CFuncs non-visual part we have defined.

  1. From the Composition Editor window menu, select "Options->Add part..." to display the Add Part dialog.
  2. Input CFunctions* as the part class, and CFunctions as the name. Verify that the Part radio button is selected, then click on the Add pushbutton.
  3. Place the crosshair anywhere on the free-form surface area, and click on the left mouse button to drop the CFunctions non-visual part.
  4. Access the upper pushbutton's context menu with the right mouse button, then select "Connect→buttonClickEvent." You see a black dotted line with a spider at the end of it.
  5. Drop the spider on the CFunctions non-visual part to complete the connection. A pop-up menu of all preferred features displays. In our scenario, this will be a list of C functions that can be invoked by the connection.
  6. Select "convertFahrenToCelsius" from the pop-up list. A dotted green line appears between the pushbutton (source) and the CFunctions part (target). The connection line is dotted to indicate that a parameter is required. In this case, the Fahrenheit value to be converted must be supplied to the C function.
  7. Provide the parameter by accessing the context menu of the green connection line, then selecting "Connect→fahrenheit." The spider appears again.
  8. Drop the spider onto the Fahrenheit spinbutton and connect to the "value" attribute, completing the parameter connection.
  9. Retrieve the result of the function call and initialize the Celsius entry field with this value. Do this by connecting the "actionResult" attribute (from the green connection's list of preferred features) to the "valueAsInt" attribute of the Celsius entry field. This enables the entry field to receive the return value of the C function.

The colors used for the connections vary to indicate the type of connection and can be a valuable clue to whether the logic is being constructed properly. Now repeat steps 4 through 9 for the Celsius to Fahrenheit controls, except call the C function convertCelsiusToFahren instead.

I assume you have been saving your work after every major change; if not, do so now. At this point, the Composition Editor should appear similar to the screen shown in Figure 11.

Figure 11. Application Parts with Connections

One remaining step provides you with a chance to work with the Class Editor. From the Composition Editor menu, select "View->Class Editor" to display the Class Editor. Look for the multi-line edit field labeled "Required include files" at the bottom right of the window. Type cfuncs.h exactly as shown in Figure 12.

Figure 12. Class Editor

Our application is now complete. Select the "Save and Generate->Part source" menu option, then the "Save and Generate->main() for Part" option. Close the Class Editor and the Visual Builder main dialog, and return to the Project window.

Setting the Build Options and Generating the Executable

We are not yet ready to build the executable file for our sample application. We still need to specify the import library of the DLL containing the C functions and the location of this import library and include file. To do this:

  1. From the Project window menu, select "Options->Link" to display the Linker Settings notebook.
  2. Switch to the Filenames page, and append cfuncs.lib to the "Libraries to use:" entry field. Do not remove the original contents of the field. (Refer to Figure 13.)
  3. Click on the OK pushbutton to accept the changes. It is not necessary to change the default settings for the compilers. The proper options are already set because we used Project Smarts to generate our project.
  4. Select "View->Tools setup" from the Project window menu to bring up the window shown in Figure 14.
  5. From the menu, select "Variables->Add...", and the Add Environment Variable dialog appears. Type lib into the Name entry field or select it from the drop-down list.
  6. Append the path where CFUNCS.LIB is stored to the end of the text in the String entry field, and then click on the Add pushbutton.
  7. Repeat steps 5 and 6, except specify include in the name entry field, and append the path for CFUNCS.H to the text in the string entry field.
  8. Close the Tools Setup window and return to the Project window. Select the "Project->Build" menu option to build the .EXE file for our sample application.
Figure 13. Linker Settings Notebook
Figure 14. Tools Setup Window

Running the Sample Application

That's it! We're done. If everything went smoothly, we should have produced an executable called VBMAIN.EXE that works as designed. VBMAIN.EXE is the default name, but you can modify it in the Project Settings notebook.

Before you take the sample application for a test drive, make sure that CFUNCS.DLL is in a directory defined in the LIBPATH statement of your CONFIG.SYS file, or it is in the same subdirectory as the executable. To run the sample from the Project window, select "Project->Run" from the menu or double-click on the VBMAIN.EXE file.

VisualAge C++ and all of its components, specifically the Visual Builder, were designed to ease the pain and speed up the effort involved in constructing software applications. The Visual Builder promotes reusability not only with logic parts, but with visual parts as well, and is a tool that maximizes rather than limits. It is probably the quickest route to the land of objects, and it enables you to test object-oriented waters without getting wet.

Download the source code (sample.exe) (cfuncs.exe) and Visual Builder files used for this sample application.