In Chapter 8, "Programming Basics," you learned a little about writing code to make your computer programs accomplish various tasks. You saw how you can manipulate data and how control statements allow you to execute repetitive tasks and to selectively execute statements. However, there is more to creating a good, maintainable program than just writing code.
One of the things you need to be able to do is create reusable pieces of code and reusable program pieces so you are not constantly reinventing the wheel (or the program, in this case). Another important skill is the ability to manage those various pieces of code and forms effectively. This chapter deals with both of these aspects of project management. First, we discuss how you can use procedures to eliminate repetitive code in your programs. Then you learn how those procedures and other program components are added to your project. Finally, this chapter gives you a brief look at compiling and distributing your programs for others to use.
As you create more and larger programs, you will often find yourself using the same block of code over and over in several places throughout your program and in multiple programs. Surely there must be a better way to handle repetitive code than to just place it in multiple locations in your program. The solution is the use of functions and procedures. Functions and procedures are segments of code that perform a particular task and then return processing to the area of the code from which they were called. This means that a procedure can be called from multiple places in your code and, if set up properly, can be used with multiple programs.
You have already been exposed to working with procedures even if you didn't know it. Each time you entered code to be executed by a command button (or other control) in response to an event, you were building an event procedure. These procedures are called by the program when an event is triggered. As you might already know, you can also create your own procedures and call them when you need them. The procedures that you build are referred to as Sub procedures (or subroutines) to distinguish them from event procedures. Although the code in earlier examples was mostly in the event procedures, it is quite possible that a "real" program will contain more code in user-defined subprocedures.
The key idea behind working with procedures is to break your program down into a series of smaller tasks. Each of these tasks can then be encapsulated in a procedure, function, or possibly a class. (Classes are discussed in Chapter 2, "Introduction to the Development Environment.") There are several advantages to programming in this manner:
TIP: To make your code reusable, use comments often. This allows another programmer (or yourself after a long period of time) to quickly see the purpose of each procedure.
Creating the Procedure As with your program as a whole, creating a procedure starts with design. You need to determine the task to be performed and the inputs and outputs of the procedure. After this is done, you can start the actual coding of the procedure. There are two ways to start building a procedure in Visual Basic--starting from scratch or using the Add Procedure dialog box. Both methods are relatively easy, and the one you use is a matter of personal preference. Also, both methods require you to be in the Code window before you can build a procedure. To create a procedure from scratch, place your cursor in the Code window in a location that is not within a currently defined function or procedure. This would be after the End Sub statement of a procedure, before the Sub statement of another procedure, or at the top of the Code window. Figure 17.1 shows where you can start.
FIG. 17.1
Start a procedure in the Code window by using a Sub statement.
TIP: Placing your procedures in alphabetical order makes it easier to find them when you page through the Code window. However, they will always be in alphabetical order in the Code window's drop-down Procedure box.
You can create a new procedure in the Code window with the following steps:
When you press Enter, three things happen--a set of parentheses is added at the end of the Sub statement, an End Sub statement is placed in the Code window, and the current object in the Procedure drop-down list of the code editing window becomes your new procedure name. This is shown in Figure 17.2 for a procedure named FirstProc.
You are now ready to enter any commands that you want to run when the procedure is called.
FIG. 17.2
The End Sub statement is automatically added when you define a new procedure.
The full syntax of a Sub procedure includes the Sub statement, the End Sub statement, and the procedure commands:
[Public | Private] [Static] Sub procname([arguments]) statements_to_be_run End Sub
The Public, Private, and Static keywords in the Sub statement are optional parameters that affect the locations that the procedure might be called from. These keywords indicate the scope of the procedure in the same way that they indicated the scope of a variable.
See " Determining Where a Variable Can Be Used," Chapter 8
The other method of creating a procedure is to use the Add Procedure dialog box (see Figure 17.3). You access this dialog box by choosing Tools, Add Procedure.
FIG. 17.3
Although typing it in by hand is faster, you can also create a new procedure
in the current module or form by using the Add Procedure dialog box.
After you are in the dialog box, perform the following steps to create the shell of your procedure:
To create a procedure, you need to choose the Sub procedure type. This is the same as the procedures that are used in handling events in your code. A function type of procedure is one that returns a specific value. These procedures are covered later in this chapter. A property procedure is one used to set or retrieve the value of a property in a form or class module. An event procedure is one that is used to respond to an event in a form or class module.
After you have entered the necessary information, choose OK. Visual Basic then creates the framework of a procedure in the Code window.
Running the Procedure After a procedure has been developed, you need a way to run it from other parts of your program. There are two methods for running a procedure--use the Call statement or use just the procedure name. With either method, you simply specify the procedure name and any arguments that are required by the procedure. (The arguments are the ones specified in the Sub statement when you defined the procedure.) The syntax for running a procedure is as follows:
Call procname([arguments])
or
procname arguments
In either syntax, procname refers to the name of the procedure. This is the name that is specified in the Sub statement that defined the procedure. Arguments refers to the parameters passed to the procedure. In the calling statement, the arguments can be literal values, variables, or functions that return the proper data type. This is different from the Sub statement where all the arguments have to be variable names. All parameters must be separated by commas.
Let's look at a brief example of a procedure that uses parameters. Suppose your program needs to log all of its operations and errors to a text file. A procedure that handled writing messages to the log file, along with a date and time, could be very useful:
Sub LogPrint(stMessage As String) Dim inFileNum As Integer inFileNum = FreeFile Open "C:\EVENTLOG.TXT" for append as #inFileNum Print #inFileNum, Now & " - " & stMessage Close #inFileNum End Sub
The following line of code calls the procedure. When calling a procedure, you can supply values for its arguments using either a variable, a literal string, or a combination of the two:
LogPrint "Error Opening the file " & stUserFile
The LogPrint procedure is very simple, yet it saves a lot of time in the long run. It makes the calling code shorter and more readable. In addition, if you ever want to change the output of the log file from a text file to a database, printer, or pager, you only have to change the LogPrint function itself.
CAUTION: Typically, you must include the same umber of parameters in the calling statement as are present in the definition of the procedure. Also, the values supplied by the calling statement must match the data types expected by the procedure. Violating either of these conditions results in an error when you run your program.
At the start of this section, I listed two methods of calling a procedure. The following line of code calls the LogPrint procedure using the other syntax:
Call LogPrint ("The server was rebooted")
As you can see, the Call keyword can either be included or omitted in running the procedure. However, the Call keyword and parentheses go together. If you use the Call keyword, you must include the parameters in a set of parentheses. I recommend using the syntax that does not use Call. As you will see after looking at the examples in the next section, this makes it easier to distinguish between procedure calls and function calls.
Passing Data to the Procedure There are two ways to get information into a procedure for processing--you can define the variables as public variables that are available everywhere in your program, or you can pass the variables directly to the procedure in the calling statement. For example, you could add a second argument to the LogPrint procedure that allows it to work with multiple files:
Sub LogPrint(stLogFile As String, stMessage As String) Dim inFileNum As Integer inFileNum = FreeFile Open stLogFile for append as #inFileNum Print #inFileNum, Now & " - " & stMessage Close #inFileNum End Sub
However, this means that if you only wanted to use one log file, you still would have to pass the file name to the procedure each time you called it:
LogPrint "C:\LOGFILE.TXT", "Error Opening the file " & stUserFile
For this particular procedure, the stLogFile argument probably does not change much throughout the program. However, hard-coding it into the LogPrint procedure does not make much sense either, so a public variable would be the logical choice:
Public stLogFileName As String Sub LogPrint(stMessage As String) Dim inFileNum As Integer inFileNum = FreeFile Open stLogFileName for append as #inFileNum Print #inFileNum, Now & " - " & stMessage Close #inFileNum End Sub
Before calling the procedure, your program would need to set the value of stLogFileName. The Public keyword makes it visible to all the other procedures in your program. The variable inFileNum, on the other hand, can only be used within the LogPrint procedure, as it should be.
If you are going to use the variables in a number of procedures and the procedure is specific to the current program, it is better to set up the variables as public variables. However, for the sake of reusability among projects, it is a good idea to keep procedures as independent as possible. To do this, you should define all the necessary parameters to be passed to the procedure in the Sub statement and pass the parameters in the calling statement.
The parameters used by a procedure can provide two-way communication between the procedure and the calling program. The procedure can use information in the parameters to perform a calculation and then pass the results back to the calling program in another parameter.
For example, the following procedure gets the height and width of a rectangle from the parameters list and then calculates the area and perimeter of the rectangle. These values are returned through the parameters list:
Sub CalcRectangle(rcWidth as Integer, rcHeight as Integer, rcArea as Integer, rcPerimeter as Integer) rcArea = rcWidth * rcHeight rcPerimeter = 2 * (rcWidth + rcHeight) End Sub
The procedure can be called by either of the following code segments in Listing 17.1.
`******************************** `This code can call the procedure `******************************** sqWid = 5 sqHgt = 5 sqArea = 0 sqPerm = 0 Call CalcRectangle(sqWid, sqHgt, sqArea, sqPerm) `************************************* `This code can also call the procedure `************************************* newArea = 0 newPerm = 0 CalcRectangle 4, 10, newArea, newPerm
TIP: This example has a single output value, which makes it more suited to a function than a sub, but we discuss that shortly in the section entitled "Working with Functions."
Passing parameters to a procedure this way is known as passing by reference. In this case, the variable name passed to the procedure and the variable name used in the procedure both refer to (reference) the same location in memory. This is what enables the procedure to modify the value that is then passed back to the calling code. You can also pass a parameter to a procedure by value. This causes the procedure to use a copy of the information that was passed to it, which prevents the procedure code from modifying the value used by the calling program.
By default, when you declare a parameter for a procedure, passing by reference is used. To modify this behavior, you must explicitly tell Visual Basic to pass the parameter by value. Do this by placing the ByVal keyword in the parameter list before each variable that is to be passed by value. This is illustrated in the following lines of code:
Sub CalcRectangle(ByVal rcWidth As Integer, ByVal rcHeight As Integer, _ _rcArea, rcPerimeter As Integer)
CAUTION: If you are passing parameters by reference, you need to explicitly declare the variable in the calling program and in the procedure, and you need to be sure that the variable types are the same.
Exiting a Procedure Early As your programs, and therefore procedures, grow in complexity, there might be times when you don't need to execute all the commands in the procedure. If you need to exit the procedure before all the commands have been executed, you can use the Exit Sub statement. One way that we often use the Exit Sub statement is in the beginning of the procedure in a routine that checks parameters for proper values. If any of the parameters passed to procedure are the wrong type or have values that could cause a problem for the procedure, we use Exit Sub to terminate the procedure before the error occurs. This is a type of data validation. The following code modifies the previous area calculation code to perform this check:
Sub CalcRectangle(rcWidth as Integer, rcHeight as Integer, rcArea as Integer, rcPerimeter as Integer) If rcWidth <= 0 Or rcHeight <= 0 Then Exit Sub End If rcArea = rcWidth * rcHeight rcPerimeter = 2 * (rcWidth + rcHeight) End Sub
Functions are very similar to procedures, with one key difference--they return a value. This value can be assigned to a variable or used in expressions. Visual Basic has a variety of built-in functions that you can use, such as Abs which returns the absolute value of a number, or Left which returns a specified number of characters from the left end of a string. You can build your own functions, as well.
To build a function, you have the same two choices you had in building a procedure--start from scratch or use the Add Procedure dialog box. To start from scratch, select the point in the Code window where you want the function to start and then enter the keyword Function followed by the name of the function. The naming conventions for functions are the same as those for procedures. To use the Add Procedure dialog box, just select the Function Type on the dialog box. Either method will create the shell of the function just as it did for a procedure. This shell is shown in the following lines of code:
Public Function NumAverage() End Function
Although the first line is an acceptable function declaration, most of the time you will define the type of value that will be returned by the function. You define this function type like you define variable types in a Dim statement--by using the As keyword followed by the variable type. This function type declaration follows the parentheses that enclose the parameter declaration. In addition, you will typically declare the parameters that are passed to the function in the declaration statement. A more complete declaration statement is shown in the following line:
Public Function NumAverage(inpt1 As Single, inpt2 As Single) As Single
The other key difference between building a function and a procedure is that you will assign a value to the function somewhere within the code of the function. This value must be of the same type as specified in the function declaration. This is shown in the second line of the following code:
Public Function NumAverage(inpt1 As Single, inpt2 As Single) As Single umAverage = (inpt1 + inpt2) / 2 End Function
NOTE: Although your function code can assign a value to the function multiple times, only the last value assigned before the end (or exit) of the function is returned.
When you call a function, you typically assign its return value to a variable in your program, or use the value in a conditional statement as shown here:
`Assigning a function to a variable AvgNum = NumAverage(25, 15) `Using a function in a conditional expression If NumAverage(num1, num2) > 20 Then Msgbox "What an average!"
NOTE: If you need your function to simply perform a task (opening a database, for example), you can call the function the same way that you would call a procedure, throwing away the return value.
There are a number of functions built and demonstrated in the FUNCDEMO.VBP project, which you can download from www.quecorp.com/... is on the companion CD-ROM.
When you create a procedure (or function), you might want to limit where it can be used, and how resources are allocated to make its code available to other parts of your program. Where a procedure can be called from is referred to as the scope of the procedure.
Procedures can be defined in either of two ways: public procedures or private procedures. Which of these keywords you use in the Sub statement determines which other procedures or programs have access to your procedure.
NOTE: The scope of procedures and functions is related to the scope of variables, which is discussed in the section entitled "Determining Where a Variable Can Be Used" in Chapter 8, "Programming Basics."
See "Determining Where a Variable Can Be Used," Chapter 8
Going Public If you want to have your procedure or function available throughout your program, you need to use the Public keyword when you define the procedure. Using the Public keyword allows a procedure defined in one form or module to be called from another form or module. However, you have to be more careful with the names of public procedures because each public procedure must have a unique name. If you omit the keywords Public and Private from the Sub statement, the procedure is set up by default as a public procedure.
Keeping It Private Using the Private keyword in the Sub statement lets the procedure be accessed from only the form or module in which it is defined. There are, of course, advantages and disadvantages to this approach. The advantage is that you can have private procedures of the same name in separate modules. The disadvantage is that the procedure is not accessible from other modules. One thing you might have noticed in working with event procedures in other chapters is that they are, by default, private procedures. This is because, typically, controls are not accessed outside of the form on which they reside. This is an example of information hiding, or encapsulation, a technique used in object-oriented programming. If you are sharing a module with a team of developers, you could define the functions they call as public, while the internal procedures they don't need to know about remain private.
Preserving Variables Typically, when a procedure is executed, the variables it uses are created, used in the procedure, and then destroyed when the procedure is terminated. However, there might be times when you want to preserve the value of the variables for future calls to the procedure. You can handle this by using the Static keyword. This keyword can be applied to the declaration of the variables in the procedure or in the declaration of the procedure itself. When Static is used in a variable declaration, only the variables included in the Static statement are preserved. If you use the Static keyword in the procedure declaration, all the variables in the procedure are preserved. In the following example, inCurrentCount is a static variable:
Public Function AddItUp(inNew As Integer) As Integer Static inCurrentCount As Integer inCurrentCount = inCurrentCount + inNew AddItUp = inCurrentCount End Function
TIP: For efficiency's sake, it's important to place your procedures in the appropriate scope. Giving a procedure too broad of a scope (for example, making a procedure public when it only needs to be private) wastes valuable system resources. If you create a public procedure, Visual Basic must allocate appropriate resources to make it available to all parts of your program. Using the Static keyword to force a procedure to "remember" its local variables causes an extra allocation of resources as well. In general, you should make procedures private if possible, and avoid the use of static variables as well. This allows Visual Basic to manage memory more efficiently, since it is free to unload the various sections of code as needed.
You can create a procedure in either of two places--a form or a module. Where you place the procedure depends upon where you need to use it and what its purpose is. If the procedure is specific to a form or modifies the properties of the form or its associated controls, you should probably place the procedure in the form itself.
If, on the other hand, you are using the procedure with multiple forms in your program or have a generic procedure used by multiple programs, you should place it in a module. The storage location of your procedure is determined by where you create it. If you want, you can move a procedure from a form to a module or vice versa by using cut-and-paste editing.
Storing a Procedure in a Form File To create a procedure in a form file, you just need to choose the form from the Project window and then access the code for the form. This is done by either double-clicking the form itself (or any control) or choosing the View Code button in the project window (see Figure 17.4). After the Code window appears, you create a procedure as described in the earlier section "Creating a Procedure."
Using a Module File for Procedures A module file contains only code, no form elements or events. If you already have a module file in your project, you can create a new procedure by selecting the file, opening the Code window, and then using the previous steps to build the procedure.
TIP: Double-clicking the module name in the Project window automatically opens the Code window for the module.
FIG. 17.4
You can select a form for your procedure from the Project window.
If you don't have a module file in your project, or if you want to use a new module, you can create a module by selecting Project, Add Module. You can also create a new module by clicking the arrow on the Add Form button in the toolbar and then choosing Module from the drop-down menu. Either way, a new module is created and the Code window appears for you to begin editing. When you save your project or exit Visual Basic, you are asked for a file name for the module file.
NOTE: The toolbar button for adding new forms and modules is a drop-down button, which means clicking the arrow will give you a list of items. Once an item has been selected, the icon on the button changes.
Although some programs you write will be simple enough that you can use a single form, most will be made up of multiple forms. One reason for this is the limitation of the amount of space on a single form. Another more important reason is that you will want to use multiple forms in your program to logically separate program tasks. For example, if you have a task in your program that is not performed often, it makes more sense to put it on a separate form than try to squeeze it on a single form with everything else. Also, loading and unloading forms as you need them saves system resources. In other words, your program takes up as little space as possible while running.
When Visual Basic first starts a new project, typically it loads one blank form, as shown in Figure 17.5. As you design your program, you add controls to this form and write code to handle events that occur on the form.
At some point in your design, you will decide that you need one or more additional forms to handle a new task or provide space to relieve the crowding on the initial form. Adding a new form is simple. You can either click the Add Form button or select Project, Add Form. This places a new blank form on the screen. This form looks just like your first form initially did. If you did not rename your first form from the default of Form1, the new form is named Form2 (or Form3, Form4, and so on). Otherwise, the new form is named Form1.
FIG. 17.5
Visual Basic starts a new project with a single blank form.
TIP: You can add files, forms, or modules from a pop-up menu by right-clicking within the Project window.
After you have added a new form, you can place controls on it and write code for its events, just like for the initial form. You also need to be able to access the new form from other forms in your program. This is handled through the Load and Unload statements and the Show and Hide methods of the form object.
See "Displaying a Form," Chapter 4
As you write more code to handle more events and more tasks, you will often find that you need to access the same procedure from a number of different places on a form or from multiple forms. If this is the case, it makes sense to store the procedure in a module file.
TIP: If you have a library of common functions, such as printing routines, keep them in a separate module file so you can easily add the library to different projects.
A module file contains only Visual Basic code. It does not contain any controls, pictures, or other visual information. When the time comes to add a module file to hold your procedures, you can do this either by clicking the arrow on the Add Form button and choosing Module from the drop-down menu, or by choosing Project, Add Module. Either of these actions adds a new module to your project and places you in the Code window for the module (see Figure 17.6).
FIG. 17.6
You can open the Code window by double-clicking the module name in the Project
window.
When you first open a new module, Visual Basic gives it the default name of Module1 (or Module2 for a second module, and so on). Like your forms and controls, it is a good idea to give the module a unique name. The module has a Name property, just as a form does. To change the name of the module, simply change the value of the Name property in the Property window.
As you add forms and modules to your program, they are added to the Project window. This window allows you to easily access any of the pieces of your program (see Figure 17.7). You simply select a form or module by clicking its name in the Project window. For a form, you can then click the View Object button to work on the design of the form, or click the View Code button to edit the code associated with the form. For a module, only the View Code button is enabled because a module has no visual elements. Double-clicking the name of a form has the same effect as clicking the View Object button. Double-clicking a module name has the same effect as clicking the View Code button.
FIG. 17.7
The Project window gives you easy access to all your forms and modules.
Forms and modules are just two of the types of components that you can add to your project. In addition, you can also add custom controls and class modules. Some of these components, such as forms and modules, are editable code. Others, such as third-party controls and DLLs, are usually already compiled. While these types of items are part of your project, they do not show up in the Project window and are added by means of some special dialog boxes.
One of the things that you have to manage is your program's references. The references point to different library routines that enable your code to perform specific tasks. For example, if you will be accessing databases with your programs, you need to specify the Data Access Object library as one that is used by your code. Controlling references is quite easy in Visual Basic. The References dialog box lets you select the references required by your program by marking the check box to the side of the reference (see Figure 17.8). Mark the ones you need and unmark the ones you don't need. You access the References dialog box by selecting Project, References.
FIG. 17.8
The References dialog box lets you choose which libraries are used by your
program.
TIP: After adding a reference to your project, its public constants and functions can be viewed in the Object Browser, which is displayed by clicking the Object Browser button or by pressing F2.
In a manner similar to library references, you can add and remove custom controls from your project. When you loaded Visual Basic, a number of custom controls were loaded into the Toolbox window automatically. However, you will usually need controls designed to perform specific tasks that are beyond the capabilities of the standard controls. You manage the custom controls in your project by using the Components dialog box (see Figure 17.9). Select Project, Components to access this dialog box. As with the References dialog box, you choose the custom controls to add to your program by marking the check box next to the control name. After you exit the dialog box, your control toolbox is modified to display the new controls.
FIG. 17.9
The Components dialog box lets you add controls to your project.
As you develop more programs, you might find that you have standard procedures or forms that can be used in many of your projects. You also might have developed custom procedures for getting the names and passwords of users, for opening files, or for any number of other tasks that are used in almost every program.
You could rebuild the form or rewrite the procedure for each program, but that would be a very inefficient way to do your program development. A better way is to reuse modules and forms that have been previously developed and fully tested.
Getting these modules and forms into your current project is a simple process. By selecting Project, Add File, you bring up the Add File dialog box (see Figure 17.10). This dialog box lets you locate and select files to be added to your current project. Unfortunately, the Add File dialog box lets you add only a single file at a time. Therefore, if you have multiple files to add, you must repeat the operation several times.
CAUTION: If you add the same form or module to separate projects, remember that changing functions in the module will affect all projects that use it. If you are about to radically change a shared module, use the Save modulename As option in the File menu or copy the module to another subdirectory first.
FIG. 17.10
The Add File dialog box can be accessed from the menu system, standard toolbar,
by right-clicking in the Project window, or by pressing Ctrl+D.
NOTE: Files with the .FRM and .FRX extensions are form files. Files with the .BAS extension are module files.
You also might want to use one of Visual Basic's form templates in your project. These templates are predefined forms that are set up for a specific function, such as an About Box, a Splash Screen, a DataGrid form, or a Tip of the Day form. The advantage of using these templates is that the skeleton of the form is already created for you. You simply add your own graphics, label captions, and minimal code to customize the form to your needs. As an example, Figure 17.11 shows the About Box form template.
FIG. 17.11
Form templates make it easy to develop common pieces of a program.
To access one of the form templates, bring up the Add Form dialog box by clicking the Add Form button on the toolbar or selecting Project, Add Form (see Figure 17.12). You can then choose one of the form types from the New tab of the dialog box.
If you create a form that you think you will use in a number of programs, you can make a template out of it as well. Simply save the form in the form template folder of Visual Basic. Then the next time you want to add a new form, your template will appear in the Add Form dialog box as well.
FIG. 17.12
Form templates are "canned" templates that can be quickly customized
and used in your project.
NOTE: If you let Visual Basic install to the default directory, the forms templates are stored in the \Program Files\DevStudio\Vb\Template\Forms folder. This folder might be different on your machine, depending on where you installed Visual Basic.
To remove a module or form from your project, simply select the form or module in the Project window and choose Project, Remove filename. Visual Basic asks you to confirm that you want to remove the file and then removes it from your project.
When you first start a programming project, Visual Basic assumes that the first form created is the one that will be displayed as soon as the program starts. Although this will be the case for many programs, for others you will want to start with one of the forms you create later in the development process. For some programs, you might not want to start with a form at all.
If the first form is not the one you want to use to start your program, Visual Basic lets you choose which of your forms is shown initially by the program. This selection is made in the Projectname - Project Properties dialog box, as shown in Figure 17.13. You access this dialog box by selecting Project, Project Properties.
FIG. 17.13
The Startup Object list lets you choose which form is
loaded when your program starts.
You might have noticed that, in addition to listing all the forms contained in your project, the Startup Object list includes the entry Sub Main. This is a reserved procedure name that lets your program start without an initial form. If you choose this option, one of your module files must include a procedure called Main.
One reason to start your program with the Sub Main option might be that you need to perform some initialization routines before loading any forms. Another reason might be if you are developing a command-line utility that requires no user interaction.
When you complete your program, it is time to move it out of the VB development environment so others can use it. The first step is to compile the source code. The objective here is to create an .EXE file (or .DLL, depending upon the project type) that can be distributed to other machines. After compiling, you create installation files for the program by using the Application Setup Wizard. The purpose of the Setup Wizard is to package your program and all necessary support files, so it will run on a machine that does not have Visual Basic installed.
When you are ready to compile your program, all you have to do is select File, Make. This menu item lists the project name and the proper file extension for the type of program you are creating. For a Standard EXE or ActiveX EXE, the file extension is .EXE. For an ActiveX DLL, the file extension is .DLL, and for the ActiveX Control, the file extension is .OCX. After selecting the Make item, you are shown the Make Project dialog box, which allows you to specify the name and location of the executable file. Visual Basic then does the rest of the work.
While Visual Basic handles the actual compilation with no intervention, there are a few decisions you need to make in the Compile tab of the Projectname - Project Properties dialog box. The first choice to make is whether to compile to P-code or native code. P-code is the way Visual Basic programs have been compiled since version 1, while compiling to native code is a new option to Visual Basic 5.0. Native code is optimized for the processor chip and runs faster than P-code, but produces a significantly larger executable file. If you choose to compile to native code, you also need to make a decision about compiler optimization. You can choose to have the compiler try to create the smallest possible code, the fastest possible code, or not perform any optimization. You also have the option of compiling your program specifically for the Pentium Pro processor.
To choose the compiler options, you need to click the Compile tab of the Project Properties dialog box (see Figure 17.14). To squeeze every last bit of speed out of VB, you might want to also look at the Advanced Optimizations dialog box, also shown in Figure 17.14. As you can see, Microsoft put these options in here with a "use at your own risk" warning. However, I usually check Remove Array Bounds Checks, because the program code itself should do this, and Remove Safe Pentium FDIV Checks, which turns off software correction for the infamous Pentium chip bug. If you want to play it safe, the Advanced Options dialog box should probably be the last thing you do.
FIG. 17.14
In Visual Basic 5, there are several options for optimizing the compiled program.
Even though you might have just compiled your code into an executable file, that executable file cannot run on its own. Users of your program must have some Visual Basic runtime files (that is, DLLs) properly installed first. I would be lying if I said that each new release of Visual Basic has made it simpler to distribute your application to other PCs; on the contrary, just the opposite has occurred. In the days of Visual Basic 3.0, sometimes copying the 400K file VBRUN300.DLL and your EXE were the only steps required. Today, the equivalent Visual Basic 5.0 DLL file is over 1 megabyte in size. Additionally, the mere presence of a required DLL file is usually not enough; more often than not it must also be registered in the Windows Registry. On the bright side, the Application Setup Wizard included with Visual Basic 5.0 is much better than previous versions. The Application Setup Wizard is used to "package" your program with the required support files, so that it can be installed from a disk, directory, or the Internet--just like any off-the-shelf program. In this section, we focus on the setup steps for a Standard EXE project.
Using the Setup Wizard with a Standard EXE Project A shortcut to the Application Setup Wizard should have been installed with VB. If you run the Setup Wizard, after you get past the introductory message you see a screen like the one in Figure 17.15.
FIG. 17.15
The first step in the Application Setup Wizard is to choose a project and
select the type of installation.
The purpose of this screen is to tell the Setup Wizard which project you want to work with, as well as what kind of installation to create. As you might guess, the Internet Download option is for distribution over the Internet. For a Standard EXE project, you should choose the default Create a Setup Program option. If you check Rebuild the Project, the Setup Wizard attempts to launch VB and compiles your EXE before adding it to the installation. I usually do not do this, because it adds an extra step. Note that you can choose Generate a Dependency File either as part of the standard setup or by itself. A dependency file holds information about all the files required by your program, for the purpose of combining the installation of your project with another one. After you press Next, you are presented with the Distribution Method screen, shown in Figure 17.16.
The screen in Figure 17.16 lets you select how to group the installation files. Unless you are distributing your application on floppy disks (which is becoming less and less common these days), you will probably want to choose one of the directory options. Single Directory means all the setup files will be placed in a single subdirectory on your hard drive. Disk Directories divides the files into floppy-size subdirectories, should you ever need to manually copy them to disk. If you know your application will always be installed from a network server or CD-ROM, Single Directory is the best choice. Depending on your choice, the next screen (not pictured here) asks you to select an installation directory or floppy disk size.
FIG. 17.16
The Application Setup Wizard can create install files on disks, a single subdirectory,
or multiple subdirectories.
Now that you have told the Application Setup Wizard where to create the install files, it presents a series of screens as it determines what files are necessary. The first screen, ActiveX Server Components, is shown in Figure 17.17. (ActiveX server components are ActiveX DLLs or EXEs that your main project uses.) Although the setup wizard automatically scans your project's references for these items, you still have the option of adding and removing them here.
FIG. 17.17
The check box indicates an item (and its dependent files, if known) will be
included in the installation package.
When you move on from the screen in Figure 17.17, the Setup Wizard scans your project and displays the File Summary, as shown in Figure 17.18. The File Summary lists all the files that the Setup Wizard thinks your application needs. If you have additional files to distribute, such as .INI or .BMP files used by your program, you can add them with the Add... button. You can also find out more information about individual files (such as the destination directory) by pressing the File Details button.
Suppose you want to add another EXE, DLL, or OCX file to your project. One reason might be because you have separated your application into multiple projects; for example, you might have created an "Administration module" for managing login IDs. If you have not already run the Setup Wizard for the other project, you might see the warning shown in Figure 17.19. Do not panic, however, as this simply means that the dependency information for the new file is not available.
FIG. 17.18
The File Summary screen allows you to add or remove files from the installation.
FIG. 17.19
This warning message indicates that the Setup Wizard could not find a dependency
(.DEP) file for the selected item.
The reason for this message is to make sure your installation works. For example, if you decide to include additional EXEs, you also need the DLLs and OCXs required by those EXEs. You can either generate the dependency information with the Setup Wizard or skip this step if you know that no special files are required. After the File Summary screen, you are given the option to save your setup template so that you can create an install for this project without answering all these questions again.
Finally, now that the Setup Wizard has all the information it needs, your installation files will be copied to the location specified earlier. After this is complete, you should be able to test your install by running SETUP.EXE.
NOTE: The setup wizard compresses installation files to save space. Compressed files are indicated by an underscore (_) in the last character of the file name, as in MYPROGRAM.EX_. If you need to compress files manually, the utility COMPRESS.EXE is included with Visual Basic.
When creating a setup for a bunch of different users, test your installation thoroughly to make sure all the necessary components are included. Testing on your own PC is not sufficient, because you already have the required DLLs and OCXs.
TIP: A method of ensuring that your installation includes all the right parts is to try it on a test machine that contains nothing but the operating system. This can be a tricky situation, because each test of the install changes the test machine. I suggest getting software that allows you to restore a PC from an image file, so that you can test with a variety of software configurations.
A Closer Look at the Setup Process You've just seen what goes into creating a set of setup files. It is probably a safe bet to assume that most computer users are already familiar with the concept of installing, or setting up, an application. Who hasn't spent 30 minutes feeding their PCs floppy disks to install some new software? From the user's viewpoint, the setup program performs a very simple function. However, for troubleshooting purposes, the developer needs to realize that there is a lot more going on than just copying files to the destination PC. One of the files created by the setup wizard, SETUP.LST, is the controlling "script" for the entire setup process. You can view SETUP.LST in a text editor, as shown in Figure 17.20.
FIG. 17.20
A typical SETUP.LST created by the Setup Wizard.
Don't let the cryptic lines of text intimidate you; the structure of the file is actually fairly straightforward. It contains all the information necessary to control the entire installation. Let's take a brief step-by-step look at how SETUP.LST is used:
FIG. 17.21
Installations created by the Setup Wizard default to the Program Files directory.
NOTE: If you need to manually register a file, use the REGSVR32 utility included with Visual Basic. ActiveX EXEs can be registered with Windows by running them with the command line parameter /REGSERVER.
Customizing Setup ow that you are familiar with what the installation process actually does, you can modify it to meet your needs. Although tampering with an "official" SETUP.LST files is probably not a supported activity, I have had success with the customizations listed in Table 17.1.
Customization | How To |
Adding Files | Copy an existing Filexx= line and increment the number. Make sure to supply the copy and registration parameters mentioned in the last section, as well as the file date, size, and version number, all of which can be obtained from the Windows Explorer. |
Default directory | The suggested install directory is usually a subdirectory of the \Program Files directory on the user's PC. To specify a different default directory, change the DefaultDir line in the [Setup] section--for example, DefaultDir=C:\MYAPPDIR. |
Forcing a directory | If you want to take away a user's option to choose the destination directory, set the DefaultDir option as previously described above. Then add the line ForceUseDefDir=1 to the [Setup] section. |
Background description | By default, the message displayed on the screen will be the project name. You can modify the Title= line in the [Setup] section to make it a bit more descriptive, as in Title="On-Line Reporting System". |
The setup program itself | If you want to run a setup program other than SETUP1.EXE, you can still use Microsoft's SETUP.EXE to install the VB5 runtime DLLs. To do this, change the Setup line in the [Setup] section to point to your program--for example, Setup=MySetup.exe. You can also remove the [Files] section entirely if your setup program doesn't need it. |
Annoying messages | Although it is not the intended purpose, setting the 7th file parameter to $(Shared) removes two warning messages regarding replacing an existing file. The messages are contradictory, like Cancel Setup? followed by Continue Setup?, and probably would confuse some users. By marking the file as a Shared component, you are telling the setup program that the user does not need to be prompted before overwriting it. |
NOTE: Microsoft includes the source code for SETUP1.EXE with Visual Basic. If you want to make changes to it, open the project SETUP1.VBP in the \kitfiles\setup1 directory.
Even though you can customize SETUP.LST to a great extent, a standard Setup Wizard install still might not be suitable for your needs. For example, you might want to create your own "wrapper" program around SETUP.EXE. This program could be very useful in a corporate environment. For example, you could temporarily map a network drive to the install server, run SETUP.EXE, and then disconnect the drive after installation. If you e-mailed this program to the users, they would not have to worry about connecting to the right network drive. Another possibility would be storing each user's date of installation in a database. As with SETUP.EXE, you might have to write this program so it would run without the VB5 runtime files. Fortunately, Microsoft includes VBRUN300.DLL with Windows 95, so you don't have to resort to C.
CAUTION: When using the Setup Wizard, the version number of your program is very important. If you do not increment the version number in the Project Properties dialog box, SETUP assumes a previous user already has the correct version; therefore, it does not need to copy over it. After an install is complete, view the ST5UNST.LOG file to see which files the Setup Wizard actually copied.
This chapter has given you a look at how you manage the various parts of your programs. You've seen several techniques for making your programming more efficient. You've also been exposed to many of the assorted components that comprise a complete program. For more information on creating and using the various parts, see the following chapters:
© Copyright, Macmillan Computer Publishing. All rights reserved.