COM Component Design and Application 4-simple call Components

Source: Internet
Author: User
Tags knowledge base

 

  Vckbase is terrible,  
  Numerous articles by netizens are good.  
  How to design components?  
  Search for data in the knowledge base!  
    From --- instructor Yang's oil logging

With the strong support of vckbase and the encouragement of replies from netizens, I can successfully complete the first three answers to the series of papers. At last, we started to write code. What do you want to write? Well, you have it! Let's start by calling simple ready-made components and introduce some related knowledge.


Ii. Start and release components

In the third round, everyone recorded a principle using the "small book:COM components are running in a distributed environment.As a result, how to start the component immediately encountered a serious problem. Let's look at this Code:

P = new object; P-> object function (); Delete P;

This kind of code is no longer familiar, so it won't be a problem to run it in a local process. But what would happen if the object was on a computer on the other side of the earth? When designing new systems, C ++ did not consider remote implementation. (Of course, it is not necessary to design a computer language ). Therefore, the function of starting components and calling interfaces is implemented by the com system.


Figure 1 component call Mechanism

It can be seen that when calling a component, the communication between the proxy (running locally) and the stub (running remotely) is actually completed. Specifically, when the customer program starts the component through the cocreateinstance () function, the proxy takes over the call, it communicates with the stub, And the stub is located locally (Remote compared to the customer Program) execute the new operation to load the object. For beginners, you can ignore it. proxies and stubs are transparent to us. Everything is okay as long as you know what it is.
The problem arises again. When will this remote object be eliminated? When I introduced the interface concept in the second round, we ignored two functions, namely, iunknown: addref () and iunknown: release (), which can be guessed by the function name, one is to add 1 to the internal reference counter (REF), and the other is to release (minus 1). When the counter is reduced to 0, it is the opportunity to release. It looks complicated, but there is no way, because it is introducing the principle. In fact, it is relatively simple to write programs. Please observe the following principles:
1. Do not call addref () after starting the component to obtain an interface pointer (). Because the system knows that you have obtained a pointer, it has helped you call the addref () function;
2. Do not call addref () after obtaining another interface pointer through QueryInterface (). Because... is the same as above;
3. When you assign an interface pointer to (save to) another variable, call addref ();
4. When you no longer need to use the interface pointer, you must execute release () release;
5. When using smart pointers, You can omit pointer maintenance. (Note 1)


Iii. Memory Allocation and release

Since I learned the C language, the teacher taught us that for dynamic memory application and release, we must abide by the principle of "who applies and who releases. Under the guidance of this principle, not only me, but you, but also the super master has designed such strange functions:
 

Function Description Comment
Getwindowtext (hwnd, lptstr, INT) Obtain the window title. You need to provide the memory pointer used to save the title, and the size of the memory in the parameter. Dizzy! I don't know the length of the window title. Do I have to provide the size ?! No way, you can only estimate the size of a larger one.
Sprintf (char *, const char *,...) Format a string. This function does not need to provide the buffer length. Well, although you don't have to give the length, do you dare to give it a small size? Hum!
Int clistbox: gettextlen (INT)
Clistbox: gettext (INT, lptstr)
Obtains the title of the subproject in the List window. You need to call two functions, first get the length, then allocate the memory, and then actually get the title content. Really annoying!

To be honest, not only do function callers feel awkward, but function designers are not even in a good mood. All of this is to satisfy the so-called principle of "who applies and who releases. The best way to solve this problem is to dynamically apply for memory in the function based on actual needs, and the caller is responsible for releasing the memory. Although this violates the above principles, COM is designed in this way based on convenience and efficiency.
 

  C Language C ++ Language Windows Platform Com Imalloc Interface BSTR
Application Malloc () New Globalalloc () Cotaskmemalloc () Alloc () Sysallocstring ()
Apply again Realloc ()   Globalrealloc () Cotaskrealloc () Realloc () Sysreallocstring ()
Release Free () Delete Globalfree () Cotaskmemfree () Free () Sysfreestring ()

These functions must be used in combination by type (for example, the memory applied for by new must be released using delete ). Within COM, of course, you can use any type of memory allocation to release functions. However, if a component needs to interact with the customer's memory, you must use the last three class Function Families in the table above.
1. BSTR memory has already been described in a wide range in the previous book and will not be repeated;
2. cotaskxxx () function family is essentially a function called in C Language (malloc ...);
3. The imalloc interface is a packaging of the cotaskxxx () function family. After packaging, some functions are also enhanced. For example, imalloc: getsize () can be used to obtain the size, and imallocspy can be used to monitor the memory usage;

