CoM use

xiaoxiao2021-03-06  23

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

The COM is the component object model, which is the abbreviation of the first three letters of Component Object Model, which can be seen everywhere in today's Windows world. The big new technologies that are emerging at any time are based on CoM. Terms such as COM objects, interfaces, and servers are also flooded in various documents. Therefore, for a programmer, not only the method of using COM, but also completely familiar with all of COM. This article describes the inner operational mechanism of COM by shallow into the COM, teaches you how to use the COM object provided by third parties (as an example of Windows Housing Components Shell). After reading this article, you can master how to use the Components in the Windows operating system and the COM objects provided by third parties. This article assumes you proficient in C language. A little MFC and ATL are used in the example code, and if you are not familiar with MFC and ATL, this article will completely thoroughly explain these code.

This article includes the following parts:

COM - what is it?

- Introduction to COM standard, what is it designed to solve? Definition of basic elements

- Terat language and the meaning of these terms. Use and process COM objects

- How to create, use and destroy COM objects. Basic Interface - Describe the Basic Interface of IUNKNOWN and Its Method. Mastering string

How to deal with strings in the COM code.

Apply COM technology - example code, exemplify all the concepts discussed herein.

Processing the HRESULT - HRESULT type description, how to monitor errors and success code.

COM - what is it?

Simply put, COM is a method of sharing binary code across applications and languages. Unlike C , it advocates source code reuse. ATL is a good illustration. Although the source level reuse is good, it can only be used for C . It also brings the possibility of name conflict, and it is not to say that it is constantly copying reusable code to cause project expansion and bloated. Windows uses DLLS to share code in binary grade. This is also the key to the running of the Windows program - reuse kernel32.dll, user32.dll, etc. However, DLLS is written for C interface, which can only be used by C or understanding C call specification. The programming language is responsible for implementing shared code instead of by the DLLS itself. This is limited by the use of DLLS.

The MFC introduces another MFC extended DLLS binary sharing mechanism. But its use is still restricted - can only be used in the MFC program. COM solves these problems by defining binary standards, ie COM clearly indicates that binary modules (DLLs and EXES) must be compiled into 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 modification in C ). Once these conditions are met, these modules can be easily accessed from any programming language. The binary code generated by the compiler is compatible with standards. This makes it easier to use these binary codes more easily. In memory, this standard form of COM object occasionally used in the C virtual function, so this is why many COM code use C reasons. However, remember that the language written in the module is independent, because the result binary code is available for all languages. In addition, COM is not unique to Win32. In theory, it can be ported to UNIX or other operating systems. But I seem to have never heard of COM outside of WINDOWS. The definition of basic elements We are looking up. The interface is just a set of functions. These functions are called methods. The interface name begins with uppercase i, such as IsHellLink in C , and interface is designed as an abstract base class, which only pure virtual functions. The interface can be inherited from other interfaces. The principle of inheritance here is like a single inheritance in C . The interface does not allow multiple inheritance.

