Programming with Microsoft Visual C++.NET 6ed [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming with Microsoft Visual C++.NET 6ed [Electronic resources] - نسخه متنی

George Shepherd, David Kruglinski

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید








VBA Early Binding


When you ran the Ex23a, Ex23b, and Ex23c 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 DISPID from the symbolic name. Not only is this inefficient, but VBA can't do type checking until it actually accesses a property or a method. Suppose, for example, that a VBA program tries to get a property value that it assumes is a number, but the component provides a string instead. VBA will give you a run-time error when it executes 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++ .NET generates a TLB file for each component. In order for VBA to locate that type library, its location must be specified in the Windows Registry. Browsers use the TypeLib Registry entries, and the COM runtime uses the Interface Registry entries for run-time 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 as a standalone, it can call the MFC AfxRegisterTypeLib function to make the necessary Registry entries, as shown here:

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

Here is theTypeLibGUID, which is 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 and requires _AFXDLL to be defined. This means you can't use the function in a regular DLL unless you copy the code from the MFC source files.



The IDL File


Now is a good time to look at the IDL file for the same project:

// Ex23b.idl : type library source for Ex23b.dll
// This file will be processed by the MIDL compiler to produce the
// type library (Ex23b.tlb).
#include "olectl.h"
[ uuid(EE56DC40-B710-4543-8841-8D9C27ADA504), version(1.0) ]
library Ex23b
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
// Primary dispatch interface for Ex23bAuto
[ uuid(125FECB2-734D-49FD-95C7-FE44B77FDE2C) ]
dispinterface IEx23bAuto
{
properties:
[id(1), helpstring("property LongData")] LONG LongData;
[id(2), helpstring("property TextData")] VARIANT TextData;
methods:
[id(3), helpstring("method DisplayDialog")]
VARIANT_BOOL DisplayDialog(void);
};
// Class information for Ex23bAuto
[ uuid(BAF3D9ED-4518-43CA-B017-2EBA332CB618) ]
coclass Ex23bAuto
{
[default] dispinterface IEx23bAuto;
};
};

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





Note

The Visual C++ utility called OLEVIEW lets you examine registered components and their type libraries.




How Excel Uses a Type Library


Let's examine the sequence of steps that Excel takes to use 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 Ex23b LIB line, as shown below. When the workbook is saved, this reference information is saved with it.




  3. Now the Excel user can browse through the Ex23b properties and methods by choosing Object Browser from the Visual Basic Editor's View menu to view the Object Browser dialog box, as shown here:





  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 IEx23bAuto

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



  5. Right after VBA executes the CreateObject statement and loads the component program, it calls QueryInterface for IID_IEx23bAuto, which is defined in the Registry, the type library, and the component class's interface map. (IEx23bAuto is really an IDispatch interface.) This is a sort of security check. If the component can't deliver this interface, the VBA program will exit. Theoretically, Excel can 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 will 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 milliseconds.

The browse capability that the type library provides is probably more valuable than the compiled linkage. If you're 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. This interface is naturally slow because all data must be funneled through VARIANT arguments and possibly converted on both ends. There's a new variation, however, called a dual interface. In a dual interface, you define your own custom interface, which is 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 either support only standard Automation types or support arbitrary types. (A detailed 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.)

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



/ 319