Working with Sub Procedures

function OpenWin(url, w, h) { if(!w) w = 400; if(!h) h = 300; window.open(url, "_new", "width=" + w + ",height=" + h + ",menubar=no,toobar=no,scrollbars=yes", true); } function Print() { window.focus(); if(window.print) { window.print(); window.setTimeout('window.close();',5000); } }
Team-Fly    

Special Edition Using Microsoft® Visual Basic® .NET
By Brian Siler, Jeff Spotts
Table of Contents
Chapter 8.  Managing Program Tasks with Procedures


The key idea behind working with any type of procedure is to break down your program 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 9, "Creating Code Components.") Programming in this manner presents several advantages:

  • You can test each task individually. The smaller amount of code in a procedure makes debugging easier and makes working on the same project with other developers easier.

  • You can eliminate redundant code by calling a procedure each time a task needs to be performed instead of repeating the program code.

  • You can create a library of procedures that can be used in more than one program, saving yourself development time in new projects.

  • Program maintenance is easier for a couple of reasons. First, because code is not repeated, any edits to a block of code must be performed only once. In addition, separating key components (for example, the user interface and the database functions) allows you to make major changes in one part of the program without recoding the whole thing.

Tip

To make your code reusable, use comments often. This extra detail allows another programmer (or yourself after a long period of time) to quickly see the purpose of each procedure and how it accomplishes its task.


Note

The techniques discussed in the following sections, while specifically targeted toward sub procedures, can be applied to function procedures as well.


Procedure Location

Procedures are created by typing the procedure code into the Code editor. Most often your procedure will be a method contained within a class, such as a Windows form class. In this case, you would enter the procedure within the form's class declaration (analogous to its Code window). You can display the form's class declaration by right-clicking the form in the Solution Explorer and choosing View Code. Procedures can also be declared within other types of classes, or in a module. A module is simply a file that contains Visual Basic code, but which is not associated with a particular form. If you want to add a module to your project, choose Add Module from Visual Basic .NET's Project menu, give the module an appropriate filename in the Add New Item dialog box, then click Open.

Note

The location of a procedure's code within your project is different from its accessibility, which will be discussed later.


Creating a Sub Procedure

As with your program as a whole, the process of creating a procedure starts with design. You need to determine the task to be performed, what information will be needed by the procedure, and what information will be returned by the procedure. After you complete this task, you can start the actual coding of the procedure. To start building a procedure in Visual Basic .NET, you simply begin typing the procedure in a code window.

Note

Whether you create your procedure in the Code window of a form or in a module, you must ensure that the procedure's code is placed within the correct portion of the Code window. If your procedure is in a form's Code window, it must be placed somewhere between the Public Class formname and End Class statements. In a module, the procedure must be between the Module modulename and End Module statements.


To create a sub procedure, you place your cursor in the Code window in a location that is not within a currently defined function or procedure. For example, you might place the cursor after the End Sub statement of a procedure, before the Sub statement of another procedure, or at the top of the Code window (below the code that is automatically generated by Visual Basic .NET). Figure 8.1 shows examples of where you might start.

Figure 8.1. Start a procedure in the Code window by using a Sub statement.

graphics/08fig01.gif

Tip

Placing your procedures in alphabetical order makes finding them easier when you page through the Code window. However, regardless of the order in which they were entered, they will always be listed in alphabetical order in the Code window's Method Name drop-down box.


Let's walk through the steps involved in creating a sample procedure named FirstProc:

  1. Begin with a new Windows Application project. Open the Code window for Form1 by clicking the View Code button in the Solution Explorer.

  2. Place the cursor just above the End Class line near the bottom of the Code window.

  3. Press the Tab key, then type the keyword Sub followed by a space.

  4. Type the name of your new procedure (FirstProc).

  5. Press the Enter key to create the procedure.

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 Method Name drop-down list of the Code window becomes your new procedure name. Figure 8.2 shows these changes for your FirstProc procedure.

Figure 8.2. The End Sub statement is automatically added when you define a new procedure.

graphics/08fig02.gif

You are now ready to enter any commands that you want to be executed when the procedure is called. For this example, let's include a simple MessageBox command that alerts the user (you) that the FirstProc sub procedure has been invoked.

  1. Make sure the cursor is between the Sub FirstProc and End Sub lines in the Code window.

  2. Type the following line of code, then press Enter:

     MessageBox.Show("FirstProc has been invoked!") 

Executing the Procedure

After you develop a procedure, you need a way to execute it as necessary from other parts of your program. To execute a procedure, you use the Call statement with the name of the procedure (procname refers to the name of the procedure):

 Call procname([arguments]) 

However, the Call keyword is optional, so you can invoke a procedure by simply typing its name:

 procname([arguments]) 

