Introduction to COM programming have to read the article: The first part what is COM, how to use COM

Source: Internet
Author: User
Tags ole

Original: Http://

The purpose of this article is to provide programming guidance to programmers who have just contacted COM and to help them understand the basic concepts of COM. The content includes a description of the COM specification , important COM terminology , and How to reuse existing COM components . This article does not include how to write your own COM objects and interfaces.

COM, the Component Object model, is an abbreviation for the first three letters of the component ObjectModel, which are found everywhere in the world of today's windows. A lot of new technology that emerges at any time is based on COM. The various documents are also flooded with terms such as COM objects, interfaces, servers, and so on. Therefore, for a programmer, not only to master the method of using COM, but also thoroughly familiar with all of COM.

This paper describes the internal operating mechanism of COM, and teaches you how to use COM objects provided by third parties (for example, Windows Shell Component shell). After reading this article, you will be able to learn how to use the built-in components of the Windows operating system and the COM objects provided by third parties .

This article assumes you are proficient in the C + + language. Using a little Bit of MFC and ATL in the example code, it doesn't matter if you're not familiar with MFC and ATL, and this article will explain the code thoroughly. This article includes the following sections:

    • What the hell is com――? Introduction to the ――com standard, which is designed to solve any problem
    • Definitions of basic elements ――com terms and meanings of these terms
    • Using and handling COM objects-how to create, use, and destroy COM objects
    • Basic interfaces-describe IUnknown basic interfaces and their methods
    • Mastering the processing of strings-how to handle strings in COM code
    • Apply COM Technology-example code to illustrate all the concepts discussed in this article
    • Handling Hresult――hresult type descriptions, how to monitor errors and success codes
What is com exactly?

To put it simply, COM is a way to share binary code across applications and languages . Unlike C + +, it advocates reuse of source code. ATL is a good example. Source-level reuse is good, but only for C + +. It also brings the possibility of name collisions, not to mention the constant duplication of code reuse that results in engineering bloat and bloat.

Windows uses DLLs to share code at the binary level. This is also the key to the operation of Windows programs-reuse Kernel32.dll, user32.dll and so on. but DLLs is written for the C interface, and they can only be used by C or the language that understands the C call specification . The programming language is responsible for implementing shared code, not by DLLs itself. In this case, the use of DLLs is limited.
MFC introduces another kind of MFC extended DLLs binary sharing mechanism. However, its use is still restricted-it can only be used in MFC programs.

COM solves these problems by defining a binary standard that COM explicitly states that binary modules (DLLs and exes) must be compiled to match the specified structure . This standard also specifies how COM objects are organized in memory. COM-defined binary standards must also be independent of any programming language, such as named adornments in C + +. Once these conditions are met, it is easy to access these modules from any programming language. The binary code generated by the compiler is compatible with the standard . This makes it easier for later people to use the binary code.

In memory, this standard form of COM objects is occasionally used in C + + virtual functions, so this is why many COM code uses C + +. But remember, the language used to write the module is irrelevant, because the resulting binary code is available for all languages.

In addition, COM is not unique to Win32. Theoretically, it can be ported to UNIX or other operating systems. But I never seem to have heard of COM outside of Windows.

Definition of basic elements

Let's look at it from the bottom up. An interface is simply a set of functions. These functions are called methods. Interface names start with uppercase I, such as ishelllink in C + +, and the interface is designed as an abstract base class, where only pure virtual functions are available.

Interfaces can inherit from other interfaces, where the principle of inheritance is like a single inheritance in C + +. Interfaces are not allowed to inherit more.

coclass (――componentobject Class) is included in the DLL or EXE, and the DLL or EXE contains code for one or more interfaces. The Component Object Class (COCLASSS) implements these interfaces. A COM object behaves as an instance of a Component object Class (COCLASSS) in memory . Note that COM "classes" and C + + "classes" are not the same, although often the COM class implements a C + + class.

A COM server is a binary (DLL or EXE) that contains one or more coclass.

Registration (registration) is a procedure for creating a registry entry that tells the Windows operating system where the COM server is located. De-Registration (unregistration) is the opposite-deleting these registry entries from the registry.

The GUID (homophonic is "fluid", meaning that the global unique identifier ――globally unique identifier) is a 128-digit number. It is a method of labeling independent of the COM programming language. Each interface and coclass has a GUID. Because each GUID is globally unique, it avoids name collisions (as long as you create them with the COM API). Sometimes you will encounter another term uuid (meaning also the globally unique identifier ――universally unique identifier). The use of UUIDs and GUIDs is the same in practice.

