Visual Basic Concepts

Global Objects and Code Libraries

You can build libraries of general-purpose procedures in Visual Basic by making the procedures methods of a class module. Set the Instancing property of the class module to any value except Private or PublicNotCreatable, so that clients can create instances of the class.

When you choose the value GlobalMultiUse for the Instancing property of a class, and then make the project, you can subsequently use the properties and methods of the class without having to explicitly create an instance of the class.

Properties and methods of a GlobalMultiUse object (or global object) are added to the global name space of any project that uses the object. That is, in another project you can set a reference to the component, and the names of the global object’s properties and methods will be recognized globally, just as if they were part of Visual Basic.

Important   The properties and methods of a global object only become part of the global name space when the component is referenced from other projects. Within the project where you created the GlobalMultiUse class module, objects created from the class are just ordinary objects.

The following code fragments show the difference between using MultiUse and GlobalMultiUse objects. Both assume that you’ve used the References dialog box to set a reference to a component that provides a Financials object whose methods are general-purpose financial functions.

Code required to use a MultiUse Financials object:

' This code goes in a standard module.
' Declare a global variable to contain the instance.
Public gfins As New Financials

' This code goes in a form that uses a method of the
'   Financials object.
Private Sub cmdCalculateResult_Click()
   txtResult.Text = gfins.LeastReasonableReturn( _
      CCur(txtBeginningBalance.Text))
End Sub

Note   When you use the code above, the Financials object is created the first time the variable gfins is used in code. This incurs a slight increase in overhead on each function call. You can avoid this by explicitly creating the Financials object in Sub Main (for standalone executables) or on first object creation (for components).

By contrast, the code to use a GlobalMultiUse Financials object requires no global variable:

Private Sub cmdCalculateResult_Click()
   txtResult.Text = LeastReasonableReturn( _
      CCur(txtBeginningBalance.Text))
End Sub

Visual Basic creates a hidden instance of the Financials class the first time a line of code containing one of its methods is executed.

Note   As explained later in this topic, the hidden instance incurs the same slight overhead per call as declaring gfins As New in the previous code example.

In the Object Browser, procedures that are part of a project’s global name space are displayed in the <globals> entry in the Classes list. Figure 8.1 shows this for a project group that uses the Financials class.

Figure 8.1   Methods of a GlobalMultiUse class appear in <globals>

The Object Browser displays the names of classes and members defined in your projects in bold type.

Tip   You can move directly to the code that defines classes and members by double-clicking names displayed in bold type.

Components That Use Global Objects Internally

Setting the Instancing property of a class to GlobalMultiUse or GlobalSingleUse allows client programs to use the properties and methods of the class as if they were global functions, but within the project where you defined the GlobalMultiUse class module, objects created from the class are not global.

For example, suppose your MyUtilities project contains a Utilities class whose Instancing property is set to GlobalMultiUse, and that the class has an InvertMatrix method. Any client project that has a reference to MyUtilities can call InvertMatix as if it were a global function. However, within the MyUtilities project, you cannot use InvertMatrix as if it were a global function.

If you want to use a global instance of the Utilities class within the MyUtilities project, you can add the following declaration to a standard module in MyUtilities:

Public Utilities As New Utilities

Thereafter, whenever you need to use InvertMatrix (or any other procedure supplied by the Utilities class), you can qualify it with the class name:

   Utilities.InvertMatrix aintMyLargeMatrix

The first time you use a method of the Utilities class in this fashion, an instance of the class is created automatically, because the global variable is declared As New. Using the class name as the name of the variable makes it clear which of the modules within your component is supplying the procedure.

Note   You must declare the global variable in a standard module, not a class module, in order for this technique to work.

Creating Object Properties for Global Objects

Visual Basic has properties of its <globals> that are themselves objects — for example, the App object and the Printers collection. You can create similar object properties for your own global classes.

Suppose you’ve created a Registry class for accessing the Windows registry, and that you have a Globals class whose Instancing property is GlobalMultiUse. The following code fragment shows how you can add a Registry property to your Globals class:

