John W. Colby
jwcolby at colbyconsulting.com
Wed Jul 28 12:35:56 CDT 2004
Wow. Could you expand on all this just a little? ;-) Are you publishing this in an ezine? In any case, good job. And I shall be reading the online references. Thanks for taking the time to write this up. John W. Colby www.ColbyConsulting.com -----Original Message----- From: accessd-bounces at databaseadvisors.com [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Ken Ismert Sent: Wednesday, July 28, 2004 12:00 PM To: 'Access Developers discussion and problem solving' Subject: [AccessD] Early and Late-Binding Redux After reading with interest the thread "More on early versus late binding", the questions posed by the various responders prompted me to do some research. This rather long post is the result. I have divided this post into two main sections: Binding Performance, and an Under-The-Hood Look at VB/COM Binding. -Ken BINDING PERFORMANCE =================== Summary: Early binding is much faster than late, and is fastest under the most typical Access usage situations. A compelling benefit of early binding is the efficiency gained when coding. When testing object binding performance, don't use objects which are bound to queries. PERFORMANCE COMPARISON What is the real-world performance difference between late and early-binding? One test is measuring the maximum calls per second that can be sustained using each method. The hands-down winner: early-binding. It is roughly forty times faster for in-process calls, and about four times faster for out-of-process calls (1). For typical Access programs, the majority of objects are run in-process, especially Forms, DAO and ADO. Out-of-process objects are most often used in Access when automating external programs like Word or Excel. Another common scenario involves creating an object, calling it a few times, and closing it. If we create and destroy objects frequently, we need to look at object activation performance. Are late-bound objects more expensive to create than early-bound ones? For in-process activation, its a tie: both binding methods create objects in the same amount of time. For out-of-process activation, it turns out that late-binding is more efficient if you are making less than 10 calls to the object. But if you are going to make more than 10 calls, early-binding has the edge (2). PRACTICAL RULES OF THUMB So, early-binding almost always beats late-binding in terms of performance, but what does that mean to you? It depends on the level of object use in your code. As a rule, the more complex your program, and the more it relies on internal object interaction, the more it can benefit from early-binding. However, if you are automating an external program, particularly across different versions, late-binding is a viable option. As a professional, you have to take binding and performance considerations into account if you are going to deliver consistent value to your customers. The most critical performance consideration is, in my view, the human performance of quickly and accurately coding an application. Look at what you get with early-binding: Intellisense, compile-time checking, and events. The first two are invaluable for catching errors before they reach production, and the last is indispensable for writing efficient, clean code. It helps you write solid code faster, which is a compelling reason to use early-binding wherever it is warranted. USING QUERY PERFORMANCE TO JUDGE OBJECT BINDING EFFICIENCY CAN BE MISLEADING Recordset objects are poor candidates to judge object binding and activation efficiency. When the underlying query is loaded, it must establish a connection to the backend database (if the query involves linked tables), parse the SQL and compile the query. These initialization costs, even in the best cases, dwarf any object activation cost incurred. A much more representative test would be to time repetitive opening, use and closing of custom VB classes not tied to data objects. AN UNDER-THE-HOOD LOOK AT VB/COM BINDING ======================================== Summary: Understanding objects in Access really means understanding COM, because it is the object foundation for VB. In COM, all object binding is done to interfaces. The object declaration determines whether a specific (early-bound) or generic (late-bound) interface is used. The overhead of late-bound object calls explains the performance disadvantages of this technique. Early-bound calls use a much more efficient mechanism. References are primarily used when coding and compiling early-bound references, not at runtime. The details of object activation reveal more about the role of the Registry, and how objects behave at runtime. INTERFACE BINDING In VB, object references bind to interfaces. An interface defines how clients communicate with an object. It is composed of a fixed set of method signatures. Think of it as the property and method declarations, with no code, that a class supports. All VB classes have a default interface, which is simply the public properties and methods in the class. VB classes can also support one or more custom interfaces, which is an external interface that a class agrees to implement. When declaring an object reference, you can specify that VB bind the reference to a specific interface (default or custom), or no interface at all, in which case VB supplies a generic interface for you, and binds to it. LATE-BOUND REFERENCES Late-bound references are determined solely by how the object reference is declared (2): Dim obj As Object Dim obj As Variant Dim obj ' Variant implied No specific interface is declared, so the references are late-bound. In late-binding, the object's default interface is hidden from VB, and can only be accessed indirectly. To backtrack a little, all VB classes implement an interface called IDispatch, originally developed to support automation. Hidden from the VB programmer's view, IDispatch provides a generic, runtime way of executing properties and methods of the classes' default interface. All late-bound VB object references use the IDispatch interface. To execute a method: 1. VB first calls IDispatch.GetIDsOfNames with the method's name. GetIDsOfNames looks up the name in the object's default interface, and returns the dispatch ID, or DispID, of the method. 2. Next, IDispatch.Invoke is called with the method's DispID and the parameter list. 3. If the method name is found, and the parameter list matches up, the method is executed, and all is well. Otherwise, a runtime error occurs. In late-binding, this process is repeated every time the method is used. This overhead accounts for a significant fraction of overall call time, and explains a lot about the performance hit taken by late-binding. It is also worth noting that for scripting environments like IE or ASP, late-binding is the only binding technique available (2). EARLY-BOUND REFERENCES Early-bound references are again determined solely by the object declaration: Dim obj As Library.CClass ' Default interface Dim obj As Library.IInterface ' Custom interface Because an explicit interface is declared, these references are early-bound. This allows VB to use vTable binding, the fastest, most efficient form of binding. All VB objects, and most COM components, support vTable binding (another form of early binding, called DISPID binding, is also supported, but not discussed here). A vTable, or virtual function table, is a list of pointers to the methods the interface supports. It is loaded into memory when the object is first instantiated. To invoke a method, VB passes a pre-compiled offset to the object's vTable, which is then resolved to the actual address of the method. The overhead of a vTable-based call is little more than that of a DLL function call, and is a fraction of the time required for a late-bound call. Additionally, a vTable can be shared by multiple instances of the same object, which saves memory when dealing with collections of objects. BINDING EXCEPTIONS There are reference types in Access that exhibit both late and early-bound qualities: Dim ctl As Access.Control Dim frm As Access.Form These special case objects are inheritance objects. All controls inherit Control, and all forms inherit Form. Notice that Intellisense works for the common properties and methods for each type. But, you can also refer to properties and methods that are not members of Form, and it will compile without error. This lets you refer to specific controls on specific forms using a generic Form reference. So, Form and Control appear to be both early and late bound: default properties and methods are early-bound, while references to specific form or control properties are late-bound. This leveraging of inheritance allows great convenience in dealing with forms and controls. HOW VB USES PROJECT REFERENCES Project References provide essential support for object-oriented programming, but their role in the VB environment not well documented. References are used when coding, compiling, and making install packages. They do not play a direct role during runtime. You can make a Project Reference in one of three ways: selecting Tools, References in the VB editor, selecting Insert, Components in VB editor, and selecting Insert, ActiveX Control in Form Design. References provide needed object information for a VB project. The first is the Class ID, or CLSID -- a unique GUID identifier for the class (11). This is one of the registry keys that facilitates retrieval of an object's type library, its server file (DLL, EXE, OCX), and other information. The second is the Type Library, which holds the definition of the interfaces supported by the object (1). Type Libraries drive IntelliSense and provide the necessary information to compile code using early bound object references. While coding, the aforementioned IntelliSense is the chief benefit of References. These same type libraries can also be viewed using the often underutilized Object Browser -- hitting F2 allows you to browse the type libraries for each Reference you have made. Note that there is also a type library for your VBA project, as well. During compilation, References are used in several ways: 1. All early-bound object references are resolved to their CLSIDs (11), and the type library is used to perform syntax checking of all property and method calls. 2. Once checked, the type library is again used to resolve the vTable offsets for all called properties and methods. In this way, the object type is specified, the method calls are verified against the specified interface, and the most efficient binding is setup, all before runtime. Since VBA is interpreted, this often happens just-in-time, but the conceptual workings are identical to its compiled sibling. RUNTIME OBJECT ACTIVATION Lastly, we will touch on COM object activation to get a feel for how objects get created at runtime. The information for the particulars of the class, (it's server file name and location, associated type libraries, etc) are stored in the Registry, and keyed by the CLSID. The server (a DLL, EXE, or OCX file) for a class contains not only the code to perform the methods, but also contains a class factory object, which houses the code used by the COM runtime to instantiate objects in that class. Runtime object creation, early-bound, typically goes like this (1): 1. Client requests a new instance of COM object 2. The COM runtime looks up the associated server DLL from the Registry using the object's CLSID, and loads it into memory. 3. The COM runtime then retrieves the requested class from the DLL. What it gets back is a reference to the Class Factory object, which uses the IClassFactory interface. Next, it calls the CreateInstance method to create the actual object instance in memory. 4. Finally, the COM runtime gets the requested interface from the object, and returns a reference to it back to the client. Its work done, the COM runtime drops out of the picture, and client and object communicate directly. So this quick look at COM activation demonstrates the role of the Registry and CLSIDs in locating and creating objects. Even for late-bound instantiation, the registry is used, but when the CLSID isn't known, the ProgID, or fully qualified class name, is used instead (11). References ========== I've covered a lot of ground quickly in this post. These resources are for the reader interested in finding out more: 1. Introduction to COM http://arcobjectsonline.esri.com/ArcObjectsOnline/GettingStarted/IntroToCOM. htm 2. Effective Visual Basic: How to Improve Your VB/COM+ Applications, Addison-Wesley 3. KB 245115 -- INFO: Using Early Binding and Late Binding in Automation http://support.microsoft.com/default.aspx?scid=kb;EN-US;q245115 4. KB 138138 -- INFO: Late, ID, Early Binding Types Possible in VB for Apps http://support.microsoft.com/default.aspx?scid=kb;EN-US;138138 5. How Visual Basic COM+ Objects Work Internally http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/mojica_1000.html 6. An Under-the-Covers Look at OLE http://www.avdf.com/aug96/art_ole.html 7. Creating a Reference to an Object http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon98/htm l/vbconassigningreferencetoactivexcomponentobject.asp 8. How Binding Affects ActiveX Component Performance http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon98/htm l/vbconhowbindingaffectsolecomponentperformance.asp 9. Speeding Object References http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon98/htm l/vbconspeedingobjectreferences.asp 10. KB 247579 -- INFO: Use DISPID Binding to Automate Office Applications Whenever Possible http://support.microsoft.com/default.aspx?scid=kb;EN-US;247579 11. CCRP Versioning Policy: New ProgIDs Used for Visual Basic Version Builds http://ccrp.mvps.org/index.html?support/faqs/progid.htm -- _______________________________________________ AccessD mailing list AccessD at databaseadvisors.com http://databaseadvisors.com/mailman/listinfo/accessd Website: http://www.databaseadvisors.com