Jeff Webb, Mike McKelvy, Ronald Martinsen, Taylor Maxwell, Michael Regelski September 1995 Special Edition Using Visual Basic 4 - Chapter 17 1-56529-998-1 Computer Programming computer programming Visual Basic OLE database applications ODBC VB VBA API This book is an all-in-one reference that provides extensive coverage of every topic and technique for creating optimized and customized applications with Visual Basic.

Chapter 17

OLE Objects Exposed


A programming language provides a way to accomplish tasks and also a structure for thinking about the tasks that you can accomplish. Visual Basic's new object-oriented language features change the way that you think about what you can accomplish. Not only are the new horizons broader, the landscape is fundamentally different.

This chapter introduces you to object-oriented programming with Visual Basic and readies your thinking for brave new vistas.

In this chapter, you learn about the following:


Visual Basic Standard Edition prevents you from creating Public class modules. Therefore, objects that you create with the Standard Edition are available only inside the application in which you define them. To create applications that share objects across applications, you need the Professional Edition or Enterprise Edition. The Enterprise edition also enables you to create objects that can be used remotely across the network.

Thinking about Objects

A well-designed object is like a black box; it handles a particular task without exposing the solution's details. The advantage of using "black boxes" is that you can stack an infinite number of them without worrying that some internal quirk within one of them will cause the whole stack to tumble.

The quirks that destabilize large applications are almost always related to global variables. The problem occurs when two unrelated procedures inadvertently use the same variable name for different purposes. If the variable is local to the procedure, no problem occurs. But if the variable is global to the application, you can get completely unpredictable results. This problem is fairly specific to large applications, simply because smaller applications have fewer variables. The fewer variables, the less likely they are to collide.

