Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

The Mini Shell extension Framework � Part II

0.00/5 (No votes)
26 Jan 2005 1  
Discussion of a small C++ framework to create Windows shell extensions (IContextMenuImpl).

Contents

Introduction

The Windows shell provides the ability to extend the context menu with new menu options. To enable this feature a shell extension must register an IContextMenu interface for a specific file extension or the global �*� extension. The Mini Shell framework discussed in this article provides a set of helper classes that can be used to create such a shell extension. The IContextMenuImpl class provides the following functionality:

  • An embedded class CMenu that makes it easy to create the correct menu entries.
  • A registration system that will forward owner drawn menu events to a �paint� handler and select a menu item command to the correct command handler.
  • A CSmallBitmapHandler class is provided by the framework to create menu items with a small bitmap in front of the menu text.

My original plan was to document IContextMenuImpl and IShellFolderImpl in one article. During finalization of the IShellFolderImpl, I decided to split the description of both classes in two articles. The primary reason for this decision is that, IShellFolderImpl is very complex and requires on its own already a lot of text to describe (will be documented in part 3). For more background info about the design model and the used .vvv file sample the reader is referred to the first article on the Mini Shell extension Framework.

Framework Requirements

The requirements for the framework are not changed since the first article. VC.NET 2002 + latest SDK or VC.NET 2003. The framework is verified on Win 98, ME, W2K and XP.

Creating a Context Menu Extension

A context menu extension is, as all other shell extensions, a COM object. The first requirement is thus, the registration of the COM class. The framework includes two ATL registrations script to do this. One registration script is intended to be used for files that are normally opened with an application and the other script should be used if the file is opened in explorer (in combination with a shellfolder extension). The included VVV sample demonstrates also a shellfolder extension and uses therefore the contextmenu_sf.rgs registration script.

