Platinum Edition Using Visual Basic 5

Previous chapterNext chapterContents


- 29 -
Using the Visual Basic Data Control

The Data control provides several buttons that enable you to move from one record to another in a recordset.
We examine how the bound controls make it easy to get information from a database to the user's screen.
You will see how to use code to add record management features to your applications.
If you want the easiest way to create a data entry form, Visual Basic can create it for you. You'll see how to use a wizard to make this happen.
You'll also see how to use Crystal Reports forms from within your program.

V isual Basic is designed to enable you, the developer, to create applications for the Windows environment quickly and easily. This ease-of-use extends to the creation of database programs as well. If you have an existing database that you want to access, Visual Basic makes it easy for you to write a complete data management and reporting application with almost no programming. You just drop a few controls on a form and set the properties. In fact, Visual Basic makes the task so easy that it can even create the data entry forms for you.

The components that make all these capabilities possible are the Data control and the data-bound controls for data entry forms and Crystal Reports for report generation. With just these few tools, you can create a wide variety of applications. Of course, as you progress to more complex applications, you need to do more of the programming yourself. But even for more complex applications, these tools provide a good first step in the programming process and enable you to create application prototypes rapidly.

Understanding the Data Control

The centerpiece of easy database applications is the Data control. The Data control is one of the controls available in Visual Basic's Toolbox, as shown in Figure 29.1. Setting up the Data control requires only four simple steps:

1. Select the control from the Toolbox.

2. Draw the control on your form.

3. Set the DatabaseName property of the control.

4. Set the RecordSource property of the control.

FIG. 29.1
The Data control is one of the standard components of the Visual Basic Toolbox.


NOTE: Following these four steps is the minimum required to set up the Data control. If you want to access non-Jet databases or use any of the control's other capabilities, you need to set additional properties. These properties are covered in Chapter 30, "Doing More with Bound Controls."

See "Exploring the Data Control In-Depth," Chapter 30

What Is the Data Control?

Basically, the Data control is a link between information in your database and the bound controls that you use to display the information. As you set the properties of the Data control, you tell it which database and what part of the database to access. By default, the Data control creates a dynaset-type recordset from one or more of the tables in your database.

The Data control also provides the record navigation functions that your application needs. With these buttons, indicated in Figure 29.2, the user can move to the first or last record in the recordset or to a record prior to or following the current record. The design of the buttons makes their use intuitive; they are similar to the buttons you would find on a VCR or a CD player.

FIG. 29.2
The VCR-like buttons on the Data control indicate their function to the user.

The recordset created by the Data control is determined by the settings of the DatabaseName and RecordSource properties. The recordset is created as the form containing the Data control loads and is activated. This recordset is active until the form is unloaded, at which time the recordset is released.


NOTE: A recordset is an object that represents the data in a physical database. Even after a recordset is released or closed, the data in the underlying table(s) is still in the database.

Adding a Data Control to Your Form

The first step in using a Data control is to add the control to your application's form. Select the Data control object from the Visual Basic Toolbox (refer to Figure 29.1). Next, place and size the Data control just as you do any other design object. After you set the desired size and placement of the Data control on your form, you can set its Name and Caption properties.

The Name property sets the control name, which identifies the control and its associated data to the bound controls. The default name for the first Data control added to a form is Data1. Additional Data controls added to a form are sequentially numbered as Data2, Data3, and so on. To change the name of a Data control, select its Name property from the Properties window and type the name you want (see Figure 29.3).

FIG. 29.3
The Data control's Caption property has been set to a more meaningful value.

The Caption property specifies the text that appears on the Data control. You usually want the caption to be descriptive of the data the control accesses. The default for the Caption property is the initial setting of the Name property (for example, Data1 for the first Data control). You can change the Caption property the same way you change the Name property (see Figure 29.3).

For the example you're creating in this chapter, add a Data control with the name datYouth and the caption Youth. Figure 29.4 shows the form with this control added.

FIG. 29.4
Draw the Data control on your form and set its caption appropriately.


TIP: You also can add code to your program to change the Data control's caption to reflect information in the current record, such as a person's name.

Two Properties Are All You Need to Set

