COM technology talks

zhaozj2021-02-11  189

COM technology talks

-

TsingXIAO

I. Overview

Since the birth of the PC, the hardware has experienced countless changes, and the CPU has only only the original Intel 8086 until PIII is full.

Over ten years. Microsoft's Windows operating system from the initial version 1.0, now will now launch Win2000, has always been a desktop system

The largest OS. As a software developer, uses Visual Basic, Visual C , Delphi including the latest

Many development environments, such as Borland C Builder, etc. For Windows development applications. It should be said that the current development conditions and if

During the year, the year was greatly improved.

If you have developed 16 Windows programs, you may know that in order to read a file, we have to use a small assembly to adjust

Use the DOS routine or use the function that has not been disclosed at the time: _lopen (). In the Win32 environment, all you have to do is

Call:: CREATEFILE () to get a file handle, of course, if you use the MFC or OWL, you can be simpler

Do it. However, in general, programmers still have to write to each line of code to write applications from scratch.

But this situation has been changed: Microsoft proposes C O m (Component Object Model, Chinese can also be translated "component pair

Icon Model ") concept, and in the latest Windows 95/98 and Win NT4 use it: We have reason to believe in

In the near future, C O m will become the most common way to build applications. If you are interested in this technology, you may wish to refer to this article, hope

From it you can learn what you want to know. If you are already C O M old, you also welcome you to criticize, my email is

Singxiao@bigfoot.com

This article is written for C programmers. When introducing the concept, I try not to mix the knowledge of the Win32 API, so that you can

Clearable see the essence of C O m. All examples are compiled with Microsoft Visual C 5 (SP3).

Generally speaking, an application is always consisting of a single binarily. Before, if this program needs to do some improvements,

To modify the source code, then compile, claim new files, and replace the original file. Now we ask for a new perspective

Question: Put the original EXE executable, divided into success, but relatively independent parts, put them, group

Procedure, constitutes software. After the future program is released, if you realize that you need to modify him, just replace problems or needs

The upgrade is scheduled. It can even be replaced with the components that do not affect the normal operation of the program. If you are familiar with

Windows programming, you may think of: DLL seems to be what you said: can be dynamically connected. In fact, COM is fully utilized.

The flexibility of Win32 DLL is actually implemented on the Windows platform.

What are the advantages of doing this? First of all: Users generally want to customize the applications used, and component technology is essentially

Customized, thus users can replace the original one by one of the components they need. Second, since the component is corresponding

Using program independent parts, we can use the same component in different programs without any problems, and the software's reusability

Greatly enhanced. Third, with the increase in network bandwidth and its importance, distributed network applications have undoubtedly become more important to buy points in the software market. Component density can make the process of developing such applications to be simplified.

So what is CoM? It is a specification that explains how to build a dynamic interrelation. He defined some to ensure that

Operation, customer (one term, a program that requires a certain component) Components must follow the standards that the COM specification is a set of component architectures.

Set the specification of the standard document form. The release form of COM is: Shape with Win32 Dynamic Link Library (DLL) or Executable File (EXE)

The executable code consisting of the formula release.

The COM component is dynamically connected, and the COM component is completely unrelated to the language. At the same time, COM components can be released in binary form.

COM components can also be upgraded into new versions without hindering old customers.

You can now think that the services that COM can provide some of the classes in C . However, the class is based on the source code, COM is not. Do not

Here to clarify some error perspectives about COM: First, COM is not a computer language. Put the COM in a computer language (such as

C , VB) is meaningless. Second, don't compare DLL and COM, because COM technology is using DLL dynamics

The link capacity is achieved, and now general views believe that the best way to utilize DLL dynamic link capabilities is COM. Of course, COM

Nor is a function set like Win32 API: it does not support or provide functions like MoveWindow to make

Specific operation. COM is not similar to the C class library such as MFC. CoM provides developers a group of development and language-independent groups

The method of the library, but COM itself does not provide any implementation. To a certain extent, COM can be considered systemically independent, Software AG

Organization is developing a series of COM support systems, which is expected to operate from Mac OS, VMS, Sco Unix to Linux from Mac OS, VMS, SCO UNIX.

COM will be implemented on the system. COM does have some specific implementation. COM itself wants to achieve a COM Library

API, providing a series of services such as customers inquiries, and registration / anti-registration of components, in general, COM libraries

Realization, programmers do not have to care about their implementation. Overall, COM provides a standard method for writing components. Follow COM

The standard component can be combined to form an application. As for those of these components, it is not important to achieve it. Assembly

And contact between customers through "interface".

Two: What is interface

As mentioned earlier, the only way to deal with the COM component and the customer is through the interface. In the implementation of C , we generally use

This component is implemented using the base class to define the interface and then utilize multiple inheritance of the C class. The following shows a simple schematic:

// iface.h

#ifndef ifce_h

#define ifce_h 1

#define interface class

Interface IA

{

PUBLIC:

Virtual func1 () = 0;

Virtual func2 () = 0;

}

Interface IB

{

PUBLIC:

Virtual func3 () = 0;

Virtual func4 () = 0;

}

#ENDIF

//--iFace.h end - //

// Test.c

#include "iface.h"

Class Ca: Public IA, IB {

PUBLIC:

CA (INT I): m_count (i) {}

Virtual func1 () {cout << "ia :: func1 is" ​​<< m_count * 1 << endl;} Virtual func2 () {cout << "ia :: func2 is" << m_count * 2 << endl;} Virtual func3 () {cout << "ib :: func3 is" << m_count * 3 << endl;} Virtual func4 () {cout << "ib :: func4 is" << m_count * 4 << endl;} INT M_COUNT;}; main () {IA * PIA; IB * PIB; CA * PCA = "New" CA (2); PIA = "PCA;" PIA> FUNC1 ();

PIA -> FUNC2 ();

PIB -> FUNC3 ();

PIB -> FUNC4 ();

DELETE PCA;

}

//--test.c end - //

In the above example, two interfaces are defined, you can notice that all of their members functions are declared as Virtual, and in functions

The end was ended with = 0. Similar to this function we are in C as a pure virtual function, if the entire class is made of pure virtual function

Come, then this class is called abstract base class. The abstract base class itself is not allocated because there is no physical function and variables. Generally

The purpose is to specify a memory structure for derived classes. For example, it seems to split the house into many small rooms, which are stipulated which

What to put (the entity of the function), but the specific thing should wait for the derived class to fill.

Here is a concept that needs to be explained: The component is not class, and we have implemented two sets of interfaces with a class, and we also

It can be used to implement more interfaces. The component itself is actually just an interface set and its collection thereof. One component may contain multiple connections

The mouth, each interface has its own implementation. At the same time, the interface is not always inherited, and the COM specification does not require a certain interface.

It must be inherited from that interface. This is because customers don't know the inheritance relationship of COM components. Inheritance to the interface is just a detail of implementation

Yes.

The QueryInterface function will be described below. This function is used to query other interfaces. The communication between the client is passed

The interface is completed. Even if the customer queries other components, it also needs to pass an interface (in other words, if a component does not support

This interface, then he must not be a COM component) The name of this interface is IUnknown, which has three functions, as shown below:

Interface IUnknown

{

Virtual HRESULT __STDCALL QUERYINTERFACE (Const IID & IID, VOID ** PPV) = 0;

Virtual ulong __stdcall addref () = 0;

Virtual ulong __stdcall release () = 0;

}

All interfaces of the COM component have inherited IUNKNOWN, so that the top three functions of each interface are queryinterface,

This is all COM interfaces can be handled as iUnknown. Customer only through a CocreateInstance function

You can create instances of the component and get it iUnknown *. HRESULT __STDCALL COCREATEINSTANCE

Const CLSID & CLSID,

IUNKNOWN * PIUNKNOWNOUTER,

DWORD DWCLSCONTEXT,

Const IID & IID,

void ** PPV

);

