VBA Early Binding

When you ran the EX25A, EX25B, and EX25C components from Excel VBA, you used something called late binding. Normally, each time VBA accesses a property or a method, it calls IDispatch::GetIDsOfNames to look up the dispatch ID from the symbolic name. Not only is this inefficient, VBA can't do type-checking until it actually accesses a property or a method. Suppose, for example, that a VBA program tried to get a property value that it assumed was a number, but the component provided a string instead. VBA would give you a runtime error when it executed the Property Get statement.

With early binding, VBA can preprocess the Visual Basic code, converting property and method symbols to DISPIDs before it runs the component program. In so doing, it can check property types, method return types, and method parameters, giving you compile-time error messages. Where can VBA get the advance information it needs? From the component's type library, of course. It can use that same type library to allow the VBA programmer to browse the component's properties and methods. VBA reads the type library before it even loads the component program.

Registering a Type Library

You've already seen that Visual C++ generates a TLB file for each component. For VBA to locate that type library, its location must be specified in the Windows Registry. The simplest way of doing this is to write a text REG file that the Windows Regedit program can import. Here's the ex25b.reg file for the EX25B DLL component:

 REGEDIT4 [HKEY_CLASSES_ROOT\TypeLib\{A9515ACA-5B85-11D0-848F-00400526305B}] [HKEY_CLASSES_ROOT\TypeLib\{A9515ACA-5B85-11D0-848F-00400526305B}\1.0] @="Ex25b" [HKEY_CLASSES_ROOT\TypeLib\{A9515ACA-5B85-11D0-848F-00400526305B}\1.0\0] [HKEY_CLASSES_ROOT\TypeLib\{A9515ACA-5B85-11D0-848F-00400526305B}\1.0\0\win32] @="C:\\vcpp32\\ex25b\\Debug\\ex25b.tlb" [HKEY_CLASSES_ROOT\TypeLib\{A9515ACA-5B85-11D0-848F-00400526305B}\1.0\FLAGS] @="0" [HKEY_CLASSES_ROOT\TypeLib\{A9515ACA-5B85-11D0-848F-00400526305B}\1.0\HELPDIR] @="C:\\vcpp32\\ex25b\\Debug" [HKEY_CLASSES_ROOT\Interface\{A9515AD7-5B85-11D0-848F-00400526305B}] @="IEx25bAuto" [HKEY_CLASSES_ROOT\Interface\{A9515AD7-5B85-11D0-848F-00400526305B}\ProxyStubClsid] @="{00020420-0000-0000-C000-000000000046}" [HKEY_CLASSES_ROOT\Interface\{A9515AD7-5B85-11D0-848F-00400526305B}\ProxyStubClsid32] @="{00020420-0000-0000-C000-000000000046}" [HKEY_CLASSES_ROOT\Interface\{A9515AD7-5B85-11D0-848F-00400526305B}\TypeLib] @="{A9515ACA-5B85-11D0-848F-00400526305B}" "Version"="1.0" 

Notice that this file generates subtrees under the Registry's TypeLib and Interface keys. The third entry specifies the path for the version 1.0 TLB file. The 0 subkey stands for "neutral language." If you had a multilingual application, you would have separate entries for English, French, and so forth. Browsers use the TypeLib entries, and the Interface entries are used for runtime type-checking and, for an EXE component, marshaling the dispinterface.

How a Component Can Register Its Own Type Library

When an EXE component is run stand-alone, it can call the MFC AfxRegisterTypeLib function to make the necessary Registry entries, as shown here:

 VERIFY(AfxOleRegisterTypeLib(AfxGetInstanceHandle(), theTypeLibGUID,        "ex25b.tlb")); 

Shown here is theTypeLibGUID, a static variable of type GUID:

 // {A9515ACA-5B85-11D0-848F-00400526305B} static const GUID theTypeLibGUID = { 0xa9515aca, 0x5b85, 0x11d0, { 0x84, 0x8f, 0x00, 0x40, 0x05, 0x26,     0x30, 0x5b } }; 

The AfxRegisterTypeLib function is declared in the afxwin.h header, which requires _AFXDLL to be defined. That means you can't use it in a regular DLL unless you copy the code from the MFC source files.

The ODL File

