COM component design and application 4 - Simple call components

xiaoxiao2021-03-18  237

Vckbase is not allowed, and the netizens have a lot of articles. How does the component design? Knowledge Base is boring! Excerpted from --- Yang Teacher's oil collection under the support of VCKBASE, under the encouragement of all netizens replying, I can successfully complete the first three times of the series of papers. Book in this book, we finally start writing code. Write something? Well, there is! Let's start from how to call out-scale simple components, but also introduce some related knowledge. Second, the startup and release of the component is in the third time, and the big house records a principle of "small book": COM components are running in a distributed environment. So, how to start the component immediately encountered a serious problem, everyone see this code: P = new object;

P-> object function ();

DELETE P; Such code is familiar, but it does not have problems in the local process. But you think that if this object is on the computer of the "Earth", what is the result? Hey, C is not considered a remote implementation when designing New (the computer language is certain, no need to design). Therefore, the function of starting the component, calling the interface, of course, is implemented by the COM system. Figure 1 The component call mechanism can be seen by the above figure. When the component is called, it is actually completed by the communication between the agent (running in local) and the stub (running at the far). Specifically, when the client starts the component via the CocreateInstance () function, the agent takes over the call, it and the stub communication, the reset it is located local (relative to the customer program is remote) Execute the NEW operation load object. For beginners, you can do it, agents and stubs are transparent to us. As long as it knows how it is, there is everything OK. The problem is coming again, when is this remote object destroyed? At the time of the second time, we deliberately ignored two functions at the time, that is, IUnknown :: addRef () and iunknown :: release (), can guess from the function name, one is the internal reference record (REF) plus 1, one is released (minus 1), when the logger is reduced to 0, it is the opportunity to release. It looks very complicated, no way, because this is in the introduction principle. In fact, when we write the program, please comply with several principles: 1, after the startup component gets an interface pointer (Interface), do not call AddRef (). Because the system knows that you get a pointer, it has helped you call the addRef () function; 2, after another interface pointer, do not call AddRef (). Because ... and the above truth; 3, when you assign the interface pointer to another variable, call AddRef (); 4, when no need to use the interface pointer Be sure to perform Release () release; 5. When using a smart pointer, the maintenance of the pointer can be omitted; (Note 1) Third, memory allocation and release have learned from the C language, the teacher taught us: for dynamic memory Application and release, must abide by the principle of "who apply, who releases". Under the guidance of this principle, not only me, not only you, even if you have designed such a weird function:

Function Description Reviews getWindowText (HWND, LPTSTSTR, INT) obtains window titles. You need to give the memory pointer used in the parameter, and the size of this memory. gosh! I don't know the length of the window title, but I have to provide size? ! No way, can only be estimated to give a big size. Sprintf (char *, const char *, ...) formats a string. This function does not have to give the length of the buffer. Well, although you don't have to give a length, do you dare to give a small size? Humph! INT CLISTBOX :: GetTextlen (int) Clistbox :: getText (int, lptstr) Get the title of the sub-item of the list window. Need to call two functions, first get the length, then assign memory, and then achieve the title content. Really annoying! To be honest, not only the function caller feel awkward, even the function of the function is not so cool, but all this is to meet the principle of "who is applying, who releases". The best way to solve this problem is that the function is applied to the memory within the actual needs, and the caller is responsible for release. Although this is contrary to the above principles, COM is really designed as convenient and efficiency. C language C language Windows platform COMIMalloc interfaces BSTR application malloc () newGlobalAlloc () CoTaskMemAlloc () Alloc () SysAllocString () to re-apply realloc () GlobalReAlloc () CoTaskRealloc () Realloc () SysReAllocString () to release free () deleteGlobalFree () CoTaskMemFree () Free () sysfreestring () These functions must be used in conjunction with the type (such as: New application memory, you must release it with Delete). Inside COM, of course you can use any type of memory allocation release function, but if the component needs to be interactive with the customer, you must use the subsequent three types of functions in the above table. 1. In the BSTR, there is a relatively rich introduction, no longer repeat; 2, the cotaskxxx () function family, it is essentially a function of calling the C language (malloc ...); 3, IMALLOC interface It is also a packaging for the cotaskxxx () function family. After packaging, there are also some features, such as: imiqueoc :: getSize () can get the size, use IMALLOCSPY to monitor memory usage; four, parameter delivery direction In the C language function declaration, especially when the parameter is a pointer, You can't see it in the direction of delivery. For example: void fun (char * p1, int * p2); I would like to ask, which one is income? Which one is from? It is or all income or all participation? COM needs to be clearly marked in the direction of the parameter direction due to the problem of memory allocation and release, etc. In the future, we write the program, just like the following: HRESULT ADD ([in] long n1, [in] long N2, [out] long * pnsum); // idl file (Note 2)