Private mRegistry As Registry

Private Sub Class_Initialize()
   Set mRegistry = New Registry
End Sub

Public Property Get Registry() As Registry
   Set Registry = mRegistry
End Sub

Once you’ve compiled your component, you can reference it from other projects. If the Registry class includes a FindKeyContaining method, you might write code like this to use it:

Private Sub Command1_Click()
   lblResult.Caption = _
      Registry.FindKeyContaining(txtInput.Text)
End Sub

This code assumes that the form contains a text box in which the user enters a string to be located (txtInput), and a label in which the registry key is displayed (lblResult). Notice that you didn’t have to create an instance of Globals before using the Registry object.

Tip   Always use Property Get when you add an object property to your global object. If you use a public variable instead, you can accidentally destroy the object the property provides by setting the property to Nothing.

Guidelines for Using Global Objects

You may find the following useful in getting the most out of global objects:

  • Constants you provide using Enums are Long integers; you can use global objects to provide string and floating point constants, as described in "Providing Named Constants for Your Component," in "General Principles of Component Design."

  • When you encounter name conflicts, use the type library name of the component to resolve the conflict.

    For example, suppose you were using both MyUtilities and YourUtilities, and that YourUtilities had a GlobalMultiUse class named General that also included a method named LeastReasonableReturn. You would code the following to ensure that the method in YourUtilities was used:

    Private Sub cmdCalculateResult_Click()
        txtResult.Text = _
            YourUtilities.LeastReasonableReturn( _
                CCur(txtBeginningBalance.Text))
    End Sub
    

    Important   If conflicting names are not qualified, Visual Basic uses the library that appears highest in the References dialog box. Unless the procedures have different arguments, no compile-time errors occur.

  • Choose procedure names carefully. While it may seem convenient to use common words or phrases, this increases the likelihood that other libraries will contain functions with the same name. Qualifying procedures with the type library name may be even less convenient than explicitly declaring a global object variable.

    Important   Global name space pollution is a serious issue. For an example and discussion, see "Creating a Reference to an Object," in "Programming with Components," in the Visual Basic Programmer’s Guide.

  • Implicit creation isn’t the only way to use global objects. You can declare variables of a GlobalMultiUse class, and explicitly create instances. If you have two libraries with a lot of name conflicts, short global variable names may be easier to type than long, user-friendly type library names.

Important   Each client that uses the properties and methods of a GlobalMultiUse class gets its own instance of the class. In other words, the "Global" in GlobalMultiUse does not mean "one global instance that all clients share."

Limitations of GlobalMultiUse Objects

When you’re deciding whether to use a global object or explicitly declare a variable to hold an instance of an object, the following may be of use:

  • You can’t set the hidden reference to a global object to Nothing when you’re done using it. Visual Basic does not provide any way to access the hidden global object directly.

  • GlobalMultiUse is a convenience for programmers; you incur the same slight overhead on each procedure call as you would if you used a global variable declared As New (for example, As New Financials).

  • As explained earlier in this topic, when you are authoring a component that provides a GlobalMultiUse class, you cannot use the properties and methods of the class if they were global procedures.

  • You can’t use global objects to replace global procedures in the VB and VBA libraries. These libraries always appear at the top of the References dialog box, before any other libraries. Procedures with the same name in a global object can only be accessed by qualifying the procedure name with the type library name.

GlobalSingleUse Objects

For out-of-process components only, you can set the Instancing property of a class module to GlobalSingleUse. If you do this, a separate instance of your component will be loaded into memory for each client. This requires a lot more memory than providing GlobalMultiUse objects.

If you simply want each client to have a separate thread of execution for your global procedures, consider using GlobalMultiUse for your global objects and making your out-of-process component multithreaded, as described in "Scalability and Multithreading."

Note   GlobalSingleUse is not allowed in ActiveX DLL projects, because multiple instances of a DLL cannot be loaded into a clients process space.

For More Information   See "Scalability Through Multiple Processes: SingleUse Objects."