With either method, you simply specify the procedure name and any arguments that may be required by the procedure. (You will learn about arguments a little later in this chapter.)

Let's complete our example by adding a Button control that will invoke the FirstProc sub procedure when clicked:

  1. Enter Form1's Design mode by clicking the "Form1.vb [Design]" tab at the top of the Code window.

  2. Add a Button control to the form.

  3. Change the Button control's Name property to cmdTest, and change its Caption property to Click Me.

  4. Double-click cmdTest so you can create its Click event procedure (which is automatically named cmdTest_Click).

  5. Type Call FirstProc and press Enter.

  6. Add a second Button control to the form. Set its Name property to cmdTest2 and its Caption property to Me Too.

  7. Add the code Call FirstProc to cmdTest2's Click event procedure as well.

Note

Remember, the Call keyword is optional. We're using it explicitly here for clarity.


You can now test your FirstProc sub procedure by running the program and clicking the Click Me and Me Too buttons. Each time you click either button, you should be presented with a message box reporting that FirstProc has been invoked. Note that the same block of code (FirstProc) is being executed from multiple locations (the Click event procedures of the two buttons).

Passing Data to a Procedure with Arguments

The procedure in the previous example did not require any data to do its job. It simply displayed a message box reporting that the procedure had been invoked. Often, your procedures will need to receive some data from the calling part of your program to perform their intended tasks. You can accomplish this by passing arguments to your procedures.

Arguments (also known as parameters) are pieces of information passed to procedures. To use arguments in a procedure, you first code the procedure so it is expecting an argument. You must then make sure you supply values for the arguments when you call the procedure.

Let's illustrate this concept with an example of a procedure that uses an argument. Suppose your program needs to log various operations and errors to a text file. A procedure that handles writing messages to the log file, along with the date and time that the message was written, could be very useful.

Creating a Procedure That Accepts Arguments

In this example,we will create a sub procedure named LogPrint. It will receive one argument, which represents the message that we want to write to the log file. This will also be a good opportunity to demonstrate placing procedures in a separate module, rather than putting them in a form's Code window.

To begin creating the LogPrint sub procedure, perform the following:

  1. Start with a new Windows Application project, or continue working with an existing one.

  2. Select Project, Add New Item from Visual Basic .NET's menu system.

  3. In the Add New Item - Procedures dialog box, make sure Module is selected in the Templates area on the right, give it an appropriate filename (the default, Module1.vb, is fine for our example), and click Open.

  4. You should be taken to Module1's Code window. If not, right-click Module1.vb in the Solution Explorer, and choose View Code.

  5. Position the cursor between the Module Module1 and End Module delimiters.

  6. Type Public Sub LogPrint(strMessage As String) and press Enter.

Let's pause here to discuss the line of code you just typed. As you already know, LogPrint is the name of the sub procedure, and the Public keyword declares that it can be called from anywhere in the application. The remainder of the line the part in parentheses is the argument list for the procedure. The argument list consists of a series (in this case, only one) of argument names and types. This example tells us that the procedure expects to be passed one argument of type String. strMessage is the name that will be used to represent that argument within the procedure, just as if it were a variable.

Note

You may have noticed that when you pressed Enter after typing the Public Sub statement, Visual Basic .NET added the keyword ByVal before your strMessage argument. This specifies that when the procedure is invoked, the value sent from the calling code for the strMessage argument will be passed by value as opposed to being passed by reference. Don't worry about this for now; you will learn about passing arguments by value and by reference later in this chapter.


This procedure will utilize file input/output operations that are exposed through the System.IO namespace. Therefore, we need to reference the namespace in this module. To do so, place the cursor at the top of the module at the beginning of the Module Module1 line and press Enter. Move the cursor up to the blank line that was created (above Module Module1), then type the following:

 Imports System.IO 

For more on namespaces, p. 119

To continue coding the procedure, place the cursor back in the body of the LogPrint procedure (between Public Sub LogPrint and End Sub) and type the following lines of code:

 Dim filLogFile As TextWriter, strFullMsg As String  filLogFile = File.AppendText("c:\eventlog.txt")  strFullMsg = Now & " - " & strMessage  filLogFile.WriteLine(strFullMsg)  filLogFile.Close() 

Let's examine this code line-by-line. The first line, Dim filLogFile As TextWriter, strFullMsg As String, declares that this procedure will have two local variables. The first variable, filLogFile, will be a variable of the TextWriterclass, which is inherited from the System.IO namespace and provides character output functionality. Recall that we referenced System.IO at the beginning of the module. We will utilize filLogFile in this procedure to handle the work of writing to our log file. The second variable, strFullMsg, is a String that will be used to construct the full message line to be written to the log file.

