The Loan and Dice sample objects shown earlier in this chapter don't display visible interfaces, such as forms, to the user. Many objects don't present a visible interface, but there will be cases in which you'll want to create objects that use forms to collect data from the user.
It's very easy to add a form to an ActiveX EXE or ActiveX DLL project, but you need to be aware of one major "gotcha"objects that display forms need to carefully manage the creation and destruction of those forms. A client application will never interact directly with a form in an ActiveX component (these forms are private to the component), so it's important that all housekeeping of the form be correctly implemented by the object within the component that is responsible for the form. Otherwise, instances of the object can remain hidden in memory, consuming resources and occasionally causing unexpected results.
The following code shows the class module definition for an object named User. This object is used to gather name and password information and displays a modal form with two text boxes, named txtName and txtPassword, and an OK button, named cmdOK.
`USER.CLS
`~~~.Name
Property Get Name()
Name = frmPass.txtName
End Property
`~~~.Password
Property Get Password()
Password = frmPass.txtPassword
End Property
`~~~.Show
Sub Show()
frmPass.Show vbModal
End Sub
Private Sub Class_Terminate()
`Unload form when object is destroyed
Unload frmPass
End Sub
The form, named frmPass, contains only one event procedure to hide the form when the user clicks OK. This lets the object's creator validate the user name and password and quickly redisplay the form if the entered data is incorrect. The data on the form isn't cleared, making it easier for the user to make corrections.
`FRMPASS.FRM
Private Sub cmdOK_Click()
Hide
End Sub
To use this object, another application simply creates an instance of the object and then calls the Show method. The code below shows an example of how this can be done on a form containing a command button named cmdSignOn. Note the syntax for referencing the User class in the project named PasswordSample.
Private Sub cmdSignOn_Click()
`Create an instance of the object
Dim usrSignOn As New PasswordSample.User
`Loop until user enters Guest password
Do While usrSignOn.Password <> "Guest"
`Display dialog box
usrSignOn.Show
Loop
End Sub
Figure 5-6 shows an example of the User object form.
Figure 5-6. Example of an object that displays a form.
To see the importance of managing form creation and destruction, remove the User object's Class_Terminate event procedure, and then create the object from another application, as shown above. When the cmdSignOn_Click event procedure ends, the usrSignOn variable loses scope and is destroyed, but the frmPass form remains loaded, running in a hidden instance of the object's application.
If the object is defined in an EXE component, you can view this hidden instance in the Windows Task Manager by pressing Ctrl-Alt-Delete. You'll have to end the task from the Task Manager so that you can correct this problem and recompile a corrected version. Don't leave a "bad" version of this object around to cause problems laterhidden instances of object applications can be difficult to detect.
In general, you use the Class_Initialize and Class_Terminate event procedures to manage the creation and deletion of forms. Because this sample was so short, I let the form be created implicitly by whichever property or method was called first. I could just as easily have been explicit by including this Class_Initialize event procedure:
`Add to USER.CLS to be explicit
Private Sub Class_Initialize()
`Create form when object is created
`by calling Show method
Show
End Sub
NOTE
It's a good idea to always be explicit when you create and destroy forms in objects. This will save time down the road when you are debugging.
There are several related Visual Basic statements that let you add your own user-defined events to your objects. I mention this here because one of the best uses for this technique is to provide a way for private forms owned by objects in ActiveX components to immediately react with client applications. An event raised in a private form can trigger an immediate response in the ActiveX object responsible for that form, and that object can in turn raise an event back in the client application. The Books Online documentation topic Adding a Form to the ThingDemo Project provides a good example of this scenario.