Testing the Code for the CPassword Class
You need a way to test the code in the CPassword class to make sure it works as it should. To do so, you need to create a new project and name it TestPassword . Then, create a form with the controls shown in Figure 15.4.
Figure 15.4. The form for the TestPassword project.
The button names are btnAdd , btnCheck , and btnExit . The middle two text boxes are named txtPassword and txtConfirm . You cannot see these names in the figure because I have set the PasswordChar property to an asterisk ( * ). This means that any character typed into these text boxes appears as an asterisk instead of the character typed by the user . This prevents anyone watching the user from seeing the password as it is typed into the program.
The TestPassword Code
The code to test the CPassword class is shown in Listing 15.6. Notice the first line in the listing. This statement tells Visual Basic .NET that the code for any calls to the CPassword class is found in the CPassword library. (You will see how to do this toward the end of this chapter, in the section "Creating Your Own Class Library.") For the moment, you can just think of the CPassword class code as being available via the CPassword library file.
Listing 15.6 The Code to Test the Password Class
Imports CPassword Public Class frmTestPassword Inherits System.Windows.Forms.Form Dim MyCheck As New Password() Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles btnAdd.Click Dim length, Level, Passed As Integer If txtSecurity.Text = "" Then MessageBox.Show("Must enter a security level.") Exit Sub End If Level = CInt(txtSecurity.Text) Passed = MyCheck.AddNewUser(txtName.Text, txtPassword.Text, Level) If Passed = False Then ' See if this user is OK to add. Beep() ' Guess not... length = Len(txtPassword.Text) If length < 4 Or length > 30 Then ' Was the password length OK? MessageBox.Show("Error. Password must contain _ between 4 and 30 characters.") txtPassword.Text = "" txtConfirm.Text = "" txtPassword.Focus() ElseIf Level < 1 Or Level > 10 Then ' How about the security level? MessageBox.Show("Error. Security level must be between 1 and 10") txtSecurity.Text = "" txtSecurity.Focus() Else ' Already in the list. MessageBox.Show("Error. User name already in list") End If Exit Sub End If ' If we get here, all's OK. MessageBox.Show("User added to list successfully") End Sub Private Sub btnCheck_Click(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles btncheck.Click Dim Password As String, SecurityLevel As Integer Password = MyCheck.GetPassword(txtName.Text, txtPassword.Text) SecurityLevel = MyCheck.GetSecurityLevel(txtName.Text) End Sub Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles btnExit.Click MyCheck = Nothing ' This releases the object Me.Dispose() End Sub Private Sub txtConfirm_Leave(ByVal sender As Object, ByVal e As _ System.EventArgs) Handles txtConfirm.Leave If txtConfirm.Text <> txtPassword.Text Then MessageBox.Show("The two passwords do not match.") txtPassword.Text = "" txtConfirm.Text = "" txtPassword.Focus() End If End Sub End Class
Near the top of Listing 15.6 is this line, which defines a CPassword object:
Dim MyCheck As New Password()
The empty parentheses after the CPassword class name simply tell Visual Basic .NET that the CPassword class constructor does not have any parameters passed to it.
When you compile and run the program, a MyCheck object of the CPassword class is created. Given its position in the program, you can see that it has module scope, so you do not need to worry about passing it to other procedures in the program. This scope level is fine for testing purposes, although local scope would be better in a real program.
If you click the Add button, the btnAdd object's Click() event code is executed. Although the code is somewhat long, it does little more than call the AddNewUser() procedure in the CPassword class. That is done with this statement:
Passed = MyCheck.AddNewUser(txtName.Text, txtPassword.Text, Level)
When the call is completed, Passed is either -1 or . (Again, Passed is an Integer rather than a Boolean because you might want to change the return value later.) If Passed is -1 , a message is displayed that says the user has been added to the list. All the rest of the code is used to decide what type of error caused Passed to be returned as . If we coded AddNewUser() to return Integer values that vary according to the type of error that occurred, you could simplify the code in the test program, perhaps by using a Select statement. Implementing such error processing would be a worthwhile exercise for you to try.
Checking a User and Password
You have probably noticed that the btnCheck object's Click() event really doesn't do anything. However, it appears in the code so you have a convenient place to put a breakpoint so you can observe what is actually taking place in the CPassword class.
You should place a breakpoint on the first statement in the btnCheck object's Click() event. After you have added a few users to the list, try entering a username and password combination that is already in the list. Then click the Check button.
When you reach the breakpoint, single-step the program by pressing the F10 key. When you enter the GetPassword() procedure of the CPassword class, you see the code from Listing 15.5. The first call is made to CreateChecksum() , which returns a value that is assigned to Check . The user's password and Check are then passed to EncodePassword() . The result is passed back and assigned to EncodedPW . This string should look very strange . For example, the password joyce1 comes back as JPKMwtpr>Ayd!Oi6E/EBb3BONUIOho .
The code then calls DecodePassword() with the data you just created. If everything is working right, you should get your original password back in the variable named Temp . The code then does a simple test to see if the original and decoded passwords are the same, and it returns True or False accordingly .
If you make the encoded password accessible through EncodePassword() , the procedure could be called and the password written to a database. Then, when anyone viewed the database, he or she would not be able to decipher the user's password. A call to DecodePassword() would put the password back into a readable format.
GetPassword() is not doing much because it is written simply to test the encoding and decoding of the password. In a real program, this routine would probably be used to encode the user's password before writing it to a database for retrieval at some later time. The constructor code would then be used to read the database table with the password rather than build the dummy list shown in the present constructor code.
Releasing Objects Gracefully
Earlier in this chapter we discussed class constructors and how they are used to initialize an object. It would seem to make sense that if there are class constructors, there would be class destructors, too. This is the case in other languages, such as C++. However, it is not the case in Visual Basic .NET. No class destructor is automatically called when an object goes out of scope. Let's examine the test program a little more closely.
When you end the test program and click the End button, this statement is executed:
MyCheck = Nothing
In the strictest sense, this statement is not called, but you need to understand its purpose anyway.
Recall from earlier discussions that the New keyword causes an object to be created. (By the term created, I mean the object has an lvalue in memory.) Also remember from Table 4.1 in Chapter 4, "Data Types and Numeric Variables ," that each object requires 4 bytes of storage. This might have seemed weird at first glance. After all, how can every object use only 4 bytes of memory? What is actually happening is that the variable associated with the New keyword is a reference variable that points to the object being created. In the TestPassword program, MyCheck is a reference variable that points to a memory location where the CPassword object is stored.
It would be nice if, when you are done using the object, you could tell Windows you no longer need the resources associated with the object. You can do that by setting the object to Nothing . The Nothing keyword actually resolves to the default value for the data type of the variable being used. For reference variables, however, Nothing means that the variable is no longer associated with any object. Because the variable is no longer tied to an object, Windows is free to reclaim the resources associated with that object. The process of reclaiming program resources is called garbage collection. Note that those resources always involve some amount of memory but could also involve other resources, such as system ports, print resources, database connections, and the like.
Why is garbage collection important? After all, when you end the program, its resources are freed anyway. In complex programs, there is always the risk of running out of system resources. Recall from the discussion of defining variables in Chapter 4 that Visual Basic .NET always has to ask Windows for the necessary memory for the variable. If Windows is getting low on resources, it automatically begins the garbage collection process.
Garbage collection may seem like a very complex process that involves incantations, crushed bat wings, and eye of newt. But stated in simple terms, garbage collection is the process by which Windows looks for reference variables that are no longer in use and reclaims the resources associated with those reference variables. Assigning the keyword Nothing to a variable is an explicit way to tell the garbage collection process that the resources associated with the object can be collected and made available for other uses.
Note that the garbage collection process is a background process that Windows does automatically. Because the garbage collection method is part of the System object, however, you could directly call the garbage collection method. However, it is not necessary to do so and is probably best left to Windows to decide when to do garbage collection. The only time you need to worry about garbage collection is when a class uses resources other than memory. You will learn more about this topic again in Chapter 26, "Using Visual Basic .NET on the Web," when you begin to use additional (nonmemory) resources. The simple program under investigation here, however, doesn't need to worry about garbage collection.