www.pudn.com > ctxmenu_src.rar > ShellCtxMenu.cpp


#include "stdafx.h" 
#include "resource.h" 
#include "priv.h" 
#include "ShellExt.h" 
#include "CtxMenu.h" 
 
#include  
#include  
#include "io.h" 
 
// utilities 
#include "ShUtils.h" 
#include "FileProcess.h" 
#include "CancelDlg.h"               
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
/*---------------------------------------------------------------- 
 
  FUNCTION: CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO) 
 
  PURPOSE: Called by the shell after the user has selected on of the 
           menu items that was added in QueryContextMenu(). This is  
           the function where you get to do your real work!!! 
 
  PARAMETERS: 
    lpcmi - Pointer to an CMINVOKECOMMANDINFO structure 
 
  RETURN VALUE: 
 
 
  COMMENTS: 
  
----------------------------------------------------------------*/ 
 
STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) 
{ 
	// look at all the MFC stuff in here! call this to allow us to  
	// not blow up when we try to use it. 
	AFX_MANAGE_STATE(AfxGetStaticModuleState( )); 
 
	HINSTANCE hInst = AfxGetInstanceHandle(); 
 
    ODS("CShellExt::InvokeCommand()\r\n"); 
 
	HWND hParentWnd = lpcmi->hwnd; 
                                       
	HRESULT hr = NOERROR; 
 
    //If HIWORD(lpcmi->lpVerb) then we have been called programmatically 
    //and lpVerb is a command that should be invoked.  Otherwise, the shell 
    //has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has 
    //selected.  Actually, it's (menu ID - idCmdFirst) from QueryContextMenu(). 
	UINT idCmd = 0; 
 
   if (!HIWORD(lpcmi->lpVerb))  
   { 
      idCmd = LOWORD(lpcmi->lpVerb); 
 
		// process it 
		switch (idCmd)  
      { 
		default: 
		case 0: // operation 1 
		case 1: // operation 2 
			{ 
            // get a CWnd for Explorer 
				CWnd *pParentWnd = NULL; 
				if (hParentWnd!=NULL) 
					pParentWnd = CWnd::FromHandle(hParentWnd); 
 
            // disable explorer 
				::PostMessage(hParentWnd, WM_ENABLE, (WPARAM)FALSE, (LPARAM)0); 
 
            // create our process/cancel dialog 
				CCancelDlg *pCancel; 
				try  
				{ 
					pCancel = new CCancelDlg; 
				}  
				catch (CMemoryException *e)  
				{ 
					e->ReportError(); 
					e->Delete(); 
					pCancel=NULL; 
               return hr; 
				} 
 
            // show it 
				pCancel->Create(pParentWnd); 
				if (::IsWindow(pCancel->m_hWnd))  
				{ 
					pCancel->ShowWindow(SW_SHOW); 
				} 
 
            int iFiles = m_csaPaths.GetSize(); 
 
            // process files in m_csaPaths 
            pCancel->SetTotalItems(iFiles); 
 
            // wrap this whole thing in a nice try/catch 
				try  
            { 
					// do it! 
					for (int i=0; i < iFiles; i++)  
               { 
                  // get the current file. this array is filled in CShellExt::Initialize 
                  CString csFile = m_csaPaths.GetAt(i); 
 
                  // update progress dialog 
						CString f; f.Format("Processing file %d of %d", i + 1, iFiles); 
                  pCancel->SetProgText(f); 
						pCancel->SetPathText(csFile); 
                  pCancel->StepIt(); 
 
                  // move some Windows messages around 
						ShMsgPump(); 
 
                  // this struct carries info to and from the thread 
                  ThreadInfo is; 
						is.bDone = FALSE; 
						is.bStop = FALSE; 
						is.csFile = csFile; 
 
						////////////////////////////////////////////////////// 
						// start the worker thread 
						CWinThread *pThread = AfxBeginThread(FileProcessThreadFunc,  
																	(LPVOID)&is, 
																	THREAD_PRIORITY_NORMAL, 
																	0, 
																	CREATE_SUSPENDED); 
 
						////////////////////////////////////////////////////// 
						// did we create OK? 
						if (pThread ==NULL)  
						{ 
							ODS("Thread creation falied\n"); 
							break; 
						} 
 
						////////////////////////////////////////////////////// 
						// start doing some real work 
 
                  // this will start the thread for real.  
						if (pThread->ResumeThread()==-1)  
						{ 
							ODS("Resume thread failure\n"); 
							break; 
						} 
						 
                  BOOL bCancel = FALSE; 
						BOOL bDone = FALSE; 
                  int iCurPercentDone = 0; 
                  int iLastPercentDone = -1; 
 
						////////////////////////////////////////////////////// 
                  // now, we just sit back and wait 
						// for the thread to signal finished 
 
						while (!bDone)  
                  { 
							// test for cancel signal from the progress dialod 
							bCancel = GET_SAFE(pCancel->m_bCancel); 
							if (bCancel)  
							{ 
								ODS("bCancel (main)\n"); 
								SET_SAFE(is.bStop, TRUE); 
							} 
 
							// test for thread finished 
							bDone = GET_SAFE(is.bDone); 
 
                     // get progress 
                     iCurPercentDone = GET_SAFE(is.iPercentDone); 
 
                     // update the progress meter 
                     if (iCurPercentDone!=iLastPercentDone) 
                     { 
                        pCancel->SetItemPercentDone(iCurPercentDone); 
                        iLastPercentDone = iCurPercentDone; 
                     } 
 
                     // let the dialog breathe 
							ShMsgPump(); 
						} 
 
						ODS("bDone (main)\n"); 
 
                  // operation cancelled. abort the whole thing... 
						if (bCancel) 
						{ 
							ODS("cancelled (main)\n"); 
							break; 
						} 
 
                  // handle any errors that may have popped up 
                  int iErr = GET_SAFE(is.iErr); 
 
                  if (iErr!=0) 
                  { 
                     CString msg; 
                      
                     pCancel->ShowWindow(SW_HIDE); 
                      
                     msg.Format("Error : %d", iErr); 
 
 
                     UINT res = AfxMessageBox(SHELLEXNAME + msg, MB_OKCANCEL); 
 
                     // if the user presses 'cancel', abort 
                     if (res==IDCANCEL) 
                     { 
                        break; 
                     } 
 
                     // bring back our progress dialog 
                     pCancel->ShowWindow(SW_SHOW); 
 
                  } // err 
 
               } // file loop 
				}  
				catch (CException *e)  
				{ 
					e->ReportError(); 
					e->Delete(); 
				} 
 
				pCancel->ShowWindow(SW_HIDE); 
				pCancel->ShutDown(); 
 
				::PostMessage(hParentWnd, WM_ENABLE, (WPARAM)TRUE, (LPARAM)0); 
			} 
			break; 
		}	// switch on command 
	} 
 
   return hr; 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
// 
//  FUNCTION: CShellExt::GetCommandString(...) 
// 
//  PURPOSE: Retrieve various text strinsg associated with the context menu 
// 
//	Param			Type			Use 
//	-----			----			--- 
//	idCmd			UINT			ID of the command 
//	uFlags			UINT			which type of info are we requesting 
//	reserved		UINT *			must be NULL 
//	pszName			LPSTR			output buffer 
//	cchMax			UINT			max chars to copy to pszName 
// 
//////////////////////////////////////////////////////////////////////// 
 
STDMETHODIMP CShellExt::GetCommandString(UINT idCmd, 
                                         UINT uFlags, 
                                         UINT FAR *reserved, 
                                         LPSTR pszName, 
                                         UINT cchMax) 
{ 
   ODS("CShellExt::GetCommandString()\r\n"); 
	 
	AFX_MANAGE_STATE(AfxGetStaticModuleState( )); 
 
	HINSTANCE hInst = AfxGetInstanceHandle(); 
 
	switch (uFlags)  
   { 
	case GCS_HELPTEXT:		// fetch help text for display at the bottom of the  
							// explorer window 
		switch (idCmd) 
		{ 
			case 0: 
            strncpy(pszName, "Do something to the selected file(s)", cchMax); 
				break; 
			case 1: 
            strncpy(pszName, "Do something else to the selected file(s)", cchMax); 
				break; 
         default: 
            strncpy(pszName, SHELLEXNAME, cchMax); 
				break; 
		} 
		break; 
 
	case GCS_VALIDATE: 
		break; 
 
	case GCS_VERB:// language-independent command name for the menu item  
		switch (idCmd) 
		{ 
			case 0: 
            strncpy(pszName, "Operation1", cchMax); 
				break; 
			case 1: 
            strncpy(pszName, "Operation2", cchMax); 
				break; 
         default: 
            strncpy(pszName, SHELLEXNAME, cchMax); 
				break; 
		} 
 
		break; 
	} 
    return NOERROR; 
} 
 
/////////////////////////////////////////////////////////////////////////// 
// 
//  FUNCTION: CShellExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) 
// 
//  PURPOSE: Called by the shell just before the context menu is displayed. 
//           This is where you add your specific menu items. 
// 
//  PARAMETERS: 
//    hMenu      - Handle to the context menu 
//    indexMenu  - Index of where to begin inserting menu items 
//    idCmdFirst - Lowest value for new menu ID's 
//    idCmtLast  - Highest value for new menu ID's 
//    uFlags     - Specifies the context of the menu event 
// 
//  RETURN VALUE: 
// 
// 
//  COMMENTS: 
// 
/////////////////////////////////////////////////////////////////////////// 
 
STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, 
                                         UINT indexMenu, 
                                         UINT idCmdFirst, 
                                         UINT idCmdLast, 
                                         UINT uFlags) 
{ 
   AFX_MANAGE_STATE(AfxGetStaticModuleState( )); 
 
   return CreateShellExtMenu(hMenu,  
                              indexMenu,  
                              idCmdFirst,  
                              idCmdLast,  
                              uFlags,  
                              (HBITMAP)m_menuBmp.GetSafeHandle()); 
}