The following CODE demo creates a component:

EXTERN "C" const guid clsid_com1 =

0x32bb8230, 0xb41b1 0x11cf, 0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82);

EXTERN "C" const guid iid_ix =

0x32bb8230, 0xb591c 0x11ff, 0xc1, 0xb0, 0xc7, 0xf8, 0x21, 0x35, 0x1c, 0x2f);

Coinitialize ();

IA * PIX = NULL;

HRESULT HR = :: COCREATEINSTANCE

CLSID_COM1,

NULL,

CLSCTX_INPROC_SERVER,

IID_IX,

(void **) & PIX

);

En (ac))

{

PIX -> fx ();

Pix -> Release ();

}

Extern "C" const guid is actually a so-called "global unique marker" (Global Unique Identifier). We specify

It represents different interfaces. In other words, if you find that there are two GUIDs identical, you completely reason to believe that they are indicated by the same

interface. (There is a special algorithm to generate this structure, ensuring that it is unique in time and space.) Next Coinitialize function

Initialize the COM library. This step is very important. If there is no initialization, the operations that will be done will fail.

Let's take a look at the HRESULT value. This is a 32-bit return value whose highest bit indicates whether the function call is successful. The sixteenth contains

It is the return value of the function, and the remaining 15 bits contain more details of this type and return value originated. In order to determine if the function call is