After you place the Data control on your form, you need to make the connection between the Data control and information stored in a database. You do so by setting the Data control's properties. Although several properties can affect the way a Data control interacts with the database, only two properties are required to establish the link to a Jet database: the DatabaseName and RecordSource properties. Specifying these two properties tells the Data control what information to retrieve from the database and causes the Data control to create a recordset that allows nonexclusive, read/write access to the data.


NOTE: The DatabaseName property is not the same as the Name property mentioned earlier. The Name property specifies the name of the Data control object. This name references the object in code. The DatabaseName property specifies the name of the database file that the Data control is accessing.

What's in a Name? For Jet databases, the DatabaseName property is the name of the database file. To enter the name, select the DatabaseName property from the Properties window and type the database's file name. If you'd like to locate the database by browsing, click the ellipsis button (...) at the right of the property input line to display the DatabaseName dialog box, as shown in Figure 29.5. Browse to the appropriate database file and click OK. The selected file name and path are automatically entered into the DatabaseName property (see Figure 30.6).

FIG. 29.5
Use the Properties window to set the database name for the control.

FIG. 29.6
You can enter a database name or choose it from the DatabaseName dialog box.


CAUTION: If you browse to the DatabaseName property at design time using the dialog box, the property will include a fully qualified path to the database's file name, for example, C:\MyData\LMS\TMS1112.MDB. This may be dangerous since the database will be expected to be in the same exact location at runtime. It would be better to allow some flexibility in the location of the database: set the DatabaseName property using no path (that is, use TMS1112.MDB), in which case your program would expect to find it in the program's current directory; use a relative path from the current directory (that is, use LMS\TMS1112.MDB); or set the property from code based on user input or some type of program initialization parameters (that is, use Data1.DatabaseName = stDataLocation).

Straight from the Source After you've set the DatabaseName property, specify the information you want from that database with the RecordSource property. If you are working with a single table as your recordset, you can enter the table name or select it from the list of tables, as shown in Figure 29.7.

FIG. 29.7
You can select the RecordSource property from a list of tables available in the database.

If you want to use only selected information from a table or use information from multiple tables, you can use a SQL statement in the RecordSource property. To do this, you can either set the RecordSource property to the name of a QueryDef in the database that contains a SQL statement or enter a valid SQL statement as the value of the RecordSource property. You can use any SQL statement that creates a recordset. (You can also include functions in your SQL statement.) If you're using a QueryDef, it must be a QueryDef that has already been defined and stored in the database.


TIP: To make sure that your SQL statements work correctly, you can test them in Visual Data Manager. Then copy and paste to place the statements in the RecordSource property.

Getting Acquainted with Bound Control Basics

Bound controls in Visual Basic are controls that are set up to work with a Data control to create database applications; hence, the controls are "bound" to information in the database. Most of the bound controls in Visual Basic are simply standard controls that have additional properties allowing them to perform data access functions. A few custom controls are designed specifically to work with the Data controls. These controls are covered in Chapter 30, "Doing More with Bound Controls."

See "Other Bound Controls," Chapter 30

The controls that you use as bound controls are ones with which you are already familiar:

These controls are highlighted in the Toolbox shown in Figure 29.8.

FIG. 29.8
Several familiar controls also have properties that let them access data.

What Do These Controls Do?

Each bound control is tied to a Data control and, more specifically, to a particular field in the recordset attached to the Data control. The bound control automatically displays the information in the specified field for the current record. As the user moves from one record to another using the navigation buttons of the Data control, the information in bound controls is updated to reflect the current record.

The bound controls are not limited, however, to just displaying the information in the record. Most also can be used to modify the information. To do so, the user just needs to edit the contents of the control. Then, when the current record is changed or the form is closed, the information in the database is automatically updated to reflect the changed values.


NOTE: Because the Label control has no editable portion, the data displayed in the Label cannot be changed. Also, if a control is locked or editing is otherwise prevented, the user cannot change the value of the information.

You use each of the basic bound controls to edit and display different types of data. With the bound controls, you can handle strings, numbers, dates, logical values, and even pictures and memos. Table 29.1 lists the five basic bound controls and the types of database fields that they can handle. The table also lists the property of the control that contains the data.

Table 29.1 Different Controls Used to Handle Different Types of Data

Control Name Data Type Control Property
Label Text, Numeric, Date Caption
TextBox Text, Memo, Numeric, Date Text
CheckBox Logical, True/False Value
PictureBox Long Binary Picture
Image Long Binary Picture

