Copyright ©1996, Que Corporation. All rights reserved. No part of this book may be used or reproduced in any form or by any means, or stored in a database or retrieval system without prior written permission of the publisher except in the case of brief quotations embodied in critical articles and reviews. Making copies of any part of this book for any purpose other than your own personal use is a violation of United States copyright laws. For information, address Que Corporation, 201 West 103rd Street, Indianapolis, IN 46290 or at support@mcp .com.

Notice: This material is excerpted from Special Edition Using CGI, ISBN: 0-7897-0740-3. The electronic version of this material has not been through the final proof reading stage that the book goes through before being published in printed form. Some errors may exist here that are corrected before the book is published. This material is provided "as is" without any warranty of any kind.

CHAPTER 21- Tips and Techniques for Visual Basic

In this chapter, you learn about writing Visual Basic applications using the Common Gateway Interface for Windows (3.x, 95, NT) Web servers. The Windows CGI standard is quite different from the usual UNIX-type CGI, so you also look at how it works.

Visual Basic is a programming environment that's frequently used to implement applications for Windows CGI because it's relatively easy to learn and has many powerful built-in functions you can use to process forms and access databases.

In this chapter, you set up a simple Windows CGI application in Visual Basic step by step. After that, you move on to setting up forms and decoding the data returned by the user. You also examine database-access programming in Visual Basic and setting up a Web-searchable phone number database. Finally, you review server performance issues and alternative scripting languages.

In this chapter, you learn the following:

What You Should Already Know

For this chapter, I assume that you have some Visual Basic programming skills and that you know how to handle simple Visual Basic projects. If you haven't used Visual Basic before, you still might want to read this chapter and follow the examples presented and read a good book on Visual Basic programming as soon as you start to alter the projects for your own use. You're expected to have Visual Basic installed on your system. Later, I discuss the preferred version of Visual Basic you should use. The examples given here are focused on Visual Basic, but if you have some experience with programming environments such as Delphi, you may be able to port the examples to those environments.

For purposes of this chapter, I also assume that you have access to a properly configured Web server that supports the Windows CGI standard. The scripts discussed here have been tested with the Website Web server versions 1.0 and 1.1, but any other server that runs under Windows 95 or NT and supports Windows CGI will work.

You can download several try-before-you-buy versions of the Web servers. You can obtain the Website Web server, which runs under Windows 95 and Windows NT, from this site. You can even install a Web server on a PC that isn't connected to the Internet and use the loopback IP address to access it (http://127.0.0.1). Read the documentation that comes with your Web server on how to install it on your system.

The Windows Common Gateway Interface

Standard CGI was used by the pioneers of CGI to develop applications using UNIX shell scripts and the Perl language. Data is passed from the server to the CGI application, and vice versa, using environment variables. The disadvantage of using standard CGI for Web servers running under Windows is that Windows 3.x and Windows 95 can't efficiently pass environment variables to Windows CGI applications. Under Windows NT, in principle, it's possible to pass environment variables in the UNIX way. However, CGI programming with Visual Basic using environment variables is difficult because some of the functions that are used in UNIX-type CGI applications programmed in C are missing in Visual Basic.

The DOS CGI interface was the first attempt to make CGI applications run with Windows Web servers. Because Windows has no basic command interpreter, you need to rely on a DOS session to run CGI applications. The DOS CGI application is usually a batch (.BAT) file or a DOS executable. Data is passed to the CGI application using environment variables. The main disadvantage of using DOS CGI is, besides the limited capabilities of batch files, that Windows has to create a DOS virtual machine for every CGI request. This means you can run only a very limited number of CGI processes at the same time. What's more, this approach reportedly results in memory leaks that eat up your server's memory and require frequent reboots.

The Windows Common Gateway Interface (Windows CGI) was developed by Bob Denny, author the Windows Web servers WinHTTPD and Website, to overcome the limitations of DOS CGI. As mentioned previously, Windows has no native command interpreter (Windows NT is an exception). Therefore, the Windows CGI application needs to be a Windows executable. In a goal to minimize programming efforts and keep the interface simple, data from server to client, and vice versa, is passed via input and output files instead of environment variables.

The input file is in the same format as Windows initialization (.INI) files. You might have noticed that Windows applications share a common file format to store setup parameters (like the four most recently accessed files) in an .INI file. The .INI files share the same format because Windows contains services that allow programmers to read and write these files quickly and easily. These services are part of the application programming interface (API) and are usually referred to as API calls. Using the .INI file format was a brilliant idea because most Windows CGI applications are written in Visual Basic. Although it's a powerful programming environment, Visual Basic contains limited and particularly slow file read and write capabilities. The API calls allow you to read these files quickly and reliably from within Visual Basic.

How Does Windows CGI Work?

Before moving on to some CGI programming examples in Visual Basic, let me briefly discuss the mechanisms behind Windows CGI. Suppose that you're selling pizzas using the Internet. You want people to log on to your Web server and order a pizza using their Web browsers. You present users a form like the one shown in figure 21.1. A user fills in all details and submits the form.

Fig. 21.1

You can easily order a pizza online.

The user's Web browser contacts your server and submits the data that was filled in the fields and the path of the CGI application that handles the request. Figure 21.2 shows what happens when the user submits the data.

Fig. 21.2

During a Windows CGI request, the server launches an application that processes an input file and sends results to an output file. The output file is subsequently sent back by the server.

After all data is sent by the user's Web browser, the server launches the CGI application. This is done using the following command-line syntax:

cgi-application cgi-data-file content-file output-file url-args

Here's a breakdown of the syntax:

So what happens after the server launches the CGI application? The CGI application initializes and reads the data from the input file. Depending on the input, the application generates an output file.

Suppose that all fields have been filled in properly by the user and that the order can be acknowledged. The CGI application then writes order accepted to the output file and exits. The Web server notices that the CGI application has ended, reads the output file, and sends the data from the output file back to the user.

Format of the CGI Input and Output Files

As discussed earlier, the first thing a CGI application needs to do after it's launched is read the input file written by the Web server. Listing 21.1 shows a typical input file.

Listing 21.1 Contents of a Typical Input File
 [CGI]
Request Protocol=HTTP/1.0
Request Method=GET
Executable Path=/cgi-win/order.exe
Server Software=WebSite/1.0
Server Name=server.domain.com
Server Port=80
Server Admin=user@mailserver.com
CGI Version=CGI/1.2 (Win)
Remote Address=123.123.123.123
Authentication Method=Basic
Authentication Realm=Web Server

[System]
GMT Offset=3600
Debug Mode=No
Output File=c:\temp\59ws.out