Line two, filLogFile = File.AppendText("c:\eventlog.txt"), invokes the AppendText method of the File class to create a TextWriter variable (filLogFile) that appends text to a file named c:\eventlog.txt. If this file does not exist, it will be created; otherwise, it will be appended to.

The third line, strFullMsg = Now & " - " & strMessage, uses the argument that will be passed into the procedure. Note how the argument, strMessage, is treated just like any other variable within the procedure. We use the Now function, which reports the current system date and time, to combine with a hyphen and the input argument strMessage to create the complete line that will be written to the log file.

The next line, filLogFile.WriteLine(strFullMsg), invokes the WriteLine method of the filLogFile object to actually write the text contained in strFullMsg to the log file.

Finally, the last line (strmOutput.Close()) closes the TextWriter and releases the system resources that it uses.

Passing Arguments to the Procedure

When calling a procedure that expects arguments, you supply values for the arguments by listing them in the Call statement, in parentheses after the procedure name. Each value supplied can be in the form of a variable, a literal string or number, or some combination of the two. Any of the following would be valid calls to the LogPrint procedure:

 Call LogPrint("Program started normally.")  strTemp = "User logged on."  Call LogPrint(strTemp)  Call LogPrint("Error opening file " & strUserFile) 

You can test your LogPrint procedure by adding a Button control to your project's main form, then using some form of the Call statement to invoke LogPrint with a test message. After you have done this a few times, use Windows Explorer to locate the file c:\eventlog.txt. Double-click it to view its contents in Notepad.

Remember, you can omit the Call keyword when invoking a procedure:

 LogPrint("Program started normally.") 

The LogPrint procedure is 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 format of the output file or change the destination of the log information from a text file to a database, printer, or pager, you have to modify only the LogPrint function itself.

Optional Arguments

Typically, you must include the same number of arguments in the calling statement as are present in the definition of the procedure. Occasionally, however, you may need to create a procedure that has one or more optional arguments. You can accomplish this by using the Optional keyword before one or more of the arguments in the argument list portion of the Sub statement.

Consider an enhancement to the LogPrint procedure whereby under certain circumstances you want to display information to the user via a message box in addition to writing a line to the log file. You can modify the declaration of the LogPrint procedure to include an optional second argument that represents text to be displayed in a message box as follows:

 Public Sub LogPrint(ByVal strMessage As String, _    Optional ByVal strDisplayMsg As String = "") 

Notice the keyword Optional in the preceding declaration. Arguments marked as optional can be left out when calling a procedure. In a procedure's declaration, an optional argument can be given a default value to be utilized if the calling code does not use the argument. In the previous example, if the calling program does not explicitly specify a value for the strDisplayMsg argument, the default value (an empty string, which was specified via the code = "" at the end of the optional argument declaration) is passed to the procedure. If your procedure needs to know whether a value was passed, you can use an If statement to compare the value of the argument to the default.

Note

When declaring optional arguments in a procedure's argument list, you must specify a default value. This ensures that the argument is populated whether or not it was included in the call to the procedure.


Tip

If you are calling a procedure that asks for multiple arguments, and you want to specify some of the arguments while leaving out one or more optional ones, you can use commas to skip over the optional arguments that you are leaving out. As an example, consider the procedure MyProc, which asks for four arguments, of which the second and third are optional. If you want to include the first, third, and fourth arguments but leave out the (optional) second argument, you could utilize the following calling code:

 Call MyProc(155, , 2.87, 37000) 

This would have the effect of passing the value 155 for MyProc's first argument, using the default value for its optional second argument, passing 2.87 for the third argument, and 37000 for the fourth argument.


After you have allowed for the possibility of one or more optional arguments, you can include code in your procedure to utilize the arguments. In the case of LogPrint, we will check to see whether the optional argument, strDisplayMsg, contains some value other than an empty string. We can assume that if it does contain an empty string, either the calling code did not pass a value for the argument, or an empty string was actually passed, indicating that no message is to be displayed to the user. If strDisplayMsg contains something other than an empty string, its contents will be displayed to the user via a message box.

Here is the code for the revised LogPrint:

 Public Sub LogPrint(ByVal strMessage As String, _    Optional ByVal strDisplayMsg As String = "")      Dim filLogFile As TextWriter, strFullMsg As String      Dim intTemp As Integer      If strDisplayMsg > "" Then          intTemp = MessageBox.Show(strDisplayMsg, "System Message")      End If      filLogFile = File.AppendText("c:\eventlog.txt")      strFullMsg = Now & " - " & strMessage      filLogFile.WriteLine(strFullMsg)      filLogFile.Close()  End Sub 

To call your modified LogPrint procedure with only one argument, use code just as if it only required a single argument:

 Call LogPrint("Program started normally.") 