STDMETHOD (Add) (/ * [in] * / long n2, / * [in] * / long * pnsum); // .h file If the parameter is dynamically allocated memory pointer So comply with the following regulations:

Direction Applicant Release Man Tips [in] After the caller caller component receives the pointer, the memory cannot be redistributed [OUT] component caller component returns the pointer, the caller "Love" (Note 3) [in, out] The caller caller component can reassign the memory 5. Examples of the sample program, and get the progID by CLSID. (The program is an example. If you run incorrect, hey, you didn't install Word?) :: Coinitialize (null); HRESULT HR;

// {000209FF-0000-0000-C000-000000000046} = word.application.9

CLSID CLSID = {0x209FF, 0, 0, {0XC0, 0, 0, 0, 0, 0, 0, 0X46}};

LPolestr LPWProgid = NULL;

HR = :: ProgidFromClsid (CLSID, & lpwProgID);

En (ac))

{

:: MessageBoxw (NULL, LPWPROGID, L "progid", MB_OK);

IMALLOC * PMalloc = NULL;

HR = :: Cogether Malloc (1, & pmalloc); // get imalloc

En (ac))

{

PMalloc-> free (lpwprogid); // Release PROGID memory

Pmalloc-> release (); // Release IMALLOC

}

}

:: Couninitialize (); Example 2, how to use the "Browse Folder" to select the dialog window. CString Browsefolder (HWND HWND, LPCTSTSTSTR LPTITLE)

{

// Call the SHBROWSEFORFolder acquisition directory (folder) name

// Parameter hWnd: parent window handle

// Parameter LPTILE: Window Title

CHAR SZPATH [MAX_PATH] = {0};

Browseinfo M_Bi;

m_bi.ulflags = bif_returnonlyfsdirs | BIF_STATUSTEXT;

m_bi.hwndowner = hwnd;

m_bi.pidlroot = 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 (:: shrnelloc (& pmalloc))) / / get the IMALLOC distributor interface

{

PMalloc-> free (PIDL); // Release memory

Pmalloc-> release (); // Release interface

}

}

Return szpath;

}

Example 3, display a JPG image in the window. Void CXXXView :: Ondraw (CDC * PDC)

{

:: Coinitialize (NULL); // COM initialization

HRESULT HR;

CFILE FILE;

File.open ("c: //aa.jpg", cfile :: moderad | cfile :: sharednynone); // Read file content DWORD dwsize = file.getlength ();

Hglobal HMEM = :: GMEM_MOVEABLE, DWSIZE

LPVOID LPBUF = :: Globalock (HMEM);

File.readhuge (LPBUF, DWSIZE);

File.Close ();

:: GlobalUnlock (HMEM);

IStream * pstream = NULL;

IPicture * PPicture = NULL;

// Get the ISTREAM by Hglobal, the parameter true indicates that the memory is released while the iStream is released.

HR = :: CreateStreamonhglobal (HMEM, True, & Pstream);

Assert (ac));

HR = :: OLELOADPICTURE (Pstream, Dwsize, True, IID_IPICTURE, (LPVOID *) & PPICTURE);

Assert (hr == s_ok);

Long nwidth, nheight; // wide high, mm_himetric mode, unit is 0.01 mm

PPICTURE-> GET_WIDTH (& nwidth); // Wide

PPicture-> Get_Height (& nHEight); // High

Original display //

CSIZE SZ (NWIDTH, NHEIGHT);

PDC-> HimetrikeTodP (& SZ); // Conversion MM_HIMETRIC mode unit is mm_text pixel unit