[Accept]
image/gif=Yes
image/x-xbitmap=Yes
image/jpeg=Yes
image/pjpeg=Yes
*/*=Yes

[Extra Headers]
Connection=Keep-Alive
User-Agent=Mozilla/2.0b3 (Win95; I)
Pragma=no-cache
Host=123.123.123.123

If you focus on the [CGI] section, a couple of things may attract your attention: one of them is Request Method. The user requests this method to be performed by the server (GET in this case).

See  "Request-Specific Environment Variables,"  for more information on request methods. 

As you can see, the input file contains more interesting information. In the [Extra Headers] section, you can detect the type of Web browser of the user. The User-Agent item tells you that a Netscape 2.0 browser running under Windows 95 is used (Mozilla is the name that the Netscape developers use for their browser). The user's Internet IP address is shown after the Host item (it's 123.123.123.123 in this case). You can use all this data in your CGI application.

Listing 21.2 shows another input file.

Listing 21.2 Input File for a User's POST Request
 [CGI]
Request Protocol=HTTP/1.0
Request Method=POST
Executable Path=/cgi-win/order.exe
Server Software=WebSite/1.0

Server Name=server.domain.com
Server Port=80
Server Admin=user@mailserver.com
CGI Version=CGI/1.2 (Win)
Remote Address=123.123.123.123
Authentication Method=Basic
Authentication Realm=Web Server
Content Type=application/x-www-form-urlencoded
Content Length=115

[System]
GMT Offset=3600
Debug Mode=No
Output File=c:\temp\5ews.out
Content File=c:\temp\5ews.inp

[Form Literal]
size=large
extra=cheese
name=Danny Brands
address=123 Main St.
phone=1-234-567

[Accept]
image/gif=Yes
image/x-xbitmap=Yes
image/jpeg=Yes
image/pjpeg=Yes
*/*=Yes

[Extra Headers]
Connection=Keep-Alive
User-Agent=Mozilla/2.0b3 (Win95; I)
Host=127.0.0.1

The input file now mentions Request Method=POST. In this case, a user submits data, as shown in the [Form Literal] section. As you can see, he has ordered a pizza. The address, phone number, what kind of pizza-the information is all there.

Processing Input and Output Files and Common VB CGI Libraries

As mentioned previously, the input file is in the .INI file format. If you know a little bit about Visual Basic programming, you may know that getting the information out of this file is quite complicated and would probably be unacceptably slow. Fortunately, Windows contains very powerful API calls that let you read data from these files quickly and easily. The GetPrivateProfileString API call is used for this purpose.

Even more fortunately, Bob Denny, inventor of Windows CGI, has released a standard Basic framework that does all file input and output for you using these API calls. It's distributed with the Website Web server. You can obtain cgi.bas file from the Internet at this site. You just need to add this file to your Visual Basic project and use the routines stored in it.

I mention the API call for two reasons. First, it's platform-dependent. When you want to recompile a CGI script that works fine under 16-bit Visual Basic using the 32-bit version, you might need to change it to the 32-bit equivalent. Second, you might want to read something from the input file that wasn't implemented in the cgi32.bas framework. In this case, you need to use the API function by yourself. Look at the cgi32.bas file to see how it's done.

For other programming environments, such as Borland Delphi and Microsoft Visual C++ (MSVC++), common Windows CGI libraries are available from the Internet, too. A framework for MSVC++ is distributed with the Website version 1.1 Web server (installed in the \cgi-src\cppsample directory). You can download a free trial version of Website from the Internet at this site. Information about Delphi Windows CGI framework components can be found at: this site and this site.

Creating a CGI Application Using VB

In this section, you create your first CGI application, which allows you to request a user's e-mail address and return a form, showing that the address has been successfully submitted. Later, you add more fields and see how to decode them.

You start by setting up the project in Visual Basic. I'm assuming that you're using Visual Basic 4, the 32-bit version. See the later section "Obtaining the Latest Version of Visual Basic" for more information.

Previous versions of Visual Basic require another version of the CGI framework (cgi.bas, which is distributed with the WinHTTPD Web server; available from the Internet at this site). The 16-bit version of Visual Basic 4 should work fine with cgi32.bas, but I advise you to use the 32-bit version. (See the later section "Server Performance" for a discussion on this subject.)

Run Visual Basic, and create a new project by opening the File menu and choosing New. Remove all forms (if any) by opening the File menu and choosing Remove. Next, remove all modules in a similar way (if any). Then open the Tools menu and choose Custom Controls to open the Custom Controls dialog box. Make sure that you deselect everything on the list, so you can decrease the number of modules your project needs to load and significantly increase your CGI application's performance. Then close the Custom Controls dialog box.

Next, open the File menu and choose Add File; then add the file cgi32.bas to your project. It's the basic CGI framework and should be in your Web server's CGI-SRC directory or your current directory. The code supplied here is tested with version 1.7 of cgi32.bas but should work with older and newer versions as well.

Be careful with the cgi32.bas file because you use it in all projects. In principle, you never need to edit this file.

Now add a Basic file in which you can place your own code. Open the Insert menu and choose Module to add a Basic file to the project. Visual Basic names it Module1 for you.

You should never add a form to a CGI application; it relies on input and output files and never needs to open a window during execution. A form will slow down execution of your application.

Now you're ready to create the procedure that starts execution after the CGI executable is launched by the server. This procedure is called CGI_Main. When you're reviewing an existing CGI application, you should always start looking in this procedure. Open the code window of Module1. Make sure that you're in the general-declarations section of Module1; then create the CGI_Main procedure by typing the following:

Sub CGI_Main

Visual Basic then creates the procedure for you. In the same way, create an Inter_Main procedure in the general-declarations section of Module1 by typing this line:

Sub Inter_Main

The Inter_Main routine is used only when the script isn't executed by a Web server, and you don't use this routine in this project. However, cgi32.bas contains a call to the Inter_Main subroutine, and you can't compile the project without it.

Generating a Form by Using Your Visual Basic Application

Now you can add functionality to your CGI project. First, determine what method the users request when they launch the script. You can access the request method using the CGI_RequestMethod variable. This method, as discussed earlier, is either GET or POST. You need to decide what to do on receipt of each of these requests.

The GET method is used when the CGI script is accessed for the first time. In this case, you send users a form to request that they type in an e-mail address. Make sure that you're in the general-CGI_Main procedure of Module1. Then add the code shown in bold in listing 21.3 (everything between the Sub CGI_Main() and End Sub lines).

Listing 21.3 The CGI_Main Procedure of email.bas
Sub CGI_Main()

If CGI_RequestMethod = "GET" Then
        SendReQuest
        Exit Sub
End If

End Sub

This code results in the SendReQuest procedure being called when the user requests the GET method. In this procedure, you generate an HTML document.

Next, add the SendReQuest procedure. In the general-declarations section of Module1, enter all the code shown in listing 21.4. (Visual Basic creates the SendReQuest procedure for you after you type the Sub SendRequest line.)

Listing 21.4 The SendReQuest Procedure of email.bas
Sub SendReQuest()

Send ("Content-type: text/html")
Send ("")
Send ("<HTML><HEAD><TITLE>")
Send ("Please fill in your e-mail address.")
Send ("</TITLE></HEAD>")
Send ("<BODY>")
Send ("<FORM METHOD=""POST"" ACTION=""/cgi-win\email.exe"">")
Send ("")
Send ("Please fill in your E-mail address and press submit.")
Send ("<INPUT SIZE=30 NAME=""EMailAddress"">")
Send ("<INPUT TYPE=""submit"" VALUE=""Submit"">.")
Send ("")
Send ("</FORM>")
Send ("</BODY></HTML>")

 End Sub

