Write c ++ code with better reusability -- band object and comtoys (2)

Source: Internet
Author: User

Compile/Zhao Xiangning

Original: Paul dilascia

MSJ November 1999 & December 1999

Keywords: bands object, desk bands, info/Comm bands, explorer bar, and tool bands.

This document assumes that you are familiar with C ++, COM, and IE.

Download the source code of this article: mybands.zip (KB)
Testeditsrch.zip (75kb)

Part 1: Introduction to band objects

The second part is bandobj's class hierarchy and mybands service program registration.

Bandobj class hierarchy

After reading the first part, you should understand how to use bandobj to compile the band object (define a guid and then call addbandclass). Next we will go further to bandobj, reveal how it works. From bandobj, we can see that it involves three classes: cbandobjdll, cbandobjfactory, and cbandobj. The relationship between these three classes and MFC is shown in Figure 5:

Figure 5

Cbandobjfactory is the class factory for creating cbandobj objects. You do not need to use this class directly. When you call addbandclass from the initinstance function, cbandobjdll creates a new class factory and adds the class factory to a list:

Bool cbandobjdll: addbandclass (...) {cbandobjfactory * pfact = oncreatefactory (...); pfact-> m_pnextbandfact = m_pbandfactories; m_pbandfactories = pfact; return true;} oncreatefactory is a virtual function that only returns a new class factory. Cbandobjfactory * cbandobjdll: oncreatefactory (...) {return New cbandobjfactory (...);}

The purpose of oncreatefactory here is that once you want to derive your own factory class, you can derive from cbandobjfactory and reload oncreatefactory so that bandobj can use it. For clarity, I have omitted the parameter. The parameter here is the same as the parameter passed to addbandclass: Class ID, MFC runtime class, type ID, and resource ID. Cbandobjfactory transmits the first two parameters to MFC, and the last two parameters are used by itself.

CBandObjFactory::CBandObjFactory(REFCLSID clsid,    CRuntimeClass* pClass,   const CATID& catid, UINT nIDRes)   :  COleObjectFactory(clsid, pClass, FALSE, NULL){   m_catid = catid;   m_nIDRes = nIDRes;}      

Bandobj does not process a class factory in the usual way. Generally, declare_olecreate and implement_olecreate are used when compiling COM objects in MFC. It creates coleobjectfactory as a static object. One of the problems with using these macros is that they write the class coleobjectfactory into the code, so that you cannot use other classes. The second problem is that they create the class factory as static data, again, I wrote the class factory code named cyourclass: to death. So why should we use these macros? They are provided for convenience. If you want to create your own class factory in the stack instead of using some other classes, this is advantageous. As long as I derive from coleobjectfactory, when com calls DLL to create an object, every object factory class coleobjectfactory will add itself to the master list of an MFC search, in this way, MFC finds this class when creating an object. By dynamically creating a class factory in the heap, bandobj can be hidden in the programmer's field of view.

Register the mybands Service Program

Technically speaking, we still haven't fully figured out the full picture of the band object, but don't worry. Let's look at the registration issue. Registration is like breathing in the nose, and is indispensable in COM. The following is the registration entry for the Web search box in the Registry on my machine:

Hkey_classes_root clsid {certificate} = "& Web search box" inprocserver32 = mybands. dll threadingmodel = apartment implemented categories {00021492-0000-0000-c000-000000000046}

The preceding three registrations are available on all the com servers in the process:
CLSID -- the ID of the band object class,
Inprocserver32 -- indicates an in-process server, which must be a DLL
Threadingmodel -- thread model,
The last registration entry is the kind ID we mentioned earlier: categories. Generally, when a COM Object declares its type, it columns it in the hkcr/CLSID/GUID/implemented categories portal.
The registration and marketing of the comobject must be implemented through the regsvr32.exe program. When you use the following command:

Regsvr32.exe mybands. dll // register regsvr32.exe/u mybands. dll // deregister

Regsvr32 calls the dedicated entry dllregisterserver to register mybands. If the/u parameter is used, it calls dllunregisterserver to log out of mybands. The bandobj. cpp file provides their default standard implementations, including dllgetclassobject and dllcanunloadnow. These default implementations call special MFC functions to complete the corresponding work, such:

STDAPI DllRegisterServer(){   AFX_MANAGE_STATE(AfxGetStaticModuleState());   return COleObjectFactory::UpdateRegistryAll(TRUE) ? S_OK : SELFREG_E_CLASS;}

Coleobjectfactory: updateregistryall traverses all class factories and calls updateregistry (true) for each class factory ).
The same is true for dllunregisterserver, but it uses false to call the MFC function. Coleobjectfactory: The updateregistry function implements registration control, but it does not recognize the band type. Therefore, you must write some code to do this.

Simplify tedious Registration

If you have used Windows APIs to register component objects, you must know how painful it is. Regcreatekey, regsetvalue, regclose... I was completely confused when I first came into contact with these things. Fortunately, there is another better way to implement this book, that is, to use the ATL Registry (Registrar ). It is one of my favorite ATL features. With it, registration of COM objects is easy. Its function is a bit like regedit, which allows loading a special. RGS script (similar to the. reg file). The script can be used not only to add but also to delete the registration entry. In fact, given a script, the Registrar (more or less) knows how to log out (unregister ). That is to say, you can use the same script for registration and cancellation. This is really cool, because the work of canceling components is often ignored by most programmers (too lazy ), if you can log out automatically, the Registry will not be contaminated.
It is easy to use the ATL register. For example:

CComPtr<IRegistrar>ireg; ireg.CoCreateInstance(CLSID_Registrar,                        NULL, CLSCTX_INPROC); ireg->FileRegister("foo.rgs");      

The sharp arc in the first line of this code is very interesting. It is an ATL smart pointer (which will be discussed below ). Cocreateinstance: Create a registrar object and use it directly. However, I am a little nervous about the sharp arc. I hate to see this sharp arc in the Code unless I have to use it for comparison and conversion. Therefore, I wrote a small class ciregistrar in comtoys to further simplify it and hide the sharp arc that is not pleasing to the eye. This class actually encapsulates the ATL smart pointer:

CTRegistrar r; r->FileRegister("foo.rgs");      

In this way, you only need to instantiate ctregistrar and call the cocreateinstance method by the constructor. The call of the fileregister ("foo. RGS") method remains unchanged. Iregistrar is capable of registering and deregistering a script file, or even a resource. All iregistrar methods are in the atliface. h file. Cbandobjfactory: updateregistry has a common implementation that is responsible for finding registered resources with the same ID as the class factory and calling the Register to load it.

BOOL CBandObjFactory::UpdateRegistry(BOOL bRegister){   static const LPOLESTR RT_REGISTRY =      OLESTR("REGISTRY");   UINT nID = GetResourceID();   if (!::FindResource(AfxGetResourceHandle(),     MAKEINTRESOURCE(nID), CString(RT_REGISTRY)))     return FALSE;   CTRegistrar iReg;   OnInitRegistryVariables(iReg); // see below   LPOLESTR lposModuleName = /* get module pathname */   HRESULT hr = bRegister ?     iReg->ResourceRegister(lposModuleName, nID,        RT_REGISTRY) :     iReg->ResourceUnregister(lposModuleName, nID,        RT_REGISTRY);   return SUCCEEDED(hr);}      

Here we use a typical MFC method to process resources, and bandobj makes good use of resource IDs. All you need to do to register and deregister your band object is to write a registration script-without having to write any code! And only one function is involved in the code. In fact, you don't even need to write the registration script because the bandobj example program has already written a script file, which applies to any band object. Use it directly.

// In the example, all scripts are placed in the Application resource mybands. RC idr_infoband registry discardable "bandobj. RGS "idr_commband registry discardable" bandobj. RGS "idr_0000band registry discardable" bandobj. RGS"

However, how can we use the same registration script for three different COM objects? Don't they have different names and class IDs? This is the benefit of iregistrar. Check the registration script bandobj. RGS. % CLSID %, % classname %, and % module % are everywhere. What do these signs mean? These are all variables. Before processing the script, the register will replace these variables with the actual values (class ID, class name, and module name. So how does it know what value to use? Because you told it -- or bandobj told it. You may notice that there is a call to oninitregistryvariables in updateregistry. At this point, bandobj defines its variables.

BOOL CBandObjFactory::OnInitRegistryVariables(IRegistrar* pReg){     USES_CONVERSION;     pReg->AddReplacement(OLESTR("CLSID"),  StringFromCLSID(m_clsid));     pReg->AddReplacement(OLESTR("MODULE"), T2OLE(GetModuleName()));     pReg->AddReplacement(OLESTR("ClassName"), T2OLE(GetClassName()));     return TRUE;}      

The following is a list of all variables created in cbandobjfactory, which are automatically defined by bandobj.

% CLSID % = Class ID (guid) (coleobjectfactory: m_clsid) % module % = DLL full path name % title % = title (resource substring 0) % classname % = readable com Class Name (resource substring 1) % progid % = progid (resource substring 2)

To add your own variables, such as % timestamp % or % myreleaseversion %, you only need to derive a new class factory and reload oninitregistryvariables. Do not forget to call the base class, because MFC calls updateregistry for each class factory, and for each class, the variables are reinitialized. In mybands, the % CLSID % of the first class factory is clsid_myinfoband, And the % CLSID % of the second class factory is CLSID _ mycommband, the % CLSID % of the third class factory is clsid_my1_band. The same script processes the registration of three objects !.
Iregistrar is so cool, so I wrote my own command line utility rgsrun to load the RGS file. It is very useful for testing and debugging scripts or removing unnecessary garbage from the registry, some features are not available in regedit. This utility is provided together with the example in this article. In the autoexec. BAT file, I use rgsrun to load a file: autoexec. RGS. Different explorer options are set, and the file is automatically loaded every time windows starts.

Type Registration

If you carefully read this article, you will notice that the above mentioned script file does not contain any information about band object type registration. Why? Where can bandobj register its type information? I used another variable to do this. It is % catid %, and there is always an interface in the com library to apply it, and the type is no exception. The formal type registration method is implemented through icatregister:

Bool cbandobjfactory: updateregistry (bool breg) {... // use icatregister to register/deregister types ctcatregister ICAT; refiid CLSID = m_clsid; HR = bregister? ICAT-> registerclassimplcategories (CLSID, 1, & m_catid): ICAT-> unregisterclassimplcategories (CLSID, 1, & m_catid); // return, bypass MFC return hR = s_ OK ;}

It can be seen that the use of ATL smart pointers, comtoys class and ctcatregister makes programming easier. You only need to declare the instance. (To be continued)

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.