IV,Parameter transfer direction

In C language function declaration, especially when the parameter is a pointer, you cannot see its transmission direction. For example:
Void fun (char * P1, int * P2); which of the following are input parameters for P1 and P2? Which one is the output parameter? Even all input parameters or all output parameters? Due to issues such as memory allocation and release, com needs to specify the parameter direction. In the future, we will write programs like the following:

Hresult add ([in] Long N1, [in] Long N2, [out] Long * pnsum); // IDL file (note 2) stdmethod (ADD) (/* [in] */long N1,/* [in] */long N2,/* [out] */long * pnsum );//. h file

If the parameter is a dynamically allocated memory pointer, follow the following rules:
 

Direction Applicant Released Prompt
[In] Caller Caller After the component receives the pointer, it cannot reallocate the memory.
[Out] Components Caller After the component returns a pointer, the caller "Love your location" (note 3)
[In, out] Caller Caller The component can reallocate the memory.

V. sample programs

Example 1: Obtain the progid from clsid. (The program uses word as an example. If the running is incorrect, hey, you have not installed word ?)

: Coinitialize (null); hresult hr; // {000209ff-0000-0000-c000-000000000046} = word. application.9clsid CLSID = {0x209ff, 0, 0, {0xc0, 0, 0, 0, 0x46 }}; lpolestr lpwprogid = NULL; HR =: Married (CLSID, & lpwprogid ); if (succeeded (HR) {: messageboxw (null, lpwprogid, l "progid", mb_ OK); imalloc * pmalloc = NULL; HR =: cogetmalloc (1, & pmalloc); // obtain imallocif (succeeded (HR) {pmalloc-> free (lpwprogid); // release progid memory pmalloc-> release (); // release imalloc }}:: couninitialize ();

Example 2: How to Use "Browse folder" to select a dialog window.

