Figure 4 CEditMenuHandler

EditMenu.h
// MSDN — November 2000
// If this code works, it was written by Paul DiLascia.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT
#include "menuinit.h"

// CEditMenuHandler duplicates the edit control context menu
// in a way that can be extended.
//
// To use it:
// - Call Install when your edit control is created/subclassed.
// - Call OnEditCommand to handle any command in the range 
//   ID_EDIT_FIRST to ID_EDIT_LAST.
// - Call OnUpdateEditCommand to handle any UPDATE_COMMAND_UI in the
//   range ID_EDIT_FIRST to ID_EDIT_LAST.
//
class CEditMenuHandler : public CPopupMenuInitHandler {
public:
   CEditMenuHandler();
   ~CEditMenuHandler();
   BOOL Install(CWnd* pWnd, UINT nIDMenu);
   void Remove() { Unhook(); }

   // call these to handle/update cut, copy, paste etc.
   virtual BOOL OnEditCommand(UINT nID);
   virtual BOOL OnUpdateEditCommand(CCmdUI* pCmdUI);

protected:
   UINT m_nIDMenu;
   virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp);
   virtual BOOL OnContextMenu(CPoint pt);
};

#define ID_EDIT_FIRST ID_EDIT_CLEAR
#define ID_EDIT_LAST  ID_EDIT_REDO
EditMenu.cpp
// MSDN — November 2000
// If this code works, it was written by Paul DiLascia.
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably Windows NT 
#include "StdAfx.h"
#include "EditMenu.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CEditMenuHandler::CEditMenuHandler()
{
}

CEditMenuHandler::~CEditMenuHandler()
{
}

// Install edit menu handler. You must supply a menu ID of a menu that
// has Cut, Copy, Paste, etc.
//
BOOL CEditMenuHandler::Install(CWnd* pWnd, UINT nIDMenu)
{
   m_nIDMenu = nIDMenu;
   return !HookWindow(pWnd);
}

// Generic menu item update: enable/disable standard menu items based
// on whether text is selected, something to paste, etc. You must call
// this to update the edit commands when you get an MFC
// ON_UPDATE_COMMAND_UI notification for an edit command.
//
BOOL CEditMenuHandler::OnUpdateEditCommand(CCmdUI* pCmdUI)
{
   CEdit* pEditWnd = DYNAMIC_DOWNCAST(CEdit,CWnd::FromHandle(m_hWnd));
   if (pEditWnd) {
      UINT nID = pCmdUI->m_nID;
      switch (nID) {
      case ID_EDIT_CUT:
      case ID_EDIT_COPY:
      case ID_EDIT_CLEAR:
         int beg,end;
         pEditWnd->GetSel(beg,end);
         pCmdUI->Enable(beg<end);
         return TRUE;
      case ID_EDIT_UNDO:
         pCmdUI->Enable(pEditWnd->CanUndo());
         return TRUE;
      case ID_EDIT_PASTE:
         pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
         return TRUE;
      case ID_EDIT_SELECT_ALL:
         pCmdUI->Enable(pEditWnd->GetWindowTextLength()>0);
         return TRUE;
      }
   }
   return FALSE; // not handled
}

// Handle standard edit command: perform cut, copy, paste, etc. You
// must call when you get an edit command (ON_COMMAND notification).
//
BOOL CEditMenuHandler::OnEditCommand(UINT nID)
{
   CEdit* pEditWnd = DYNAMIC_DOWNCAST(CEdit,CWnd::FromHandle(m_hWnd));
   if (pEditWnd) {
      switch (nID) {
      case ID_EDIT_UNDO:
         pEditWnd->Undo();
         return TRUE;
      case ID_EDIT_CUT:
         pEditWnd->Cut();
         return TRUE;
      case ID_EDIT_COPY:
         pEditWnd->Copy();
         return TRUE;
      case ID_EDIT_PASTE:
         pEditWnd->Paste();
         return TRUE;
      case ID_EDIT_CLEAR:
         pEditWnd->Clear();
         return TRUE;
      case ID_EDIT_SELECT_ALL:
         pEditWnd->SetSel(0,-1);
         return TRUE;
      }
   }
   return FALSE; // not handled
}

// Internal WindowProc intercepts WM_CONTEXTMENU.
//
LRESULT CEditMenuHandler::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
{
   if (msg==WM_CONTEXTMENU) {
      return OnContextMenu((CPoint)lp);
   }
   return CPopupMenuInitHandler::WindowProc(msg, wp, lp);
}

//////////////////
// Display context menu. Override to do something different.
//
BOOL CEditMenuHandler::OnContextMenu(CPoint pt)
{
   CMenu editMenu;
   VERIFY(editMenu.LoadMenu(m_nIDMenu));
   CMenu* pSubMenu = editMenu.GetSubMenu(0);
   pSubMenu->TrackPopupMenu(0,pt.x,pt.y,CWnd::FromHandle(m_hWnd));
   return TRUE; // handled
}