HostContextMenu.cpp

Go to the documentation of this file.
00001 /*  Helper to create context menu for host objects and execute user choice
00002 
00003     Copyright (C) 2007  Alexander Lamaison <awl03@doc.ic.ac.uk>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License along
00016     with this program; if not, write to the Free Software Foundation, Inc.,
00017     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018 */
00019 
00020 #include "stdafx.h"
00021 #include "HostContextMenu.h"
00022 
00023 /*------------------------------------------------------------------------------
00024  * CHostContextMenu::Initialize
00025  * Initialises the context menu object for a given host connection object.
00026  * Used in place of passing parameters to a constructor due to ATL template.
00027  * The PIDL passed in is an absolute PIDL to the host connection RemoteFolder
00028  * and is needed to perform ShellExecuteEx on if the Connect item is chosen.
00029  *----------------------------------------------------------------------------*/
00030 STDMETHODIMP CHostContextMenu::Initialize( PCIDLIST_ABSOLUTE pidl )
00031 {
00032         ATLTRACE("CHostContextMenu::Initialize called\n");
00033         if (pidl == NULL)
00034                 return E_POINTER;
00035 
00036         // TODO: use a PidlManager to verify PIDLs?
00037 
00038         m_pidl = ILClone( pidl );
00039         return S_OK;
00040 }
00041 
00042 // IContextMenu
00043 
00044 /*------------------------------------------------------------------------------
00045  * CHostContextMenu::QueryContextMenu : IContextMenu
00046  * Adds items to the given context menu (hMenu).
00047  * The first position at which the item should be inserted is given in 
00048  * indexMenu (TODO: when would this not be 0?).  The menu command IDs should
00049  * lie between idCmdFirst and idCmdLast and are saved for later use.
00050  * We return the largest command id of the menu items created plus one.
00051  *----------------------------------------------------------------------------*/
00052 STDMETHODIMP CHostContextMenu::QueryContextMenu(
00053         __in HMENU hMenu, __in UINT indexMenu, __in UINT idCmdFirst,
00054         __in UINT idCmdLast, __in UINT uFlags)
00055 {
00056         ATLTRACE("CHostContextMenu::QueryContextMenu called\n");
00057         ATLASSERT(idCmdFirst + MENUOFFSET_LAST < idCmdLast);
00058 
00059         // Add menu item at next position with menu command calculated from offset
00060         InsertMenu( hMenu, indexMenu++, MF_BYPOSITION, 
00061                 idCmdFirst + MENUOFFSET_CONNECT, _T("&Connect") );
00062 
00063         // The CMF_DEFAULTONLY flag tells namespace extensions to add only 
00064         // the default menu item - we only have one at all, currently, but
00065         // when we have more we will need: if (uFlags & CMF_DEFAULTONLY)
00066 
00067         // Set Connect menu verb as default
00068         if (!(uFlags & CMF_NODEFAULT))
00069                 SetMenuDefaultItem( hMenu, idCmdFirst + MENUOFFSET_CONNECT, false );
00070 
00071     // Return largest menu offset + 1
00072         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(MENUOFFSET_LAST + 1));
00073 }
00074 
00075 /*------------------------------------------------------------------------------
00076  * CHostContextMenu::GetCommandString : IContextMenu
00077  * Language-independent verb or status bar help string requested.
00078  * The request can be for either an ANSI or a unicode version (indicated
00079  * with uType) and both should be supported.  Returns S_OK or E_INVALIDARG if
00080  * idCmd is not valid for this menu.
00081  *----------------------------------------------------------------------------*/
00082 STDMETHODIMP CHostContextMenu::GetCommandString(
00083         __in UINT_PTR idCmd, __in UINT uType, __reserved UINT *pReserved, 
00084         __out_awcount(!(uType & GCS_UNICODE), cchMax) LPSTR pszName, 
00085         __in UINT cchMax)
00086 {
00087         ATLTRACE("CRemoteFolder::GetCommandString called\n");
00088         (void)pReserved;
00089         HRESULT hr = E_INVALIDARG;
00090 
00091         // Validate idCmd (deals with GCS_VALIDATE into the bargain)
00092         if(idCmd < MENUOFFSET_FIRST || idCmd > MENUOFFSET_LAST)
00093         return hr;
00094 
00095         // If the code reaches an ANSI GCS_ case it is most likely because the 
00096         // unicode version failed and Explorer is trying ANSI as a fallback
00097 
00098         switch(uType)
00099         {
00100         case GCS_HELPTEXTA:
00101                 if (idCmd == MENUOFFSET_CONNECT)
00102                         hr = StringCchCopyA(pszName, cchMax,
00103                                 "Connect to remote filesystem over SFTP");
00104                 break;
00105 
00106         case GCS_HELPTEXTW:
00107                 if (idCmd == MENUOFFSET_CONNECT)
00108                         hr = StringCchCopyW((PWSTR)pszName, cchMax,
00109                                 L"Connect to remote filesystem over SFTP");
00110                 break; 
00111 
00112         case GCS_VERBA:
00113                 if (idCmd == MENUOFFSET_CONNECT)
00114                         hr = StringCchCopyA(pszName, cchMax, "connect");
00115                 break;
00116 
00117         case GCS_VERBW:
00118                 if (idCmd == MENUOFFSET_CONNECT)
00119                         hr = StringCchCopyW((PWSTR)pszName, cchMax, L"connect");
00120                 break;
00121 
00122         default:
00123                 hr = S_OK;
00124                 break; 
00125         }
00126         return hr;
00127 }
00128 
00129 /*------------------------------------------------------------------------------
00130  * CHostContextMenu::InvokeCommand : IContextMenu
00131  * A menu command has been selected to execute on the PIDL.
00132  * The chosen command can be either an ANSI verb, a unicode VERB or a menu ID.
00133  * We parse the value passed to determing which one and then execute the 
00134  * chosen command.
00135  * Currently, only the 'connect' command is supported and we simply invoke
00136  * the default action for a folder type (open).
00137  * If the command verb/id is not recognised we return E_FAIL.
00138  *----------------------------------------------------------------------------*/
00139 STDMETHODIMP CHostContextMenu::InvokeCommand(
00140         __in CMINVOKECOMMANDINFO *pici )
00141 {
00142         ATLTRACE("CRemoteFolder::InvokeCommand called\n");
00143 
00144         BOOL fUnicode = FALSE;          // Is CMINVOKECOMMANDINFO struct unicode?
00145         MENUOFFSET menuCmd = MENUOFFSET_NULL;
00146                                                                 // Store chosen command from parsing
00147         CMINVOKECOMMANDINFOEX *piciEx = { 0 };
00148                                                                 // pici cast to unicode version (if needed)
00149 
00150         if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&
00151            (pici->fMask & CMIC_MASK_UNICODE))
00152         {
00153                 // Given command info struct is actually a unicode version,
00154                 // cast accordingly
00155                 fUnicode = TRUE;
00156                 piciEx = (CMINVOKECOMMANDINFOEX *) pici;
00157         }
00158 
00159         if (!fUnicode && HIWORD(pici->lpVerb))                          // ANSI
00160         {
00161                 if (!StrCmpIA( pici->lpVerb, "connect" ))
00162                         menuCmd = MENUOFFSET_CONNECT;
00163         }
00164         else if(fUnicode && HIWORD(piciEx->lpVerbW))            // Unicode
00165         {
00166                 if(StrCmpIW( piciEx->lpVerbW, L"connect" ))
00167                         menuCmd = MENUOFFSET_CONNECT;
00168         }
00169         else if(LOWORD(pici->lpVerb) == MENUOFFSET_CONNECT)     // Menu ID
00170         {
00171                 menuCmd = MENUOFFSET_CONNECT;
00172         }
00173         else                                                                                            // Invalid verb/ID
00174         {
00175                 // An attempt was made to invoke a verb/ID not supported by
00176                 // this menu's PIDL. For the time being, we are assuming this
00177                 // doesn't happen and all cases are caught by one of the above.
00178                 UNREACHABLE;
00179                 return E_FAIL;
00180         }
00181 
00182         ATLASSERT(menuCmd >= MENUOFFSET_FIRST && menuCmd <= MENUOFFSET_LAST);
00183 
00184         // Set up ShellExecute to execute chosen verb on this menu's PIDL (m_pidl)
00185         SHELLEXECUTEINFO sei;
00186         ZeroMemory(&sei, sizeof(sei));
00187         sei.cbSize = sizeof(sei);
00188         // Needed if multiple menu items used
00189         // if (menuCmd == MENUOFFSET_CONNECT)
00190         //     sei.lpVerb = _T("connect");
00191         sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
00192         sei.lpIDList = ILClone(m_pidl);
00193         sei.lpClass = _T("folder");
00194         sei.hwnd = pici->hwnd;
00195         sei.nShow = SW_SHOWNORMAL;
00196 
00197         HRESULT hr = (ShellExecuteEx(&sei)) ? S_OK : E_FAIL;
00198 
00199         ILFree((LPITEMIDLIST) sei.lpIDList);
00200 
00201         return hr;
00202 }
00203 
00204 // CHostContextMenu
00205 

Generated on Mon Nov 12 22:43:52 2007 for Swish by  doxygen 1.5.3