Adding Controls to Your Forms

To add a bound control to your form, select the control from the Toolbox and draw it on the form. Figure 29.9 shows a text box added to the form that contains the Data control.

FIG. 29.9
You draw bound controls on your form just as you draw any other control.


TIP: Hold down the Ctrl key when you click a control in the Toolbox, and you can add multiple controls of that type to your form. This way, you don't have to click the control's Toolbox button repeatedly. When you're done, click the mouse pointer button in the Toolbox.

Data Display in Two Easy Properties

For a bound control to work with the data from a recordset, you must first tie the bound control to the Data control representing the recordset (recall that we've already discussed how to bind the Data control to physical data). You do this by setting the bound control's DataSource property. Depending on the specific control used, you might have to set other properties. By working on the sample Retail Items data entry screen throughout the remainder of this chapter, you will learn several of the bound controls, which properties you must set, and how to set them.

Setting the DataSource Property To set the DataSource property, select it from the Properties window for your control. Click the arrow to the right of the input area to see a list of all the Data controls on the current form. To set the DataSource property, select one of the controls from the list. Figure 29.10 shows this procedure.

FIG. 29.10
Select the DataSource property for the bound control from a list of the form's Data controls.


TIP: Double-click the DataSource property to scroll through the available Data controls.

Setting the DataField Property Although the DataSource property tells the bound control from which Data control to retrieve data, you still need to tell the bound control what specific data to retrieve. You do so by setting the DataField property. This property tells the control which field of the recordset will be handled by this bound control. To set the DataField property of the control, select the DataField property from the Properties window, click the arrow to the right of the input area, and select one of the fields from the displayed list. The list includes all available fields from the recordset defined in the specified DataSource (see Figure 29.11).

FIG. 29.11
Select the DataField property for the bound control from the list of fields in the selected Data control.


TIP: Double-click the DataField property to scroll through the available fields.


CAUTION: You cannot select a field for the DataField property from a list until the DataSource property has been set.

Creating a Simple Application

To help further illustrate the concepts of creating a data access application, let's walk through the process of creating a data entry form using the biblio database, which is included with Visual Basic.

Setting Up the Form

The first step in setting up the data access form is to start a new project. Add a Data control to the default form. Change the Data control's Name property to dtaMain and its Caption property to Author Info. Next, set the DatabaseName and RecordSource properties of the Data control. First, set the DatabaseName property to the path to biblio.mdb on your hard drive. After you set the database name, you can set the RecordSource property. From the property's selection list, select the Authors table. The Data control is now ready for use.

The next step in creating the data access form is to add the bound controls. To make the example easy, just use text boxes for each of the fields. Also, for each field, place a label control on the form to identify the information in the text box. For the sample case, you need three text boxes and three corresponding labels. The DataSource property of all the text boxes is dtaMain, which is the name of the Data control you just created. For each text box, you also need to specify a DataField property. Remember that the DataField property ties the control to a specific field in the database. Table 29.2 lists the DataField settings for each text box and the suggested captions for the corresponding label controls. The table uses the default names for the text boxes.

Table 29.2 DataField and Caption Settings for the Data Access Form

TextBox Name DataField Caption for Corresponding Label
Text1 Au_ID Author ID:
Text2 Author Name:
Text3 Year Born Year Born:

After you add the bound controls and set their properties, your form should look like the one shown in Figure 29.12.

FIG. 29.12
You can create a simple data entry form by using just the Data control and bound text boxes.

Navigating the Database

Now that you have created the data entry form, try it out by running the program. As the program first starts, you should see the form load, and the information for the first record should appear in the text boxes. Now you can see how the Data control is used to navigate through the records of the database. You can move to the first record, the previous record, the next record, or the last record by clicking the appropriate button on the Data control.

With this simple program you can even update and edit the database. Try typing a year in the Year Born text box and moving to another record. This enters new information into the database.


TROUBLESHOOTING:The records of the database seem to be in random order, not alphabetical order. You have not created an error or done anything wrong in setting up the form. You are seeing the records presented in the physical order of the table, the order in which the records were entered. If you want to see the records in alphabetical order, place the following string in the RecordSource property of the Data control:

Select * from Authors Order by Author 

Then run the program again. You can also set the RecordSource property from code:

frmMain.dtaMain.RecordSource = "Select * from Authors Order by Author"

frmMain.dtaMain.Refresh



Essential Functions the Data Control Forgot

As you can see, the Data control is quite flexible, but it lacks a few functions that are necessary for most data entry applications--specifically, adding and deleting records. To overcome these shortcomings, you can add the functions to the data entry screen using program commands assigned to a command button.

To add these functions to the sample application, add two command buttons named Add and Delete to the form. To make the buttons functional, add the code segments shown in Listing 29.1 to the Click event of the appropriate button.

Listing 29.1 ProgramName.ext--Program Statements Placed in the Click Event of Command Buttons to Add Capabilities to the Data Entry Screen

`Command to add a new record,
`place in click event of Add button
dtaMain.Recordset.AddNew
`Commands to delete a record,
`placed in click event of Delete button
dtaMain.Recordset.Delete
If Not dtaMain.EOF Then
   dtaMain.Recordset.MoveNext
Else
   dtaMain.Recordset.MoveLast
End If

As you can see, this listing does not enter a command to invoke the Update method. (Updates are done automatically by the Data control whenever you move to a new record or close the form.)


NOTE: You add the MoveNext and MoveLast commands to the Delete button to force a move to a new record. After a record is deleted, it is no longer accessible but still shows on-screen until a move is executed. If you do not force a move and try to access the deleted record, an error occurs.

Your data entry form should now look like the one shown in Figure 29.13.

FIG. 29.13
You can add new capabilities to the data entry screen by assigning program commands to command buttons.

Creating Forms Automatically

The bound controls make it easy for you to create data entry forms with a minimum of effort. You just draw the controls on your form, set a few properties, and you're done. What could be easier?

Well, actually you can create data entry forms in an even easier way--by using the Data Form Wizard (DFW). The DFW is one of the add-ins that comes with Visual Basic. Using this add-in, you can select a database and a record source; then it creates your data entry form automatically. Of course, the form might not be exactly like you want it, but you can easily change the default design and then save the changes. Using the DFW is a great way to create a series of data entry forms rapidly for a prototype or for a simple application.

Setting Up the Data Form Wizard

As you learned in the preceding section, the DFW is one of the add-ins that comes with Visual Basic. If, however, you look at the Add-Ins menu in Visual Basic, you don't see this option initially. You have to first tell Visual Basic that you want access to the form designer. You do so by choosing Add-Ins, Add-In Manager. The dialog box shown in Figure 29.14 then appears.

FIG. 29.14
By using the Add-In Manager, you can add capabilities to your Visual Basic design environment.

To access the DFW, click the box next to the text in the Add-In Manager. A check mark then appears in the box. Next, click the OK button and you're set. Now, when you select the Add-Ins menu, you see the DFW as one of the items. Selecting the DFW opens the first dialog box of the wizard, which you can see in Figure 29.15. This screen tells you a little about the DFW. You can choose not to have this form presented on subsequent uses of the DFW.

FIG. 29.15
The Data Form Designer automatically creates data entry forms for you.

Clicking the Next button on the initial form takes you to the second screen of the DFW. This screen, shown in Figure 29.16, enables you to choose the type of database that your form will be accessing. To choose a database type, simply click the type name in the list and then click the Next button to continue creating your form.

FIG. 29.16
You can choose to create a form from many common desktop databases.

Getting to the Source of Your Data

After you have chosen the type of database to use, you need to choose the actual database and record source with which you will be working. The screen shown in Figure 29.17 enables you either to enter the name of the database or to select the database from a dialog box. Clicking the Browse button on the dialog box presents you with a database dialog box that enables you to choose the database to open. After selecting the database, you are returned to the Database screen of the DFW. You might notice at this point that the file name of the selected database, including the full path, has been entered in the text box on the form.

FIG. 29.17
The Database screen allows you to specify the database and the types of record sources to use.

In addition to specifying the database name, you can also specify the types of record sources that will be displayed for selection in a later screen. You can choose to have tables, queries, or both displayed. You make your selection by clicking the appropriate check boxes. When you have finished, you need to click the Next button to proceed.

The next screen enables you to select the type of data entry form that you want the DFW to create. There are three types of data entry forms that can be created:

Choosing the type of form to create not only affects the appearance of the form but also determines what recordset(s) must be selected for the form. For a single record or grid form, you only need to select a single record source. For the Master/Detail form, you need to select two record sources. You really don't have to worry too much about this because the wizard guides you through it. That's what wizards are for, right?


CAUTION: If you are creating a Master/Detail form, you need to have established a relation between the tables you select. The relation information is what is used to keep the information synchronized.

Choosing Fields with the Data Form Wizard

After you have selected the database and the type of form, you need to select the table or query to use for the form and the actual fields that you want to have included on the form. This is done on the Record Source screen of the wizard, as shown in Figure 29.18.

FIG. 29.18
You choose the record source and fields using simple combo boxes and lists.

To set up the fields for the form, you need to follow these steps:

1. Select a record source from the combo box.

2. Select the fields to include by clicking the field names in the Available Fields list. You can double-click a field to select it or highlight the field and click the selection button (>).

3. Place the fields in the desired order by moving them in the Selected Fields list. You move a field by highlighting it and then clicking the up or down buttons. (This step is optional.)

4. Select the column on which to sort the recordset by choosing it from the Column to Sort By combo box. (This step is optional.)

5. Click the Next button to move to the next screen.

What Does This Button Do?

After selecting all of the fields that you want on the form, you have one final set of choices to make--the buttons that you want to appear on your form. You make this selection in the Control Selection screen of the DFW, shown in Figure 29.19.

Fig. 29.19
You can choose a number of command buttons to appear on your form.

Table 29.3 lists the buttons that you can elect to have appear on your data form.

Table 29.3 Command Button Controls and Their Functions

Available Controls Function
Add Adds a new record to the recordset and clears the data entry fields.
Delete Deletes the current record.
Refresh Causes the Data control to reexecute the query used to create it. This process is necessary only in a multi-user environment.
Update Stores any changes made to the data entry fields to the database for the current record.
Close Closes and unloads the data entry form.

You are now ready for the final step of the DFW--actually creating your form. In the last screen of the DFW, you specify the name of the form (the DFW gives you a default name) and then click the Finish button. This starts the creation process. At this point, you sit back and relax for a minute while the DFW does the work. When it is finished, your program has a new data form, and all you did was answer a few questions and make a few selections. Figures 29.20 through 29.22 show you the various types of data forms that can be created with the DFW.

FIG. 29.20
A Single Record data form created by the Data Form Wizard.

FIG. 29.21
A Grid data form created by the Data Form Wizard.

FIG. 29.22
A Master/Detail data form created by the Data Form Wizard.

Using Crystal Reports with Visual Basic 5

Although the Data control and bound controls do a great job of enabling you to create forms to enter and display data, they don't have any reporting capabilities. As a result, if you want to display and print reports, you need some additional capabilities. Visual Basic does have a Printer object with which you can send information to the printer. However, trying to set up a custom database report with the Printer object requires a lot of programming and a lot of trial and error.

Fortunately, you can accomplish database reporting in an easier way. Visual Basic comes with a reporting product--Crystal Reports. The Crystal Reports custom control that comes with Visual Basic allows you to access reports from within your Visual Basic program. The Crystal Reports control provides a link between the Crystal Reports engine and the reports you create with the report designer.

Crystal Reports Control

The first step in accessing Crystal Reports is to make the control available to your program. First, you need to add the Crystal Reports control to your Visual Basic Toolbox. To do so, choose Components from the Project menu of Visual Basic. The Components dialog box, shown in Figure 29.23, then appears. In this dialog box, you can specify which custom controls are available in your project.

FIG. 29.23
You must make the Crystal Reports control available to your project by selecting it in the Components dialog box.


TIP: You also can access the Components dialog box by right-clicking the Toolbox and choosing Components from the pop-up menu or by pressing Ctrl+T.


TROUBLESHOOTING: The Crystal Reports control does not show up in the Custom Controls dialog box. If you elected to perform a custom setup of Visual Basic, you might have left Crystal Reports out of the setup process. You need to rerun the Visual Basic setup program and add Crystal Reports.


Check Your Version of Crystal Reports!
If you have a version of Crystal Reports on your machine that is greater than version 4.6.1 (the version that comes standard with VB5), you will need to uninstall it first before you can install the version that comes with Visual Basic 5. After you have uninstalled your existing version of Crystal Reports, you can then install the version that comes with Visual Basic 5. If you want to use the newer version that you previously had, you can reinstall it at this time.

Certain releases of the newest Crystal Reports (version 5.108) DLLs and OCXs may not be completely replaced or overwritten when you install a older version of Crystal Reports. This can produce reports that work fine on the development machine but produce inconsistent results on the user's machine.


Setting Up the Control

After the Crystal Reports control is available in your Toolbox, you can use it in your program. To gain access to the control, simply select it from the Toolbox, and place it on the form from which you plan to access reports. Because the Crystal Reports control is not visible at runtime, it appears only as an icon on your form. After the control is on the form, you can set the properties that access the reports you create with the report designer.

Specifying the Report to Run The key property that you need to specify is the ReportFileName property. This property specifies the actual report that you will run from your program. You can easily set this property by clicking the ellipsis button that appears to the right of the property in the Properties window. The Crystal Reports Property page, shown in Figure 29.24, then appears. From this page, you can specify the name of the report and whether the report should go to the printer, a preview window, a file, or a message through the MAPI interface.

FIG. 29.24
Select the report name and destination from the Property page of Crystal Reports.

On the Property page, you can either type the name of the report into the field for the ReportFileName property or select the report from a file dialog box by clicking the ellipsis button on the Property page.

Selecting the ReportFileName is the minimum setup for Crystal Reports. At this point, you can write the line of code necessary to run the report and test it by running your program.

Setting Optional Properties Although only the ReportFileName is required for a report, you might want to use several optional properties with the report. The first of these properties is the SelectionFormula property. This property enables you to limit the number of records that are included in the report. The SelectionFormula property is similar to the Where clause of a SQL statement but uses its own particular format to enter the information. To specify the SelectionFormula, you must specify the name of the recordset and the field to be compared. You must express this recordset/field combination in dot notation and enclose it in curly brackets. After specifying the recordset and field, you must specify the comparison operator and the value to be compared. The final result is an expression like the following:

{MemberShipList.OrgCode}=1

You also can use multiple expressions by including the And or Or operators.


CAUTION: If you enter a SelectionFormula when you're designing your report, any formula you enter in the SelectionFormula property of the Crystal Reports control provides an additional filter on the records.

Another optional property is the CopiesToPrinter property. This property enables you to print multiple copies of your report easily at one time. You can set this property to any integer value.

Taking Action

After you add the Crystal Reports control to your form and set its properties, you are ready to start printing, right? Well, not quite. You still have to tell Crystal Reports when to print the report. To do so, you write a line of code to initiate the report. The line of code sets the Action property of the Crystal Reports control to 1. The report then prints using the report file and other properties that you set. If you have your report set up to preview on the screen, it looks like the one shown in Figure 29.25. The following is the code to run this report (rptMember is the name of the Crystal Reports control):

rptMember.action = 1

FIG. 29.25
Printing the desired report to the screen.

Setting Properties at Run Time

Because you will probably have a number of reports that you need to print, you need to be able to change the Crystal Reports control's properties at run time; otherwise, you would need a separate report control for each of your reports. All the major properties of the Crystal Reports control, such as ReportFileName and SelectionFormula, are available at run time. You set these properties, like any other properties, to new values using an assignment statement. The following code sets up the Crystal Reports control for a new report and specifies a selection criteria based on user input:

rptMember.ReportFileName = "CntyMbr.rpt"
rptMember.SelectionFormula = "{MemberShipList.OrgCode}=" & OrgID
rptMember.action = 1

The other property you might need to set at runtime is the DataFiles property. This property is not available at design time. The property specifies the name of the database file to be used with the report. Now you might be thinking, "I told the report what file to use when I created it." That is true, but when you created the report, the database file was stored with a path based on your directory structure, and your path might not be the same as the directory structure of your users.

The DataFiles property is actually an array with the first element number of 0. If you're using more than one database in your report, you need to set the value of each DataFiles array element. For most of your reports, however, you will be using only a single database. The following line of code shows you how to set the value of the DataFiles property for the database; this line assumes that the database file is in the same folder as your application:

rptMember.DataFiles(0) = App.Path & "\Members.mdb"

From Here...

In this chapter, you learned how to set up a database application quickly for an existing database. If you would like to learn more about related topics, check out the following:


Previous chapterNext chapterContents


Macmillan Computer Publishing USA

© Copyright, Macmillan Computer Publishing. All rights reserved.