Cstring browsefolder (hwnd, lpctstr lptitle) {// call shbrowseforfolder to obtain the directory (folder) Name // parameter hwnd: parent window handle // parameter lptitle: window title char szpath [max_path] = {0}; browseinfo m_bi; m_bi.ulflags = bytes | bif_statustext; rows = hwnd; rows = NULL; m_bi.lpsztitle = lptitle; m_bi.lpfn = NULL; m_bi.lparam = NULL; m_bi.pszdisplayname = szpath; lpitemidlist pidl =: shbrowseforfolder ( & M_bi); If (pidl) {If (! : Shgetpathfromidlist (pidl, szpath) szpath [0] = 0; imalloc * pmalloc = NULL; If (succeeded (: shgetmalloc (& pmalloc ))) // obtain the imalloc Allocator interface {pmalloc-> free (pidl); // release the memory pmalloc-> release (); // release the interface} return szpath ;}

Example 3: display a jpg image in the window.

Void cxxxview: ondraw (CDC * PDC) {: coinitialize (null); // com initializes hresult hr; cfile file; file. open ("C: // aa.jpg", cfile: moderead | cfile: sharedenynone); // read the file content DWORD dwsize = file. getlength (); hglobal hmem =: globalalloc (gmem_moveable, dwsize); lpvoid lpbuf =: globallock (hmem); file. readhuge (lpbuf, dwsize); file. close ();: globalunlock (hmem); istream * pstream = NULL; ipicture * ppicture = NULL; // get istream from hglobal. If the parameter is true, istream is released, release memory hR =: createstreamonhglobal (hmem, true, & pstream); Assert (succeeded (HR); HR =: oleloadpicture (pstream, dwsize, true, iid_ipicture, (lpvoid *) & ppicture); Assert (hR = s_ OK); long nwidth, nheight; // width/height, mm_himetric mode, unit: 0.01mm ppicture-> get_width (& nwidth); // width: ppicture-> get_height (& nheight ); /// high ////// original large display ///// csize SZ (nwidth, nheight); PDC-> himetrictodp (& sz ); // The mm_himetric conversion mode is measured in mm_text pixels. The unit is ppicture-> render (PDC-> m_hdc, 0, 0, Sz. CX, Sz. cy, 0, nheight, nwidth,-nheight, null); // display by window size // crect rect; getclientrect (& rect); // ppicture-> render (PDC-> m_hdc, 0, 0, rect. width (), rect. height (), // 0, nheight, nwidth,-nheight, null); If (ppicture) ppicture-> release (); // release ipicture pointer if (pstream) pstream-> release (); // release the istream pointer and release hmem: couninitialize ();}

Example 4: Create a shortcut on the desktop
Before reading the code, let's take a look at the structure of the "shortcut" component.

 
Figure 2 interface structure of the shortcut component

From the structure diagram, we can see that the "shortcut" component (clsid_shelllink) has three (in fact, more than one) interfaces, each of which completes a set of functions. The ishelllink interface (iid_ishelllink) provides a shortcut for parameter read/write (see figure 3). The ipersistfile interface (iid_ipersistfile) provides a shortcut for persistent file read/write. Object persistence (note 5) is a very common and powerful interface family. But today, we only need to know two of these functions: ipersistfile: Save () and ipersistfile: load (). (Note 6)

 
Figure 3. Attributes of shortcuts

# Include <atlconv. h> void createshortcut (lpctstr lpszexe, lpctstr lpszlnk) {// create a blockchain method // parameter lpszexe: full path name of the EXE file // parameter lpszlnk: full path name of the shortcut file :: coinitialize (null); ishelllink * PSL = NULL; ipersistfile * PPF = NULL; hresult hR =: cocreateinstance (// start component clsid_shelllink, // shortcut clsidnull, // for aggregation (note 4) clsctx_inproc_server, // iid_ishelllink, // IID (lpvoid *) & PSL) of the shell32.dll service in the process; // obtain the interface pointer if (Succeeded (HR) {PSL-> setpath (lpszexe); // full path program name // PSL-> setarguments (); // command line parameters // PSL-> setdescription (); // remarks // PSL-> sethotkey (); // shortcut key // PSL-> seticonlocation (); // icon // PSL-> setshowcmd (); // window size // obtain the directory name tchar szworkpath [max_path] based on the EXE file name;: lstrcpy (szworkpath, lpszexe); lptstr Lp = szworkpath; while (* LP) LP ++; while (''//''! = * LP) LP --; * Lp = 0; // set the default working directory of the EXE program, PSL-> setworkingdirectory (szworkpath ); hR = PSL-> QueryInterface (// persistence file query interface pointer iid_ipersistfile, // persistence interface IID (lpvoid *) & PPF ); // obtain the interface pointer if (succeeded (HR) {uses_conversion; // convert it to the Unicode string PPF-> Save (t2cole (lpszlnk), true ); // save} If (PPF) PPF-> release (); If (PSL) PSL-> release ();: couninitialize ();} void onxxx () {createshortcut (_ T ("C: // winnt // notepad.exe "), // Notepad program. Note: Is your system also in this directory? _ T ("C: // Documents and Settings // administrator // desktop // my notepad. lnk "); // create the full path name of the shortcut (lnk) file on the desktop. Note: Is your system also in this directory? // If you use a program to find the desktop path, you can check the registry // HKEY_CURRENT_USER/software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders}


VII. Summary

The content described in this article is more practical. Do not just copy the code, but understand it. Use the msdn instructions to think about the code and understand its meaning. Okay, try to forget the code! Three days later (if you haven't forgotten it, you will have three days later). If you don't refer to the sample code, you can read the msdn code at will, you can complete these four routines independently, so congratulations, you are getting started: 0) from the next time, we will use ATL for com development. Are you ready?

Homework, leave homework ......
1. You have learned how to create a shortcut. Do you know how to read its attributes? (If you cannot write this program, you don't have to continue learning. Because... use your brains! I have never seen a student as stupid as you !)
2. The ipicture interface is used in Example 3 to display a jpg image. Now you can complete a function to convert a JPG file to a BMP file.

Note 1: Concepts and usage of smart pointers will be introduced later.
Note 2: The IDL file will be introduced next time.
NOTE 3: You can do whatever you want in Northeast China. I don't care.
Note 4: Aggregation. For details, refer to in 30th :-)
Note 5: persistence. ipersistxxxxxx is a very powerful interface family.
Note 6: Do you want to know all functions of the ishelllink and ipersistfile interfaces? Don't wait. Go to msdn ......
I. Preface

Hello, comrades, friends, and leaders.
 

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: info-contact@alibabacloud.com 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.