Work, you need to use the succeed and failed macro.

The COCREATEINSTANCE function is provided by the COM function library, its role is to find it in the system according to the components and interfaces of the query.

The file (typically always an EXE or DLL file) and then create the component and query its interface. In general, the specific implementation of this function is

Related to the system, will be mentioned later, in the Windows system, the query registry has determined which file of a particular component is in. on

The example query is a CLSID_COM1 component, so as a component may contain multiple interfaces, we use IID_IX to make the required

Interface, clsctx_inproc_server is a constant, which specifies that the component is a DLL (due to the DLL running in the customer's memory space,

Therefore, it can be called the process within the process). The last parameter is incorporated into an interface pointer, which will return the queryed interface pointer. I want to see,

A component pointer may be used by several customers, so there is a means to let component instances know that they are being used by several customers.

This way he can destroy himself when he can make it right. If the destruction is actually improper, for example, there is a pointer is being used, then

The call to the pointer will fail later and the user program will crash. COM uses a very simple means to make a so-called reference count: dimension

Check a global variable of a component or interface, but the value of the variable is zero, it is here. CocreateInstance actually produces an instance of the component and has called an addRef () function internally to set the reference count 1. Because of this, the example final

The called release () function is to do clean up: This interface pointer has completed its work, so calling release () tells it:

Reduce your reference count. If this is not done, the component will always remain in the memory until the application is not cleared from the stack.

The call to the addRef and the release function is to better control the life of the component, of course, if processed, it can be appropriately reduced.

AddRef / Release pair to improve performance. A special case is that when a component of a component is completely included in another component,

We may not count the components contained. I am not prepared to discuss the optimization problem, because of the general application, guarantee the program

Strong and stable are the most important. I have to introduce ProgID here. Progid actually appreciates a CLSID. some

Language, such as Visual Basic uses proGID instead of CLSID to represent components. Here, please note that the programmer is only following the progid.

A conventional provisions have no mandatory standards for specific implementations, so it is also possible to conflict with the name. General

Said, Progid has the following format: ..

Take my registry as an example:

Inshandler.insHandler.1

Imgutil.cosniffstream.1

StaticMetafile

Netscape.help.1

However, because PROGID does not have a special naming rule, it is also entirely possible to have a different name different from the above format. Sometimes customers

Don't care about the component version it is connected. In other words, customers only need to know that the component is full. Therefore, the components often have

A Progid-independent PROGID, this Progid is mapped to the latest version of the installed. Complete conversion from Progid to CLSID

Very simple, just need to use the two functions provided in the COM library CLSIDFROMPROGID and PROGIDFROMCLSID.

CLSID CLSID;

CLSIDFROMPROGID (L "Netscape.help.1", & clsid);

The above L "is an extended macro that converts the normal ANSI string into a Unicode string.

