Early Binding vs. Late Binding: The Essential Guide for VBA Developers
The Absolute Minimum Every VBA Developer Absolutely, Positively Must Know About Early and Late Binding in COM (No Excuses!)
(In case you didn't know, the subheading is an homage to this classic Joel Spolsky article.)
What is Binding?
"Binding is the act of replacing function names with memory addresses where the code will 'jump to' when the function is called."
Let's use a visual:
In the image above, imagine that cells E3, E4, E5, and E6 are memory offsets for the Excel Application object.
Here is some sample code that creates a new instance of Excel and then immediately terminates it:
Dim xl As Excel.Application
Set xl = CreateObject("Excel.Application")
xl.Quit
The actual code to execute the Quit method within the Excel Application resides in memory at cell E6. When VBA executes the line xl.Quit
, it calls the code in cell E6 of our image.
How it knows to go to cell E6 is the difference between early and late binding.
Early Binding: Direct Access to Code
With early binding, our VBA code resolves the call to xl.Quit
at compile time.
It stores the offset to that method so that it can jump straight there at runtime. When our code hits the xl.Quit
line at runtime, it will do the following:
- Get the memory address of the Excel.Application instance:
A1
- Move 4 columns right and 5 rows down to get the address of the Quit method:
E6
The memory address of the Excel.Application instance is stored in the object variable xl
. Since the offsets were resolved at compile time, jumping to the Quit method is very fast.
Late Binding: Lookup By Name
With late binding, our VBA code resolves the call to xl.Quit
at runtime.
Let's update our code from above to use late binding (NOTE: only the first line changes):
Dim xl As Object 'Excel.Application
Set xl = CreateObject("Excel.Application")
xl.Quit
Since our code hasn't resolved the offset to the Quit method, it has to look up the address of the method by name within an index inside the object. When our code hits the xl.Quit
line at runtime, it will do the following:
- Go to the method index:
B2
- Search for a method named "Quit":
B3
- Get the address to that method:
C3
- Jump to the address of the Quit method:
E6
As you can see, there are additional steps involved with resolving a method call to a COM object at runtime.
This is why you will read that early binding performs better than late binding. It absolutely does. It just doesn't matter. The difference is imperceptible in nearly every situation.
Early Binding Requires a Type Library
With early binding, how does our code learn the offsets to the various function calls?
It gets this information by referencing the object's type library. When you go to Tools > References... and check the box next to "Microsoft Excel 16.0 Object Library," that is what you are doing. You are telling VBA, "Hey, whenever you need to resolve one of these Excel.Application method calls, go fetch the offsets from this here object type library."
This is why you will get a compile error on the line Dim xl As Excel.Application
if you uncheck the Excel object library. Your code has no way to fetch the method offsets for that object.
Late Binding Objects Must Implement IDispatch
With late binding, how does our code know where to find the method index within the object?
It actually does this via early binding. That is, the offset to the method index is resolved at compile time. Our code knows to go 1 column to the right and 1 row down to get to the method index. From there, it performs a lookup to find its final destination.
Not all COM objects support late binding. Only those objects that implement the IDispatch interface support late binding. The IDispatch interface has four methods to facilitate this method lookup approach:
- GetIDsOfNames
- GetTypeInfo
- GetTypeInfoCount
- Invoke
You don't need to worry about the details of how those methods work; VBA handles all that for you automatically.
Late Binding's Biggest Advantage: Multi-Version Compatibility
You'll often read that late binding is better than early binding because it avoids compatibility issues.
This is especially true when it comes to referencing the various Office application object libraries (Excel, Word, Outlook, etc.). But why is it better?
Let's continue with our example from above. Imagine that our end user's computer has a different version of the Excel.Application class that added a Charts
collection:
This new property appears between the Sheets and Range properties within the memory structure of the Excel.Application method. Let's step through the early binding and late binding approaches from above:
Early Binding FAILS
- Get the memory address of the Excel.Application instance:
A1
- Move 4 columns right and 5 rows down to get the address of the Quit method:
E6
Remember, with early binding, the offsets were resolved at compile time based on the object library on our development machine. And within that Excel object library, the Quit method was 4 columns over and 5 rows down. But on our end user's computer, that address offset now holds the Range property!
Late Binding FOR THE WIN!
- Go to the method index:
B2
- Search for a method named "Quit":
B4
- Get the address to that method:
C4
- Jump to the address of the Quit method:
E7
With late binding, the method offset gets resolved at runtime. Instead of relying on a type library on the development computer, we get the method offset directly from the COM object itself on the end user's computer.
With late binding, the address of the Quit method correctly resolves to cell E7
on our end user's computer.
Early Binding Has Its Place
When you rely on late binding in your VBA code, you give up four big advantages:
- Type safety
- IntelliSense
- Named constants
- Event handling
That's why I recommend that you use early binding during development, but switch to late binding prior to deployment. With that approach, you gain most of the advantages of the first three items in the list above. Unfortunately, that doesn't help the event handling situation. Simply put, if you want to handle your COM object's events, you'll need to use early binding.
Epilogue: A Note for the Pedants Out There
I did a fair amount of hand waving and terminology simplification in this article to teach a fairly deep and complex topic in about five minutes. Read the Microsoft article linked below for a more technically precise, more thorough, and (much) longer version of the differences between early and late binding.
That said, if anything I wrote is factually inaccurate, please let me know in the comments so that I can get it corrected. Thanks!
External references
Referenced articles
UPDATE [2021-11-28]: Added "event handling" as a fourth disadvantage of late binding (h/t @philivc).
Image by Chris Keller from Pixabay