Body
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
P
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
H1
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
H2
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
H3
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
H4
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
H5
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
H6
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
Li
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
TD
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
TH
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
DD
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
DT
{
Color: Black;
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-size: 10PT
}
Body
{
Background-color: #fffff;
Color: # 000000
}
Li
{
List-style: none
}
UL
{
List-style: none
}
OL
{
List-style: none
}
H1
{
Font-weight: bold
}
H2
{
Font-weight: bold
}
H3
{
Font-weight: bold
}
H4
{
Font-weight: bold
}
H5
{
Font-weight: bold
}
TH
{
Font-weight: bold
}
H2
{
Color: # ff9900
}
H3
{
Color: # ff9900
}
H5
{
Color: # ff9900
}
H1
{
FONT-SIZE: 16PT
}
H2
{
Font-size: 13PT
}
H3
{
Font-Family: Arial, Sans-Serif;
Font-size: 11PT
}
H4
{
FONT-SIZE: 10pt; margin-bottom: 0px;
Margin-top: 2px
}
H5
{
FONT-SIZE: 9PT;
Font-weight: bold;
Margin-bottom: 2px
}
H6
{
COLOR: # 626262;
FONT-SIZE: 65%;
Font-Weight: Normal: Normal
}
DD
{
Margin-Left: 20px
}
Preserver
{
Background-color: #fbedbb;
Background-image: URL (/Images/codebg.gif);
FONT: 9PT "Courier New", Courier, Mono;
Padding-bottom: 5pt;
Padding-left: 5pt;
Padding-right: 5pt;
Padding-top: 5pt;
White-space: pre;
Width: 100%
}
Code
{
Color: # 990000;
Font-Family: "Courier New", Courier, Mono
}
A: LINK
{
Text-Decoration: None
}
A: Visited
{
Text-Decoration: None
}
A: ACTIVE
{
Text-Decoration: underline
}
A: Hover
{
Text-Decoration: underline
}
.top
{
Cursor: HAND
}
.Menugroup
{
Background-color: # ffcc99;
Cursor: Hand;
Font-Family: Tahoma, Arial, Sans-Serif;
Font-weight: Normal;
Position: relative;
TOP: 0px;
Width: 124px
}
.Mi
{
Background-color: # ffcc99;
Color: Black;
Cursor: Hand;
Font-Family: Verdana, Arial, Sans-Serif
FONT-SIZE: 8pt;
Font-weight: Normal;
Width: 118px
}
.Mis
{
Background-color: # ffcc99;
Color: Black;
Cursor: Hand;
Font-Family: Verdana, Arial, Sans-Serif
FONT-SIZE: 8pt;
Font-weight: Normal;
Width: 118px
}
.Min
{
Background-color: # ffcc99;
Color: Black;
Cursor: Hand;
Font-Family: Verdana, Arial, Sans-Serif
FONT-SIZE: 8PT;
Font-weight: Normal;
Width: 118px
}
.Man
{
Background-color: # ffcc99;
Color: Black;
Cursor: Hand;
Font-Family: Verdana, Arial, Sans-Serif
FONT-SIZE: 8pt;
Font-weight: Normal;
Width: 118px
}
.Mi
{
Text-Decoration: None
}
.Min
{
Text-Decoration: None
}
.Mi
{
Border-bottom: # ffcc99 1px solid;
Border-left: # ffcc99 1px solid;
Border-right: # ffcc99 1px solid;
Border-top: # ffcc99 1px sol; margin-left: 3pt;
Padding-left: 3PT
}
.Mis
{
Border-bottom: # ffcc99 1px solid;
Border-left: # ffcc99 1px solid;
Border-right: # ffcc99 1px solid;
Border-top: # ffcc99 1px solid;
Margin-left: 3pt;
Padding-left: 3PT
}
.Min
{
Border-bottom: # ffcc99 1pt solid;
Border-left: # ffcc99 1pt solid;
Border-right: # ffcc99 1pt solid;
Border-top: # ffcc99 1pt solid
}
.Min
{
Margin-left: 2px;
Padding-left: 2px
}
.Man
{
Margin-left: 2px;
Padding-left: 2px
}
.sidebar
{
Color: #fffff;
FONT-SIZE: 9PT;
Font-weight: bold;
Text-Decoration: None
}
.navbar
{
Color: White;
FONT-SIZE: 8pt;
Font-weight: bold;
Text-Decoration: None
}
.navbar: Hover: HOVER
{
Color: Blue
}
.navbar: Active
{
Color: Red
}
.infobar
{
FONT-SIZE: 8pt;
Margin-left: 0pt;
TEXT-INDENT: 0PT
}
.infobarlist
{
FONT-SIZE: 8pt;
Margin-left: 1.5em;
Text-indent: -1.5em
}
.Infobarheader
{
Color: # AB2600;
FONT-SIZE: 9PT;
Font-weight: bold;
Margin-bottom: -10px
}
.Hoverlink
{
Border-bottom: # ffcc99 1px;
Border-left: # ffcc99 1px;
Border-Right: # ffcc99 1px;
Border-top: # ffcc99 1px;
FONT-SIZE: 8pt;
Padding-bottom: 2px;
Padding-left: 4px;
Padding-right: 4px;
Padding-top: 2px;
Text-Decoration: None
}
A.hoverlink
{
Color: blue;
Cursor: HAND
}
A.hoverlink: Hover
{
Background-color: # ffcc99;
Border-bottom-color: #fbedbb;
Border-bottom-style: outset;
Border-left-color: white;
Border-left-style: outset;
Border-Right-Color: #fbedbb;
Border-right-style: output;
Border-top-color: white;
Border-top-style: outset;
Padding-bottom: 1px;
Padding-left: 3px;
Padding-right: 3px;
Padding-top: 1px
}
A.hoverlink: Active
{
Background-color: # ffcc99;
Border-bottom-color: white;
Border-bottom-style: INSET; Border-Left-Color: #fbedbb;
Border-left-style: INSet;
Border-Right-Color: White;
Border-right-style: INSet;
Border-Top-Color: #fbedbb;
Border-top-style: INSet;
Padding-bottom: 1px;
Padding-left: 3px;
Padding-right: 3px;
Padding-top: 1px
}
Tt.equation
{
Font-Family: 'Times New Roman', Serif;
FONT-SIZE: 10PT;
Font-style: itract;
White-Space: Pre
}
UL.DownloadLOAD
{
Margin-left: 1em
}
Ul.download Li
{
Font-Family: Verdana, Arial, Helvetica, Sans-Serif
FONT-SIZE: 9PT;
List-style: URL (/IMAGES/SAVE.GIF)
}
.MAINHEADER
{
Color: Black;
Font-Family: Tahoma, Helvetica, Arial, Sans-Serif
FONT-SIZE: 155%;
Font-weight: bold
}
.formutton
{
Background-color: # e08900;
Border-bottom-color: #fbedbb;
Border-left-color: #fbedbb;
Border-Right-Color: #fbedbb;
Border-Top-Color: #fbedbb;
Color: White;
FONT-SIZE: 90%;
Font-Weight: 700
}
.Sitenewsheading
{
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-weight: bold
}
.Devnewsheading
{
Font-Family: Verdana, Helvetica, Arial, Sans-Serif;
Font-weight: bold
}
.Devnewsheading
{
FONT-SIZE: 10.5pt
}
.links
{
Font-size: 8PT
}
.messagetiplele
{
Font-size: 8PT
}
.SiteNews
{
Font-size: 8PT
}
.Smalltext
{
Font-size: 8PT
}
.Sitenewsheading
{
Font-size: 8PT
}
.Devnewscontent
{
Font-size: 9PT
}
.MessageContent
{
Font: 9.5pt Verdana, "Courier New", Courier, Mono
}
.DEFAULT
{
Font-Family: Verdana, Helvetica, Arial, Sans-Serif
}
.forum_link: LINK
{
Color: # e08900;
Text-Decoration: None
}
.forum_link: visited
{
Color: # e08900;
Text-Decoration: None
}
.forum_link: Active
{
Color: # e08900;
Text-Decoration: None
}
.forum_link: Hover
{
Color: # e08900;
Text-Decoration: underline
}
.forum_hilite
{
Background-color: Yellow
}
.CPP-Comment
{
Color: Green;
Font-style: italic
}
.cpp-keyword
{
Color: Blue
}
.cpp-preprocessor
{
Color: Navy
}
.cpp-string
{
Color: Purple
}
.cpp-literal
{
Color: MidNightBlue
}
Table # tblbuttonbar
{
Margin-top: 1px
}
.clsbutton
{
Background-color: # ff9900;
Border-bottom: # ff9900 1px solid;
Border-left: # ff9900 1px solid;
Border-Right: # ff9900 1px solid;
Border-top: # ff9900 1px solid;
Color: # 333300;
Cursor: Hand;
FONT-SIZE: 8pt;
Font-weight: bold;
Text-Decoration: None
}
Table.Clsbutton: Hover
{
}
Td.clsButtonBar Table.Clsbutton TD
{
Padding-bottom: 1px;
Padding-left: 1px;
Padding-right: 1px;
Padding-top: 1px
}
Example of this article Download (19K) (CodeProject.com)
In the first part of this guide, I gave you a introduction to a shell extension and demonstrate an operation of a context menu extension of a simple file. In the second part, I will demonstrate how to operate multiple files in one operation. This extension is a utility that registers and unresses the COM server. It also demonstrates how to use the ATL dialog class CDialogImpl. I will explain the second part by explaining some special registry keys, through these keys, you can call your extension by any file, not those pre-selected types (.txt).
The second part assumes that you have read the first part, so you know the basic knowledge of the context menu extension. In addition, you must also understand the basic knowledge of COM, ATL and STL.
The beginning of the context menu extension - what can it do?
This housing extension will enable you to register and uninstall those COM servers in EXE, DLL, and OCX. Unlike we do in the first part, this extension will operate all the selected files when you right click on the event.
Start using AppWizard
Run AppWizard and make a new ATL COM Wizard App. We call it dllreg. Keep all default options in the wizard, click Finish. We now have an empty ATL project that will generate a DLL, but we have to add your own housing to extend COM objects. In the ClassView tree, right-click the Dllreg Classes item, select New ATL Object.
In the ATL Object Wizard, the first panel has chosen Simple Object, as long as you click Next. In the second panel, enter DLLREGSHLEXT in the SHORT NAME editing control, and then click OK (other edit box in the panel will be done automatically). This creates a class named CDLREGSHLEXT, which contains basic code for implementing a COM object. We will add our code to this class.
Initialization interface
In this extension, our ishellextinit :: initialize () implementation will be quite different. There are two reasons, first we will list all selected files; second, we will test whether we have the exit of the registered (Register) and unreguses. We will only consider files with DllregisterServer () and DllunregisterServer (). Others will be ignored. We will use list controls and STL strings and list classes, so you must first add as follows in the stdafx.h file:
#include
#include
#include
#include
Typedef st :: list
Our CDLREGSHLEXT class will also need some member variables:
protected:
Hbitmap m_hregbmp;
Hbitmap m_hunregbmp;
String_list m_lsfiles;
TCHAR M_SZDIR [MAX_PATH];
The bitmap used in the two context menu is loaded in the constructor of CDLREGSHLEXT:
CDLREGSHLEXT :: CDLREGSHLEXT ()
{
m_hregbmp = loadingbitmap (_Module.getModuleInstance (),
MakeintResource (IDB_REGISTERBMP);
m_hunregbmp = loadingbitmap (_Module.getModuleInstance (),
MakeintResource (IDB_UNREGISTERBMP);
}
After you add iShellextinit to the list of interfaces implemented by CDLREGSHLEXT (see the first part for this operation), let's start writing the initialize () function.
Initialize () will perform the following steps:
Changing the current directory is a directory that is being viewed in the resource browser window; lists all selected files; for each file, try to load it with loadLibrary (); if loadLibrary () successfully, see if this file has DllRegisterServer () And DllunRegisterServer () function exit; if the two exits are found, add the file name of the file name to the list of we can operate, M_LSFiles.
HRESULT CDLREGSHLEXT :: Initialize
LPCIDLIST PIDLFOLDER,
LPDataObject pdataobj,
HKEY HPROGID)
{
Tchar Szfile [MAX_PATH];
Tchar Szfolder [MAX_PATH];
Tchar Szcurrdir [MAX_PATH];
Tchar * pszlastbackslash;
Uint unusfiles;
HDrop HDROP;
Formatetc etc = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM STG = {TYMED_HGLOBAL};
Hinstance hinst;
Bool bchangeddir = false;
HRESULT (STDAPICLTYPE * PFN) ();
Very large partial variable! The first step is to get an HDROP from the pDATAOBJ parameters of the pass. This is similar to the extension of the first part. // read the list of folders from the data object. The Data Object. They're Stored in HDROP
// Format, So Just Get The HDrop Handle and the Use The Drag 'N' Drop Apis
// on it.
IF (failed (PDO-> GetData (& etc, & strg)))
Return E_INVALIDARG;
// Get an HDrop Handle.
HDrop = (HDROP) GlobalLock (strg.hglobal);
IF (null == HDROP)
{
ReleaseSTGMEDIUM (& STG);
Return E_INVALIDARG;
}
// DETERMINE How Many Files Are Involved in this Operation.
Unumfiles = DragQueryFile (HDROP, 0xFfffffff, NULL, 0);
The next thing to do is a For loop that gets the next file name (using DragQueryFile ()) and tries to load it with LoadLibrary (). The work of some directory changes are pre-made in the actual example project of this article. I have ignored it here because it is a bit too long.
For (uint ufile = 0; ufile { // Get the next filename. IF (0 == DragQueryfile (HDROP, UFILE, SZFILE, MAX_PATH)) CONTINUE; // Try & load the dll. Hinst = loadLibrary (SZFILE); IF (null == hinst) CONTINUE; Next, we will see if it has two exits of the necessary functions. // Get the address of dllregisterServer (); (FarProc &) PFN = GetProcaddress (Hinst, "DLLREGISTERSERVER"); // if IT WASN'T FOUND, SKIP The File. IF (NULL == PFN) { Freelibrary (HINST); CONTINUE; } // Get the address of dllunregisterServer (); (FarProc &) PFN = GetProcaddress (Hinst, "DllunregisterServer"); // if IT Was Found, We can operate on the file, so add it to // Our List of files (m_lsfiles). IF (NULL! = PFN) { m_lsfiles.push_back (szfile); } Freelibrary (HINST); } // end for The final step is (in the last IF block) Add file name to m_lsfiles. M_lsfiles is a STL list set for saving strings. This list is later, it will be used when we traverse all files registration and uninstall. The last thing to do in Initialize () is to release resources and return the appropriate value to Explorer. // Release resources.globalunlock (strg.hglobal); ReleaseSTGMEDIUM (& STG); // if We found any files we can work with, returno s_ok. Otherwise, // RETURN E_INVALIDARG SO We don't get called again for this right-click // Operation. Return (m_lsfiles.size ()> 0)? S_OK: E_INVALIDARG; } If you look at an example of an example project code, you will find that I have to cross the file name of the video to calculate which directory is being viewed. You may be wondering why I don't have to use the PIDLFolder parameter. Although in the document of PIDLFolder, it is interpreted as "Item List of Item Sign" (The Item Identifier List for the Folder That Contains The Item Whose Context Menu Is Being Displayed) (I am sorry I can't Translate this sentence is good, post the original text for reference). " However, when I test on Windows 98, this parameter is always NULL, so it is useless. Add our menu item The next thing is the icontextMenu method. As before, you need to add IconTextMenu to the interface list implemented by CDLREGSHLEXT. Once again, the steps of doing these are in the first part. We will add two menu items to the menu, one for registered files, one to uninstall them. These items look as follows: Our QueryContextMenu () implementation begins like the first part. We check UFLAGS if the CMF_DEFAULTONLY flag exists immediately. HRESULT CDLREGSHLEXT :: QueryContextMenu Hmenu Hmenu, Uint umenuindex, Uint uidfirstcmd, UINT Uidlastcmd, UINT UFLAGS) { UINT UCMDID = UidFirstCMD; // if the flags include cmf_defaultonly kil dam''t do anything. IF (uflags & cmf_defaultonly) { Return make_hresult (severity_success, facility_null, 0); } Below, we add the "Register Servers" menu item. Some new things here: We set a bitmap to the menu item. This is a bit similar to the winzip menu, and a small icon is displayed next to the menu command. // Addur register / unregister items. INSERTMENU (HMENU, UmenuIndex, MF_String | MF_BYPOSITION, UCMDID , _T ("Register Server (s)")); // set the bitmap for the register item. IF (NULL! = m_hregbmp) { SetMenuItemBitmaps (HMENU, UmenuIndex, MF_BYPOSITION, M_HREGBMP, NULL); } UmenuIndex ; SetMenuItemBitmaps () API Function We are next to the menu. Note that ucmdid is an increase in, this next time we call INSERTMENU (), its command ID will be more than the previous 1. At the end of this step, UmenuIndex is added because our second menu item will be displayed after the first one. Then say the second menu item. It is very similar to the first. INSERTMENU (HMENU, UmenuIndex, MF_String | MF_BYPOSITION, UCMDID , _T ("Unregister Server (s)"))); // set the bitmap for the unregister item. IF (NULL! = M_HunRegbmp) { SetMenuItemBitmaps (HMENU, UmenuIndex, MF_BYPOSITION, M_HUNREGBMP, NULL); } Finally, we tell Explorer we have added several menu items. Return make_hresult (severity_success, facility_null, 2); Provide sensitive help and verbs As in front, when Explorer needs to display sensitive help or get verbs, the getcommandstring () method is called. A slightly different from the previous one is that we have added 2 menu items, so we must first check the UCMDID parameters to know which menu items are calling the eXplorer. #include HRESULT CDLREGSHLEXT :: getcommandstring Uint ucmdid, UINT UFLAGS, Uint * pureserved, LPSTR SZNAME, Uint cchmax) { LPCTSTSTSZPROMPT; Uses_Conversion; IF (uflags & gcs_helptext) { Switch (UCMDID) { Case 0: Szprompt = _t ("Register All Selected COM Servers); Break; Case 1: Szprompt = _t ("Unregister All Selected COM Servers); Break; DEFAULT: Return E_INVALIDARG; Break; } If UCMDID is 0, then we are calling the first (register). If 1, the second (unregister) is called. After determining the help string, we copy it to the supplied cache, if necessary, first convert it into a unicode form. // Copy the help text inteo the support buffer. If the shell wants // a Unicode String, We need to case szname to an lpcwstr. IF (UFLAGS & GCS_UNICODE) { LSTRCPYNW ((LPWSTR) SZNAME, T2CW (SZPROMPT), CCHMAX); } Else { LSTRCPYNA (SZName, T2CA (SZPROMPT), CCHMAX; } } In this extension, I also wrote the code to provide a verb. However, when I test under Windows 98, Explorer never call getCommandString () to get a verb. I even wrote a test program that calls shellexecute () in the DLL and try to use the verb, but it still doesn't work. I don't know if this situation will be different under Windows NT. Here, I ignore those verbs related code. If you are interested, you can find it in the example project. Execute user selection Explorer calls our InvokeCommand () method when the user clicks on one of our menus. InvokeCommand () first checks the high word of LPVERB (High Word). If it is non-zero, it is the name of the verb being called, because we know that the verb does not work properly (at least in Win 98), we ignore it. Otherwise, if its low word is 0 or 1, then we know that one menu item is clicked. HRESULT CDLREGSHLEXT :: InvokeCommand (lpcminvokecommandinfo pcmdinfo) { // if lpverb really points to a string, Ignore this function call and bail out. IF (0! = HiWord (Pinfo-> LPVERB)) Return E_INVALIDARG; // Check That Lpverb is one of our commands (0 OR 1) Switch (Pinfo-> LPVERB)) { Case 0: Case 1: { CPROGRESSDLG DLG (& M_Lsfiles, Pinfo); Dlg.domodal (); Return S_OK; } Break; DEFAULT: Return E_INVALIDARG; Break; } } If LPVERB is 0 or 1, we create a dialog (inherited from ATL Class CDialogIMPL) and pass the file name list. All actual work is done in the CProgressDLG class. Its OnInitDialog () function initializes list controls and then calls CProgressdlg :: DOWORK (). DOWORK () traverses the file name list in CDLREGSHLEXT: :: Initialize () and then calls the appropriate function in the file. The basic code is as follows; not complete because I deleted the part of the error check and populate the list control. However, this is enough to demonstrate how to traverse a list of files and perform each one. Void CProgressdlg :: DOWORK () { HRESULT (STDAPICLTYPE * PFN) (); String_list :: const_iterator it, ipden; Hinstance hinst; LPCSTR PSZFNNAME; HRESULT HR; Word wcmd; WCMD = loword (m_pcmdinfo-> lpverb); // We Only Support 2 Commands, So Check The Value Passed in Lpverb. IF (WCMD> 1) Return; // determine Which Function We'll Be Calling. Note That Sense Strings Are // not enclosed in the _t macro, Since getProcaddress () Only takes an // ANSI STRING for the function name. PSZFNNAME = WCMD? "DllunregisterServer": "DLLREGISTERSERVER"; For (it = m_pfilelist-> begin (), ity = m_pfilelist-> end (); It! = ity; IT ) { // Try to load the next file. Hinst = loadingLibrary (it-> c_str ()); IF (null == hinst) CONTINUE; // Get The Address of The Register / Unregister Function. (FarProc &) PFN = GetProcaddress (Hinst, pszfnname); // if it isn n't found, Go on to the next file. IF (NULL == PFN) CONTINUE; // Call the function! HR = PFN (); I need to explain that FOR loop because the STL collection class is a bit of a bit of stunning, if you are not used to using it. M_PFileList is a pointer to the M_LSFiles list in the CDLREGSHLEXT class. (This pointer is passed to the CPROGRESSDLG constructor.) The STL list set has a type called const_iterator, which is an abstract entity similar to the POSITION type in the MFC. A const_iterator variable is like a pointer to a constant object in a list, so this traverser (Iterator) can use -> access itself. The traverser can use from the increasing implementation to advance in the list. So, this FOR cycle is initialized to call List :: begin () to get the first string in the "pointing" list, then call list :: end () to get a traverser "point" list "Last", the location of the last string. (I put these words in quotation marks to emphasize, start, and the end of the concept is abstract by const_iterator type, and must pass the const_iterator method [like begin ()] or operator [like ]. These traversers are assigned to IT and ITEND separately. This loop has been carried out until IT is equal to iTend; meaning, when IT has not reached the "end" of the list. This traverser IT will increase from each time in the loop process so that it can reach a string in a list. In the traversal, the expression it-> c_str () is used -> operator. Because IT is like a pointer to String (remember, m_pfilelist is a list of STL String), IT-> c_str () calls the c_str () function in the current point to IT. C_STR () Returns a C-type string pointer, since this is an LPCTSTR. The remainder of DOWORK () is to release memory and error checks. You can get all code from the progressdlg.cpp file of the example project. (I just realized that it is "IT", how is it. I am sorry!) :) Registered housing extension This DLLREG extension operates the executable, so we register it by the EXE, DLL, and OCX file calls. As in the first part, we can do these things in the RGS script, DllRegshlext.RGS. Below is registered our extension to extend the required scripts for the context menu for the above extension file. HKCR { Noremove DLLFILE { Noremove Shellex { Noremove ContextMenuHandlers { Forceremove Dllregsvr = S '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}' } } } Noremove EXEFILE { Noremove Shellex { Noremove ContextMenuHandlers { Forceremove Dllregsvr = S '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}' } } } Noremove OcxFile { Noremove Shellex { Noremove ContextMenuHandlers { Forceremove Dllregsvr = S '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}' } } } } The format of the RGS file, and keyword Noremove and Forceremove have explained in the first part, if you forget what they mean. As we extends the previous extension, under NT / 2000, we need to add our extension to "Approved" extension list. Implement this process code in the DllRegisterServer () and DllunregisterServer () functions. I don't want to show these code because it is just some simple registry access, but you can never in the example project. What should it look like? When you click on one of our men, the dialog box will appear, the result of the display: The list control shows the file name and operation of each file. When you select an item, a more detailed message will be displayed below. If you fail, there will be a description of the call failed. Other ways to register extensions So far, our extension is only determined by the file type call. By registering under hkcr / * becomes a context menu extension makes it possible to be invoked by any file operation: HKCR { Noremove * { Noremove Shellex { Noremove ContextMenuHandlers { Forceremove Dllregsvr = S '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}' } } } } The HKCR / * key is extended by the outer casing called by all files. Note that the extension mentioned in the document is also called by other housing objects (files, directories, virtual folders, control panel items, etc.), but I don't have this in the test. These extensions are only called by files in the file system. In the shell version 4.71 or more, there is a key called HKCR / ALLSystemObjects. If we register under this button, our extension will be called all files and directory in the file system, except for the root directory. (The extension of root catalog is registered under HKCR / Drive.) However, when I registered under this button, I saw some strange phenomena. The "Send to" menu also uses this button, and it is mixed in the middle of the DLLREG menu: You can also write a context menu extension of an operating directory. If you have such an example, please see my article: a Utility to Clean Up Compiler Temp Files (a utility that clears the compile temporary file). (Translator: It is really a good game :)) Finally, in the shell version 4.71 or more, you can make your context menu in the user right-click the resource manager window background that is viewing the directory (including the desktop). In order to make your extension be called, you must register under the HKCR / Directory / Backgroundlers key. Using this method, you can add menu items or any other directory to your desktop context menu. Parameters passed to iShellextinit :: Initialize () are a bit different, I will explain it in my future article. to be continued…… Then, the third part we will practice a new extension and query. It will display a pop-up description of some housing objects. I will also show you how to use MFC in the housing extension. You can get the latest version of this and other articles from the following URL: http://home.inreach.com/mdunn/code/