Next, the contents of the SendRequest procedure will be discussed. You may have noticed that you use the Send() routine to write data to the output file; this routine is defined in the cgi32.bas framework. The SendRequest procedure begins with the following line:

Send ("Content-type: text/html")

The users' Web browsers need to know what kind of data is being sent. In this case, you send HTML, but you could also send a GIF picture, a sound file, a binary executable, and so on, as long as you indicate this with the correct content-type. If you forget to include a content-type HTML statement, an error is generated.

Starting an HTML page with a title is a good custom. The title is shown on the title bar of the users' Web browsers after the HTML document is loaded. The title is added with the following code:

Send ("<HTML><HEAD><TITLE>")
Send ("Please fill in your e-mail address.")
Send ("</TITLE></HEAD>")

To set up a form in HTML that can be submitted to a server, you need to specify the FORM METHOD, which tells the users' Web browsers what method to request. In this case, the users' Web browsers perform a POST request. What's more, you see what action will be performed. The users contact the server and request it to execute the email.exe file (your CGI executable). You could specify the full URL to your server, too, but you would have to change the script when you move it to another server. The way the URL is specified now, the user's browser will fill in the rest of the URL. In this case, the following is used:

Send ("<FORM METHOD=""POST"" ACTION=""/cgi-win\email.exe"">")

Note
This line contains two double quotation marks. In Visual Basic, quotation marks have a special meaning. If you specify two double quotation marks, Visual Basic ignores the first and regards the second as a plain text quotation mark. For instance, METHOD=""POST"" results in METHOD="POST" being sent to the users.

Next, you create an input field in which the users can fill in their e-mail addresses:

Send ("<INPUT SIZE=30 NAME=""EMailAddress"">")

The input field is 30 characters wide and is described by the identifier EMailAddress. You can add several other options, which are discussed later. For now, you can be satisfied with this simple field. The only thing you need to add is a Submit button:

Send ("<INPUT TYPE=""submit"" VALUE=""Submit"">.")

Notice that this button is another input type. The caption put on the button is determined by the VALUE variable; in this case, the caption is "Submit".

Ending the HTML form with the proper syntax is a good custom:

Send ("</FORM>")
Send ("</BODY></HTML>")

Now you can save your project and prepare the CGI executable. Save the project by opening the File menu and choosing Save Project. Save Module1 (the module you added to the project) as email.bas and the project as email.vbp. You can save these files in a separate directory or in your server's CGI-SRC directory.

