Condividi tramite


Visual Basic Concepts

How Binding Affects ActiveX Component Performance

Binding is the process of setting up a property or method call that’s to be made using a particular object variable. It’s part of the overhead of calling the property or method.

The time required to call a procedure depends on two factors:

  • The time required to perform the task the procedure was designed to do, such as finding the determinant of a matrix.

  • The overhead time required to place the arguments on the stack, invoke the procedure, and return.

As a component author, you’ll do everything you can to minimize the first item. The second item, however, is not entirely under your control.

The overhead for a method call depends on the type of binding Visual Basic uses for the method call, which in turn depends on the way a client application declares object variables, which in turn depends on the developer of the client application.

To ensure that developers who use your component get the best possible performance, you may want to include the information in this topic in the Help file for your component.

Note   Binding affects all property and method calls, including those the objects in your component make to each other. Thus the binding issues discussed here can also affect the internal performance of your component.

Types of Binding

There are two main types of binding in Automation — late binding and early binding. Early binding is further divided into two types, referred to as DispID binding and vtable binding. Late binding is the slowest, and vtable binding is the fastest.

Late Binding

When you declare a variable As Object or As Variant, Visual Basic cannot determine at compile time what sort of object reference the variable will contain. Therefore, Visual Basic must use late binding to determine at run time whether the actual object has the properties and methods you call using the variable.

Note   Late binding is also used for variables declared As Form or As Control.

Each time you invoke a property or method with late binding, Visual Basic passes the member name to the GetIDsOfNames method of the object’s IDispatch interface. GetIDsOfNames returns the dispatch ID, or DispID, of the member. Visual Basic invokes the member by passing the DispID to the Invoke method of the IDispatch interface.

For an out-of-process component, this means an extra cross-process method call, essentially doubling the call overhead.

Note   You cannot call the methods of the IDispatch interface yourself, because this interface is marked hidden and restricted in the Visual Basic type library.

Early Binding

If Visual Basic can tell at compile time what object a property or method belongs to, it can look up the DispID or vtable address of the member in the type library. There’s no need to call GetIDsOfNames.

When you declare a variable of a specific class — for example, As Widget — the variable can only contain a reference to an object of that class. Visual Basic can use early binding for any property or method calls made using that variable.

This is the recommended way to declare object variables in Visual Basic components and applications.

Important   Whether early or late binding is used depends entirely on the way variables are declared. It has nothing to do with the way objects are created.

Tip   Early binding dramatically reduces the time required to set or retrieve a property value, because call overhead is a significant fraction of the total call time.

vTable Binding

In the fastest form of early binding, vtable binding, Visual Basic uses an offset into a virtual function table, or vtable. Visual Basic use vtable binding whenever possible.

Objects created from Visual Basic class modules support all three forms of binding, because they have dual interfaces — that is, vtable interfaces derived from IDispatch.

If client applications declare variables using explicit class names, Visual Basic objects will always be vtable bound. Using vtable binding to call a method of an in-process component created with Visual Basic requires no more overhead than calling a function in a DLL.

Note   For in-process components, vtable binding reduces call overhead to a tiny fraction of that required for DispID binding. For out-of-process components the change is not as great — vtable binding is faster by a small but significant fraction — because the bulk of the overhead comes from marshaling method arguments.

DispID Binding

For components that have type libraries but don’t support vtable binding, Visual Basic uses DispID binding. At compile time, Visual Basic looks up the DispIDs of properties and methods, so at run time there’s no need to call GetIDsOfNames before calling Invoke.

Note   While you can ensure that early binding is used (by declaring variables of specific class types), it’s the component that determines whether DispID or vtable binding is used. Components you author with Visual Basic will always support vtable binding.