Keywords: shell, namespace, icontextmenu, shell, namespace, context menu
Article difficulty: primary
Introduction (What is the shell contextmenu)
With more and more software extensions, resource manager becomes more powerful and easy to use, before compressed one or more files, you have to find a shortcut to compression software and open him. Then, a series of selection operations, this is absolutely annoying to me, and there is a housing menu extension mechanism, you only need to select the file you want to operate in the Explorer. Then popup the right-click menu to select the appropriate item to get it, more convenient.
Oh, hit, this article is not to introduce how to add a menu extension to the resource manager (Note 1), but introduce how to call the context menu with rich features in your own program. For example, the local file window on the left of FlashFXP (Figure 1):
(Figure 1: Assuming that you open the FTP software to discover some files to discover these files yet, what should I do? Switch to the resource manager to pack them and return to FlashFXP? No no no, don't do so inefficiency Things, in the left window of Flashfxp, then press and hold the SHIFT button and pop up the right button. Take a look, it is too wonderful. In the future, you can use your favorite to enjoy it directly in the FTP. )
(Note 1: Basically, write a context menu extension is easier to implement, with a large number of articles and sample code available from http://www.codeproject.com/shell)
HOW TO IMPLEMENT
We know that in Win32 is in the form of a housing name space (Note 2), each folder in the housing name space implements an ISHELLFOLDER interface, we can query or indirectly through this interface. Get other related interfaces.
The interface with the context menu of the object (Note 3) is IconTextMenu, which interface can be obtained by the ISHELLFOLDER :: GetuiObjectof method through the parent folder of the object. After getting this interface, you can use the iconTextMenu :: queryContextMenu method to generate a menu item of the context menu, call the corresponding command with IconTextMenu :: InvokeCommand. It looks very simple? Here's a specific implementation, including how to get an object's parent folder iShellfolder interface, how to get icontextMenu, and how to call all methods of IconTextMenu.
(Note 2: The concept of the namespace of the shell, I recommend everyone to see Jiang Weihua's Windows House Name Space Browse, more information can be obtained from MSDN)
(Note 3: The object here refers to a node in the enclosure name space, the object may be a folder, it is possible to be a file, it is also possible to be a virtual folder, for example: my computer, online neighbor, control Panel, etc.)
Specific implementation and examples
For the sake of simplicity, this example is based on the dialog engineering based on the MFC. List the subfolders and files under the C dote in a listbox control. Right-click each of the listbox to pop up the corresponding enclosure context menu. .
(1) Enumerate the folders and files under the C drive and added to listbox: Steps are as follows:
a) Get the ISHELLFOLDER interface pointer of the desktop with ShgetDesktopFolder, which is a way we have achieved other objects ISHELLFOLDER.
b) Get the PIDL of the drive C with ishellfolder :: parsedisplayName, then pass the resulting PIDL as a parameter to ISHELLFOLDER :: BindToObject to get the Drive C's ISHELLFOLDER interface pointer. c) You can get an enumerator with the iShellfolder :: Enumjects method you just get the C drive, and you can enumerate the PIDL of the subfolders and files under the C disc. You can get the display name of the object represented by PIDL through GetDisplayNameO, so we add this name to listbox, and save the corresponding PIDL with CListbox: Setitemdata, use J
Sample code:
...
LPMalloc PMalloc;
LPITEMIDLIST PIDLC = NULL;
LPITEMIDLIST PIDLITEMS = NULL;
ISHELLFOLDER * psfdesktop = NULL;
IShellfolder * psffolderc = null;
LPENUMIDLIST PPENUM = NULL;
Ulong celtfetched;
HRESULT HR;
Strret strdispname;
Tchar pszdisplayName [max_path];
Ulong Uattr;
HR = SHGETMALLOC (& PMalloc);
HR = SHGETDESKTOPFOLDER (& PsfDesktop);
HR = psfdesktop-> pasedisplayName (GetsafehWnd (), NULL, L "C: ///", NULL, & PIDLC, NULL)
HR = psfdesktop-> bindtoobject (PIDLC, NULL, IID_ID_IDFOLDER, (Void **) & psffolderc);
Psfdesktop-> release ();
HR = psffolderc-> enumobjects (GetSafehWnd (), Shcontf_folders | Shcontf_nonfolders, & Ppenum
While (hr = ppenum-> next (1, & pidlitems, & celtfetched) == s_ok && (celtfetched) == 1)
{
Psffolderc-> getDisplayNameOf (Pidlitems, SHGDN_INFOLDER, & STRDISPNAME);
Uattr = sfgao_folder;
Psffolderc-> GetAttributesof (1, (lpcitemidlist *) & pidlitems, & uattr);
StrretTobuf (& Strdispname, Pidlitems, PszdisPlayName, Max_Path);
CString strdisplayName;
IF (uattr & sfgao_folder)
{
STRDISPLAYNAME.FORMAT ("% s% s% s", "[", pszdisplayname, "]");
}
Else
{
STRDISPLAYNAME = pszdisplayname;
}
M_ListBox.SetItemData (m_listbox.insertstring (-1, strdisplayname), (dword) pidlitems;
}
Ppenum-> release (); pmalloc-> free (pidlc);
PMalloc-> Release ();
m_psffolderc = psffolderc;
...
(2) Responding to the mouse click message, obtain the IconTextMenu interface and pop up the menu;
The GetuiObjectof method of the ISHELLFOLDER interface through the C drive We can get the IconTextMenu interface of one or more specified child nodes of the node. The prototype is as follows:
HRESULT GETUIOBJECTOF
HWND HWNDOWNER,
UINT CIDL, / / Specify the number of PIDLs of the PIDL in the array of APIDL points to the APIDL
LPCITEMIDLIST * APIDL, // Point to CIDL PIDL, you need to note that these PIDL must be relative
Refiid riid, // We want a context menu interface, here is specified as IID_ICONTEXTMENU_
Uint * rgfreserved,
Void ** PPV
);
HRESULT HR;
ContextMenu * pcm = null;
HR = m_psffolderc-> getuiObjectof (GetSafehWnd (), Arylistboxsel.getsize (),
(Lpcitemidlist *) PPIDLS, IID_ICONTEXTMENU, NULL, (VOID **) & PCM);
After getting IconTextMenu, we have to provide a handle of a pop-up menu and pass him to IconTextMenu :: queryContextMenu,
If the method is successful, add the appropriate menu item in our menu.
CMenu Menu;
Menu.createPopupnupmenu ();
HR = PCM-> QueryContextMenu (menu.m_hmenu, 0, 1, 0x7ft, cmf_normal | cmf_explore);
With a menu item, we can pop up the menu, we specify the TPM_RETURNCMD flag to specify that the TRACKPOPUPMENU must return the ID of the user's selected menu item to call the true shell action by IconTextMenu :: InvokeCommand later:
IDCMD = menu.trackpopupmenu (TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RightButton,
Pt.x,
Pt.y,
AFXGETMAINWND ());
IF (idcmd)
{
CMinvokeCommandInfo CMI;
Cmi.cbsize = sizeof (cminvokeCommandInfo);
CMI.Fmask = 0;
CMI.hwnd = getsafehwnd ();
Cmi.lpverb = (lpcstr) (int_ptr) (idcmd - 1);
Cmi.lpparameters = NULL;
Cmi.lpdirectory = NULL;
CMI.NSHOW = SW_SHOWNORMAL;
cmi.dwhotkey = 0;
Cmi.hicon = NULL;
HR = PCM-> InvokeCommand (& CMI);
}
// Note: In fact, there are two interfaces associated with the context menu, which is IconTextMenu2 and IconTextMenu3, which is used to implement the self-drawing behavior of the extended menu item. Here is the simplicity, there is no call to us, in common use We must have the relevant methods of querying these two interfaces and receives the two interfaces related to the messages related to the menu of WM_DRAWITEM / WM_INITMENUPOPUP, otherwise the self-painting menu items and child menu items will not normal. display. Please see the source code included in this article. (3) Do not pop up the menu directly call the menu item corresponding to the command?
Do you still remember how to display a file or folder attribute dialog box?
YES, use shellexecuteEx and specify the LPVERB domain of shellexecuteInfo to Properties, but this method can only view the properties of a file, how do you view multiple?
To know that shellexecuteex view file properties ultimately relying on IconTextMenu, the answer is still on IconTextMenu, we only need to pass the file or file PIDL you want to view when calling getuiObjectof, then call the InvokeCommand method to OK. .
IF (m_psffolderc! = null)
{
HRESULT HR;
IconTextMenu * pcm = null;
HR = m_psffolderc-> getuiObjectof (GetSafehWnd (), AryListBoxSel.getsize (), (lpcitemidlist *) PPIDLS, IID_ICONTEXTMENU, NULL, (Void **) & PCM);
En (ac) && pcm! = null)
{
CMinvokeCommandInfo CMI;
Cmi.cbsize = sizeof (cminvokeCommandInfo);
CMI.Fmask = 0;
CMI.hwnd = getsafehwnd ();
CMI.lpverb = "Properties"; // When the menu is pop-up, this is the cmdid selected by the user, but at this time we have no pop-up menu, so you can only call in Verb, please refer to MSDN for more information on Verb.
Cmi.lpparameters = NULL;
Cmi.lpdirectory = NULL;
CMI.NSHOW = SW_SHOWNORMAL;
cmi.dwhotkey = 0;
Cmi.hicon = NULL;
HR = PCM-> InvokeCommand (& CMI);
PCM-> Release ();
}
}
Postscript and reference
In fact, there are a lot of articles for shell programming in the Internet (of course, most of them are English, how to find more tray program L), there are many good articles on www.codeproject.com, but because they focus on Reusable On the same, C puts the chaos and seven-eight-piece, so that we can't learn the mechanism of the shell extension and calls, this article shows you the most straightforward way to call the shell in your program.
Of course, the younger brother is limited, there is a mistake in the text, and I hope to get your correct.
This article demonstrates the source code: http://iunknown.com.cn/9cbs/kshellcontextMenu.rar
reference:
View of Windows Shell Name Space By Jiang Weihua
Use shell contextmenu in your application (This author provides a class, call shell contextmenu in your program only need two three lines of code, very convenient J)
Platform Sample: ENUMDESK
MSDN Library-> Platform SDK Document-> User Interface Services-> Windows Shell