PPicture-> Render (PDC-> M_HDC, 0, 0, SZ.CX, SZ.CY,

0, NHEIGHT, NWIDTH, -NHEIGHT, NULL;

Press window size display

// CRECT Rect; getClientRect (& Re);

// 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 while released HMEM

:: Couninitialize ();

}

Example 4, look at the structure of the "Shortcut" component before reading the code. Figure 2, the interface structure of the shortcut component can be seen from the structural diagram, "shortcut" component (CLSID_SHELLINK), 3 (actually more than "interface, each interface completes a set of related functions. The iShellLink interface (IID_ID_IDLINK) provides shortcut parameter read and write functions (see Figure 3), the IPERSISTFILE interface (IID_IPERSISTFILE) provides read and write function for shortcuts. The persistence of the object (Note 5) is a very common interface family. But today, we just know two functions, you can: ipersistfile :: save () and iPersistFile: loading (). (Note 6) Figure 3, various attributes in shortcuts #include Void Createshortcut (LPCTSTSTSTSZEXE, LPCTSTST LPSZLNK)

{

// Establish a block

// Parameter LPSZEXE: EXE file full path name

// Parameter LPSZLNK: Shortcut File Full Path Name

:: Coinitialize (NULL);

IShellLink * psl = null;

IPERSISTFILE * PPF = NULL;

HRESULT HR = :: COCREATEINSTANCE (// Startup Components

CLSID_SHELLINK, // Shortcut CLSID

NULL, // Polymerization (Note 4)

CLSCTX_INPROC_SERVER, // Delivery (shell32.dll) service

IID_IDLLINK, IID of ISHELLLINK

(Lpvoid *) & psl); // Get interface pointer

En (ac))

{

PSL-> setPath (lpszexe); // full path program name

// psl-> setarguments (); // command line parameters

// psl-> setdescription (); // Remarks

// psl-> sethotKey (); // shortcut

// psl-> seticonlocation (); // icon

// psl-> setshowcmd (); // window size

/ / According to the file name of EXE, get the directory name

Tchar SzworkPath [MAX_PATH];

:: lstrcpy (szworkpath, lpszexe);

LPTSTR LP = SzWorkPath;

While (* lp) lp ;

While ('' // ''! = * lp) lp -;

* lp = 0;

/ / Set the default work directory for the EXE program

PSL-> SetworkingDirectory (SzWorkPath);

hr = psl-> queryinterface (// Find continuous file interface pointer

IID_IPERSISTFILE, // Continuous Interface IID

(Lpvoid *) & ppf); // Get interface pointer

En (ac))

{

Uses_conversion; // Convert to 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 that your system is also this directory?

_T ("C: // Documents and Settings // Administrator // Desktop / My Notepad .Lnk")

);

The full path name of the shortcut (LNK) file is established on the desktop. Note that your system is also this directory?

// If you use a program to find a path to look for a desktop, you can check the registry.

// HKEY_CURRENT_USER / SOFTWARE / Microsoft / Windows / CurrentVersion / Explorer / Shell Folders

}

7. The content introduced by small junction is more practical. Don't just copy the code, but must understand it. Combined with the description of MSDN to think about the code and understand its meaning. Ok, try to forget the code! Three days later (if you haven't forgotten, then three days), you are not referring to the sample code, but you can read the MSDN, you can complete these four routines independently, so congratulations, You have started: 0) Starting from the next time, we have to use ATL to do COM development work, is your old man ready? Homework, stay homework ... 1, you have learned how to build shortcuts, then do you know how to read its properties? (If you can't write this program, then you don't have to continue to learn. Because ... I haven't seen my brain! I haven't seen the students like you!) 2, the sample program three is used. The iPicture interface displays a JPG image. Then you now complete a function, convert the JPG file to the BMP file.

Note 1: The concept and usage of the intelligent pointer, follow-up introduction. Note 2: IDL file, you will introduce it. Note 3: Northeast, I want to do anything, anyway, I don't care. Note 4: Aggregation, may introduce it in the 30th :-) Note 5: Continuous, IPersistxxxxx is a very powerful interface family, follow-up. Note 6: Want to know all the functions of the ISHELLLINK, IPERSISTFILE interface? Don't worry, go see MSDN ...

I. Introduction

Comrades, friends, leaders, everyone.

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

New Post(0)