class ATL_NO_VTABLE CContextMenu :
  public CComObjectRootEx<CComSingleThreadModel>,
  public CComCoClass<CContextMenu, & __uuidof(CContextMenu)>,
  public IContextMenuImpl<CContextMenu>
{
public:

static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()
{
  return IContextMenuImpl<CContextMenu>::UpdateRegistry(IDR_CONTEXTMENU, 
    bRegister, L"Sample ShellExtension ContextMenu",
    __uuidof(CShellFolder), wszVVVExtension);
}

The code example above shows the class definition and the static function UpdateRegistry that ATL will call to register and unregister the extensions. This static function is normally implemented with the DECLARE_REGISTRY_RESOURCEID macro which is added automatically by the ATL class wizard. To instruct ATL which interfaces our object supports a �COM_MAP� must be setup. The code below shows the interfaces the VVV sample selects to support. The IContextMenu2 and IContextMenu3 interfaces are needed because the VVV sample uses an owner drawn menu item.

BEGIN_COM_MAP(CContextMenu)
  COM_INTERFACE_ENTRY(IShellExtInit)
  COM_INTERFACE_ENTRY(IContextMenu)
  COM_INTERFACE_ENTRY(IContextMenu2)
  COM_INTERFACE_ENTRY(IContextMenu3)
END_COM_MAP()

The base class of the framework IContextMenuImpl<> must be notified which extensions needs to be handled.

CContextMenu()
{
  RegisterExtension(_T(�.vvv�));
}

The last required function that must be implemented is the OnQueryContextMenu. This function is called by the framework after it received a call from the shell through the COM function QueryContextMenu. The code below shows the implementation for the VVV sample. The first step checks if the files selected by the user only contain .vvv selected files. In the second step the extension checks if only one file is selected (theoretically, only one check is needed). The first entry that is created is a submenu with an owner draw handler. Two menu items are added to this new submenu. The CSmallBitmapHandler class is provided by the framework. CEditWithNotepadCommand and CAboutMSFCommand are command handlers of the VVV sample.

// Purpose: called by the 'impl' class. Request to configure the menu

void OnQueryContextMenu(IContextMenuImpl<CContextMenu>::CMenu& menu,
                        const std::vector<CString>& filenames)
{
  if (ContainsUnknownExtension(filenames))
    return; // only extend the menu when

            // only .vvv files are selected.


  if (filenames.size() != 1)
    return; // only add to the context menu when 1 file is selected.


  CMenu menuVVV = 
    menu.AddSubMenu(IDS_CONTEXTMENU_VVV_SUBMENU_HELP,
                    CCustomMenuHandlerPtr(new
                    CSmallBitmapHandler(IDS_CONTEXTMENU_VVV_SUBMENU,
                    IDB_MENUICON)));

  menuVVV.AddItem(IDS_CONTEXTMENU_EDIT_WITH_NOTEPAD,
                  IDS_CONTEXTMENU_EDIT_WITH_NOTEPAD_HELP,
                  CContextCommandPtr(new CEditWithNotepadCommand()));

  menuVVV.AddItem(IDS_CONTEXTMENU_ABOUT_MSF_HELP,
                  CContextCommandPtr(new CAboutMSFCommand()),
                  CCustomMenuHandlerPtr(new
                  CSmallBitmapHandler(IDS_CONTEXTMENU_ABOUT_MSF,
                                      IDB_MENUICON)));
}

Command Functors

The framework uses functors to forwarded the selected menu item as action to the shell extension. These functor objects must be passed as one of the arguments when menu items are created. The functor CEditWithNotepadCommand used by the sample will start notepad to edit the selected .VVV file. The CreateProcess function that is used is a �short� version of the Win32 CreateProcess function and is one of the utility functions provided by the framework.

class CEditWithNotepadCommand : public CContextCommand
{
public:
  virtual void operator()(const CMINVOKECOMMANDINFO* /* pici */,
                          const std::vector<CString> & filenames)
  {
    ATLASSERT(filenames.size() == 1); // can only handle 1 file.


    // Use the command line param to pass 

    // the exe filename. This cause

    // Windows to use the path to find notepad.

    CString strCmd = _T("notepad.exe \"") + filenames[0] + _T("\"");

    CreateProcess(NULL, strCmd.GetBuffer());
  }
};

The other CAboutMSFCommand functor is even simpler. It just formats a string and displays it to the user. The IsolationAwareMessageBox messagebox function is called to use the new XP style (when running on XP). Tip: MessageBox is one of the functions that is not redefined by the SDK headers when isolation aware is enabled, it must be called explicit.

class CAboutMSFCommand : public CContextCommand
{
public:
  virtual void operator()
    (const CMINVOKECOMMANDINFO* pici,
     const std::vector<CString> & /* filenames */)
  {
    CString strText;
    strText.Format(IDS_CONTEXTMENU_ABOUT_MASK,
                   HIWORD(MSF_VER), LOWORD(MSF_VER));

    IsolationAwareMessageBox(pici->hwnd, strText,
      LoadString(IDS_CONTEXTMENU_CAPTION), MB_OK);
  }
};

Owner Draw Menus

The basic menu system has changed very little in the history of Windows. To provide a �cooler� look, many applications draw their own menus. The windows shell menu itself only uses images for the �open with� and �send to� submenus. A contextmenu extension can also use owner draw menu items. There are three options to add graphics to a menu item:

  • Owner draw. The extension is completely free to draw the menu itself.
  • Using a small menu bitmap. Menu items can use a small bitmap before the text. The X mark before �close� in the system menu is a good example (not supported on all Windows versions).
  • Use a custom check mark.

CSmallBitmapHandler

The framework provided a support class CSmallBitmapHandler that can be used to add small bitmaps (13x13) to menu items. This class uses the custom check mark option to add the small bitmap before the text. The main advantage of this technique is that the text of the menu item is drawn the same as all other menu items. This prevents that the �added� menu item looks different or strange. Complete owner drawn items and bitmap menu items are better reserved for a submenu that is under complete control of the extension.

History

  • 0.87

    Improved version of IContextMenuImpl. Added support for owner draw menu items.

  • 0.85

    Initial version of IContextMenuImpl.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here