Packaging your modules as objects with properties and methods is a natural way to expand Visual Basic's capabilities. You can create objects for use within a single project, or make those objects available to other applications through OLE Automation.
In this chapter, you learn how to do the following:
To create OLE Automation objects, you first must have Visual Basic Professional or Enterprise Edition. Although you can create objects with the Standard Edition, you can use those objects only within the current project.
With Visual Basic, you can create your own objects that have properties and methods. Each object is contained in a module, the name of which identifies the object. Visual Basic now has three types of modules: code modules, form modules, and class modules.
Code modules now support object-style syntax. For example, the following line calls the Average function in Module1:
MODULE1.BAS defines the Average function as a procedure, as follows:
Module1.Average's syntax looks just like that of an object reference, with one significant difference: instances. Code modules have one static instance that the application creates on startup. Form and class modules can have multiple instances with separate storage for each.
You can use objects within a single project, or across projects as OLE Automation objects. You use different types of modules to define different types of objects, as shown in table 18.1.
Table 18.1 Module Types and Their Uses
Module Type | Default Name | Use |
---|---|---|
Code module | Modulen | Defines procedures, variables, and constants for use within the current project. Code modules don't usually have a visual interface. |
Form module | Formn | Defines a visible object for use within the current project. |
Class module | Classn | Defines an object for use by the current application or other applications and projects. Class modules enable other applications to control the current application as an OLE Automation object. |
Objects that you define in code modules and form modules are called internal objects, because you use them within the project in which you defined them. Objects that you define in class modules are called OLE Automation objects, because they are available to other projects and applications through OLE Automation.
Class modules are perhaps the most interesting type of module for creating objects, because they are available to other projects and applications through OLE Automation. Class modules enable you to create compiled libraries of code that you can use in the current project or other applications. Class modules have two properties not found in code and form modules:
You set the Instancing and Public properties in the class module's Properties window, as shown in figure 18.1.
Use the class module's Instancing and Public properties to make an object available to other applications.
To create an OLE Automation object, follow these steps:
Sub AddText(Text)
Form1.Print Text
End Sub
To use the OLE Automation object that you created in the preceding section, follow these steps:
Private Sub Command1_Click()
Dim x As Object
Set x = CreateObject("Project1.Class1")
x.AddText Text1
End Sub
If your OLE Automation object doesn't recognize methods and properties that you've just defined, check to ensure that you are running the right version of the object. When debugging, you can easily load the .EXE version accidentally rather than the new version that Visual Basic hasn't yet compiled. To avoid this, be sure to use GetObject in your container application and start the OLE Automation application in the other instance of Visual Basic before calling the object from the container application.
When you click the Command1 button on Form1, the CreateObject function starts the OLE Automation object application, PROJECT1.EXE, and returns a reference to the Class1 object. The AddText method then places the text in the Text1 text box on the OLE Automation object's form, as shown in figure 18.2.
Running the simple OLE Automation object from another application.
To identify OLE Automation objects to other applications, you use a string called a programmatic identifier or ProgID. The CreateObject and GetObject functions use this string to query the system registration database to find the application.
For OLE Automation objects, the programmatic identifier consists of the name that you enter in the Project Options dialog box's Project Name text box and the name of the class module that defines the object. Figure 18.3 shows this relationship.
The string that you use with CreateObject and GetObject consists of the project name and the class module name.
Visual Basic registers programmatic identifiers for all class modules that have their Instancing property set to Creatable Single Use or Creatable MultiUse. Therefore, a project with more than one creatable class has multiple entries in the registration database.
Visual Basic doesn't register applications permanently until you run the application outside of the programming environment. When you run the application within Visual Basic, it creates a registration entry in a temporary area that Visual Basic controls. Figure 18.4 shows the difference between permanent and temporary entries in the system registration database.
Visual Basic adds a temporary registration entry when you debug an OLE Automation object. After you build the .EXE file and run the application, the entry becomes permanent.
Objects defined in forms, procedures, and code modules are available only within the current project. Using a method from an internal object isn't any different from using a procedure defined in the module. The following code lines show alternative syntax for calling the Average() procedure in Module1:
Both object and old-style syntax display the same result. However, using object syntax gives you a few advantages over the old syntax:
Code modules aren't truly objects. However, objects defined in a form module are full-blown objects. Thus you can use form modules, but not code modules, in any statement or function that takes an object reference. Examples of such statements and functions include the following:
Another major difference is that forms have a built-in visual interface (the form) and modules don't. Use form modules for objects that have an appearance or that you need to use as objects with the preceding statements. Use code modules to perform general support tasks, such as mathematical operations.
Class modules provide the external interface that a project exposes to other applications. Code and form modules define the properties and methods used internally in the project. Without the class modules to act as the connection point, different programs could not communicate.
You identify objects by their module name. By default, Visual Basic names modules based on their module type—Form1, Module1, Module2, Class1, and so on. Instead of relying on these default names, you should carefully choose descriptive names for your objects, just as you would for the procedures, variables, and other symbols in your project.
The object names that you choose should be as obvious as possible. For instance, an application that provides one OLE Automation object might name the object "Application." A project that uses many internal objects might have its own object-naming convention, using such prefixes as mod, frm, and cls to identify the type of object. Although naming objects is a subjective process, there are a few OLE conventions to follow. Chapter 20, "Designing Object Libraries," discusses OLE naming guidelines for objects.
To change the name of a module, follow these steps:
Select the module to rename in the project window.
Use the Properties window to rename a module.
As mentioned previously, you can use module names when calling procedures in Visual Basic. For example, the following code line displays the result of the Average() function in Module1:
This line is syntactically identical to the Pmt method in the Visual Basic for Applications (VBA) object library:
In fact, a module's Sub and Function procedures are equivalent to an object's methods. Like Function procedures, methods that return values enclose their arguments in parentheses, as in the preceding example. Like Sub procedures, methods that don't return values omit the parentheses. The following two lines demonstrate methods that don't return values:
You use special Property procedures to create properties for an object. Table 18.2 describes the different types of procedures that you use when creating objects.
Table 18.2 Types of Procedures That Objects Use
Procedure Type | Use |
---|---|
Sub | Defines methods that don't return a value |
Function | Defines methods that return a value |
Property Get | Returns a property's value |
Property Let | Assigns a property's value |
Property Set | Sets the property to a reference to an object |
Properties can have one or all three types of property procedures. Usually, properties have both a Property Get and Property Let procedure. Listing 18.1 shows a pair of property procedures that define the NumLock property:
Listing 18.1 Two Property Procedures That Define the NumLock Property
You use a property procedure the same way that you use object properties. The following code lines display the Num Lock key state and then turn on the Num Lock key:
To create a read-only property, create Property Get procedure for the property and omit the Property Let procedure. The following code shows a read-only SystemDirectory property that returns the Windows system directory:
You can read the new SystemDirectory property, but you cannot set it. The following assignment statement causes a "Procedure type mismatch" error:
"Procedure type mismatch" is not a trappable error; that is, you cannot handle such an error in code. To be a little kinder to your application's users, define a Property Let procedure that triggers an error, as in the following example:
You can trigger any error value with the Error statement. Error 383 is the error code that Excel returns when you try to assign a value to one of its read-only properties.
To create a write-only property, define a Property Let procedure and omit (or return an error for) the Property Get procedure. Write-only properties are far less common than read/write and read-only properties.
Properties that contain objects have Property Get and Property Set procedures. As you might expect, working with objects is more complicated than setting or returning simple values. Listing 18.2 shows procedures that demonstrate four common operations:
Listing 18.2 Creating Object Properties
The TestObject() procedure demonstrates how to use the Property Get Basic procedure:
The AssignObject() procedure demonstrates how to use the Property Let Basic procedure to set an object reference with assignment rather than using the Set statement:
You might not want to let users create object references by using assignment. You simply determine which is clearer: allowing assignment, requiring the Set statement, or prohibiting the setting of references altogether.
One of the fastest ways to get up and running with OLE Automation is to add a class module to an existing application. To do so, follow these steps:
The following sections describe each of these steps in greater detail, using the VB Terminal (VBTERM.VBP) sample application included on the Visual Basic distribution disks.
To make the VB Terminal sample application an OLE Automation object that you can use from other applications, you must change event procedures declarations in VBTERM.FRM from Private to Public. This change enables you to call the event procedures from the class module that provides the OLE Automation object that other applications use.
To change the VB Terminal event procedure declarations to Public, follow these steps:
For now, you need only change these declarations. The other event procedures can remain Private.
You use these Public event procedures in the next section.
After making it possible to call the crucial event procedures from outside a form, you can create a class module to repackage those procedures as methods. To create a class module for VB Terminal, follow these steps:
Change the Name and Public properties of the new class.
If you have Visual Basic Professional Edition but get an error message when you try to create a Public class module, your installation might be corrupt. Try reinstalling the Visual Basic development environment.
After making event procedures Public and creating a class module to call those event procedures, you can run and test VB Terminal as an OLE Automation object. To run VB Terminal as an OLE Automation object, follow these steps:
The Project tab of the Options dialog box enables you to change the project name and select the StartMode.
When you are satisfied with the VB Terminal OLE Automation object, you can build it as an .EXE file and test it outside of the Visual Basic environment.
To build and test the VB Terminal application as an .EXE file, follow these steps:
Building an OLE Automation .EXE file is the same as for any other project.
Running the .EXE file reregisters the application in the system registration database. This reregistration maintains the registration entry even if the user moves or renames the file. In some cases, you must rerun the application outside of Visual Basic to get CreateObject to work after changes to the OLE Automation object.
The methods defined so far for VB Terminal are quite simple: they merely repackage existing event procedures without adding any more logic. The limitation of defining such simple methods is that the interface is not as programmable as you might want it to be. For instance, the Dial method displays an input box to get the phone number, whereas a more useful technique is to enable Dial to accept a phone number argument.
The next few sections refine the VB Terminal OLE Automation object by adding or modifying the following features:
With these additional or modified features, VB Terminal becomes quite useful to other applications.
The Dial method calls the MDial_Click event procedure in VBTERM.FRM, which displays an input box. This call isn't necessary if Dial has a phone number argument. To add a phone number argument to Dial, you must modify the VBTERM.FRM and APPLICAT.CLS files.
The first change is to split the MDial_Click event procedure into two procedures, as shown in listing 18.3.
Listing 18.3 Splitting the MDial Click Event Procedure
Next, change the Dial method in APPLICAT.CLS to take an optional argument. If the user omits the argument, call MDial_Click as before; if the user includes the argument, call the new DialNumber procedure. The following code lines show the new Dial method:
Knowing whether the comm port is open is important to any application that wants to send a command string directly to VB Terminal. The port's status is also useful if other applications can open or close the port. To provide these features, you should add a read/write PortOpen property to the VB Terminal OLE Automation object.
Deciding whether to provide an item as a property or as a method is often difficult. Usually, properties represent the state of an object and methods represent an action that the object takes.
The following PortOpen property enables other applications to get and set the PortOpen property for the MSComm control on the VB Terminal form:
Another useful feature to provide is a way to send command strings directly to the VB Terminal application. This feature enables another application to configure the modem by using standard modem commands and to send strings for logging on to services, exchanging data, and so on.
The SendLine method sends a string of characters to the comm port. If the VB Terminal Echo flag is on, the characters echo in the Terminal window; otherwise, the window does not display the characters. The following code is the SendLine method:
If you want to send commands to VB Terminal, you probably also want it to return information. For these purposes, you must define two related properties: TrapText and Text.
Normally, when VB Terminal receives data from the comm port, that data triggers the OnComm event procedure in VBTERM.FRM. This procedure retrieves the data and clears the buffer. To retrieve this data from another application, you must delay the OnComm event by increasing the threshold value that triggers the event. As listing 18.4 shows, if you set the TrapText property to True, you increase the MSComm control's threshold value to its maximum setting. This setting enables you to retrieve the data in the buffer from another application by using the Text property, which is described next.
Listing 18.4 The TrapText Property
The Text property (listing 18.5) returns the text that was in the comm port's input buffer. It also echos the received text in the VB Terminal window if Echo is on.
Listing 18.5 The Text Property
Property procedures provide a good way to extend form display attributes. For instance, you can display a Help window on top of all other windows by choosing Help, Always On Top. To display the window this way with a Visual Basic form, you must call the Windows API function SetWindowPos. This technique isn't elegant, because SetWindowPos takes seven arguments, most of which the function doesn't even use when setting the window to display always on top of all others. A more natural (or BASIC-like) technique is to repackage the SetWindowPos function in an OnTop property.
Listing 18.6 shows the declarations and property procedures that you use to create the OnTop property. When you set the form's OnTop property to True, the form appears on top of all other windows. When set to False, the form displays as it normally does.
Listing 18.6 Setting the OnTop Property
You need only one version of the declare for the SetWindowPos API. Choose the one that you need based on whether you are writing a 16- or 32-bit application.
To see the OnTop property at work, add the preceding code to a form, then set the form's property in code. The following Click event procedure demonstrates turning OnTop on and off:
You can document your objects, properties, and methods at two levels:
Figure 18.10 shows how to use the Object Browser to display Help for your object, properties, and methods.
The Object Browser.
To document the object's properties and methods in a project, follow these steps:
To find Help for a project's objects, properties, and methods, you can use the Object Browser to search for the file name in the Help File text box of the Project page of the Options dialog box.
Enter the description and Help context ID in the Member Options dialog box.
To document a class or module, click on the class or module name in the Object Browser in step 4. This deselects the properties and methods in the class or module.
Help for a project's objects, properties, and methods resides in the same Help file as for the rest of the project. When designing your Help file, you should be careful not to confuse users by including highly technical programming topics in the same table of contents used by people seeking Help on your application's user interface.
You cannot redefine any existing form properties or methods. Therefore, you cannot create Property procedures that use the same name as any form property, and you cannot create any Sub or Function procedures that use the same name as any form method.
This prevents you from changing a form's built-in behavior. For instance, preventing a form's window state from changing in code is sometimes useful. The following Property procedure prevents other procedures from changing a form's window state:
Visual Basic enables you to add this procedure to a form, but when you try to run the project, it causes the error message "Member already exists on this form." The following names are restricted within a form module:
Similarly, Visual Basic reserves about 100 names for its own use. If you try to use these names as identifiers in any module, you get an error with the form "Expected: description", where description is some text describing the keyword's usual use. The following are the names that Visual Basic restricts within any module:
In this chapter, you learned about creating objects and the many different facets of using them. You learned about their properties and how to create and use OLE objects from other processes.
To learn more about related topics, see Chapter 19, "Creating Object Collections," which discusses in more detail how to create collections of objects. Collections can be very useful and time saving from a programming point of view.
© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.