You have a better chance of avoiding problems with global variables if you observe rigorous variable-naming conventions. Some organizations even have personnel whose sole job is to allocate variable and procedure names. (Although their job may sound trivial, these people are actually quite powerful within their organizations; if you get on their wrong side, you'll be prefixing all your variable names with ImSoSorry.)

Visual Basic 4.0 enables you to keep sensitive variables and procedures inside a black box called an object. Objects are more than just another level of scope�they are a programming structure that provides a new form of containment, as shown in figure 17.1.

Fig. 17.1

Visual Basic adds objects to its traditional programming structures.

Objects protect procedures and variables through their instances. Calling procedures must get an instance of the object from another procedure or create a new instance of the object themselves to have access to items in the object. Each instance of an object provides its own private storage, which other instances of the same object do not affect.

Objects also benefit programmers by molding the design process around things rather than processes. Windows applications tend to promote nonlinear user interaction. Object-oriented design focuses on creating self-contained objects that manage nonlinear tasks better than applications that you create using structured programming techniques, as shown in figure 17.2.

Fig. 17.2

Object-oriented programming focuses on "what" rather than "how."

Objects in Visual Basic

For most Visual Basic programmers, forms are the best visible example of objects. Each form has a definition that the programmer creates at design time and stores in a form module (.FRM). At run time, Visual Basic creates an instance of the form, and that instance has predefined methods and properties. Methods and properties always apply to a single instance of the form, as shown in figure 17.3.

Fig. 17.3

The Move method applies to a single instance of a form, no matter how many instances of the same form exist.

Until Visual Basic 4.0, forms were not considered full objects, because you couldn't add methods or properties to them. All data and procedures in a form module were local to that form�you had to use global variables or built-in Form properties to get data in or out of a form.

Visual Basic 4.0 lets you declare Public variables and procedures within a form module. Items that you declare as Public look just like a form's built-in properties and methods. With this new feature, Visual Basic forms are now true objects. Visual Basic 4.0 also adds a new type of file, the class module. Class modules are similar to form modules, but lack the built-in user interface.

Use form modules to define objects that have a user interface. Use class modules to define objects that lack a user interface or that must be available outside of an application.

Creating Instances

You create the definition of an object at design time as a form module or a class module. The actual object is an instance of the class that Visual Basic creates at run time. This distinction is important, and causes much confusion among people learning object-oriented programming (see fig. 17.4).

Fig. 17.4

A class defines an object; an object is an instance of a class.

Another important detail is that form modules are self-instantiating, but class modules are not. In other words, Visual Basic automatically creates an instance of a form when you refer to the form's properties or methods in code. You've probably run into this as a bug in your code�inadvertently referencing a form's Visible property loads the form invisibly, as shown in figure 17.5.

Fig. 17.5

Referring to a form property automatically creates a "ghost" instance of the form.

This self-instantiation doesn't happen with class modules. To create an instance of a class module, You must use the New keyword in a declaration as shown in figure 17.6.

Fig. 17.6

You must declare a variable as a New class to create an object from a class module.

Destroying Instances

Objects that you create from form modules exist until you call the Unload statement on the form. Objects that you create from class modules exist as long as one or more variables refer to the object. Visual Basic objects follow the same reference-counting conventions as all OLE objects:

Listing 17.1 demonstrates reference counting. When Proc1 runs, Visual Basic creates a new object based on the Class1 class module (references = 1). At the end, Proc1 sets the vModule module-level variable to refer to the new object (references = 2). When clsProcedure loses scope, Visual Basic does not destroy the object (references = 1). Later, Proc2 shows that the object still exists by displaying its IExist property. Setting vModule to Nothing finally destroys the object (references = 0).

Listing 17.1 A Demonstration of Reference Counting

' Declare a module-level
' generic variable.
Dim vModule As Variant
Private Sub Proc1()
' Create a new instance of an object
' (references = 1).
Dim clsProcedure As New Class1
' Set a property in the object.
clsProcedure.IExist = True
' Establish another reference
' to the object (references = 2).
Set vModule = clsProcedure
' clsProcedure loses scope.
' (references = 1).
End Sub
Private Sub Proc2()
' Displays True -- object still exists!
MsgBox vModule.IExist
' Destroy object (references = 0).
vModule.IExist = Nothing
End Sub

Creating and Destroying Objects That Display Forms

An object that displays forms or controls does not automatically unload those forms or controls when Visual Basic destroys the object. If you hide a form or control, you can create a "lost reference" that stays around as long as the application is running�consuming memory and resources. Figure 17.7 shows the flow of control that can create a lost reference to a loaded form.

Fig. 17.7

Object1 creates a new, hidden Form1. After Object1 loses scope, Form1 remains in memory.

Classes that create forms or controls should use the class module Initialize and Terminate events to create and delete those objects. Listing 17.2 shows the Initialize and Terminate event procedures for a simple class that displays a form. The Initialize event procedure creates a new instance of a form. The Terminate method unloads the form and sets the newForm variable to Nothing.

Listing 17.2 The Initialize and Terminate Event Procedures for a Simple Class

' Module-level variable.
Private newForm
Public Function Class_Initialize()
' Create a new instance of a form.
Set newForm = New Form1
' Display the new form.
newForm.Show
End Function
Public Sub Class_Terminate()
' Destroy the instance of the form
' created by Create.
Unload newForm
' Invalidate the reference to the form
' This prevents other class members from
' reinstantiating the form without going
' through Initialize.
Set newForm = Nothing
End Sub

The following code creates and then deletes a new object by using the preceding methods. Although Delete correctly unloads the form from memory, you still must set the object variable to Nothing or let the variable lose scope to destroy the object.

Sub Main()
' Create the new object and establish
' a reference to is.
Dim objForm As New Class1
' Destroy the object (or simply let the
' variable lose scope -- same affect.
Set objForm = Nothing
End Sub

The Initialize and Terminate events in listing 17.2 are similar to C++ constructor and destructor functions. However, C++ constructor and destructor functions can take arguments to initialize data in the object. The Visual Basic Initialize and Terminate events do not take arguments; you must initialize data by using methods and properties that you define in the class or form module.

Rules of Thumb

Objects in themselves don't solve any of your programming problems. For objects to be helpful, you must observe some general rules. Because programming is a subjective and creative process, the rules aren't absolute or immutable. They give you a starting point from which you can work to develop your own style and preferences.

The following two rules of thumb are adapted from The C++ Programming Language by Bjarne Stroustrup, the father of object-oriented programming. The following adaptation modifies some rules to use terms familiar to Visual Basic programmers, and others have been changed or omitted because of limitations in Visual Basic's approach to objects (Visual Basic is not yet fully object-oriented):

The Future of Visual Basic Objects

The previous section mentioned that Visual Basic is not yet fully object-oriented. That isn't an excuse for C++ or SmallTalk programmers to dismiss the language; Visual Basic is still the most productive tool for creating Windows programs. The limitations bear mentioning, however, because they are the language features that you can expect Microsoft to add in future releases:

Applications That You Can Create with Objects

Applications that use objects can be large or small. They can be completely stand-alone or used as components in other applications. Table 17.1 lists the types of applications that you can create with Visual Basic's new object-oriented features.

Table 17.1 Types of Applications Creatable with Visual Basic 4.0's Object-Oriented Features

Type of Application Example(s) Chapter in Which Discussed
New general-purpose data types, such as extended Integer or recursive types. TYPES.VBP, OUTLINE.VBP 21
OLE components for use in other applications as add-ins. SYSTEM.VBP 18, 21
Stand-alone applications that provide services and data sharing to other applications. CDPLAYER.VBP 17
Components to run in separate processes for performance reasons. VBTERMINAL.VBP 18
Internal components used as a structuring technique within an application. CDPLAYER.VBP, WINDOWS.VBP 17, 19
Extensions to the Visual Basic programming environment. REGADDIN.VBP 24

OLE Automation and Object Libraries

Objects can be used internally in a single application or externally among multiple applications. Objects available for external use are sometimes called OLE Automation objects, because they are available through the OLE 2.0 OLE Automation interfaces.

Applications that include one or more OLE Automation objects are called object libraries. Object libraries are similar to conventional dynamic link libraries (DLLs), except that object libraries provide their features through objects rather than functions. Also unlike DLLs, object libraries use the Visual Basic data types, not C-specific types like null-terminated strings and pointers.

To create internal or external objects, you use the same programming techniques. The settings of two class module properties determine whether an object is available to other applications: Creatable and Public. For this reason, most of the procedures and examples in this book apply equally well to internal and external objects.

OLE Automation Requirements

To create applications that multiple applications can use, you must use Visual Basic 4.0 Professional Edition. The Standard Edition does not enable you to create class modules that have their Public property set to True. Therefore, Standard Edition objects are visible only within the project that defines them.

The Standard Edition also doesn't let you create Visual Basic add-ins, which are OLE Automation objects that enable you to extend the Visual Basic programming system. For example, an add-in might provide templates and wizards for certain types of applications that are commonly created in Visual Basic. These objects contain some special methods for loading and registering the add-in in Visual Basic.

You can create internal objects using Visual Basic Standard Edition. To use any of the object samples in this book with existing Standard Edition projects, simply add the desired class, form, and code module files to the existing project.

What You Cannot Create

You can't create OLE objects that support in-place editing with Visual Basic. Visual Basic applications display information only in the context of forms, which are separate windows or dialog boxes in an application. You can use Visual Basic to insert text, graphics, and other OLE objects into documents in OLE container applications, however.

Planning an Application with Objects

The CD Player sample application (CDPLAYER.VBP) demonstrates how to build an application out of objects. Analyzing the task to be performed�playing an audio CD�yields three features that you can represent as objects:

In addition, the application has a user interface, or control panel, to the CD player. You can represent this interface or control panel as a form object. You can represent all these objects graphically as shown in figure 17.8.

Fig. 17.8

Your code can represent the physical aspects of a CD player as objects.

Mapping an application's initialization, termination, and interaction graphically, as shown in figures 17.9 and 17.10, is helpful when building applications with objects. As you sketch your application, don't worry about the details of how you will do something; object-oriented design focuses on identifying what each object represents and which objects control other objects.

Mapping Object Initialization

A separate class or form module in Visual Basic defines each of the preceding objects. Objects can create or destroy each other as events occur. When CDPLAYER.VBP runs, the Application object creates ControlPanel and Title objects. The Title object creates an instance of the Track object for each track on the CD. Figure 17.9 shows the flow of initialization when CDPLAYER.VBP starts.

Fig. 17.9

The Application class creates the initial objects, which in turn create others.

Figure 17.9 indicates that the Application object and Title object both need Initialize event procedures to create subordinate objects: the Application object's Initialize event procedure creates the ControlPanel and Title objects; the Title object's Initialize event procedure creates a collection of Track objects.

Mapping Object Termination

When CDPLAYER.VBP shuts down, the Title and Track objects lose scope and are destroyed automatically. The Application object, however, must unload the ControlPanel object because it is a form and does not otherwise go away. Figure 17.10 shows how the application destroys its objects when it terminates.

Fig. 17.10

The Application object must unload the form before terminating; other objects are unloaded as they lose scope.

Figure 17.10 indicates that only the Application object needs a Terminate event procedure. The Application object's Terminate event procedure unloads the ControlPanel that it creates on initialization. Other objects don't require Terminate event procedures, because Visual Basic unloads them as they lose scope when the application ends.

Mapping Object Interaction

The CDPLAYER.VBP responds to events through its objects. The ControlPanel object receives all user events, because it is the only visible part of the application. The Application object responds to all programmatic requests through the its Public methods and properties, as shown in figure 17.11.

These interactions help determine the various navigational properties and methods that you must create to move among objects. The next section discusses how you create these properties and methods.

Identifying Methods and Properties to Create

After mapping the objects in a cleanly organized way, you can identify the methods and properties for each class. The best way to do so is in two passes:

Fig. 17.11

User events go directly from the form to the device; OLE Automation requests go through the Application object.

Sometimes this process requires that you add or rename objects. The software design process is unavoidably iterative. (You hope that it doesn't become an infinite loop.)

Navigational Methods and Properties

Table 17.2 lists the navigational methods and properties for each class in the CDPLAYER.VBP sample application. The members in bold are unique to this application. The other members are standard navigational items that Microsoft recommends for all Public objects. The standard navigational items are especially useful when debugging an object application. For this reason, you should always include them, even though they are a little boring to cut and paste between classes.

Table 17.2 CDPLAYER.VBP's Navigational Methods and Properties

Object Member Return Value
Application Application Application object
Parent Application object
Name "CD Player"
Title Title object of the current CD
Title Application Application object
Parent Application object
Name The name of the CD
CurrentTrack The Track object that is playing
Tracks The collection of all Track objects on the CD
Track Application Application object
Parent The Title object that created the track
Name The name of the track

Functional Methods and Properties

Table 17.3 shows the functional methods and properties for each class in the CDPLAYER.VBP sample application. These are the methods and properties that do the work for the objects.

Table 17.3 CDPLAYER.VBP's Functional Methods and Properties

Object Member Description
Application Play Starts playing the CD
PlayNext Skips to the next track
PlayPrevious Skips to the previous track
StopPlaying Stops playing the CD
Eject Ejects the CD
Quit Exits the application
Visible Sets or returns the visible state of the application
ElapsedTime Returns the minutes and seconds that the CD has been playing
frmControlPanel CurrentTitle Keeps track of the name of the CD currently playing
ElapsedMinutes Returns the minutes that the CD has been playing
ElapsedSeconds Returns the seconds that the CD has been playing
CurrentTrack Returns the index of the track that currently is playing
Tracks Returns the number of tracks on the CD
Track Sets the tracks about which to get information
TrackPosition Returns the start position of a track on the CD
TrackLength Returns the length of a track on the CD
Command Executes a string command on the MCI control
Title None Provides a way to organize tracks; doesn't contain functional members
Track StartPosition Returns the track's starting position on the CD
Length Returns the length of the track

The following are some interesting aspects of table 17.3:

Creating an application using objects is a subjective, creative endeavor. In the CDPLAYER.VBP sample, you could have applied the Play method to the Title object just as well as to the Application object. By placing the method in the Application object, however, you make the syntax that you use from other applications a little simpler (Application.Play rather than Application.Title.Play).

CDPLAYER.VBP is not complete. Like all software, it awaits new features. Ideally, it should store CD titles and song names in a data file, then retrieve those names when the appropriate CD is loaded. It should also support play lists, shuffle, and other standard CD player features. Using objects and the framework provided, it's relatively easy to imagine many ways to enhance the sample application by providing all these features.

The challenge of object-oriented programming is to think in terms of objects rather than procedures. Whether you are creating a new PlayList object or serializing the Title object to a file, objects give you a new way to tackle programming problems.

In the words of Brian Kernighan, "The only way to learn a programming language is by writing programs in it." So let's get started!

From Here...

For more information on the following topics, see the following chapters:


© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.