the class ID or CLSID is the GUID of the named coclass. The interface ID or IID is the GUID of the named interface.

There are two reasons to use a GUID extensively in com:

1.GUIDs is just a simple number that can be processed by any programming language;

2.GUIDs can be created by anyone on any machine, and once created, it is unique. As a result, COM developers can create their own unique GUIDs without conflict with GUIDs created by other developers. This eliminates the need to centrally authorize the release of GUIDs .

An HRESULT is an integer number that COM uses to return an error and a successful code. In addition, there is no meaning, although the H prefix, but there is no meaning of the handle. There will be more discussion of it below.

Finally, the COM library is part of the operating system that interacts with you when you use COM, and it often refers to the COM itself. But they are described separately in order to avoid confusion.

Using and working with COM objects

Each language has its own way of dealing with objects. For example, C + + is creating objects in the stack, or dynamically allocating them with new. Because COM must be language Independent, the COM library provides itself with an object management routine. The following is a comparison of COM object Management and C + + object management:

Create a new object

In C + +, use the new operator, or create an object in the stack.

COM, call the API in the COM library.

Delete Object

In C + +, use the delete operator, or kick the stack object out.

In COM, all objects keep their own reference count. The caller must notify the object when the object is exhausted. When the reference count is zero, the COM object frees itself from memory.

Thus, the two phases of object processing: creation and destruction, are indispensable. Notifies the COM library which interface to use when creating a COM object. If this object is created successfully, the COM library returns a pointer to the requested interface. The method is then invoked through this pointer, just as with regular C + + object pointers.

To Create a COM object

In order to create a COM object and obtain an interface from this object, you must call the COM library's API function, CoCreateInstance (). The prototype is as follows:

HRESULT CoCreateInstance (  refclsid  rclsid,  lpunknown punkouter,  DWORD     dwClsContext,  REFIID    riid,  lpvoid*   PPV);

Here are the parameter explanations:

1.rclsid:coclass clsid, for example, can be passed Clsid_shelllink create a COM object to establish a shortcut.

2.pUnkOuter: This parameter is used only for aggregation of COM objects, and it uses it to add new methods to existing coclass. A null parameter value means that no aggregation is used.

3.dwClsContext: Indicates the kind of COM server being used. This article uses the simplest COM server, an in-process (in-process) DLL, so the parameter value passed is clsctx_inproc_server. Note that this is not an arbitrary use of clsctx_all (in ATL, it is a default value) because failure is caused on Windows95 systems that do not have DCOM installed.

4.RIID: The IID of the request interface. For example, you can pass Iid_ishelllink to get IShellLink interface pointers.

5.PPV: The address of the interface pointer. The COM library returns the requested interface through this parameter.

When you call CoCreateInstance (), it is responsible for finding the location of the COM server in the registry, loading the server into memory, and creating the coclass instance that you requested . The following is an example of a call that creates an instance of an Clsid_shelllink object and requests a pointer to the IShellLink interface of the object.

