OLE Automation gained a reputation early on for being slow and unwieldy. This was due to the initial implementation of OLE Automation only supporting late binding. OLE 2.0 currently supports three types of binding:
1. Late Binding
2. ID Binding
3. Early or Vtable Binding
To understand why the various types of bindings perform differently, you need to understand a little bit about the implementation of OLE Automation. OLE Automation controllers use the OLE IDispatch interface to gain access to OLE objects. IDispatch identifies all members (methods and properties) by a number, the Dispatch ID (DISPID). Programmers, on the other hand, know object members by name. The resolving of these names to determine which functions to call (known as binding) is the main performance impediment in OLE Automation. Each of the binding types mentioned above implement this binding in different manners.
Late binding is the slowest method and the one that gave OLE Automation a reputation for slowness. In late binding, the OLE Automation controller knows nothing about the object at compile time. At run time, all of the binding information is determined on the fly. The controller determines the DISPIDs by calling the IDispatch::GetIDsOfNames function. After determining the DISPID of the function it wants to call, it then call IDispatch::Invoke specifying the DISPID. In addition to being slow, this method provides no validity or syntax checking at compile time, since the information is determined on the fly at run time.
ID Binding is the next-fastest binding method for OLE Automation. In ID binding a type library is provided for the OLE Automation controller. This type library documents each of the DISPIDs of the various members. At compile time, the DISPIDs are determined and compiled into the application. When calling, the member function only needs to call IDispatch::Invoke, bypassing a call to IDispatch::GetIDsOfNames. This method is almost twice as fast as late binding.
Early binding (also known as Vtable Binding) is the fastest OLE Automation method. Early binding totally bypasses the entire IDispatch interface and allows the controller to bind directly to the members in the object. Early binding does not use DISPIDs and will not work on a straight IDispatch implementation. The developer of the object must have provided a dual interface that is a combination of an IDispatch and a VTable interface. At compile time the type library for the object is read to determine the location in the VTable of each member. Code is then generated to directly call the function through the VTable. Early binding provides compile time type checking and, if an in-process OLE server is used, offers significant performance gains over the other binding methods. This is because there is no need to marshal arguments for the IDispatch::Invoke, no indirection through the Invoke call, and no marshaling is required in the server to unpack the various arguments before calling the member. Marshaling is the process of packing and unpacking arguments for a remote procedure call. With VTable binding on an in-process server, each member access equates to a direct function call. On an out-of-process OLE Server (EXE), this process will be slightly slower due to the overhead of the remoting code required to call the function in another process.
An interesting tidbit is that the main communication method for VBA is OLE Automation! Don't let performance be the determining factor in your choice of the C API over OLE Automation. Well-written OLE Automation code can be just as fast as code that uses the C API.