COM Component Design and Application (11)

Source: Internet
Author: User
Idispatch and dual Interfaces .

Author: Instructor Yang

Download source code

I. Preface
Some time ago, due to busy work, I was not able to write in time. In the meantime, I received a letter from many netizens asking and encouraging me. I would like to express my gratitude to you here. Cough... I also need a job to support my family ......
The previous response introduced two methods to write component programs for the automated (idispatch) interface. One is to write the "pure" idispatch interface in the MFC mode; the second is to use the ATL method to compile the "dual interface" component.

Ii. idispatch and dual Interfaces
To call common COM component functions, you must load the Type Library File TLB (for example, # import in VC) of this component ). However, in a script program, because the script is interpreted and executed, you cannot use the method of loading the Type Library for pre-compilation. So how does the script interpreter use the COM component? This is where the automation (idispatch) component is amazing. The idispatch interface needs to implement four functions. The caller can call all functions of the automation component only through these four functions. The four functions are as follows:
 

Hresult gettypeinfocount (
[Out] uint * pctinfo)
How many types of libraries are provided in the component? Of course, it is generally one.
However, if you implement multiple idispatch interfaces in a component, it is not necessary (note 1)
Hresult gettypeinfo (
[In] uint itinfo,
[In] lcid,
[Out] itypeinfo ** pptinfo)
The caller uses this function to obtain the desired type library.
Fortunately, in the case of 99%, we don't need to care about the implementation of these two functions, because both MFC and ATL help us complete the default implementation. If we complete the function code by ourselves, you can even directly return e_notimpl to indicate that no implementation is implemented. (Note 2)
Hresult getidsofnames (
[In] refiid riid,
[IN, size_is (cnames)] lpolestr * rgsznames,
[In] uint cnames,
[In] lcid,
[Out, size_is (cnames)] dispid * rgdispid)
Obtain the function serial number based on the function name to prepare for calling invoke.
The so-called function serial number, you can observe the double interface IDL file and the odl file of MFC, each function and attribute will have a description like [ID (serial number.
Hresult invoke (
[In] dispid dispidmember,
[In] refiid riid,
[In] lcid,
[In] Word wflags,
[In, out] dispparams * pdispparams,
[Out] variant * pvarresult,
[Out] partition info * p1_info,
[Out] uint * puargerr)
Execute the function according to the serial number.
We do not need to care about the implementation of the component program written using MFC/ATL. If you write your own code, this function is similar to the following:
Switch (dispidmember)
{
Case 1:...; break;
Case 2:...; break;
....
}
In fact, branch calling is performed according to the serial number. (Note 3)
 

From the implementation of the invoke () function, we can see that the execution efficiency of the program using the idispatch interface is relatively low. From the perspective of efficiency, ATL implements an interface mode called dual. Let's take a look at what a dual interface is:


Figure 1 dual INTERFACE STRUCTURE

It can be seen that the so-called double interface actually contains three interfaces in a virtual function table of a vtab (because any interface is derived from iunknown, so I will not emphasize iunknown, is called a double interface ). If we call QueryInterface () from any interface to obtain another interface pointer, the obtained pointer address is the same. What are the advantages of the double interface? A: Okay, how good, especially good ......
 

Usage Because So
Script Language component The interpreter only recognizes the idispatch interface. Can be called, but the execution efficiency is the lowest
Use components in compiled languages It recognizes the idispatch Interface Can be called, and execution efficiency is relatively low
Use components in compiled languages After it loads the type library, it knows the ixxx interface. You can call the ixxx function directly, with the highest efficiency.

Conclusion

The dual interface not only meets the ease of use of the script language, but also meets the efficiency of the compilation language.
So are all the COM component interfaces we write implemented using double interfaces?
Error! No! No!
If you do not explicitly want to support script calls, it is best not to use dual interfaces, because:

If all functions are placed in a double interface, the hierarchy, structure, and category are unclear.
If multiple dual interfaces are used, other problems may occur (note 4)
The dual interface and idispatch interface only support Automatic Parameter types, which are restricted and inconvenient to use in some cases.
There are still many disadvantages, but I cannot think of them now ......

Iii. Usage
If your development environment is vc6.0, use the simple6 component in the ninth return as an example to download it ......
If your development environment is vc.net 2003, use the simple8 component in the tenth return as an example to download it ......
Hey, it doesn't matter if you don't download it, because you only need to download this sample program, which contains the required components. But do not forget to register it before using it: regsvr32.exe simple6.dll or regsvr32.exe simple8.dll (do not forget to enter the installation directory of the component ). After successful registration, you can use the following methods:
 

Sample program Use of automated components Brief Description
Example 0 Call in script In the ninth or tenth rounds, we have already introduced
Example 1 API call Reveal the call principle of idispatch, but it will be exhausted if you use it like this.
Example 2 Smart pointer packaging class using ccomdispatchdriver This is much easier than using APIs directly!
Example 3 How to package an MFC loaded Library Simple! Easy to use! Common! However, it uses the idispatch interface in essence, so the execution efficiency is slightly lower.
Example 4 Use the # import method to load the Type Library # Use components in import mode. Let's talk about them in the seventh session. Common! For dual-interface components, you can directly call user-defined interface functions without going through idispatch, so the execution efficiency is the highest.
Example x VB, Java, C #, BCB, Delphi ....... I will not, but I will go to consult senior personnel.

Example 1: How idispatch works

Void demo () {: coinitialize (null); // com initialize CLSID; // obtain clsidhresult hR =: clsidfromprogid (L "simple8.dispsimple. 1 ", & CLSID); Assert (succeeded (HR); // if a failure occurs, it indicates that the idispatch * Pdisp = NULL is not registered. // The component is started by clsid, and get the idispatch pointer hR =: cocreateinstance (CLSID, null, clsctx_all, iid_idispatch, (lpvoid *) & Pdisp); Assert (succeeded (HR); // if it fails, comlpolestr pwfunname = l "add" is not initialized; // you are prepared to obtain the serial number dispiddispid of the add function; // The obtained serial number, prepare to save to here hR = Pdisp-> getidsofnames (// function iid_null, & pwfunname, // array 1 of function names based on function names, // The number of elements in the function name array locale_system_default, // use the default language environment & dispid); // return value assert (succeeded (HR); // if it fails, the component does not have the variantarg V [2]. // The parameter V [0] required to call the add () function. vt = vt_i4; V [0]. lval = 2; // The second parameter, an integer of 2 V [1]. vt = vt_i4; V [1]. lval = 1; // The first parameter, integer 1 dispparams = {v, null, 2, 0}; // wrap the parameter in this structure variant vresult; // The calculation result hR = Pdisp-> invoke returned by the function (// call the function dispid, // The function is specified by the dispid iid_null, locale_system_default, // use the system's default language environment dispatch_method, // The method is called, not the attribute & dispparams, // parameter & vresult, // return value null, // ignore Exception Handling null ); // do not consider assert (succeeded (HR) for error handling; // if the request fails, the parameter passing error cstring STR; // The result STR is displayed. format ("1 + 2 = % d", vresult. lval); afxmessagebox (STR); Pdisp-> release (); // release interface pointer: couninitialize (); // release com}

Example 2: How to Use the ccomdispatchdriver smart pointer packaging class

Void demo () {// The clsid CLSID has been initialized by com; // obtain the clsidhresult hR =: clsidfromprogid (L "simple8.dispsimple. 1 ", & CLSID); Assert (succeeded (HR); // if a failure occurs, the ccomptr <iunknown> spunk is not registered. // The clsid starts the component, and get the iunknown pointer hR =: cocreateinstance (CLSID, null, clsctx_all, struct, (lpvoid *) & spunk); Assert (succeeded (HR); ccomdispatchdriver spdisp (spunk ); // The constructor can only pointer ccomvariant V1 (1), V2 (2), vresult; // parameter hR = spdisp. invoke2 (// call the function L "add" with two parameters, // The function name is add & V1, // The first parameter, the value is an integer 1 & V2, // The second parameter; Value: integer 2 & vresult); // return value assert (succeeded (HR); // if it fails, it indicates that or no add function is available, or the parameter is invalid cstring STR; // The result STR is displayed. format ("1 + 2 = % d", vresult. lval); afxmessagebox (STR );}

The invoke2 () function is used in the example program. In fact, you can also use invoke0 (), invoke1 (), invoken (), putproperty () based on different functions (), getproperty ()...... and so on.

Example 3: load the Type Library and generate a packaging class to use
This method is simpler to use. If you observe the implementation of the packaging class that MFC helps you produce, you will find that it actually calls the idispatch interface function. To use vc6.0, follow these steps:
1. Create an MFC Application
2. Enable classwizard, execute add class, and select from a Type Library


Figure 2. Load Type Library

3. Find the component File simple6.dll you want to use (The TLB file can also be used), select the interface, and then confirm


Figure 3. Select the interface to be packaged in the Type Library

4. Enter the call code where appropriate

# Include "simple6.h" // the header file void demo () of the packaging class {// It has been initialized by com. The idispsimple spdisp; // The spdisp object of the packaging class. createdispatch (_ T ("simple6.dispsimple. 1 ") // start the spdisp component. XXX (...); // call the function spdisp. releasedispatch (); // Release Interface}

To use vc.net, follow these steps:
1. Create an MFC Application
2. Execute the "Add/Add class" menu and select "Type Library in the MFC category"


Figure 4. Add the MFC class in the Type Library

3. Select the component File simple8.dll (or TLB file) and the interface to be packaged.


Figure 5. Select files and interfaces

4. Enter the call code at an appropriate location

# Include "cdispsimple. H "// the header file void demo () of the packaging class {// has initialized the cdispsimple spdisp through COM; // The spdisp object of the packaging class. createdispatch (_ T ("simple8.dispsimple. 1 ") // start the spdisp component. XXX (...); // call the function spdisp. releasedispatch (); // Release Interface}

Example 4: Use # import to call Components
# The import method has been introduced in the seventh round, so it is not a long time. After downloading the sample program in this example, you can check it out. And you must master this method, because it runs at the fastest speed.

Iv. Summary
Leave homework. In all the component programs we previously implemented, only interface methods (functions) are added, but interface properties (variables) are not added. It's very easy to practice by yourself, then write a program to call it. In fact, for VC, there is not much difference between calling properties and calling methods (VC packs properties as getxxx ()/putxxx () or getxxx ()/putxxx () function methods ), however, in other languages (such as the scripting language), it is more convenient to set the attribute value to: object. property = variable or constant. Get the property value: Variable = object. attribute.
At this point, this book has been broken down. I have more knowledge about component design and usage, and I will try again to break it down ......

NOTE 1: The implementation of multiple automated interfaces will be discussed later.
NOTE 2: when you introduce itypelib: gettypeinfo () in the future, let's review idispatch: gettypeinfo.
NOTE 3: When we introduce "events" later, we will actually implement an idispatch: invoke () function.
Note 4: This issue will be discussed when multiple dual interfaces are introduced.
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.