Now is a good time to look at the ODL file for the same project.

 // ex25b.odl : type library source for ex25b.dll // This file will be processed by the MIDL compiler to produce the //  type library (ex25b.tlb) [ uuid(A9515ACA-5B85-11D0-848F-00400526305B), version(1.0) ] // GUID for the type library—matches TypeLib Registry key and  //  AfxOleRegisterTypeLib parameter library Ex25b {     // library name for Excel's object borrower     importlib("stdole32.tlb");     // primary dispatch interface for CEx25bAuto     [ uuid(A9515AD7-5B85-11D0-848F-00400526305B) ]     // GUID from component's interface map—matches Registry Interface      //  entry     dispinterface IEx25bAuto     {         // name used in VBA Dim statement and Object list         properties:             // NOTE - ClassWizard will maintain property             //  information here.             //  Use extreme caution when editing this section.             //{{AFX_ODL_PROP(CEx25bAuto)             [id(1)] long LongData;             [id(2)] VARIANT TextData;             //}}AFX_ODL_PROP         methods:             // NOTE - ClassWizard will maintain method              //  information here.             //  Use extreme caution when editing this section.             //{{AFX_ODL_METHOD(CEx25bAuto)             [id(3)] boolean DisplayDialog();             //}}AFX_ODL_METHOD     };     [ uuid(A9515AD8-5B85-11D0-848F-00400526305B) ]      // component's CLSID          coclass Ex25bAuto     {         [default] dispinterface IEx25bAuto;     };     //{{AFX_APPEND_ODL}} }; 

As you can see, numerous connections exist among the Registry, the type library, the component, and the VBA client.

A useful Visual C++ utility, OLEVIEW, lets you examine registered components and their type libraries.

How Excel Uses a Type Library

Let's examine the sequence of steps Excel uses to utilize your type library:

  1. When Excel starts up, it reads the TypeLib section of the Registry to compile a list of all type libraries. It loads the type libraries for VBA and for the Excel object library.

  2. After starting Excel, loading a workbook, and switching to the Visual Basic Editor, the user (or workbook author) chooses References from the Tools menu and checks the EX25B LIB line.

    When the workbook is saved, this reference information is saved with it.

  3. Now the Excel user will be able to browse through the EX25B properties and methods by choosing Object Browser from the Visual Basic Editor's View menu to view the Object Browser dialog.

  4. To make use of the type library in your VBA program, you simply replace the line

     Dim DllComp as Object 

    with

     Dim DllComp as IEx25bAuto 

    The VBA program will exit immediately if it can't find IEx25bAuto in its list of references.

    click to view at full size.

  1. Immediately after VBA executes the CreateObject statement and loads the component program, it calls QueryInterface for IID_IEx25bAuto, which is defined in the Registry, the type library, and the component class's interface map. (IEx25bAuto is really an IDispatch interface.) This is a sort of security check. If the component can't deliver this interface, the VBA program exits. Theoretically, Excel could use the CLSID in the type library to load the component program, but it uses the CLSID from the Registry instead, just as it did in late binding mode.

Why Use Early Binding?

You might think that early binding would make your Automation component run faster. You probably won't notice any speed increase, though, because the IDispatch::Invoke calls are the limiting factor. A typical MFC Invoke call from a compiled C++ client to a compiled C++ component requires about 0.5 millisecond, which is pretty gross.

The browse capability that the type library provides is probably more valuable than the compiled linkage. If you are writing a C++ controller, for example, you can load the type library through various COM functions, including LoadTypeLib, and then you can access it through the ITypeLib and ITypeInfo interfaces. Plan to spend some time on that project, however, because the type library interfaces are tricky.

Faster Client-Component Connections

Microsoft has recognized the limitations of the IDispatch interface. It's naturally slow because all data must be funneled through VARIANTs and possibly converted on both ends. There's a new variation called a dual interface. (A discussion of dual interfaces is beyond the scope of this book. See Kraig Brockschmidt's Inside OLE, 2d ed. [Microsoft Press, 1995], for more information.) In a dual interface, you define your own custom interface, derived from IDispatch. The Invoke and GetIDsOfNames functions are included, but so are other functions. If the client is smart enough, it can bypass the inefficient Invoke calls and use the specialized functions instead. Dual interfaces can support only standard Automation types, or they can support arbitrary types.

There is no direct MFC support for dual interfaces in Visual C++ 6.0, but the ACDUAL Visual C++ sample should get you started.



Programming Visual C++
Advanced 3ds max 5 Modeling & Animating
ISBN: 1572318570
EAN: 2147483647
Year: 1997
Pages: 331
Authors: Boris Kulagin

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net