COM Component Design and Application (2)

Source: Internet
Author: User

COM Component Design and Application (2)
Guid and Interface

Author: Instructor Yang

I. Preface

After the book is connected, the problem of saving XLS (Excel) data has been solved in the DOC (Word) composite file. Then, we need to solve another problem: when the word program reads the composite file and encounters XLS data, how can it start Excel? How can I enable EXCEL to read, parse, and display XLS data?

Ii. CLSID Concept

There is a very simple solution, that is, to store the program name that processes the data before the object data. (See the upper left corner)

Figure 1. CLSID Concept

This is indeed a simple method, but the problem is also very serious. On the computer of "James", the Excel path is "C: \ Office \ excel.exe". If you copy this doc file to the computer of "James, the Excel path of "Li Si" is:
"D: \ Program Files \ Microsoft Office \ excel.exe", finished :-(
As a result, Microsoft came up with a solution, that is, to indirectly describe the path of the processing program of these object data using CLSID (Note 1) instead of a direct path representation method. CLSID is actually a number, or a 16-byte number. Observe the Registry () and save the program path name in localserver32 (DLL component uses inprocserver32) under the primary key of hkcr \ CLSID. The clsid structure is defined as follows:

Typedef struct _ guid {DWORD data1; // random number word data2; // time-related word data3; // time-related byte data4 [8]; // related to NIC Mac} guid; typedef guid CLSID; // component idtypedef guid IID; // Interface ID # define refclsid const CLSID & // common statements and value assignment methods CLSID clsid_excel = {0x00024500,0x0000 ,0 x ,{ 0xc0, 0x00,0x00,0x00,0x00,0x00,0x00,0x46 }}; struct _ declspec (UUID ("uid") clsid_excel; Class declspec_uuid ("uid ") clsid_excel; // the representation in the Registry {00024500-0000-0000-c000-000000000046}

Using a number to indirectly represent the program name is indeed a good idea, which achieves the transparency of the component location and facilitates the expansion of DCOM (remote component ). But, but, but... CLSID has 16 bytes totaling 128 bits. Why do we use such a long number? When I was still in kindergarten, people designed socket and used TCP/IP protocol for network communication. Each computer involved in communication has a 4-byte IP address, ranging from 0 to 0 ~ 255,255,255,255. A total of 4.2 billion addresses. However, I did not expect that, since the Internet chose the TCP/IP protocol, the allocation of 4.2 billion addresses is not enough for the working people of the world. In addition to working people, refrigerators, color TVs, rice cookers, mobile phones, and laptops all need to be connected to the Internet. Enable the rice cooker in the office to cook rice for me. After work, I will be able to eat ready-made rice. How happy ?! (Note: My wife is a leader in our house, so I cook. Cough ......)
Thanks to the lessons learned, Microsoft designed CLSID/IID to use 16 bytes of the guid concept. Well, there are 6 billion people around the world, and each person is assigned 1 billion numbers per second, you need to allocate 180 billion years. It will not be used until the earth is gone :-)

3. Generate CLSID
 

  1. If you use the development environment to write component programs, IDE will automatically generate CLSID for you;
  2. You can manually write CLSID, but do not repeat it with the CLSID generated by others, so it is not recommended to do it seriously. (However, Microsoft's CLSID is all written manually, which is called "only Xu Zhou officials set fire, click ");
  3. In the program, you can use the cocreateguid () function to generate CLSID;
  4. Use the tool to generate a guid (note 2 );

Run the "VC directory \ common \ tools \ guidgen.exe" program in vc6.0 (you can add the tool program to the development environment by referring to the method described in the previous article to facilitate calling ). In the vc.net version, you can run the command in the menu "tool \ create guid.

IV,ProgidConcept

A CLSID must be specified for each COM component and cannot be duplicated. It uses 16 bytes, which means it is "impossible" to ensure the repetition probability. However, for ease of use, Microsoft also supports another string name method called progid (note 3 ). See the progid subkey content of the Registry (note 4 ). Since CLSID and progid are actually two different representations of a concept, we can use either of them in the program. (Some people hate it and do not count. Clearly, the purpose of GUID is to prohibit duplication, but it is allowed to use progid ?! Progid is the name of a string, which is too likely to be repeated. I am also writing a program. I plan to use the progid of this program as "Excel. Application".) The following describes the conversion methods and related functions between CLSID and progid:

Function Function Description
Clsidfromprogid (), clsidfromprogidex () Obtain CLSID from progid. There's nothing to say. You can write it yourself. check Registry Bay.
Progidfromclsid () The progid is obtained by clsid. After the caller completes using the progid, The progid memory will be released (note 5)
Cocreateguid () Generates a guid randomly.
Isequalguid (), isequalclsid (), isequaliid () Compare whether two IDs are equal
Stringfromclsid (), stringfromguid2 (), stringfromiid () The clsid-style string in the registry is obtained by clsid and IID. Note that the memory is released.

V. History of interfaces

By now, we know that CLSID or progid uniquely represents a component service program. Based on these IDs, you can load and run components and provide services for client programs. (The method for starting the component program will be introduced one after another ). Next, we will discuss how to call functions provided by components? ----- Interface.
As a client programmer, it hopes or requires that my program only writes once and can call any component without any modification. For example:

  1. You can embed excel in word, picture, and ActiveX documents published by any third party ...... that is to say, even the word itself does not know what the person who uses it will insert into the doc;

  2. You can insert an ActiveX into an HTML file, or a Script script,... plug-in you write yourself can also be inserted into the IE environment. In order to complete your function, you will never ask Microsoft to modify IE ?!

This requirement is a bit difficult, and office development is stuck. Coincidentally, one day old O (the Chief Engineer of the Office Project) and Small B (the Chief Engineer of the VB project) were drinking together, and old o talked to Mr. B about his troubles:
Old O: How can I write program C and call functions in program s written by others? (C indicates the customer program, and s indicates the program that provides the service)
B: Are you confused? Let s be a DLL. You can go to loadlibrary (), getprocaddress (),... freelibrary ()?!
Old O: Nonsense! It would be easy. The problem is, I don't even know what the s program is doing? What can we do? How can I call it?
Small B: Oh... This is relatively advanced, but I cannot tell you, because I'm afraid you are not impressed.
Old O :~! · # ¥ % ...... -*......
Small B: Well, in VB, we have developed a standard that allows any VB developer to put a function applet written by him on the toolbar of VB, in this way, it seems that he has extended the functions of VB.
Old O: Oh? That's what vbx is?
Small B: I'm sorry... don't look at vbx. I did not see it. But guess what? Tens of thousands of VB programmers put their vbx applets with various functions on the Internet for sharing.
Old O: Oh ~~~, So what is your vbx standard?
Small B: Hey hey ...... it is very simple, that is, seven functions must be implemented in vbx. The seven function names and functions must be initialization, release, display, and Message Processing ......, I cannot care about what it wants internally. I only need to call the Seven functions I need when needed.
Old O: Oh ~~~, That's all... By the way, I have an emergency. I'm leaving. 88. Pay the bill ......
Small B: Hello! Hello... What are you doing when you are in such a hurry? Your wallet is lost :-)
Old O lost his wallet and rushed back to the office excitedly. He began to think ......

1. My program C should be able to call program B written by anyone. Then B must provide the functions F1 (), F2 (), F3 (), K1 (), and K2 () as required in advance ().
2. Basic is interpreted and executed, so its functions do not need to consider the writing order, as long as the function name is given, the interpreter can find it. But I am using C ++ ......
3. After C ++ compilation, the Code does not contain the function name and only the function address. Therefore, I must improve the function entry by using vtab (virtual function table:

Figure 2. vtab Structure

4. It is not good enough. It should be improved because all function addresses in a table are not flexible, difficult to modify, and difficult to expand. Well, you have it! Function types:

Figure 3 structure of multiple vtabs

5. Now there are two vtab virtual function tables. How can I find another table from one table? Well, you have another solution. I want you to implement a function, and the function address must be placed at the beginning of all tables (the first function pointer in the table ), this function is called QueryInterface (). It completes the function of searching from one table to another: (in addition to the QueryInterface () function, it also completes the other two functions, called addref () and release (). The functions of these two functions will be discussed later)

Figure 4. COM interface structure

6. For the convenience of future description, the method (figure 4) is no longer used, and the concise style shown in Figure 5 is used:

Figure 5. Simple COM interface structure

Vi. interfaces (Interface) Concept

1. functions provide their addresses through the vtab virtual function table. from another perspective, no matter what language is used for development, the code generated by the compiler can generate this table. In this way, the "binary feature" of the component is easily implemented to meet the cross-language requirements of the component.
2. Assume that a pointer variable stores the first address of the vtab. This variable is called "interface pointer" (note 6). When the variable is named, traditionally, it starts with "I. In addition, to distinguish different interfaces, each interface must have a name, which is the same as CLSID and is called IID in guid mode.
3. Once the interface is published, it cannot be modified. Otherwise, the forward compatibility problem may occur. This property is called "interface immutability ".
4. The component must have three functions: QueryInterface, addref, and release. They also form an interface called "iunknown ". (Note 7)
5. Any interface actually contains the iunknown interface. As you access more interfaces, you will be more aware of the "inheritance" of the interface ".
6. On any interface, calling the first function in the table is actually calling the QueryInterface () function to obtain another interface pointer you want. This is called "interface transmission"
7. If function declaration is required in C/C ++, the component must also provide the header file of C language. No! To enable com to have cross-language capabilities, it is decided not to provide the corresponding function interface declaration for any language, but to independently provide a declaration called the Type Library (TLB. The IDE environment of each language generates the packaging required by its own language based on TLB. This is called "Independence of interface declaration" (note 8)

VII. Customer ProgramNegotiated call with components

  Back to our previous topic, if a component is embedded in word, how does word negotiate to use this component? The following is a simulated dialog process between containers and components:
 

  ContainerNegotiation Component response
1 Start the component according to clsid.
Cocreateinstance ()
Generate the object, execute the constructor, and execute the initialization action.
2 Do you have the iunknown interface? Yes. Here you are!
3 Well, that's great. Do you have the ipersiststorage interface? (Note 9)
Iunknown: QueryInterface (iid_ipersiststorage ...)
No!
4 It's really bad. I don't even have this. Do you have the ipersiststreaminit interface? (Note 10)
Iunknown: QueryInterface (iid_ipersiststreaminit ...)
Ha, this one is available!
5 Okay, okay. It's similar. You can initialize it for me now.
Ipersiststreaminit: initnew ()
OK. Initialization is complete.
6 Finished? Good! Now you can read the data.
Ipersiststreaminit: load ()
After reading it. Based on the data, it is displayed in the window.
7 Okay. Now let's process the user's mouse and keyboard messages ...... ......
8 Oh! The user wants to save and exit the program. Has your data been modified by the user?
Ipersiststreaminit: isdirty ()
Changed. The user has modified the settings.
9 Well, how much storage space does your data need after the user modifies it?
Ipersiststreaminit: getsizemax ()
Well, I am counting... okay, it takes kb in total.
10 Dizzy, how much space do you use such a gadget ?!...... Okay, you can save it.
Ipersiststreaminit: Save ()
Thank you. I have saved it.
11 Well. Thank you. (Note 11)
Ipersiststreaminit: release (); iunknown: release ()
Execute the destructor to delete the object.
12 I should quit myself ......
Postquitmessage ()
 

The container (or client) communicates with the component and negotiates the call. If component A implements the IA interface, the container will use it. If component B does not provide the IA interface, but it provides the IB interface, then the container will call the function of the IB interface ...... in this way, the container program does not need to know what the component is, what language the component is developed in, and where the disk location of the component is. Amazing! Wonderful! Why is it easy!

VIII. Summary

In the second session, two very important concepts are introduced: CLSID and interface. Since the entire article is a conceptual description without the help of sample programs, the reader may not be very thorough or thorough in understanding it. Don't worry, we are about to enter the component program design stage. At that time, you will read this article again based on the specific program code. Why? Oh... read again! Slowly, the old man understands this :-)

Leave homework ......
1. What is the iid of the idispatch interface? (Ah ~~~ Stupid. In the source program, right-click and execute go to definition)
2. How many functions does the ipicture interface have? What are functions? (Stop playing! How old are you? If you want to display jpg images in a program, go to msdn)
Do you want to know why the com function always returns hresult? Do you want to know how to use BSTR and variant? Want to know how to use memory in com? Do you want to know how to use Unicode ?...... ~~~, I can't tell you now, I tell you now, for fear that you are not impressed! And listen to the next decomposition ......

Note 1: CLSID = Class ID has introduced the functions for writing CLSID into the composite file: writeclassstg () and istorage: setclass ().
NOTE 2: GUID is a globally unique identifier. CLSID/IID actually uses the guid concept.
NOTE 3: progid = program id, equivalent to CLSID, is represented by a string.
NOTE 4: The registry subkeys progid and versionindependentprogid indicate the real progid and version-independent progid respectively. For example, if Excel is installed on my computer, its progid = "Excel. application.9", and versionindependentprogid = "Excel. application ".
Note 5: For memory management of the COM component, see subsequent articles.
Note 6: interface = interface. In the past, Microsoft did not call it an interface, but protocol. In fact, I think this word is more appropriate.
Note 7: iunknown is named "I don't know" :-). Its IID is iid_iunknown. If it is represented in registry style, its value is {commandid -0000-0000-c000-000000000046 }.
Note 8: TLB is generated by compiling the file IDL that describes the interface. For more information about IDL, see the subsequent articles.
Note 9: ipersiststorage is an interface used to save/read data using the storage function of composite files.
Note 10: ipersiststreaminit is an interface used to save/read data by using the stream function of the composite file.
Note 11: Goodbye. That's English. Goodbye.

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.