HRESULT     hr;  ishelllink* PISL;   hr = CoCreateInstance (Clsid_shelllink,         //coclass CLSID  NULL,                    //Not with aggregation  clsctx_inproc_server,    / /server type  iid_ishelllink,/          /interface IID   (void**) &PISL);        Pointer  to interface if (SUCCEEDED (HR))  {  //call method with Pisl  }  else  {  //Cannot create COM object, HR is error code  }    


First, declare an HRESULT and IShellLink pointer that accepts the CoCreateInstance () return value. Call CoCreateInstance () to create a new COM object. If HR accepts a code that represents success, the succeeded macro returns TRUE, otherwise false is returned. Failed is a macro that corresponds to succeeded to check for failure codes.

To Delete a COM object

As I said earlier, you don't have to release COM objects, just tell them you've run out of objects. IUnknown is the interface that every COM object must implement, and it has a method, Release (). Call this method to notify the COM object that you no longer need this interface for this object. Once this method is called, the interface cannot be used again because the COM object may disappear from memory.

If your application uses many different COM objects, it is important to call release () after an interface is exhausted. If you do not release the interface, the COM object (DLLs containing the code) will remain in memory, which adds unnecessary overhead. If your application is going to run for a long time, you should call the CoFreeUnusedLibraries () API while your application is idle. This API will unload any COM servers that are not clearly referenced, so this also reduces the memory overhead used by the application.

Continue with the example above to illustrate how to use release ():

Create a COM object as above, and then,   if (SUCCEEDED (HR))  {       ////Call method with PISL/       /Notify COM object to no longer use it       pisl->release ();  


The IUnknown interface basic interface is discussed in detail ――iunknown

Each COM interface is derived from IUnknown. The name is a bit misleading, without the meaning of the Unknown (Unknown) interface. It's intended that if you have a IUnknown pointer to a COM object, you don't have to know what the potential object is, because each COM object implements IUnknown. There are three methods of IUnknown:

AddRef ()-Notifies the COM object to increase its reference count. If you make a copy of the interface pointer once, you must call this method once, and both the original value and the copied value are used. The AddRef () method is not used in the example of this article;

Release ()-Notifies the COM object to reduce its reference count. See the previous release () sample code snippet;

QueryInterface ()-Requests an interface pointer from a COM object. This method is used when the coclass implements more than one interface;

I've seen the use of release () before, but how do I use QueryInterface ()? When you create an object with CoCreateInstance (), you get a pointer to the interface that is returned. If the COM object implements more than one interface (excluding IUnknown), you must use the QueryInterface () method to obtain any additional interface pointers you need. The prototype of QueryInterface () is as follows:

HRESULT IUnknown::QueryInterface (  refiid iid,  

Here are the parameter explanations:

1.IID: The IID of the requested interface.

2.PPV: The address of the interface pointer, QueryInterface () returns this interface on success with this parameter.

Let's continue with the example of the shell link. It implements the IShellLink and IPersistFile interfaces. If you already have a ishelllink pointer, PISL, you can request the IPersistFile interface from a COM object:

HRESULT hr;  ipersistfile* pipf;  hr = Pisl->queryinterface (Iid_ipersistfile, (void**) &pipf);  

This can be used because each COM interface is derived from IUnknown.

Then use the succeeded macro to check the value of HR to determine the invocation of QueryInterface (), and if successful you can use the new interface pointer as you would with other interface pointers, Pipf. However, you must remember to call Pipf->release () to notify the COM object that it has run out of this interface.

do a good job of string processing

This section will take some time to discuss how to handle strings in COM code. If you are familiar with Unicode and ANSI, and you know how to convert them, you can skip this section, or read this section.

Whenever a COM method returns a string, the string is a Unicode string (this refers to all methods written to the COM specification). Unicode is a set of character encodings, similar to ASCII, but with two bytes representing one character. If you want to better control or manipulate the string, you should convert it to a TCHAR type string.

TCHAR and functions starting with _t (such as _tcscpy ()) are designed to allow you to process Unicode and ANSI strings with the same source code. In most cases the code is written to handle ANSI strings and ANSI Windowsapis, so in the following, unless otherwise stated, I mean the character/string refers to the TCHAR type. You should be familiar with the type of TCHAR, especially when you read about code written by someone else, pay special attention to the TCHAR type.

When you return from a COM method to get a Unicode string, you can convert it to a char type string in one of the following ways:

    1. Call the WideCharToMultiByte () API;
    2. Call the CRT function wcstombs ();
    3. Use the CString constructor or assignment operation (MFC only);
    4. Convert macros using an ATL string;
1.WideCharToMultiByte ()

You can use WideCharToMultiByte () to convert a Unicode string into an ANSI string. The prototype for this function is as follows:

int WideCharToMultiByte (  UINT    CodePage,  DWORD   dwFlags,  lpcwstr lpwidecharstr,  int     Cchwidechar,  LPSTR   lpmultibytestr,  int     cbmultibyte,  LPCSTR  Lpdefaultchar,  Lpbool  


Here are the parameter explanations:

CodePage: Unicode characters are converted into code pages. You can pass CP_ACP to use the current ANSI code page. The code page is a 256 character set. The character 0――127 is the same as ANSI encoding. The character 128――255 differs from ANSI characters in that it can contain graphic characters or diacritics. Each language or region has its own code page, so it is important to use the correct code page for displaying accented characters correctly.

dwFlags: dwFlags determines how Windows handles the "compound" Unicode character, which is a character that is followed by a phonetic symbol.

such as è is a compound character. If these characters are in the code page specified by the codepage parameter, nothing will happen.

Otherwise, Windows must convert it. Passing Wc_compositecheck makes this API check for non-mapped composite characters.

Passing Wc_sepchars allows Windows to divide characters into two segments, the word multibyte pronunciation, such as e '.

Passing Wc_discardns makes Windows discard the diacritics.

Passing Wc_defaultchar allows Windows to replace compound characters with the default characters described in the Lpdefaultchar parameter.

The default behavior is wc_sepchars.

lpwidecharstr The Unicode string to convert.

Cchwidechar The length of the lpwidecharstr in Unicode characters. Usually pass-1, indicating that the string is terminated with 0x00.

Lpmultibytestr accepts the byte size of the converted string's character buffer cbmultibytelpmultibytestr.

Lpdefaultchar Optional – When dwflags contains Wc_compositecheck | Wc_defaultchar a single-character ANSI string that is passed when a Unicode character cannot be mapped to an equivalent ANSI string, containing the "default" character being inserted. You can pass NULL to let the API use the system default character (one is a question mark).

Lpuseddefaultchar Optional-a pointer to the bool type that sets it to indicate whether the default character was inserted into the ANSI string. You can pass NULL to ignore this parameter.

I'm a little dizzy ...!!!!!!!!!!!!!!!!!!!!!!. com's string processing is difficult to understand. Moreover, the documentation is much more complex than the actual application. Here's an example of how to use this API:

Suppose you already have a Unicode string wszsomestring  ... Char Szansistring[max_path];  WideCharToMultiByte (CP_ACP,                //ansi code page  Wc_compositecheck,//check accent character  wszsomestring,         //original Unicode string  -1,                    //-1 meaning string with 0x00 end  szansistring,          //Purpose char string  sizeof (szansistring),  //Buffer size  NULL,                  //Gravy train save string  null);                

After calling this function, Szansistring will contain the ANSI version of the Unicode string. After calling this function, Szansistring will contain the ANSI version of the Unicode string.

2.wcstombs ()

This CRT function wcstombs () is a simplified version, but it ends the invocation of WideCharToMultiByte (), so the end result is the same. The prototype is as follows:

size_t wcstombs (  char*         mbstr,  const wchar_t* wcstr,  size_t         count);  


Here are the parameter explanations:

1.MBSTR: Accepts the character (char) buffer of the result ANSI string.

2.WCSTR: The Unicode string to convert.

The buffer size referred to by the 3.COUNT:MBSTR parameter.

Wcstombs () uses Wc_compositecheck in its call to WideCharToMultiByte () | Wc_sepchars logo. Using Wcstombs () to convert the Unicode string in the previous example, the result is the same:


CString in MFC contains constructors and assignment operations that accept Unicode strings, so you can use CString to implement transformations. For example:

Suppose there is a Unicode string wszsomestring   ... CString str1 (wszsomestring); Convert CString str2 with a constructor   ;   STR2 = wszsomestring; Converting with assignment operations
4.ATL macro

ATL has a handy set of macros for string conversions. W2A () is used to convert a Unicode string to an ANSI string (the memory method is "wide to ANSI"-wide character to ANSI). In fact, using OLE2A () is more accurate, meaning "ole" means a COM string or an OLE string. Here are some examples of using these macros:

Or suppose there is a Unicode string wszsomestring  ... {  char szansistring[max_path];  Uses_conversion; Declare this macro to use the local variable  lstrcpy (szansistring, OLE2A (wszsomestring));  

The OLE2A () macro "returns" the pointer of the converted string, but the converted string is stored in a temporary stack variable, so use lstrcpy () to obtain its own copy. Several other macros are w2t () (Unicode to TCHAR) and w2ct () (Unicode to constant TCHAR strings).

There is a macro ole2ca () (Unicode to a constant char string) that can be used in the example above, OLE2CA () is actually a correction macro, because the second parameter of lstrcpy () is a constant char*, which is discussed in detail later in this article.

On the other hand, if you do not want to do the above complex string processing, even though it remains a Unicode string, if you are writing a console application, you should use the full variable std::wcout when outputting/displaying the Unicode string, such as:

Wcout << wszsomestring;

But remember, std::wcout only Unicode, so you have to use Std::cout output/display If you are "normal" strings. For Unicode string literals, use the prefix l flag, such as:

Wcout << L "The oraclesays ..." << Endl << wszoracleresponse;


If you keep the string Unicode, you have two restrictions on programming:

You must use the Wcsxxx () Unicode string handler function, such as wcslen ();

Unicode strings cannot be passed in Windows APIs in a Windows 9x environment. To write applications that can run on both 9x and NT, you must use the TCHAR type, as detailed in MSDN.

Use the example code to summarize the above content

The following two examples illustrate the COM concepts described in this article. The code also contains an example project for this article.

Using a single-interface COM object

Introduction to COM programming have to read the article: The first part what is COM, how to use COM

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: 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.