I. Preface
Book connection back,
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
When the program reads the composite file and encounters XLS data, how does it start Excel? How can I enable EXCEL to read, parse, and display XLS?
What about 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 the DOC file to the computer of "James, the Excel path of "Li Si" is:
"D:/program files/Microsoft Office/office/excel.exe", finished :-(
So Microsoft came up with a solution, that is, using
CLSID (Note 1) indirectly describes the path of the processing program for these object data. CLSID
It is actually a number, or a 16-byte number. Observe the Registry (), In the hkcr/CLSID/{...} primary key
Localserver32 (the DLL component uses inprocserver32) stores the program path name. 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 the MAC of the NIC
} Guid;
Typedef guid CLSID; // component ID
Typedef guid IID; // Interface ID
# Define refclsid const CLSID &
// Common statements and Assignment Methods
CLSID clsid_excel = {0x00024500,0x0000, 0 x, {0xc0, 0 x, 0 x, 0 x, 0 x, 0 x, 0 x, 0x46 }};
Struct _ declspec (UUID ("00024500-0000-0000-c000-000000000046") clsid_excel;
Class declspec_uuid ("00024500-0000-0000-c000-000000000046") clsid_excel;
// Indicates the method in the registry.
{00024500-0000-0000-c000-000000000046}
Using a number to indirectly represent the program name is indeed a good idea, achieving the transparency of component location and convenient Extension
DCOM (remote component ). But, but, but... CLSID
There are 16 bytes of 128-bit binary data. Why 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
4.2 billion addresses in total. However, I did not expect that, since the Internet has chosen TCP/IP
After the agreement, 4.2 billion addresses will not be allocated to the working people around the world. In addition to working people, refrigerators, color TVs, rice cookers, mobile phones, and laptops all need to be connected to the Internet. In the office
How happy is my meal when I get home from work after I open a rice cooker on the Internet ?! (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
- If you use the development environment to write component programs, IDE will automatically generate CLSID for you;
- 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 ");
- In the program, you can use the cocreateguid () function to generate CLSID;
- 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 vc.net, you can run the command in "tool/create guid.
IV,ProgidConcept
Each COM component must specify
CLSID. duplicate names are not allowed. It uses 16 bytes, which means it is "impossible" to ensure the repetition probability. However, Microsoft also supports
Another string name method is progid (note 3 ). See the progid subkey content of the Registry (note 4 ). Because CLSID and progid
It is actually two different forms of a concept, so we can use any one in the program. (Some people hate it and do not count. Clear guid
The purpose of progid is to prohibit duplication, but it is allowed to use progid ?! Progid
It is the name of a string, so it is too likely to be repeated. I also wrote a program, and I plan to use the progid of this program.
The following describes the conversion method 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:
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;
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 vtabs.
In a virtual function table, how can I find another table from one table? Well, you have another method. I want you to implement a function, and the function address must be placed at the beginning of all tables (the first function in the table refers
Needle), this function is called
QueryInterface (): (in addition to the QueryInterface () function, the other two functions are also completed by the way, 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,
C/C ++ must declare the function in advance.
The component must also provide the header file of the C language. No! In order 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 Type Library
(TLB) statement. 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
IA interface, but it provides the IB interface, then the container will call IB
Interface functions ...... 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 programming stage.
At that time, you read this article again based on the specific program code, but did not understand it? 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 com
How should I use the memory? 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 that the real progid is not related to the version.
Progid. For example, if Excel is installed on my computer, its progid = "Excel. application.9 ",
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.