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?