If you want to provide the second argument, simply add it to the argument list of the calling code, as follows:

 strTemp1 = "Invalid logon attempt by SNEWSOM."  strTemp2 = "An invalid logon attempt has been detected and logged."  Call LogPrint(strTemp1, strTemp2) 

Caution

Be sure that the values supplied by the calling statement match the data types expected by the procedure. Violating this condition results in an error when you run your program.


Argument Passing Options

When declaring arguments in your procedures, you can specify how they will be passed to the procedure by the calling program. Depending on the option you select, the arguments used by a procedure can provide two-way communication between the procedure and the calling program. The arguments passing options are as follows:

  • ByVal, which stands for by value, means the value of the argument is passed to the procedure from the calling program. This is the default argument-passing mechanism and is generally used with input-only arguments.

  • ByRef, which stands for by reference, means that the calling program passes a memory reference to the procedure. This method of argument declaration can not only be used to send information into a procedure, but also to return information to the calling program.

For example, the following procedure gets the height and width of a rectangle from the arguments list and then calculates the area and perimeter of the rectangle. These values are returned through the arguments list:

 Sub CalcRectangle(ByVal nWidth as Integer, ByVal nHeight as Integer, _      ByRef nArea as Integer, ByRef nPerimeter as Integer)      nArea = nWidth * nHeight      nPerimeter = 2 * (nWidth + nHeight)  End Sub 

The procedure's first two arguments, nWidth and nHeight, are passed using the ByVal (by value) keyword, indicating that the actual value of the parameter is passed into the procedure. The other two arguments, nArea and nPerimeter, are passed ByRef (by reference) Using ByRef causes the calling code to pass a reference to the memory location used by a variable as the parameter (instead of the actual values of the variables). This allows the procedure to modify the variables, which in turn can be read by the calling code to determine the results of the calculations performed by the procedure.

The procedure can be called by using variables for both the input and output arguments, as follows:

 nWid = 5  nHgt = 5  nArea = 0  nPerm = 0  CalcRectangle (nWid, nHgt, nArea, nPerm) 

It can also be called by using literal values for the input arguments and variables for the output arguments:

 nArea = 0  nPerm = 0  CalcRectangle 4, 10, nArea, nPerm 

In either case, after the call to CalcRectangle, the values of nArea and nPerm can be referenced by the calling code in order to determine the results of the calculations:

 MessageBox.Show("The area of the rectangle is " & nArea) 

Note

If you use literal values for the ByRef arguments, obviously you cannot access the return values.


To further clarify this difference, think back to our discussion of variables in Chapter 6, "Storing Information in Variables." A variable points to a storage location in the computer's memory. Using the ByRef keyword forces the calling program's variable and the parameter to share a memory location. Because both variable names point to the same memory location, changes made within the procedure will be available to the calling program, as in the following example function:

 Sub ChangeString(ByRef AnyString As String)      AnyString = "After"  End Sub  Dim sSampleString As String  sSampleString = "Before"  ChangeString sSampleString 

Changing the value of AnyString within the procedure causes the value of sSampleString to be changed as well. This capability enables the procedure to modify the value that is then passed back to the calling code. On the other hand, using the ByVal keyword makes the calling program's variable and the parameter use separate memory locations. This approach 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. However, you can still modify the variable within the scope of the procedure.

Exiting a Procedure Early

As your programs, and therefore your procedures, grow in complexity, sometimes you might not 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 I 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 a procedure are the wrong type or have values that could cause a problem for the procedure, I use Exit Sub to terminate the procedure before the error occurs. Using the statement this way is a type of data validation. The following code modifies the previous area calculation code to perform this check:

 Sub CalcRectangle(ByVal nWidth as Integer, ByVal nHeight as Integer, _      ByRef nArea as Integer, ByRef nPerimeter as Integer)      If nWidth <= 0 Or nHeight <= 0 Then          nArea = 0          nPerimeter = 0          Exit Sub      End If      nArea = nWidth * nHeight      nPerimeter = 2 * (nWidth + nHeight)  End Sub 

Depending upon the coding conventions employed by your organization (or by yourself), having multiple exit points within a procedure may be frowned upon. If so, the preceding procedure could be rewritten as follows:

 Sub CalcRectangle(ByVal nWidth as Integer, ByVal nHeight as Integer, _      ByRef nArea as Integer, ByRef nPerimeter as Integer)      If nWidth > 0 And nHeight > 0 Then          nArea = nWidth * nHeight          nPerimeter = 2 * (nWidth + nHeight)      Else          nArea = 0          nPerimeter = 0      End If  End Sub 

    Team-Fly    
    Top
     



    Special Edition Using Visual Basic. NET
    Special Edition Using Visual Basic.NET
    ISBN: 078972572X
    EAN: 2147483647
    Year: 2001
    Pages: 198

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net