CoClass (Component Object Class - "Nent Object Class) is included in DLL or EXE and includes a code of one or more interfaces. Component Object Class (Coclasss) implements these interfaces. The COM object is an instance of the CoclassS in memory. Note that COM "class" and C "class" are different, although often COM class is a C class. The COM server is a binary (DLL or EXE) that contains one or more CoClass. Registration is a process of creating a registry entry telling the Windows operating system COM server where you are. Cancel registration is the opposite - remove these registered portions from the registry. GUID (Harmony "Fluid" means the world's unique marker - Global Unique Identifier is a 128-bit number. It is a marking method that is independent of COM programming language. Each interface and CoClass have a Guid. Because every GUID is unique worldwide, the name conflict is avoided (as long as you create them with COM API). Sometimes you will also encounter another term UUID (meaning the world's unique marker --universally unique identifier). UUIDS and GUIDs are the same in actual use. Class ID or CLSID is a GUID named CoClass. The interface ID or IID is a GUID of the naming interface. There are two reasons whose GUIDs are widely used in COM: 1. Guids is just simple numbers, and any programming language can be processed. 2, Guids can be created by anyone on any machine, once it is created, it is unique. Therefore, COM developers can create their own unique Guids without conflict with the GUIDs created by other developers. This eliminates the need for a centralized authorization to release the Guids. HRESULT is the integer number of COM to return errors and success code. In addition, don't have it, although prefixed with H, there is no handle. It will be discussed below. Finally, the COM library is part of the operating system interacting with you when you use COM, which often refers to COM itself. However, in order to avoid confusion, it is described separately. Using and processing COM objects each language has its own way you handle objects. For example, C is created in the stack, or dynamically assigned by NEW. Because COM must be independent of the language, the COM library provides object management routines for themselves. Below is a comparison for COM object management and C object management: Create a new object C , use the new operator, or create an object in the stack. Call the API in the COM library. Delete the object C , use the Delete operator, or kick the stack object. In COM, all objects keep their own reference count. The caller must notify the object when using this object. When the reference count is zero, the COM object releases yourself from memory. It can be seen that two phases of object processing: creating and destroying, it is not possible. When you create a COM object, you want to inform the COM library which interface to use. If this object is created, the COM library returns a pointer to the requested interface. Then use this pointer to call the method, just like using a regular C object pointer. Creating a COM object In order to create a COM object and get 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); The following is the parameter explanation:

Rclsid Coclass CLSID, for example, can pass CLSID_SHELLLINK to create a COM object to create a shortcut.

Punkouter This parameter is only used for the aggregation of COM objects, which uses it to add new methods to existing CoClass. The parameter value is NULL means that the aggregation is not used.

DwclsContext indicates that the COM server used is the simplest COM server, an in-process DLL, so the passing parameter value is CLSCTX_INPROC_SERVER. Note Not will not use CLSCTX_ALL here (in ATL, it is a default), because there is no failure on Windows 95 systems where DCOM is installed.

The IID of the RIID request interface. For example, IID_ISHELLLINK can be passed to get the ISHELLLINK interface pointer.

The address of the PPV 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, loads the server to memory and creates the CoClass instance you requested.

The following is an example of a call, creating an instance of a CLSID_SHELLLINK object and requests to point to this object ishelllink interface pointer. HRESULT HR; ishelllink * pisl; hr = cocreateInstance (CLSID_SHELLINK, // CLSID NULL, / / ​​is not used with aggregate clsctx_inproc_server, // server type IID_ID_ID_IDLINK, / / ​​interface IID (void **) & pisl); // Point to the interface Pointer IF (SUCCEEDEDED) {// Call method with PISL} else {// cannot create a COM object, HR is the error code} first declares a HRESULT and ISHELLLINK pointer to accept COCREATEINSTANCE () return values. Call cocreateInstance () to create a new COM object. If the HR accepts a code that represents the successful code, the successded macro returns True, otherwise it returns false. FAILD is a macro corresponding to successded to check the failed code. Deleting a COM object says, you don't have to release the COM object, just tell them that you have used the object. IUNKNOWN is an interface that must be implemented in every COM object. It has a method, relation (). Call this method to notify the COM object You no longer need an object. Once this method is called, this interface cannot be used again, because this COM object may disappear from memory. If your application uses many different COM objects, it is very important to call Release () after you run a certain interface. If you don't release the interface, this COM object (including the code's DLLS) will remain in memory, which will increase unnecessary overhead. If your application is running for a long time, you should call the COFREEUNUSEDLIBRARIES () API during the application. This API will uninstall any COM server without obvious reference, so this also reduces the memory overhead used by the application. Continue with the above example to explain how to create a COM object as above, then, if (successded (HR)) {// Call method with PISL // Notify COM objects No longer use it PISL-> The iUnknown interface will be discussed in detail next. Basic Interface - IUNKNOWN Each COM interface is derived from IUNKNOWN. This name is a bit misleador, in which there is no unknown interface. Its original interest is if there is an IUNKNOWN pointer to a COM object, you don't have to know what the potential object is because each COM object implements iUnknown. IUNKNOWN has three methods: addRef () - Notes COM object Add its reference count. If you have a copy of the interface pointer, you must call once, and the original value and the copy value are used. ADDREF () method is not used in the examples herein. Release () - Notes COM objects to reduce its reference count. See the previous Release () sample code segment. QueryInterface () - requests an interface pointer from a COM object. This method is used when CoClass implements more than one interface. I have seen Release () use, but how to use queryinterface ()? When you create an object with CoCreateInstance (), you get a returned interface pointer. If this COM object implements more than one interface (excluding iUnknown), you must use the queryinterface () method to get any additional interface pointers you need.

The prototype of the queryinterface () is as follows: HRESULT IUNKNOWN :: QueryInterface (REFIID IID, VOID ** PPV); The following is the parameter explanation: IID of the interface requested by the IID. The address of the PPV interface pointer, queryinterface () returns this interface when this parameter is successful. Let us continue the case of the shell link. It implements the ISHELLLINK and IPERSISTFILE interface. If you already have an ishelllink pointer, PISL, you can request an IPERSISTFILE interface from a COM object: HRESULT HR; IPERSISTFILE * PIPF; HR = PISL-> Queryinterface (IID_IPERSISTFILE, (Void **) & PIPF); then use the succeeded macro to check the value of HR To determine the call of queryinterface (), if you succeed, you can use the new interface pointer, PIPF as other interface pointers. But you must remember calling the PIPF-> Release () Notification COM object has been used to use this interface. Carefully do string to handle this part will take time to discuss how to process strings in COM code. If you are familiar with Unicode and ANSI, you can skip this part if you want to convert them, otherwise you will read this part. No matter when, as long as the COM method returns a string, this string is a Unicode string (herein refers to all methods written to the COM specification). Unicode is a character encoding set similar to ASCII, but represents a character with two bytes. If you want to control or operate strings better, you should convert it to a TCHAR type string. TCHAR and the start of _T (such as _tcscpy ()) are designed to allow you to use the same source code to process Unicode and ANSI strings. The code written in most cases is used to handle ANSI strings and ANSI Windowsapis, so in, unless otherwise stated, what I said is TCHAR type. You should master TCHAR types, especially when you read the relevant code written by others, pay special attention to TCHAR types. When you returns a Unicode string from a COM method, you can convert it into a CHAR type string: 1, call the widechartomultibyte () API. 2, call the CRT function WCSTOMBS (). 3. Use the CSTRING constructor or assignment (for MFC only). 4, use the ATL string conversion macro. WideChartomultibyte () You can convert a Unicode string into an ANSI string with widechartomultibyte (). This function has the following prototype: int WideCharToMultiByte (UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar); The following parameters are explained: CodePage Unicode characters into code page. You can pass CP_ACP to use the current ANSI code page. The code page is 256 character sets. Characters 0--127 are the same as ANSI coding. Characters 128-255 are different from the ANSI characters, which can contain graphic characters or pronunciation symbols. Each language or region has its own code page, so it is important to use the correct code page to correctly display the stress character. DWFLAGS DWFLAGS determines how Windows handles the "composite" Unicode character, which is a character with a pronunciation symbol. If è is a composite character.

If these characters are in the code page specified by the CODEPAGE parameter, I don't have anything. Otherwise, Windows must be converted. Pass WC_CompositeCheck makes this API checks non-mapping composite characters. Pass wc_sepchars makes Windows to divide characters into two sections, namely characters plus, such as E.. Pass wc_discardns causes Windows to discard the pronunciation symbol. Pass wc_defaultchar allows Windows to replace the compound character with the default character described in the LPDefaultChar parameter. The default behavior is wc_sepchars. LpWideCharstr To convert Unicode strings. CchwideChar LPWideCharstr's length in Unicode characters. Usually transmit -1, indicating that this string ends at 0x00. LPMULTIBYTESTR accepts the character buffer CBMULTIBYTE LPMULTIBYTESTR of the converted string. LPDEFAULTCHAR Optional - When dwflags contains WC_CompositeCheck | WC_DEFAULTCHER and a Unicode character cannot be mapped to a single-character ANSI string passed when the equivalent ANSI string contains the inserted "default" characters. You can pass NULL, allowing the API to use the system default character (a write method is a question mark). LpuseDDefaultchaar Optional - Points to a pointer to the Bool type, set it to indicate whether the default character has been inserted into an ANSI string. You can pass NULL to ignore this parameter. I am a little dizzy ...! Everything is difficult ..., don't figure out that these things are hard to figure out COM's string processing. What is more than the actual application is much more complicated than the actual application. The following will give an example of how to use this API: // Suppose already has a Unicode string wszsomeString ... char szanstruing [max_path]; widechartomultibyte (cp_acp, // ANSI code page WC_CompositeCheck, // Check the stress character wszsomeString, // / The original Unicode string -1, // -1 means string with 0x00 end szansistring, // destination char string sizeof (szanstruing), // buffer size null, // fat default string null); // ignore this After the parameter calls this function, SzansString will contain the ANSI version of the Unicode string. WCSTombs () This CRT function wcstombs () is a simplified version, but it ends the call of widechartomultibyte (), so the final result is the same. The prototype is as follows: size_t wcstombs (char * mbstr, const wchar_t * wcstr, size_t count); the following is the parameter interpretation: MBSTR accepts the character (char) buffer of the ANSI string. WCSTR wants to convert Unicode strings. The cushion size refers to the count mbstr parameter. WCSTombs () uses the WC_CompositeCheck | WC_SEPCHARS flag in its call to WideChartomultibyte (). Use WCSTOMBS () to convert the Unicode string in the previous example, the same as the result: WCSTombs (SzansString, Wszsomestring, sizeof (szanstring)); CString MFC CString contains a constructor and accepts assignment operations of the Unicode string, so you can use cstring Implement conversion.

For example: // Assume that there is a Unicode string WSZSomString ... CString str1 (wszsomestring); // converts CString str2 with constructors; str2 = wszsomeString; // Use assignment operation to convert the ATL macro ATL has a set of very convenient macros for string Conversion. W2a () is used to convert Unicode strings to an ANSI string (memory method is "wide to ANSI" - wide character to ANSI). In fact, OLE2A () is used more accurate, "OLE" means a COM string or OLE string. The following is an example of using these macros: #include // or assumes having a Unicode string wszsomeString ... {char szanstruing [max_path]; Uses_conversion; // Declare the local variable of this macro to use LSTRCPY (SzansInsiString, OLE2A (WSZSomstring)) } 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 get its own copy. Other several macros are W2T () (Unicode to Tchar) and W2CT () (Unicode to constant TCHAR string). There is a macro is OLE2CA () (Unicode to constant char string), which can be used in the example above, and OLE2CA () is actually a corrected macro because the second parameter of lstrcpy () is a constant char *, about this Question This article will be discussed in detail later. On the other hand, if you don't want to do more than the above complex string processing, although it remains a Unicode string, if you are writing, you should use the console application, the output / display Unicode string should be used with full variables std :: wcout, such as: Wcout << wszsomeString; but remember, std :: wcout only recognizes Unicode, so if you are "normal" string, you have to use std :: coup output / display. For Unicode Series, you want to use the prefix L, such as: wcout << l "The Oracle Says ..." << endl << wszoraclesponse; if the string is unicode, there are two restrictions in programming: - must be used WCSXXX () Unicode string handle, such as WCSLEN (). - Unicode strings cannot be delivered in the Windows API in the Windows 9X environment. To write applications that can run on 9x and NT, you must use TCHAR types. For details, please refer to MSDN. Summary The above is summarized below the following examples to demonstrate the COM concepts described in this article. The code also includes examples of this article. The first example of the single COM object is displayed is displayed in a single interface COM object. This may be the simplest example you have encountered. It uses the active desktop component object class (CLSID_ACTIVEDESKTOP) in the housing to get the file name of the current desktop wallpaper. Please confirm that the active desktop is installed in the system. The following is the programming step: initialize the COM library. (Initialize) Create a COM object interacting with the event desktop and gets the IACTIVEDESKTOP interface. Call the getWallPaper () method of the COM object. If getWallpaper () is successful, the output / display wallpaper file name is output. Release the interface (Release ()). Remove the COM library.

Wchar wszwallpaper [max_path]; cstring strpath; hResult HR; IactiveDesktop * PIAD; / / 1. Initialize the COM library (let Windows load DLLS). It is usually called // Coinitialize (NULL) or other startup code in the initInstance () of the program. The MFC program uses AFXoleinit (). Coinitialize (NULL); // 2. Create a COM object using the active desktop component object class provided by the housing. // Fourth parameter notification COM What interface (here is IactiveDesktop). Hr = cocreateInstance (CLSID_ACTIVEDESKTOP, NULL, CLSCTX_INPROC_SERVER, IID_ID_IACTIVEDESKTOP, (Void **) & piad); if (succeededed (HR)) {// 3. If The COM object is created, then call the getWallPaper () method of this object. HR = PIAD-> getWallpaper (WSZWallpaper, Max_Path, 0); if (succeededed (hr)) {// 4. If getWallpaper () is successful, output it returned by the file name. / (Note that the Unicode string WSZWALLPAPER is displayed here. Wcout is dedicated, functionality and coup. WCOUT << L "Wallpaper path is: / n" << wszwallpaper << endl << endl;} else {cout << _t ("getwallpaper () failed.") << endl << endl;} // 5. Release the interface. Piad-> release ();} else {cout << _t ("COCREATEINSTANCE () failed.") << endl << endl;} // 6. Remove the COM library. The MFC program does not use this step, it is done automatically. Couninitialize (); in this example, output / display Unicode string WSZWALLPAPER is std :: wcout. The second example of using multiple interfaces shows how to use a COM object QueryInterface () function that provides a single interface. The code for the Code Create the Shell Link Component Object class of the housing The shortcut to the wallpaper file we obtained in the first example is the programming step: initialize the COM library. Create a COM object for establishing shortcuts and get the iShellLink interface. Call the setPath () method of the iShellLink interface calls the queryinterface () function of the object and gets the IPersistFile interface. Call the Save () method of the IPersistFile interface. Release interface Recover COM library cstring swallpaper = wszwallpaper; // convert the wallpaper path to ANSI ishellLink * Pisl; IPERSISTFILE * PIPF; // 1. Initialize the COM library (let Windows load DLLS). Usually call // Coinitialize in InitInstance () (NULL) or other startup code. The MFC program uses AFXoleinit (). Coinitialize (NULL); // 2. Create a COM object using the shell link component object class provided by the housing. . // The fourth parameter notifies the COM what interface (here is IllLink).

HR = COCREATEINSTANCE (CLSID_SHELLLINK, NULL, CLSCTX_INPROC_SERVER, IID_ID_ID1LLINK, (VOID **) & PISL); if (succeededed (hr)) {// 3. Set shortcut target (wallpaper file) path. HR = PISL-> setPath (SWALLPAPER); if (successtededed (HR)) {// 4. Get the second interface of this object (ipersistfile). HR = PISL-> QueryInterface (IID_IPERSISTFILE, (VOID **) & PIPF; if (successded (hr)) {// 5. Call the save () method Save a file shortcut. The first parameter is // Unicode string. HR = PIPF-> Save (l "c: //wallpaper.lnk", false); // 6A. Release the IPersistFile interface. PIPF-> Release ();}} // 6. Release the ISHELLINK interface. PISL-> Release ();} // Output Error message section is omitted here. // 7. Remove the COM library. The MFC program does not use this step, it is done automatically. Couninitialize (); Handling HRESULT is prepared for some simple error processing with successded and failed macros. It is mainly to study the HRESULT returned from the COM method to achieve full understanding and skilled applications. HRESULT is a 32-bit symbol integer, its non-negative value is successful, and the negative value is failed. HRESULT has three domains: degree bits (indicating successful or failed), function code and status code. The function code indicates what components or programs come from HRESULT. Microsoft gives different components more of the function code, such as: COM, task scheduling programs, etc. have function code. Function code is a 16-bit value, which is not there, without other intrinsic meaning; it is freely associated between numbers and meaning; the value similar to getLastError (). If you look for an error code in the Winerror.h header file, you will see a number of hRESULT values ​​listed in [Function] _ [Prime] _ [Description] Named Specification, and the universal HRESULT (similar E_OUTOFMEMORY) returned by the component is in the name. There is no function code in. For example, regdb_e_readregdb: Function Code = Regdb, refers to "Registry Database" "; degree = E meaning error (Error); Description = readRegDB is a description of the error (meaning that you cannot read the registry database). S_OK: No function code - general (generic) hresult; degree = S; Success; OK is the status description indicating everything is good (Everything ''s OK). Fortunately, there is a way to see the WINError.h file easier method to determine the meaning of HRESULT. Error Lookup, which is provided using VC, can easily find the HRESULT built-in function code. For example, suppose you forget to call Coinitialize () before cocreateInstance (). CocreateInstance () The value returned is 0x800401F0.

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

New Post(0)