Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - shellcontextmenu1.jpg

Introduction

This article explains how to use my self-written CShellContextMenu class which makes it possible to use the shell contextmenu in your own application (the one that shows if you right-click on an object in the Windows Explorer).

Why CShellContextMenu

I have a lot of projects in which i work with files/folders. So I wanted to use the common shell contextmenu for those. Microsoft put a wonderful example on how to achieve this in their Platform SDK, called EnumDesk. But since not all people understand Shell interfaces and the code should be reusable, I wrapped things up in a C++ class. I also did some google-searching to get some good ways of implementing this. The class hides all the interface-related stuff; you can either use normal file system paths (f. ex. c:\windows) or PIDLs to obtain the shell contextmenu. So here it this, the CShellContextMenu class which makes it easy as hell to use the shell contextmenu.

CShellContextMenu scm;        
// instantiate class object

scm.SetObjects (TEXT ("file:///c://">c:\\"));    

// we whant shellcontext menu for drive c:\ 

scm.ShowContextMenu (this, point);    
// point is a CPoint objects which indicates where the contextmenu should 

// be shown this refers to a MFC-window class (showcontextmenu needs that 

// to set the owner window)

There's just one other importing thing you have to do. In your InitInstance () function of your CWinApp derived class insert the following lines of code, that's neccessary otherwise not all shell contextmenu items would be shown.

// Initialize OLE 2.0 libraries

if (!AfxOleInit ())
{
    AfxMessageBox (TEXT ("Unable to load OLE 2.0 libraries!"));
    return (FALSE);
}
and put the following #include statement in your project's stdafx.h file.
#include <afxole.h>    // for OLE

That's all you need to pop-up the shell contextmenu for drive C. CShellContextMenu also supports multiple files/folders. Just pass an CStringArray to CShellContextMenu::SetObjects () and you'll get a contextmenu which refers to all the items specified in that array. That corresponds to selecting multiple objects in Windows Explorer and than right-click on the selection. Keep in mind that if you pass multiple files/folder/shell objects, they have to be all in the same folder. This is no limitation of CShellContextMenu, rather then how the IContextMenu interface is implemented in the Windows Shell. CShellContextMenu also works with PIDLs. If you don't know what PIDLs are then it won't matter, cause CShellContextMenu handles the stuff for you. I would also suggest that you have a look at SetObjects (...) and the other functions to get a better grab to shell interfaces. The source code is also heavily commented, so with MSDN at hand there shouldn't be any problems.

How CShellContextMenu works

Let's have an inside look in CShellContextMenu and see what it really does under the hood to obtain that handy shell contextmenu.

First take a look at those SetObjects (...) methods.

void SetObjects (CString strObject);
// one file system path (file/folder)

void SetObjects (CStringArray &strArray);
// array of multiple file system paths (files/folders)

void SetObjects (LPITEMIDLIST pidl);
// full qualified PIDL of shell object

void SetObjects (IShellFolder * psfFolder, LPITEMIDLIST pidlItem);
// relative PIDL and its parent IShellFolder interface

void SetObjects (IShellFolder * psfFolder, LPITEMIDLIST * pidlArray, 
                 int nItemCount);
// array of multiple relative PIDLs and their parent IShellFolder interface

With the SetObjects (...) you tell CShellContextMenu for which objects (file/folder/shell object) you wish to have the contextmenu. For people who don't know how to handle PIDLs or if your program just works with usual file system paths I implemented two overriden methods of SetObjects (...) that accept a CString or a CStringArray as argument and CShellContextMenu converts the given file system path(s) into PIDLs and retrieves its IShellFolder interface. That's neccessary because the IContextMenu interface is only accessable via the IShellFolder interface which only takes PIDLs as an argument. Now we take some in-depths look at ShowContextMenu which actually does the work.

UINT CShellContextMenu::ShowContextMenu(CWnd *pWnd, CPoint pt)
{
    int iMenuType = 0;    
    // to know which version of IContextMenu is supported

    LPCONTEXTMENU pContextMenu;    
    // common pointer to IContextMenu and higher version interface

   
    if (!GetContextMenu ((void**) &pContextMenu, iMenuType))    
        return;    // something went wrong


    if (!m_Menu)
    {
        delete m_Menu;
        m_Menu = NULL;
        m_Menu = new CMenu;
        m_Menu->CreatePopupMenu ();
    }

    // lets fill the our popupmenu  

    pContextMenu->QueryContextMenu (m_Menu->m_hMenu, 
                  m_Menu->GetMenuItemCount(),0, MIN_ID, MAX_ID, CMF_EXPLORE);
 
    // subclass window to handle menurelated messages in CShellContextMenu 

    WNDPROC OldWndProc;
    if (iMenuType > 1)    // only version 2 and 3 supports menu messages

    {
        OldWndProc = (WNDPROC) SetWindowLong (pWnd->m_hWnd, 
                GWL_WNDPROC, (DWORD) HookWndProc);
        if (iMenuType == 2)
            g_IContext2 = (LPCONTEXTMENU2) pContextMenu;
        else	// version 3

            g_IContext3 = (LPCONTEXTMENU3) pContextMenu;
    }
    else
        OldWndProc = NULL;

    UINT idCommand = Menu.TrackPopupMenu (TPM_RETURNCMD | TPM_LEFTALIGN, 
                                          pt.x, pt.y, pWnd);
    
    if (OldWndProc) // unsubclass

        SetWindowLong (pWnd->m_hWnd, GWL_WNDPROC, (DWORD) OldWndProc);

    // see if returned idCommand belongs to shell menu entries

    if (idCommand >= MIN_ID && idCommand <= MAX_ID)
    {   //executes related command

        InvokeCommand (pContextMenu, idCommand - MIN_ID);    
        idCommand = 0;
    }

    pContextMenu->Release();
    g_IContext2 = NULL;
    g_IContext3 = NULL;

    return (idCommand);
}

As you can see ShowContextMenu takes a pointer to a CWnd object and a CPoint object as arguments. The CWnd pointer is needed for later subclassing and CPoint is used to determine at which position the contextmenu should be shown. Note that these are screen coordinates. So, if you have client coordinates convert them via ScreenToClient (...) before passing them to ShowContextMenu. So, what is ShowContextMenu doing? First it calls the GetContextMenu (...) to retrieve the IContextMenu interface (which is then stored in pContextMenu) associated with the objects passed in SetObjects (...). The GetContextMenu is explained afterwards. What we now have to do, is to determine which version of IContextMenu we have. That's neccessary because if we have a IContextMenu higher than version 1, we need to handle the WM_DRAWITEM, WM_MEASUREITEM and WM_INITMENUPOPUP messages. These message are send to the window pointed to by pWnd which is passed in ShowContextMenu's argument list. That's the point where window subclassing comes in handy. All we have to do, is to redirect the window's default window procedure (the function which handles all the messages belonging to a window). With SetWindowLong (...) we set the new window procedure to HookWndProc (...) which is a static member function of CShellContextMenu.

Let's again take a look at the code. After we have a pointer to the IContextMenu interface we create a popup menu with CMenu's CreatePopuMenu () method. The next thing is, we let our popup menu fill with IContextMenu's QueryContextMenu (...) method. This method has four parameters. The first is the handle to the popupmenu which should be filled with the shell menu items. The second is the menu position where it starts. This could be useful because before you let the menu be filled you can insert additional menu items which are specific to your program. Therefore the 3rd and 4th parameters. They specify the lowest and highest command ID that QueryContextMenu (...) should use to fill the menu. That means, that command IDs which are below or above that range, are for you own additional menu items. CShellContextMenu has support for adding custom menus. Just call the GetMenu () method to retrieve a CMenu pointer to the popupmenu. With this you can customize the menu as you like. After that, go on as usual and call ShowContextMenu (...). The 5th parameter uses the flag CMF_EXPLORE to indicate that we want the same items that Window Explorer shows in its contextmenu. Then we subclass pWnd and redirect all messages to HookWndProc (...), but only if the IContextMenu is Version 2 or 3. With CMenu's TrackPopupMenu (...) we show the contextmenu, and store the command ID of the selected menu item in idCommand. Then we test idCommand if its between MIN_ID and MAX_ID, if so it means that a shell menu item was clicked and not one we manually inserted (btw. those constants are defined in ShellContextMenu.cpp, change them to your needs if you wish to). If its a shell menu item we call CShellContextMenu::InvokeCommand (...) which executes the appriorate command that belongs to a shell menu item and release the IContextMenu interface with pContextMenu->Release ()

Here's GetContextMenu which retrieves the highest version of IContextMenu available to the given objects. m_psfFolder is an IShellFolder interface, via its GetUIObjectsOf method we get version 1 of its IContextMenu interface. nItems is the number of object that were passed in SetObjects (...) and m_pidlArray is an array of PIDLs that are relative to m_psfFolder (IShellFolder interface). Those PIDLs were also passed in SetObjects (...) or if you passed a file system paths CShellContextMenu has automatically retrieved the corresponding PIDLs and the IShellFolder interface. If we have a valid IContextMenu interface we try to get version 3, if that fails we test for version 2 and if that too fails we stay with version 1. And that's all.

BOOL CShellContextMenu::GetContextMenu (void ** ppContextMenu,int & iMenuType)
{
    *ppContextMenu = NULL;
    LPCONTEXTMENU icm1 = NULL;
    
    // first we retrieve the normal IContextMenu 

    // interface (every object should have it)

    m_psfFolder->GetUIObjectOf (NULL, nItems, (LPCITEMIDLIST *) m_pidlArray, 
                IID_IContextMenu, NULL, (void**) &icm1);
   
    if (icm1)
    {    // since we got an IContextMenu interface we can 

        // now obtain the higher version interfaces via that

        if (icm1->QueryInterface(IID_IContextMenu3, ppContextMenu) == NOERROR)
            iMenuType = 3;
        else if (icm1->QueryInterface (IID_IContextMenu2, 
                                       ppContextMenu) == NOERROR)
            iMenuType = 2;

        if (*ppContextMenu) 
            icm1->Release();     // we can now release version 1 interface, 

                    // cause we got a higher one

        else 
        {    
            iMenuType = 1;
            *ppContextMenu = icm1;    // since no higher versions were found

        }  // redirect ppContextMenu to version 1 interface

    }
    else
        return (FALSE);    // something went wrong

    
    return (TRUE); // success

}

That's the alternative window procedure that is only used while the contextmenu is being showed. HookWndProc checks for menu reletad messages and calls the IContextMenu's HandleMenuMsg. g_IContext2 and g_IContext3 are global pointers, they are pointing to IContextMenu2 and IContextMenu3 interfaces of the contextmenu that is currently being showed. It's neccessary to have a global variable because HookWndProc is a static member function and static member functions have no this pointer, therefore it cannot access its class member variables and functions. The HookWndProc must be static because a non-static member function has always an additional this pointer, and therefore its argument list wouldn't match that of a window procedure. At the end of HookWndProc we call the original WndProc to avoid undefined behaviour of the associated window. The original WndProc is retrieved via the GetProp () API function. Refer to the MSDN for further informations on this API function.

LRESULT CALLBACK CShellContextMenu::HookWndProc (HWND hWnd, UINT message, 
                        WPARAM wParam, LPARAM lParam)
{
   switch (message)
   { 
   case WM_MENUCHAR:	// only supported by IContextMenu3

       if (g_IContext3)
       {
           LRESULT lResult = 0;
           g_IContext3->HandleMenuMsg2 (message, wParam, lParam, &lResult);
           return (lResult);
       }
       break;

   case WM_DRAWITEM:
   case WM_MEASUREITEM:
      if (wParam) 
          break; // if wParam != 0 then the message is not menu-related

  
   case WM_INITMENUPOPUP:
       if (g_IContext2)
           g_IContext2->HandleMenuMsg (message, wParam, lParam);
       else	// version 3

           g_IContext3->HandleMenuMsg (message, wParam, lParam);
      return (message == WM_INITMENUPOPUP ? 0 : TRUE); // inform caller that 

                        // we handled WM_INITPOPUPMENU by ourself

      break;

   default:
      break;
   }

   // call original WndProc of window to prevent undefined bevhaviour

   // of window

   return ::CallWindowProc ((WNDPROC) GetProp ( hWnd, TEXT ("OldWndProc")), 
             hWnd, message, wParam, lParam);
}

This little function is also very important. Without it the shell context menu would also show correctly with all the expected menu items, but it would do just nothing if you'd click on an item. So, all this function does is fill an CMINVOKECOMMANDINFO, set its lpVerb member to the idCommand (command ID of the clicked menu item) and calls the IContextMenu's InvokeCommand method, which finally executes the command that belongs to the menu item that was clicked.

void CShellContextMenu::InvokeCommand (LPCONTEXTMENU pContextMenu, 
                                       UINT idCommand)
{
    CMINVOKECOMMANDINFO cmi = {0};
    cmi.cbSize = sizeof (CMINVOKECOMMANDINFO);
    cmi.lpVerb = (LPSTR) MAKEINTRESOURCE (idCommand);
    cmi.nShow = SW_SHOWNORMAL;
    
    pContextMenu->InvokeCommand (&cmi);
}

Summary

So, that's the whole thing behind the shell contextmenu. Wasn't that hard was it?  Shell interfaces are not that difficult like they seem to be on the first look. One problem with them is that they are not well documented in the MSDN. So with a little work and some google-searching everything's possible. Before I began working with that shell context menu I didn't know much about the Shell. I did use a lot of shell functions like SHGetFileInfo and such stuff, but no real shell interfaces, PIDLs and such. Now I'm able to produce a full Windows Explorer alternative with the shell interfaces. That's not a very hard thing to do.

I hope the article is good to understand, because English is not my native language. On the other hand, it's my first development related article ever.  So hey, I think it's good enough for that.

What comes next?

I hope the example project covers CShellContextMenu fairly well, so you'll know how to use it. It also demonstrates how to add custom app-specific menu item< to the contextmenu before it is shown and shows how to imitate the right-pane listview of Windows Explorer (in a simple way). The active project configuration is set to ANSI compiling, but everything also works in UNICODE mode, which is also included as a project configuration. I'm also considering providing CListCtrl and CTreeCtrl derived classes which imitate those in Windows Explorer. But this could still be a long way ahead, because while writing this article I noticed that it's really an exhausting task, harder than actually programming :). There is already 2 or 3 article about that on codeproject.com, but I've noticed that those examples/classes are totally overblown, and therefore the source codes of those are almost impossible to follow and understand.

History

April 29th, 2003

  1. Added GetMenu () method which returns a CMenu pointer, so it is possible to freely customize the contextmenu before it is shown.
  2. Added example project which demonstrates the use of CShellContextMenu, and also shows how to add those custom menu items and imitating a Windows Explorer-like listview.
  3. Replaced the SHBindToParent function with a workaround implemention that is called SHBindToParentEx which does the same thing. That was neccessary because SHBindToParent isn't available on Windows 95/98 systems.
  4. ANSI compiling supported. Before it only worked in UNICODE mode.
  5. Fixed a bug, where CShellContextMenu caused an error when SetObjects (...) was called with a CStringArray that contained more then one file/folder.

April 10th, 2003

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralAddition [modified]
grandmasta1
21:58 13 Dec '09  
change this in function ShowContextMenu() to get the canonical Name of clicked Item:


if (idCommand >= MIN_ID && idCommand <= MAX_ID) // see if returned idCommand belongs to shell menu entries
{
InvokeCommand (pContextMenu, idCommand - MIN_ID); // execute related command
//idCommand = 0;
}

CString canonicalName;
#ifndef UNICODE
pContextMenu->;GetCommandString(idCommand, GCS_VERBA, 0, (LPSTR)canonicalName.GetBuffer(100), 100);
#else
pContextMenu->;GetCommandString(idCommand, GCS_VERBW, 0, (LPSTR)canonicalName.GetBuffer(100), 100);
#endif

pContextMenu->Release();
g_IContext2 = NULL;
g_IContext3 = NULL;

return canonicalName;

-------------------------------------------------------------
Edit: ReturnValue of this function must be a CString

modified on Monday, December 14, 2009 3:45 AM

GeneralSample for using canonical Name
grandmasta1
22:16 13 Dec '09  
check if selected Files (in CListCtrl()) was deleted by user:

void CSuchView::OnNMRclickFindlist(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = 0; // default processing

LPNMITEMACTIVATE pIA = (LPNMITEMACTIVATE) pNMHDR;

// get selected count
int count = listResult->GetSelectedCount();
if(count <= 0) return;

*pResult = 1; // no default processing

// build array for ContextMenu
CStringArray farr;
SFiles *files = NULL;
POSITION pos = listResult->GetFirstSelectedItemPosition();
int iItem = -1;
while(pos){
iItem = listResult->GetNextSelectedItem(pos);

files = (SFiles*) listResult->GetItemData(iItem);
farr.Add(files->FilePath);
}
// set FilePaths
scm.SetObjects(farr);
// open ContextMenu
CPoint pt = pIA->ptAction;
listResult->ClientToScreen(&pt);
CString canonicalName = scm.ShowContextMenu(GetMainFrame(), pt);
// if user clicked on "delete File"
if(canonicalName == _T("delete")){
// check if user has deleted the Files
for(int i = 0; i < farr.GetCount(); i++){
CFileFind ff;
if(ff.FindFile(farr.GetAt(i)) == FALSE){
// File doesn't exist - do something, e.g. delete Record in DB

}
ff.Close();
}
}
}
GeneralBugFix
grandmasta1
21:16 13 Dec '09  
change:
if(!m_Menu){
delete m_Menu;
m_Menu = NULL;
m_Menu = new CMenu;
m_Menu->CreatePopupMenu ();
}

to:
if(m_Menu){
delete m_Menu;
m_Menu = NULL;
}

if(!m_Menu){
m_Menu = new CMenu;
m_Menu->CreatePopupMenu ();
}

in function:
ShowContextMenu()
GeneralSHBindToParent
daher
7:39 6 Nov '09  
The function "SHBindToParent" does not allocate new memory, thus using free() will damage your heap and may cause crashes.

Source: MSDN. Hope this helps.
QuestionContext menu of action 'click on the background'
fralik
2:51 24 Feb '09  
Hi!
Great tutorial, thanks!

My question is similar to "How to insert a menu when right click blank place?", which was asked below.

Does anybody know how to grab the context menu, which appears if user clicks on the list view background in the explorer?

I guess I need something different from SHBindToParent, maybe SHBindToObject, but this function available only under Windows Vista. I am working with Win XP.

Best regards.
General"send to" problem
MPTP
0:14 8 Jan '09  
Hi,

This is very good application But when I select one or more files and select "send to" to My Document It copies the item but do not show the prgress percentage and at last popup a message box with text("The target can not handle this type of document").
GeneralVista64 Question
RSabet
13:16 23 Dec '08  
Hello,

your post was of great help to me, but i have a question:
after
SHBindToParent(pidl,IID_IShellFolder,(void **)&psfFolder,(LPCITEMIDLIST *)&pidlItem); you do a
free(pidlItem);
unter 32bit this works fine, but when compiling for 64 bit it craches in the free line.

According to msdn (http://msdn.microsoft.com/en-us/library/bb762114(VS.85).aspx[^]):
Note SHBindToParent does not allocate a new PIDL; it simply receives a pointer through this parameter. Therefore, you are not responsible for freeing this resource
So are we to free this pidlItem resource ?

regards
Ramin
GeneralRe: Vista64 Question
GogglesPisano
5:20 11 Mar '09  
I've found another issue in Vista 64-bit: The context menu is displayed, but all of the menu text is blank. To fix this, I replaced SetWindowLong() calls to SetWindowLongPtr() calls.

In CShellContextMenu::ShowContextMenu(), change the two lines:

    OldWndProc = (WNDPROC) SetWindowLong (pWnd->m_hWnd, GWL_WNDPROC, (DWORD) HookWndProc);

SetWindowLong (pWnd->m_hWnd, GWL_WNDPROC, (DWORD) OldWndProc);
to

    OldWndProc = (WNDPROC)::SetWindowLongPtr(pWnd->m_hWnd, GWLP_WNDPROC, (DWORD_PTR)HookWndProc);

::SetWindowLongPtr(pWnd->m_hWnd, GWLP_WNDPROC, (DWORD_PTR)OldWndProc);

This seems to correct the issue.
GeneralVista crash (on some protected files) .. fix found
noleander
10:58 11 Oct '08  
I used this package on Vista. I included the "Vista fix" from this forum (July 2007). On the whole, it worked good, but I got a crash when trying to pop-up the contextual menu on certain protected files (perhaps files my appl didnt have privilege to open?). I tracked down the crash and the fix was to:

1) Check the result of all calls to SHBindToParent() and SHBindToParentEx(). If restult is not S_OK, then set

m_psfFolder = NULL;

and return from CShellContextMenu::SetObjects().

2) In CShellContextMenu::GetContextMenu() check, first thing, if m_psfFolder = NULL; and if it is NULL then return FALSE immediately.

PS: I was passing in CString file names to ::SetObjects(), not PIDLs.
GeneralHelp Plz: Need This In Vb.Net
TheRoughGuy
3:55 10 Dec '07  
Hi,is this coding possible in VB.NET. Can any one give me .Net version of this.... Thanks In Advance....
GeneralHere's the code in .NET
AndrewVos
4:58 20 Aug '07  
I finally had the energy to do a version in .NET and had to come over here to help all the .NET people out, seeing as I was looking for this for quite a while! I put it on my blog because quite frankly I don't have the time to do a CP article. Sorry.

http://www.andrewvos.com/?p=190[^]


www.wickedorange.com

GeneralWindows Vista Bug Fix
Gautam Jain
3:54 16 Jul '07  

Hello Dear Members,

On Windows Vista, this CShellContextMenu class does not work. It shows a blank menu with no text items although the commands work.

Here is this fix for the above problem.

1. Find the declaration of the variable OldWndProc. It is declared locally in the function ShowContextMenu. Make this variable global. Move it outside the function ShowContextMenu.

2. Now change the below code:

OLD CODE:
return ::CallWindowProc ((WNDPROC) GetProp ( hWnd, TEXT ("OldWndProc")), hWnd, message, wParam, lParam);

NEW CODE:
return ::CallWindowProc (OldWndProc , hWnd, message, wParam, lParam);
The bottom line is that we must not us GetProp function. Instead we must directly use the OldWndProc.

Thanks.


Regards,
Gautam Jain http://www.conceptworld.com

GeneralRe: Windows Vista Bug Fix
SystemTools
4:42 16 Jul '07  
I have not tested it, but thanks for posting a fix !

-kevin
GeneralRe: Windows Vista Bug Fix
nanfang
0:55 10 Nov '07  
I'v got a window crash when using CContextMenu in my XP sp2.
I fixed it by the same way above. Thank you!

Howard
GeneralRe: Windows Vista Bug Fix
Javed Akhtar Ansari
19:52 24 Nov '08  
Thanks Gautam,
It works. I have one more issue on vista. Once a shell namespace dll is loaded in vista it does not unloads that for that session and hence we cannot rebuild the dll untill we restart vista.
Does any body has a solution for this?

Javed A Ansari
Software Developer
Hyderabad, India

GeneralHow can use in different folder's files ?
Johnson.ZRQ
1:51 7 Jun '07  
hello, I can use the sample for multiple files or sub-folders in the same folder. However, I can't use the sample for multiple files or sub-folders in different folders, just like window explorer's search function. Please tell me how to do that, thank's! Smile
GeneralRe: How can use in different folder's files ?
umeca74
1:10 8 Jul '07  
i blogged about this just today!
http://www.zabkat.com/blog/08Jul07.htm[^]

hth
nikos
GeneralRe: How can use in different folder's files ?
Johnson.ZRQ
23:43 12 Jul '07  
Dear nikos,
Thank's for your help. I use CDefFolderMenu_Create2 in my program after read your blog, but my program still can't use in different folder's files. My program code like this:

HKEY hkey, hkeyList[ 1 ];
RegOpenKeyEx( HKEY_CLASSES_ROOT, "*", NULL, KEY_ALL_ACCESS, &hkey );
hkeyList[ 0 ] = hkey;
CDefFolderMenu_Create2( NULL, pWnd->m_hWnd, nItems, (LPCITEMIDLIST *) m_pidlArray, m_psfFolder, ShellFoldCallBack, 1, hkeyList, &pContextMenu );
RegCloseKey( hkey );

GeneralRe: How can use in different folder's files ?
umeca74
3:52 19 Jul '07  
this call looks ok, but you should pass the desktop's pidl as the first parameter too.

As you can understand this is a complex and delicate procedure and i can't tell you what's wrong just from one line of code. Have you done everything else properly as described in the blog post?[^] Do you see any menu at all? etc
GeneralRe: How can use in different folder's files ?
Johnson.ZRQ
0:56 20 Jul '07  
I have read the blog post, then do such code for this:

2.Load CDefFolderMenu_Create2.

3.Open registry keys for the file types in the selection.

4.Supply a valid callback
HRESULT CALLBACK ShellFoldCallBack( IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if( uMsg == DFM_MERGECONTEXTMENU )
return S_OK;
else if( uMsg == DFM_INVOKECOMMAND )
return S_FALSE;
else
return E_NOTIMPL;
}

6.Pass all arguments to CDefFolderMenu_Create2.

But, I can't understand the step 1(Create a data object on the selection) and the step 5(Initialize IShellFolder wrapper), so I only use IShellFolder not the CIShellFolderSpy class. Because I don't know how to do the class CMultiDataObject.
GeneralRe: How can use in different folder's files ?
umeca74
6:53 20 Jul '07  
so you are missing around 1000 lines of code Smile
sorry but i can't possibly coach you for all this
you'll have to study the shell COM object model, figure out how to create your own dataobjects etc
good luck!
GeneralRe: How can use in different folder's files ?
Johnson.ZRQ
22:56 5 Aug '08  
Oh, yeah, I have settled this problem, ha Big Grin
Until I know how to insert a custom menu to window contextmenu, I really know the IDataObject and IShellFolder COM object how to working.

thank's so much!
QuestionHow to insert a menu when right click blank place?
hays.zhao
22:43 6 Jun '07  
For example:
when right click blank place of desktop or an opened explorer, a menu will appear.
it contain "view"
"Arrange Icons By"
"Paste"
"Paste Shortcut"
"New"
"Properties" and ...

now i want to insert a menu like "Paste", how can do it?

I know that how to insert a menu to right click menu of a file or folder as you introduced.

string keyname = "Reg Paste";
string guid = "{" + typeof(PasteMenu).GUID.ToString() + "}";
RegistryKey rk, rk2;
rk = Registry.ClassesRoot.OpenSubKey(@"xmlfile\shellex\ContextMenuHandlers", true);
rk2 = rk.OpenSubKey(keyname);
if (rk2 == null)
rk2 = rk.CreateSubKey(keyname);
rk2.SetValue("", guid);
rk2.Close();
rk.Close();

But how to registry to blank place of window?

Thanks very much if you can give me same advice!

take it easy & keep it simple....

GeneralError in VC6
Max++
0:40 27 May '07  
I try to open sample project in VC6.
I found 2 error
ChildView.cpp(258) : error C2065: 'StrFormatByteSize64' : undeclared identifier
and
ShellContextMenu.cpp(269) : error C2065: 'SHBindToParent' : undeclared identifier

Please give me some idea for solve this problem.
GeneralProblems running under Vista
SystemTools
10:56 20 Dec '06  
I have not found the cause because I don't have VS or a debugger on a Vista computer, but when running on Vista, the result is an empty menu. The menu is there, but the menu text is missing. You can select menu items and execute them, however. But the text is just gone.

I know the context menu extensions work with Vista as I have other code that does the same thing, just a bit differently and I havn't had time to determine why this code works differently.

If anyone has found a workaround, please post something.

Thanks

-Kevin


Last Updated 16 May 2003 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010