Next, compile the .EXE file by opening the File menu and choosing Make Exe. Name the executable email.exe and place it in your server's CGI-WIN directory or any other directory that's enabled for Windows CGI. This directory is usually set during the install procedure of your server but can be changed afterward (consult your server's manual).

Now, you can access the CGI executable using your Web browser. Point your Web browser to the following URL:

Replace your.servers.address with the Internet address of your Web server; if you run your Web browser and server on the same machine, you can use the loopback IP number: 127.0.0.1. (If your machine isn't connected to the Net, you do need to use the loopback IP number.) Make sure that you use a backslash (\) in the path name; many problems arise from using a forward slash (/) instead. If everything goes well, you end up with a form as shown in figure 21.3.

Fig. 21.3

After running the email.exe application with a web browser, the results should look like this.

I pointed my Web browser to the CGI script but nothing happens. What's going wrong?
Don't panic yet. First, make sure that your Web server is running and that you've supplied the correct URL for your server. If you run the server and the Web browser on the same PC, you can use the loopback IP number (127.0.0.1) as the IP address. That you can access normal HTML files on the server is a good indication that you have the right IP address and that your server is properly running.
Then convince yourself that you've placed the email.exe file in a directory that's enabled for Windows CGI applications. You can't run CGI applications from standard HTML directories on the server (such as \htdocs). Files in HTML directories are read by the server; CGI applications are executed, which is why a special directory needs to be configured for Windows CGI files. Generally, this directory is called \cgi-win.
I have the impression that the application runs okay, but the server complains about Empty output from CGI program.
You can't place a Windows CGI executable in a Standard CGI directory. The server uses a different method for launching these types of CGI applications. Whether a directory is enabled for Windows or Standard CGI is set in your server's setup, so you should consult your server's manual on this matter.
With most Web servers, precompiled CGI executables are distributed. If you can run these files, chances are high that something is wrong within your Windows CGI executable.
If you can run other CGI executables, you should check whether the version of your cgi32.bas file is recent. These scripts have been tested with version 1.7, but should in principle work with older and newer versions. Anyway, trying a newer version can't hurt. Recent versions of cgi32.bas are distributed with the Website Web server, and you can obtain them from the Internet at this site. Most problems with Visual Basic CGI scripts arise from the fact that people use the outdated cgi.bas instead of the newer cgi32.bas file in the 32-bit Visual Basic 4 environment. cgi.bas uses calls to the 16-bit Windows API, so you can't compile applications that use cgi.bas in the 32-bit VB 4 environment. You should remove the cgi.bas file and replace it with a recent version of the cgi32.bas file.
If your Web server has been set up properly but the problem lies within your Visual Basic CGI application, you'll probably receive an error message after accessing the application with your Web browser. You can then try to solve the problem using this information.
Sometimes, errors occurring within your Visual Basic program are difficult to trace. Because the CGI application is called by the server, running your application from within the Visual Basic design environment isn't particularly useful. You can add the following line to the start of the CGI_Main procedure:
MsgBox("Hello World!")
When you compile the CGI application and execute it, a small box with the message Hello World! will appear on the server PC. The application halts on this line until you click OK. You can move the MsgBox line through your application until the error is generated before the box pops up. With a little experience, you can easily track down the line that generates the error.

Decoding Forms and Generating a Response

After the users receive the form shown in figure 21.3, they can fill in their e-mail addresses and click the Submit button. However, you haven't yet written code to handle the POST request that will be generated after the users submit the form.

Now you can get back to the Visual Basic design environment and add code for the POST request method. In the email.bas module, change the CGI_Main procedure as shown in boldface in listing 21.5.

Listing 21.5 The Revised CGI_Main Procedure of email.bas
Sub CGI_Main()

If CGI_RequestMethod = "GET" Then
        SendReQuest
        Exit Sub
Else
        SendResponse
        Exit Sub
End If

End Sub

The SendResponse procedure handles the POST requests. Next, enter the SendResponse procedure as shown in listing 21.6.

Listing 21.6 The SendResponse Procedure of email.bas
Sub SendResponse()

     Dim Email as String

Email = GetSmallField("EMailAddress")

Send ("Content-type: text/html")
Send ("")
Send ("<HTML><HEAD><TITLE> Thanks!")
Send ("</TITLE></HEAD>")
Send ("Thank you for submitting your e-mail address!")
Send ("<br>")
Send ("We have registered: " + Email)
Send ("</FORM>")
Send ("</HTML>")

End Sub

The following line is meaningful because it shows how you can read fields from the form that has been submitted by the users by using the GetSmallField() function, which is part of the cgi32.bas framework:

Email = GetSmallField("EMailAddress")

The GetSmallField() function is called with the name of the field as an argument. You might have noticed that EMailAddress is the name of the input field that you specified in the SendRequest subroutine:

Send ("<INPUT SIZE=30 NAME=""EMailAddress"">")

The variable Email is sent back to the users afterward using the following code (note that you've previously declared the Email variable by using a Dim statement):

Send ("We have registered: " + Email)

Save and compile your project and run the CGI application by pointing your Web browser to the correct URL as you've done before. Then type something in the e-mail field and click Submit. If everything goes well, you see a response like the one shown in figure 21.4. Unlike what the result shows, you have, of course, not registered anything at this point.

Fig. 21.4

Filling in an e-mail address and clicking the submit button results in this screen.

Setting Up Advanced Forms

In this section, you continue with some more advanced forms. You use your existing e-mail project and edit the SendRequest procedure. In addition to the e-mail addresses, you need to query users for their names, gender, locations, and what actions they want to have taken (to be added to your mailing list, to be sent more information, to be called). You see how to set up prefilled fields, select boxes, radio buttons, check boxes, and hidden fields.

You start by editing the SendReQuest procedure in email.bas. Edit the procedure so that it looks like listing 21.7. Alternatively, you can load the file email.vbp project from the CD and follow changes made starting from the existing e-mail application.

Listing 21.7 email.vbp: The Revised SendRequest Procedure of email.bas
Sub SendReQuest()

    Send ("Content-type: text/html")
    Send ("")
    Send ("<HTML><HEAD><TITLE>")
    Send ("Please fill in your E-Mail address.")
    Send ("</TITLE></HEAD>")
    Send ("<BODY>")
    Send ("<FORM METHOD=""POST"" ACTION=""/cgi-win\email.exe"">")
    Send ("")
    Send ("Please fill in your E-mail address.")
    Send ("<INPUT SIZE=30 NAME=""EMailAddress"">")

    Send ("<p>")
    Send ("Please type your name here:")
    Send ("<INPUT SIZE=30 NAME=""Name"" VALUE=""Your name here"">")

    Send ("<p>")
    Send ("Are you:<br>")
    Send ("<INPUT TYPE=""radio"" " + _
          "NAME=""Male_or_Female"" VALUE=""Male"">")
    Send ("Male<br>")
    Send ("<INPUT TYPE=""radio"" " + _
          "NAME=""Male_or_Female"" VALUE=""Female"">")
    Send ("Female?<p>")

    Send ("<p>")
    Send ("Where do you live?")
    Send ("<SELECT NAME=""Continent"">")
    Send ("<OPTION SELECTED>North America")
    Send ("<OPTION>Europe")
    Send ("<OPTION>Other")
    Send ("</SELECT> ")

    Send ("<p>")
    Send ("Please check one or more of the following:<br>")
    Send ("<INPUT TYPE=""checkbox"" NAME=""Action"" " + _
          " VALUE=""add you to our mailinglist"">")
    Send ("Please add me to your mailinglist.<br>")
    Send ("<INPUT TYPE=""checkbox"" NAME=""Action"" " + _
          " VALUE=""send you more information"">")
    Send ("Send me more information.<br>")
    Send ("<INPUT TYPE=""checkbox"" NAME=""Action"" " + _
          " VALUE=""call you"">")
    Send ("Call me.<p>")

    Send ("<INPUT TYPE=""Hidden"" NAME=""Time"" VALUE=""" + _
          Time$ + """>")

    Send ("<INPUT TYPE=""submit"" VALUE=""Submit"">.")
    Send ("")
    Send ("</FORM>")
    Send ("</BODY></HTML>")

End Sub

The first thing you added here is a prefilled field:

Send ("Please type your name here:")
Send ("<INPUT SIZE=30 NAME=""Name"" VALUE=""Your name here"">")

The VALUE keyword places text in the input field that can be useful to suggest what users should fill in there.

After that, you set up some radio buttons using INPUT TYPE="radio". Radio buttons are used to let users choose one out of several options. If you want to group a couple of buttons, you should use the same NAME for all of them. If you want to set up two separate groups of radio buttons, you need to use a different NAME for the members of each group. The variable, specified by the identifier NAME (Male_or_Female, in this case), contains the VALUE of the radio button checked by the users. The following code results in male and female radio buttons:

Send ("Are you:<br>")
Send ("<INPUT TYPE=""radio"" NAME=""Male_or_Female"" " + _
      " VALUE=""Male or"">")
Send ("Male<br>")
Send ("<INPUT TYPE=""radio"" NAME="" Male_or_Female"" " + _
      "VALUE=""Female"">")
Send ("Female?<p>")

If the users don't check any of the buttons, the NAME identifier will be absent, and trying to decode it using the GetSmallField() function generates an error. You learn more about this situation when you decode these fields later in the section "Advanced Forms Decoding."

Another way of letting users pick one out of several options is by using a select box. This method is particularly useful when you have several options to choose from and you want your form to stay readable and compact. You can set up a select box for selecting where the user lives, as follows:

Send ("<p>")
Send ("Where do you live?")
Send ("<SELECT NAME=""Continent"">")
Send ("<OPTION SELECTED>North America")
Send ("<OPTION>Europe")
Send ("<OPTION>Other")
Send ("</SELECT> ")

The select box is identified by NAME="continent" and is filled with options using the OPTION keyword. Only three options are used here, but you can virtually use as many options as you like. When you're finished filling the select box, you use the /SELECT keyword. (Note that one option uses the SELECTED keyword. This option is the default; it shows up as preselected.)

Sometimes, you want the users to choose more than one of the available options. In this situation, use check boxes to let users choose from several actions-being added to a mailing list, being sent more information, and being called:

Send ("Please check one or more of the following:<br>")
Send ("<INPUT TYPE=""checkbox"" NAME=""Action"" " + _
      " VALUE=""add you to our mailinglist"">")
Send ("Please add me to your mailinglist.<br>")
Send ("<INPUT TYPE=""checkbox"" NAME=""Action"" " + _
      " VALUE=""send you more information"">")
Send ("Send me more information.<br>")
Send ("<INPUT TYPE=""checkbox"" NAME=""Action"" VALUE=""call you"">")
Send ("Call me.<p>")

The check boxes all have the same identifier, "Action". This variable contains the VALUE that has been specified for a box checked by the users. Because the users can check more than one box, the identifier is enumerated. Therefore, if the users check all boxes, you see the identifiers Action, Action_1, and Action_2, which all have to be decoded separately by your CGI application.

Sometimes, you might want to add something to a form that users can't see-for example, an account number, the number of pizzas ordered, and so on. You can add this information by using hidden fields that aren't shown to the users but can be decoded when they submit their forms. Just to illustrate how hidden fields work, add the current time. You might use this information to store the time the form was requested by a user:

Send ("<INPUT TYPE=""Hidden"" NAME=""Time"" VALUE=""" + Time$ + """>")

For now, save your project, compile the executable, and run it by using your Web browser. If everything goes well, you get a form like the one shown in figure 21.5. Note that the name field is prefilled with the value you specified, the select box shows the option you preselected, and the time field isn't shown.

Fig. 21.5

After you run the email.exe application, the resulting page should look something like this.

Advanced Forms Decoding

Decoding radio buttons, select boxes, and especially check boxes needs special attention. If you request to decode a non-existing field by using the GetSmallField() function, an unknown field error is generated, and a response like the one in figure 21.6 is shown.

Fig. 21.6

This figure shows a typical result of an error generated by a CGI script.

A radio button field can also be non-existing when it hasn't been clicked. You see how you can trap these errors using the VB On Error statement later.

Start by editing the SendResponse procedure as shown in bold in listing 21.8. Alternatively, you can load the email.vbp project from the CD and follow the code.

Listing 21.8 email.vbp: The Updated SendResponse Procedure of email.bas
Sub SendResponse()

Dim Email As String
Dim Name As String
Dim Male_or_Female As String
Dim Continent As String
Dim Action As String
Dim Your_Time As String
Dim n

Email = GetSmallField("EMailAddress")

Name = GetSmallField("Name")

On Error Resume Next

Male_or_Female = GetSmallField("Male_or_Female")

On Error GoTo 0

Continent = GetSmallField("Continent")


On Error GoTo Done_Decoding
    Do
        If n = 0 Then
            Action = "We will: " & GetSmallField("Action")
        Else
            Action = Action & " and " & GetSmallField("Action_" & n)
        End If
        n = n + 1
    Loop
Done_Decoding:
    Resume Done_Decoding1
Done_Decoding1:
    On Error GoTo 0

Your_Time = GetSmallField("Time")

Send ("Content-type: text/html")
Send ("")
Send ("<HTML><HEAD><TITLE> Thanks!")
Send ("</TITLE></HEAD>")
Send ("Thank you for submitting your E-Mail address! <br>")
Send ("<pre>")
Send ("We have registered: " + Email + "<br>")
Send ("         Your Name: " + Name + "<br>")
Send ("           You are: " + Male_or_Female + "<br>")
Send ("       You live in: " + Continent + "<br>")
Send ("              Time: " + Your_Time + "<br>")
Send (Action + "." + "<br>")
Send ("</pre>")
Send ("</FORM>")
Send ("</HTML>")

End Sub

The first thing that may attract your attention is the way you decode the radio buttons:

On Error Resume Next

Male_or_Female = GetSmallField("Male_or_Female")

On Error GoTo 0

You previously learned that the radio button field is non-existing when not touched by the users and that the GetSmallField function generates an error on a non-existing field. Therefore, you need to use error trapping. The On Error statement traps the error and performs a task specified behind the statement. So if the following line generates an error,

Male_or_Female = GetSmallField("Male_or_Female")

the program discards this line and continues with the execution of the next line as specified in the On Error statement. The variable Male_or_Female then stays empty. The following line resets the error handler:

On Error GoTo 0

The cgi32.bas framework also contains error-handling routines, so resetting the error handler to its defaults is a good idea.

The select box is decoded quite easily, similar to the normal input fields:

Continent = GetSmallField("Continent")

The check boxes are also decoded in a special way. Depending on the number of checked boxes, more or fewer Action fields are enumerated (Action, Action_1, Action_2, and so on). You can't predict how many fields there will be; the number of fields depends on the number of checked boxes. Because you've seen that decoding a non-existing field generates an error, you need to use error trapping here, too. You can construct a Do Loop in which you sequentially read Action, Action_1, Action_2, and so on until the GetSmallField() function generates an error (on a non-existing field). You then trap the error in the Done_Decoding routine. This then does a Resume call to the Done_Decoding1 routine, which restores the error handler:

On Error GoTo Done_Decoding
    Do
        If n = 0 Then
            Action = "We will: " & GetSmallField("Action")
        Else
            Action = Action & " and " & GetSmallField("Action_" & n)
        End If
        n = n + 1
    Loop
Done_Decoding:
    Resume Done_Decoding1
Done_Decoding1:
    On Error GoTo 0

This approach may seem impractical at first sight; however, it works well, and there's no other simple way to do it as reliably as this. Notice that you're constructing a phrase inside the Do Loop that contains the actions the users requested.

The hidden field is read by using a normal GetSmallField() call:

Your_Time = GetSmallField("Time")

All data that has been decoded is then sent back to the user, as follows:

Send ("Thank you for submitting your E-Mail address! <br>")
Send ("<pre>")
Send ("We have registered: " + Email + "<br>")
Send ("         Your Name: " + Name + "<br>")
Send ("           You are: " + Male_or_Female+ "<br>")
Send ("       You live in: " + Continent + "<br>")
Send ("              Time: " + Your_Time + "<br>")
Send (Action + "." + "<br>")
Send ("</pre>")

You use the <pre> HTML tag to align the output properly.

Now that you've finished editing the SendResponse procedure, save your project, compile it, and run it. Submitting a form of the e-mail project results in a response like the one shown in figure 21.7.

Fig. 21.7

After the user fills in some fields of the form generated by the email.exe application and clicking the Submit button, this is how a response might look.

Data Access CGI Programming

One main advantage of using Visual Basic for writing Windows CGI applications is that it has powerful data-access capabilities. Visual Basic can access almost any database. It can access Btrieve, dBASE, Microsoft Excel, and Microsoft Access databases directly and many other database formats by using an ODBC (Open Database Connectivity) driver. So if an ODBC driver is available for your database, you can access it by using Visual Basic. You can even access databases over a network, such as SQL server and other high-performance (UNIX) databases.

You would want to set up a Web-searchable database for many reasons. Suppose that you have a large database you want to make accessible for all people in your company. Because the employees probably work with several different computer platforms (such as PC, Mac, and UNIX), you need to have client applications developed for every platform that they use. Even if you succeed in getting an application for every platform, you may spend tens of thousands of dollars on obtaining software licenses, hiring programmers, and so on. Why not write a CGI script that accesses your database? Free Web browsers are available for every computer platform. A Web server shouldn't cost very much, nor should the PC it runs on either. If the information in the database is confidential, you can restrict access to your database from the outside world by using IP filtering or a user name/password combination. This is discussed later in the section "Visual Basic Security Considerations."

Setting Up a Web-Searchable Phone Number Database

In this section, you set up a Web-searchable database in Visual Basic by using the Windows CGI interface. This application allows you to search and display the contents of a phone number database. If you own a company, you might want to set up such a database to allow customers to find phone numbers (and e-mail addresses) of your employees. To keep things compact and understandable for this example, I have set up the application without using fancy HTML. However, after you understand the idea behind it, you can always enhance the look of it yourself.

This application uses features that aren't supported by the standard edition of Visual Basic, so you need the professional or enterprise edition of Visual Basic 4. Alternatively, you can use the professional edition of VB3.

The Database

First, you need a database. It should contain a few records with names, phone numbers, and e-mail addresses to illustrate how data access works with Visual Basic. In principle, you can use one of the database flavors mentioned earlier or a database for which you have an ODBC driver. In this example, I used an Access 2.0 database, but I discuss where you should alter the code for use with other databases.

You can obtain the database needed for this example in two ways:

Fig. 21.8

After you've successfully created a database using Access 2.0, the results should look something like this.

Now that you have your database, you can start writing the data-access application. The first part of it is similar to the e-mail application you created previously.

Open Visual Basic. Then open the File menu and choose New to start a new project. If you have any forms, remove them by opening the File menu and choosing Remove File. Do the same for modules (if any). Then open the Tools menu and choose References. In the References dialog box, deselect the MS DAO 3.0 Object Library item, select the MS DAO 2.5 Object Library item, and close the dialog box. This is to ensure that VB uses the proper database engine.

Add the cgi32.bas framework to your project by opening the File menu and choosing Add File. The cgi32.bas should be in your Web server's cgi-src directory.

Next, add the module that contains the data-access code. Open the Insert menu and choose Module to add the module. Visual Basic names it Module1. As with the e-mail application, add an Inter_Main procedure by typing the following in the general-declarations section of Module1:

Sub Inter_Main

Then, in the general-declarations section of Module1, add the code shown in listing 21.9.


Listing 21.9 phone.vbp: The CGI_Main Procedure of phone.bas
Sub CGI_Main()

    If CGI_RequestMethod = "GET" Then
        SendReQuest
        Exit Sub
    Else
        SendResults
        Exit Sub
    End If

End Sub

When the users access the CGI script for the first time using a GET request method, the SendReQuest procedure is executed. This procedure generates a form. When the users submit a query using the POST request method, the SendResults procedure is called; it contains the actual data access code.

Next, add the SendReQuest procedure to Module1 as shown in listing 21.10.

Listing 21.10 phone.vbp: The SendRequest Procedure of phone.bas
Sub SendReQuest()

    Send ("Content-type: text/html")
    Send ("")
    Send ("<HTML><HEAD><TITLE>" & "Phone number database" & _
          "</TITLE></HEAD>")
    Send ("<BODY>")
    Send ("<FORM METHOD=""POST"" ACTION=""/cgi-win\phone.exe"">")
    Send ("Fill in (a part of) a name and press Search")
    Send ("<br>")
    Send ("<br>")
    Send ("<INPUT SIZE=30 NAME=""query"">")
    Send ("<br>")
    Send ("<br>")
    Send ("<INPUT TYPE=""submit""")
    Send ("VALUE=""Search"">")
    Send ("")
    Send ("</FORM>")
    Send ("<HR>")
    Send ("</BODY></HTML>")

End Sub

The SendReQuest procedure generates a form with a 30-character wide input field named query. Because this example is essentially the same as the e-mail example, you can quickly move on to the actual search procedure called SendResults. Enter the code shown in listing 21.11.

Listing 21.11 phone.vbp: The SendResults Procedure of phone.bas
Sub SendResults
    Dim Db As Database
    Dim tmpDyna As Dynaset
    Dim query As String
    Dim SQLQuery As String

    query = GetSmallField("query")

    Send ("Content-type: text/html")
    Send ("")
    Send ("<HTML><HEAD><TITLE>" & "Phone number database" &
          "</TITLE></HEAD>")
    Send ("<BODY>")
    Send ("You searched for: " & query & "<br>")

    Set Db = OpenDatabase("cgi-win\phone.mdb", False, True)

    SQLQuery = "SELECT * FROM MY_Table WHERE Name like " & "'*" & _
               query & "*'"

    Set tmpDyna = Db.CreateDynaset(SQLQuery)

    If tmpDyna.RecordCount = 0 Then
         Send ("Your search produced no results.<br><br>")
    Else
        Send ("Results<br><br>")
        Do While Not tmpDyna.EOF
            Send ("<PRE>")
            Send ("          Name : " & tmpDyna("Name"))
            Send ("  Phone number : " & tmpDyna("Phone_Number"))
            Send (" Email address : " & tmpDyna("Email_Address"))
            Send ("</pre>")
            Send ("<br>")
            tmpDyna.MoveNext
        Loop
    End If

    Send ("</BODY></HTML>")

End Sub

Now you have all you need to search a database in Visual Basic and send back the results to the users. Simple, isn't it? Because you might want to set up your own Web-searchable database, I explain all code used here. If you understand how this code works, you can adapt it for use with your own database.

The SendResults routine starts with decoding the query field:

query = GetSmallField("query")

Then it includes some lines of HTML to generate a response form:

Send ("Content-type: text/html")
Send ("")
Send ("<HTML><HEAD><TITLE>" & "Phone number database" & _
      "</TITLE></HEAD>")
Send ("<BODY>")

For your users' convenience, you repeat the query that has been submitted:

Send ("You searched for: " & query & "<br>")

Next, you open the database by using the Visual Basic OpenDatabase() function. It has the following syntax:

Set db = OpenDatabase(dbname[, exclusive[, read-only[, source]]])

Here's a breakdown of the parameters:

For this example, the following line is used to open the database:

Set Db = OpenDatabase("cgi-win\phone.mdb", False, True)

Db has been previously declared using a Dim statement:

Dim Db As Database

Because you situate the database phone.mdb in the server's cgi-win directory, you use the following path to it: "cgi-win\phone.mdb". If you experience problems, you should change it to the full path, which may look like the following:

"c:\website\cgi-win\phone.mdb"

The full path, of course, depends on your setup. You don't have to place the database in your server's cgi-win directory. It works as long as you supply the correct path. You can also use a database file from another PC on your network. You should specify it as follows:

"\\server\directory\database.mdb"

Notice in the example that the database is opened in non-exclusive and read-only modes. By using these modes, you allow other applications to open the database and multiple users to use your Web-searchable database concurrently. Because you're only searching and not altering the database, opening the database in read-only mode is safe. The source string is omitted in this case because the database needs no additional information to be opened. As you learned previously, you probably need to specify this string only when you're using an ODBC driver.

After you open the database, you need to search for the terms that the users have submitted. You can do so in a couple of ways in Visual Basic, but here you use an SQL query.

See  " Generating SQL Code to Transfer Submitted Data,"  for more information on SQL. 

In this case, the following SQL query is used:

SELECT * FROM MY_Table WHERE Name like '*query*'

This query tells the VB database engine to select every record in table My_Table for which the Name field contains the string query.

The * (asterisk) wild card before and after the query string make the database engine search for substring matches. This means that the query selects all records that contain the query string, not just the ones that exactly match it. So if you search for '*fred*', not only does the database engine select records matching Fred, but it also selects Alfred and Frederique. Similarly, you can also use ? and # as single-character and single-digit (0-9) wild cards, respectively. By default, SQL queries in VB are case-insensitive. However, some ODBC drivers are case-sensitive.

SQL in Visual Basic varies slightly from ANSI (standard) SQL. If you're using an ODBC driver or direct ODBC.DLL API calls, you might need to use the ANSI equivalent of the wild cards mentioned here:
***indent following minitable within note***
Visual Basic SQL	ANSI SQL Equivalent
?	_ (underscore)
*	%

The single quotation mark (') has a special meaning in Visual Basic. You use it to add comments within your Visual Basic source code. Because you need the quotation mark for the SQL query, you precede it with a double quotation mark. You can see how that's done as you store the SQL query in the string SQLQuery (the query variable contains the name submitted by the user):

SQLQuery = "SELECT * FROM MY_Table WHERE Name like " & "'*" & _
           query & "*'"

If you want to use your own database, you can make changes to MY_Table and Name to let the database engine search the correct table and field names.

Next, the SQL query is executed by using the CreateDynaset method:

Set tmpDyna = Db.CreateDynaset(SQLQuery)

The tmpDyna object variable was earlier declared as Dynaset:

Dim tmpDyna As Dynaset

A Dynaset is a dynamic part of the database that matches the criteria of the SQL query. You first check whether the search returns anything by using the RecordCount method. If the Dynaset contains no matching records, you send a short message that the search failed:

If tmpDyna.RecordCount = 0 Then
         Send ("Your search produced no results.<br><br>")

If the Dynaset isn't empty, you read the Dynaset record by record by using the MoveNext method within a Do Loop. The Do Loop is aborted as soon as the end of the Dynaset is reached. This is done by reading the EOF property of the Dynaset, which is True after the last record is read:

Do While Not tmpDyna.EOF
    Send ("<PRE>")
    Send ("          Name : " & tmpDyna("Name"))
    Send ("  Phone number : " & tmpDyna("Phone_Number"))
    Send (" Email address : " & tmpDyna("Email_Address"))
    Send ("</pre>")
    Send ("<br>")
    tmpDyna.MoveNext
Loop

In each cycle of the Do Loop, all three fields (Name, Phone_Number, and Email_Address) for the current record are read by calling the Dynaset tmpDyna with the name of the field as an argument. (If you use another database, you should, of course, change Name, Phone_Number, and Email_Address to the correct field names.)

You're now finished with the phone Web-searchable database. To save your project, open the File menu and choose Save Project. Name your project phone.vbp and name Module1 phone.bas. Then open the File menu and choose Make EXE File to compile your project. Name your project phone.exe and place it in your server's cgi-win directory. (You can also find the project file phone.vbp and the BASIC file phone.bas on the CD-ROM that comes with this book.)

Run phone.exe by pointing your Web browser to the following URL:

Replace your.servers.address with the Internet address of your server; or if you run your Web browser on the same machine the Web server resides on, you can use the loopback IP number 127.0.0.1. (If your machine isn't connected to the Internet, you do need to use the loopback IP number.)

Your completed Web-searchable phone number database should look something like figure 21.9 on your Web browser.

Fig. 21.9

The phone.exe CGI application generates a form like this.

Now type something in the field and click Search. The results of a search for the letter a are shown in figure 21.10. All names that contain an a are listed. You also can type a name such as Paul or Carl, but this example better illustrates how the application searches for substrings.

Fig. 21.10

After you search for 'a' with the phone.exe application, the results should look something like this.

I received the error message Couldn't find file 'cgi-win\phone.mdb'. (error #3024). What's going on?
This message tells you that the path specified in the line containing the OpenDatabase statement in procedure SendResults of phone.bas is incorrect. You should change cgi-win\phone.mdb to the full path of your database.
When I try to compile the phone.vbp project, a User defined type not defined error is generated. During execution of the script, an Error Loading DLL message is generated. What's happening?
The references to the Visual Basic data object libraries are incorrect. Open the File menu and choose References. From the References dialog box, deselect MS DAO 3.0 Object Library and select MS DAO 2.5 Object Library. Depending on the type of database, you might need to select the Microsoft 2.5/3.0 Compatibility library item.
I've specified the correct path to the database, but the application still refuses to run. What more could be wrong?
If you've specified the correct path to the database and your database application still refuses to access the database, you should make sure that the Visual Basic runtime libraries for data access have been properly installed on the server PC. Even if you know what files are needed, it's not enough to just copy them to your server's hard disk.
You can, of course, install another copy of VB on the server, but there's an easier way. You can use VB's Setup Wizard to prepare installation floppies with all the libraries you need. If you select phone.vbp as the project, the Setup Wizard includes all data-access libraries, and the setup.exe file that's generated installs these libraries when executed on the server PC.
If you're using an ODBC driver, make sure that you've configured it as prescribed in the documentation that's supplied with the driver.
By default, Visual Basic 3 can't use the Access 2.0 database supplied on the CD-ROM because it supports only the Access 1.0 and 1.1 database formats. However, after the release of Access 2.0, Microsoft released a compatibility layer that allows Visual Basic 3 to use Access 2.0 databases. If you have access to the Internet, you can download the compatibility layer from Microsoft's Web site at this site. You can also contact your local Microsoft dealer.

Security Concerns and Restricting Access to Your CGI Scripts

In addition to the risks related to exposing (part) of your network to the outside world (that is, by setting up a Web server), running CGI scripts on your server requires special attention. How vulnerable your setup is depends largely on your application.

Sending Confidential Information over a Public Network

Sending confidential information over a public network is always risky. You don't want to have customers submit their credit-card numbers unprotected over the Internet. Computer hackers can easily get hold of this information. Fortunately, S-HTTP (Secure HTTP) and SSL (Secure Sockets Layer) standards have been developed, so you can securely transport data over a public network. Many Web browsers and UNIX Web servers already support these transactions. The professional edition of Website version 1.1 also supports secure transactions.

See  "Introduction to SSL,"  and "Introduction to S-HTTP,"  for more information on SSL and S-HTTP. 

Restricting Access to Your CGI Program

In some cases, you may want to restrict access to your CGI application. If your database contains confidential information, you can restrict access in several ways.

One effective way to restrict access is to place your CGI executable in a protected directory on your server. See your Web server's manual for information on setting up restricted directories. Restricting access to a directory can be done on the basis of two criteria: IP number or a user/password combination.

Restricting access on the basis of IP number-that is, allowing ranges of IP numbers or certain IP numbers access (also called IP filtering)-is particularly useful when you want to allow a large group of people access to your CGI application. Because users can't forget or lose their IP number (it's determined by their Internet connection), this method can be pretty secure. Users like this kind of access restriction because they never even notice that it's there (unless they're disallowed access, of course). The disadvantage of IP filtering is that, when users are connected through dial-up accounts, their IP numbers could be dynamically assigned. In other words, IP numbers may change slightly each time the users dial into their service providers.

You can also use the IP number within your CGI application. The CGI_RemoteAddr variable contains the IP address of the user. You can use this variable to enable parts of your CGI application for some users and disable it for others. You might want to allow employees from within your company to change their phone numbers in the corporate database and restrict outside users to searching it.

Restricting access by using a user/password combination is another way of preventing unwanted use of your application. When users access a restricted directory, the Web browser presents a dialog box asking for their user/password combination. When the users submit their user/password combination, their browsers store this information and submit it with every new request to a file in the same (protected) directory. Therefore, users have to type their user/password only once. Remember that the logon/password is sent over the network in a way that's relatively easy to intercept, unless you're using some kind of secure connection (S-HTTP, SSL).

You also can use the logon name and password in your CGI application. The CGI_AuthUser and CGI_AuthPass variables contain, respectively, the logon name and the password that have been submitted by the users. As with the IP number, you can allow and disallow certain functionality of your CGI application for certain users. Note that the CGI_AuthUser and CGI_AuthPass variables contain something only when your CGI application is in a protected directory. Furthermore, most Windows-based Web servers pass these variables to the CGI application only when the name of the CGI application starts with a dollar sign ($).

Other Security Considerations

You should take care of a number of things when setting up a Web server with CGI functionality. First, CGI applications belong in a special CGI directory. This directory is specified in your server's setup. Windows CGI executables should be in a directory that's enabled for the Windows CGI standard. When you place your CGI executable in a directory meant for HTML, users can download it, reverse-engineer it, and do all kinds of nasty things. If your CGI executable is in a properly configured CGI directory, users can only execute it, not download it.

Several Web browsers can upload files, and the capability to handle these files is being implemented in many Web servers. File handling is usually done on the server side using a CGI application. Uploading files, however, exposes your server to some security hazards. First of all, users can upload some really huge files, filling a partition on your hard disk. More serious is the possibility that hackers can upload a CGI application to your server and subsequently execute it by accessing it with their Web browsers. CGI applications that accept uploaded files should therefore preferentially be in a protected directory and uploaded files should be placed in a separate upload directory that's invisible from the outside world.

Obtaining the Latest Version of Visual Basic

Visual Basic 4 was released a couple of months after Windows 95 in 1995. It's the first version of Visual Basic that lets you develop true 32-bit applications that can use the new features of the Windows 95 and Windows NT (Win32) operating systems. Besides that, the professional and enterprise editions of Visual Basic 4 also compile 16-bit Windows applications that can run under the Win16 (Windows 3.x) environment.

Visual Basic 4 comes in three versions: standard, professional, and enterprise. The standard version contains the basic functionality of the Visual Basic development environment. You are, however, strongly advised to buy the professional edition. It contains additional database functionality that's frequently used in CGI projects. You must decide whether you want to spend the extra money for the enterprise edition, which is meant for managing large projects with multiple programmers.

The sample applications discussed in this chapter have been tested with the professional edition of Visual Basic 4. The phone database doesn't run with the standard version of Visual Basic 4.

Server Performance Issues

You're encouraged to use the 32-bit version of Visual Basic 4; the examples presented in this chapter are meant for that version. The main advantage of the Win32 over the Win16 environment is that Win32 applications pre-emptively multitask. Pre-emptive multitasking means that the operating system (Windows) assigns processor time to all processes. Win16 applications cooperatively multitask, which means that when you run a Win16 task, all other tasks stop functioning until the task ends or returns control to the system. As a result, your Web server becomes unresponsive during execution of your CGI application.

What's more, only one CGI request can run at the same time. This is annoying when your CGI application performs database lookups that, depending on the complexity of the query, can take some time. You can sometimes bypass these limitations by using the VB DoEvents statement in your program; this statement returns control to the system. Especially in data-access applications, however, you can't always use it. The 32-bit version of Visual Basic solves this problem by being pre-emptively multitasking. This means that all other processes keep running, allowing your server to serve other requests at the same time and run more CGI requests concurrently, thus serving more users at once.

Visual Basic 4 has become a large development environment that requires considerable processor power and a substantial amount of RAM. Many developers report a drop in performance when they move from VB 3 to version 4 on systems with limited RAM. When you're setting up a Web site, make sure that your server has at least 16M of RAM and a Pentium processor. When you're running Windows NT or expecting many CGI requests, you need at least 32M but preferably 64M of RAM. Reports indicate that CGI applications show an impressive performance increase after you upgrade RAM from 32M to 64M, especially on Windows NT systems.


Improving CGI Performance by Preloading Runtime DLLs
An important issue is preloading DLLs. Visual Basic is an interpreted language, which means that it needs runtime libraries during execution, generally called dynamic link libraries, or DLLs. These libraries are modules that Windows needs to load into memory before a VB application can be executed, and this can take up to several seconds. Your CGI application runs faster when these DLLs are loaded into memory beforehand, since this saves you the time of loading them during the CGI request.
Many Web servers can preload DLLs at server startup and keep them in memory for as long as the server runs. The Website Web server can do so when you use the -l command-line option. For example, httpd32.exe -l vb40032.dll starts the Web server and preloads the Visual Basic runtime library. For other Web servers, check the manual for information on this subject.
In addition to vb40032.dll (the main runtime library of Visual Basic), you might want to load other DLLs-for instance, if your application uses database access. However, what files you need to preload depends on the type of database you use.


Alternatives to Server-Based CGI: Microsoft's VBScript and JavaScript

In an attempt to minimize server load and maximize the capabilities of the Web browser, developers are working on client-side scripting languages. These scripts are basically programs within the HTML document and are interpreted by the browser. This approach results in very little load on the Web server because the scripts run on the user's PC. A document containing a script isn't static like standard HTML. Imagine a script that places a live clock in your Web browser or a script that alerts you if you improperly fill in a form (even before you send it to the server).

At the time of this writing, at least two scripting languages are being developed: Microsoft's Visual Basic Script (VBScript) and JavaScript.

See  "JavaScript," p. xx, and "Visual Basic Script," p. xx, for more information on these programming languages. 

Microsoft's VBScript will be a subset of Visual Basic that's optimized for Web browsers. The Visual Basic code can be embedded within the HTML document. A small runtime library will be called by the browser when it receives a Visual Basic script. The runtime library can be licensed for free.

Imagine that you're selling CDs on the Internet, and you want your forms to add up the total costs while the user is gathering acquisitions. You'll be able to add a script like the following to your form:

<Script>

   Sub CheckBoxLouReed.Click

      TotalAmount.Text = Cstr(Val(TotalAmount.Text) + 19.99)

   End Sub

</Script>

Note that this is just an illustrative example. Even the HTML <Script> tags still have to be negotiated with the World Wide Web standards committees. The main advantage of Visual Basic Script is that it's as intuitive and easy to learn as Visual Basic. If you've done some Visual Basic programming before, you'll probably be programming Visual Basic Script in no time.

JavaScript is another scripting language that's being implemented in the Netscape browser. Unlike the Java language, which is compiled at the server side, JavaScript is interpreted at the client side. Because it's object-oriented, JavaScript has more of a C++-type of approach and requires somewhat more advanced programming skills. Implementations of JavaScript for Web servers will also be available as alternatives for CGI.

One ongoing discussion is how safe these scripting languages are. Could someone write a computer virus in a scripting language and erase your hard disk? The JavaScript developers have dealt with this issue beforehand by disallowing write access to your hard disk. However, I have heard reports of a JavaScript that collected and submitted the user's e-mail addresses to a server as a quick and dirty way of doing market research.

Some other restrictions related to these scripting languages are in place. Suppose that you don't want to share the source code of your script with rest of the world. This is impossible with VBScript and JavaScript, because the source is sent to the user when he accesses your server; it's imbedded in the HTML document and interpreted by the user's Web browser.

In the case of a script that accesses a database, you'll need to send the database along with the script, which is, of course, undesirable. These scripting languages will certainly be useful for some applications; for other applications, you'll still need to rely on CGI.

Copyright notice: The Visual Basic projects in this chapter use the cgi32.bas Visual Basic CGI framework by Robert Denny, which is Copyright[cw] 1995, O'Reilly & Associates, Inc., All Rights Reserved, and is reproduced with permission of O'Reilly & Associates.

QUE Home Page

For technical support for our books and software contact support@mcp.com

Copyright ©1996, Que Corporation