The problem that needs to be discussed below is: Suppose I have written a component now, how can I register its interface in the registry? non-

Often simple, we only need to implement the following two functions in the component.

__declspec (dllexport) DllRegisterServer ();

__DECLSPEC (DLLEXPORT) DllunregisterServer ();

Specifically, the implementation of the DllRegisterServer is actually implemented by directly calling the registry function. In order to register or cancel a certain

Registration of a component, the functions you need to use:

RegopenKeyex

RegcreateKeyex

RegSetValueex

RegenumKeyex

RegdeleteKey

RegcloseKey

Using these functions is to include #include or add Advapi32.lib in Additional Librarys. Now one question

The question is: How do customers choose the components they need? Developers need to know if it can be found without creating a component instance

Provides a method of the desired interface. All components and interfaces in the polling system are not a way to solve, but the system overhead is quite

Big. To this end, a solution called component category is introduced.

A component category is actually an interface collection. We assigned to the collection a GUID in unique indicate it, it is called

Catid. For any component, if it implements all the interfaces of a component category, then it can register itself into this

One member of the component category. In this way, customers only need to select the appropriate component category and query all the listed components below.

For components, do not limit it only one component category. In turn, components belonging to a component class are not limited to implementation

Interface in the component category. If you are willing, you can write a component support to implement all component levels and there are additional interfaces. Component class

Don't be achieved? Using Component Category Manager (provided by Windows), it is an implementation

IcatRegister and component of the ICATINFORMATION interface. IcatRegister can complete the registration or cancellation of the new component category, too

You can register a component into a component category or cancel it. ICATINFORMATION can be used to get a component class in the system

Other data.

The component is assigned a memory, and then build a parameter (may be a returned pointer) to the customer, this is

A very common approach. The question is: Who will release this memory? This is mainly due to the fact that the establishment and customer may have different programmers.

Implemented, there is no way to establish a standard approach to allocation and release memory. The approach of various issues in COM is to provide one

Interface (IMALLOC), it can have Cogetmalloc returns. In order to allocate memory, just call IMALLOC :: Alloc,

The memory allocated with the change function can have IMALLOC :: free is responsible for releasing. In order to make more simple implementation, the COM library provides two more

Simple function:

Void cotaskmemalloc (ulong cb / * size in bytes of block to be allocated * /);

Void CotaskMemFree (Void * PV);

If you carefully read my article, you will have a concept that you are now in this way: What is the concept of COM,

What extents need to be programmers to implement, which is done by the COM library provided by the operating system. Not very strict,

The purpose of COM is to classify a variety of functions and then package into one item that is in a Windows system or

The form of EXE is specifically present, and through the registry, Window can know that the code of a particular component is in that correspondence.

DLL or EXE. Here you will tell Windows, which component do you need? We use GUID, its complex algorithm

It is exactly the same as the ID log number without two interfaces in the world! Therefore, you can uniquely determine the components, including an internal interface,

Windows can be loaded correctly when the customer needs this component. Also because this uniqueness, customers are in any

It is time to ask for Windows, and I want it is the interface in this component! Tell me you have

? At this time, through a CocreateInstance function, Windows will return the interface pointer, or simply tell you, no

turn up! So, what is the specific to this function in Windows? First, it queries the registry and finds you.

The components (components are also interface sets, and the so-called interface is a synonym of a set of functions, saying, do you understand?) If you don't find the component, the query naturally failed, the function returned, if you found it, So further, the kernel will

Windows returns the iUnknown * pointer of the component, and Windows then uses the iUnknown :: queryinterface function to query you

The specified interface is not implemented by the component (or support), you must find that you can find that the interface is general

It is always necessary to implement by your code. All the interfaces that all COM components must be implemented. One of the purposes is to let

Windows knows how to query your components. Until which interfaces have been implemented in the assembly - people who write this component, so

You have a good QueryInterface function that is responsible for returning the correct pointer, and Windows will then go to the pointer.

At the call of CocreateInstance, the whole thing is over. Did you know now?

转载请注明原文地址:https://www.9cbs.com/read-3968.html

New Post(0)