2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afs/param.h>
16 #include <sys/types.h>
18 #include "afs_shl_ext.h"
19 #include "shell_ext.h"
20 #include "volume_info.h"
21 #include "set_afs_acl.h"
23 #include "make_mount_point_dlg.h"
25 #include "server_status_dlg.h"
27 #include "submounts_dlg.h"
33 static char THIS_FILE[] = __FILE__;
37 ULONG nCMRefCount = 0; // IContextMenu ref count
38 ULONG nSERefCount = 0; // IShellExtInit ref count
41 static BOOL IsADir(const CString& strName)
45 if (_stat(strName, &statbuf) < 0)
48 return statbuf.st_mode & _S_IFDIR;
51 /////////////////////////////////////////////////////////////////////////////
54 IMPLEMENT_DYNCREATE(CShellExt, CCmdTarget)
56 CShellExt::CShellExt()
62 CShellExt::~CShellExt()
68 void CShellExt::OnFinalRelease()
70 // When the last reference for an automation object is released
71 // OnFinalRelease is called. The base class will automatically
72 // deletes the object. Add additional cleanup required for your
73 // object before calling the base class.
75 CCmdTarget::OnFinalRelease();
79 BEGIN_MESSAGE_MAP(CShellExt, CCmdTarget)
80 //{{AFX_MSG_MAP(CShellExt)
81 // NOTE - the ClassWizard will add and remove mapping macros here.
85 BEGIN_DISPATCH_MAP(CShellExt, CCmdTarget)
86 //{{AFX_DISPATCH_MAP(CShellExt)
87 // NOTE - the ClassWizard will add and remove mapping macros here.
91 // Note: we add support for IID_IShellExt to support typesafe binding
92 // from VBA. This IID must match the GUID that is attached to the
93 // dispinterface in the .ODL file.
95 // {DC515C27-6CAC-11D1-BAE7-00C04FD140D2}
96 static const IID IID_IShellExt =
97 { 0xdc515c27, 0x6cac, 0x11d1, { 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2 } };
99 BEGIN_INTERFACE_MAP(CShellExt, CCmdTarget)
100 INTERFACE_PART(CShellExt, IID_IShellExt, Dispatch)
101 INTERFACE_PART(CShellExt, IID_IContextMenu, MenuExt)
102 INTERFACE_PART(CShellExt, IID_IShellExtInit, ShellInit)
105 IMPLEMENT_OLECREATE(CShellExt, "AfsClientContextMenu", 0xdc515c27, 0x6cac, 0x11d1, 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2)
108 /////////////////////////////////////////////////////////////////////////////
109 // CShellExt message handlers
110 /////////////////////////////////////////////////////////////////////////////
113 /////////////////////////////////////////////////////////////////////////////
114 // IUnknown for IContextMenu
115 /////////////////////////////////////////////////////////////////////////////
116 STDMETHODIMP CShellExt::XMenuExt::QueryInterface(REFIID riid, void** ppv)
118 METHOD_PROLOGUE(CShellExt, MenuExt);
120 return pThis->ExternalQueryInterface(&riid, ppv);
123 STDMETHODIMP_(ULONG) CShellExt::XMenuExt::AddRef(void)
125 return ++nCMRefCount;
128 STDMETHODIMP_(ULONG) CShellExt::XMenuExt::Release(void)
136 /////////////////////////////////////////////////////////////////////////////
137 // IConextMenu Functions
138 /////////////////////////////////////////////////////////////////////////////
139 STDMETHODIMP CShellExt::XMenuExt::QueryContextMenu(HMENU hMenu,UINT indexMenu,
140 UINT idCmdFirst, UINT idCmdLast,UINT uFlags)
142 METHOD_PROLOGUE(CShellExt, MenuExt);
144 // Don't add any menu items if we're being asked to deal with this file as a shortcut.
145 if (uFlags & CMF_VERBSONLY)
146 return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)0));
148 // Check to see if there's already an AFS menu here; if so, remove it
149 int nItemsNow = GetMenuItemCount (hMenu);
150 CString strAfsItemText = GetMessageString(IDS_AFS_ITEM);
151 LPCTSTR pszAfsItemText = (LPCTSTR)strAfsItemText;
152 for (int iItem = 0; iItem < nItemsNow; iItem++) {
153 TCHAR szItemText[256];
154 if (!GetMenuString (hMenu, iItem, szItemText, 256, MF_BYPOSITION))
156 if (!lstrcmp (szItemText, pszAfsItemText)) {
157 DeleteMenu (hMenu, iItem, MF_BYPOSITION);
162 int indexShellMenu = 0;
164 // Create the AFS submenu using the allowed ID's.
165 HMENU hAfsMenu = CreatePopupMenu();
166 int indexAfsMenu = 0;
168 // The Authentication item has been removed from the AFS menu because
169 // there is now a tray icon to handle authentication.
171 //::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_AUTHENTICATION, GetMessageString(IDS_AUTHENTICATION_ITEM));
173 // Only enable the ACL menu item if a single directory is selected
174 int nSingleDirOnly = MF_GRAYED;
175 if (pThis->m_bDirSelected && (pThis->m_astrFileNames.GetSize() == 1))
176 nSingleDirOnly = MF_ENABLED;
177 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_ACL_SET, GetMessageString(IDS_ACLS_ITEM));
179 // Volume/Partition submenu of the AFS submenu
180 HMENU hVolPartMenu = CreatePopupMenu();
181 int indexVolPartMenu = 0;
182 ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUME_PROPERTIES, GetMessageString(IDS_VOL_PART_PROPS_ITEM));
183 ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE, GetMessageString(IDS_VOL_PART_REFRESH_ITEM));
184 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hVolPartMenu, GetMessageString(IDS_VOL_PART_ITEM));
186 // Mount Point submenu of the AFS submenu
187 HMENU hMountPointMenu = CreatePopupMenu();
188 int indexMountPointMenu = 0;
189 ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_SHOW, GetMessageString(IDS_MP_SHOW_ITEM));
190 ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_REMOVE, GetMessageString(IDS_MP_REMOVE_ITEM));
191 ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_MAKE, GetMessageString(IDS_MP_MAKE_ITEM));
192 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hMountPointMenu, GetMessageString(IDS_MOUNT_POINT_ITEM));
194 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH, GetMessageString(IDS_FLUSH_FILE_DIR_ITEM));
195 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH_VOLUME, GetMessageString(IDS_FLUSH_VOLUME_ITEM));
196 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOW_SERVER, GetMessageString(IDS_SHOW_FILE_SERVERS_ITEM));
197 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOWCELL, GetMessageString(IDS_SHOW_CELL_ITEM));
198 ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SERVER_STATUS, GetMessageString(IDS_SHOW_SERVER_STATUS_ITEM));
200 // The Submounts menu has been removed because the AFS tray icon
201 // and control panel now support mapping drives directly to an AFS
204 // HMENU hSubmountMenu = CreatePopupMenu();
205 // int indexSubmountMenu = 0;
206 // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_SUBMOUNTS_CREATE, GetMessageString(IDS_SUBMOUNTS_CREATE_ITEM));
207 // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SUBMOUNTS_EDIT, GetMessageString(IDS_SUBMOUNTS_EDIT_ITEM));
208 // ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hSubmountMenu, GetMessageString(IDS_SUBMOUNTS_ITEM));
211 ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
213 // Add the AFS submenu to the shell's menu
214 ::InsertMenu(hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hAfsMenu, GetMessageString(IDS_AFS_ITEM));
216 // Add a separator after us
217 ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
219 return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL,
220 (USHORT)indexAfsMenu + indexVolPartMenu + indexMountPointMenu + indexShellMenu));
223 STDMETHODIMP CShellExt::XMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
225 METHOD_PROLOGUE(CShellExt, MenuExt);
227 if (HIWORD(lpici->lpVerb ))
232 CStringArray &files = pThis->m_astrFileNames;
234 switch (LOWORD(lpici->lpVerb))
236 case IDM_AUTHENTICATION: {
244 ASSERT(files.GetSize() == 1);
245 dlg.SetDir(files[0]);
250 case IDM_VOLUME_PROPERTIES: {
257 case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE: CheckVolumes();
260 case IDM_MOUNTPOINT_SHOW: ListMount(files);
263 case IDM_MOUNTPOINT_REMOVE: {
264 int nChoice = ShowMessageBox(IDS_REALLY_DEL_MOUNT_POINTS, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_DEL_MOUNT_POINTS);
265 if (nChoice == IDYES)
270 case IDM_MOUNTPOINT_MAKE: {
271 CMakeMountPointDlg dlg;
272 ASSERT(files.GetSize() == 1);
273 dlg.SetDir(files[0]);
279 case IDM_FLUSH: Flush(files);
282 case IDM_FLUSH_VOLUME: FlushVolume(files);
285 case IDM_SHOW_SERVER: WhereIs(files);
288 case IDM_SHOWCELL: WhichCell(files);
291 case IDM_SERVER_STATUS: {
292 CServerStatusDlg dlg;
297 case IDM_SUBMOUNTS_EDIT: {
303 case IDM_SUBMOUNTS_CREATE: {
304 ASSERT(files.GetSize() == 1);
306 dlg.SetAddOnlyMode(files[0]);
322 STDMETHODIMP CShellExt::XMenuExt::GetCommandString(UINT idCmd, UINT uType,
323 UINT* pwReserved, LPSTR pszName, UINT cchMax)
325 if (uType != GCS_HELPTEXT)
326 return NOERROR; // ?????????????????????????????????????????????????
330 AfxSetResourceHandle(theApp.m_hInstance);
334 case IDM_AUTHENTICATION: nCmdStrID = ID_AUTHENTICATE;
337 case IDM_ACL_SET: nCmdStrID = ID_ACL_SET;
340 case IDM_VOLUME_PROPERTIES: nCmdStrID = ID_VOLUME_PROPERTIES;
343 case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE: nCmdStrID = ID_VOLUMEPARTITION_UPDATENAMEIDTABLE;
346 case IDM_MOUNTPOINT_SHOW: nCmdStrID = ID_MOUNTPOINT_SHOW;
349 case IDM_MOUNTPOINT_REMOVE: nCmdStrID = ID_MOUNTPOINT_REMOVE;
352 case IDM_MOUNTPOINT_MAKE: nCmdStrID = ID_MOUNTPOINT_MAKE;
355 case IDM_FLUSH: nCmdStrID = ID_FLUSH;
358 case IDM_FLUSH_VOLUME: nCmdStrID = ID_VOLUME_FLUSH;
361 case IDM_SHOW_SERVER: nCmdStrID = ID_WHEREIS;
364 case IDM_SHOWCELL: nCmdStrID = ID_SHOWCELL;
367 case IDM_SERVER_STATUS: nCmdStrID = ID_SERVER_STATUS;
370 case IDM_SUBMOUNTS_CREATE: nCmdStrID = ID_SUBMOUNTS_CREATE;
373 case IDM_SUBMOUNTS_EDIT: nCmdStrID = ID_SUBMOUNTS_EDIT;
383 LoadString (strMsg, nCmdStrID);
385 strncpy(pszName, strMsg, cchMax);
390 /////////////////////////////////////////////////////////////////////////////
391 // IUnknown for IShellExtInit
392 /////////////////////////////////////////////////////////////////////////////
393 STDMETHODIMP CShellExt::XShellInit::QueryInterface(REFIID riid, void** ppv)
395 METHOD_PROLOGUE(CShellExt, ShellInit);
397 return pThis->ExternalQueryInterface(&riid, ppv);
400 STDMETHODIMP_(ULONG) CShellExt::XShellInit::AddRef(void)
402 return ++nSERefCount;
405 STDMETHODIMP_(ULONG) CShellExt::XShellInit::Release(void)
413 /////////////////////////////////////////////////////////////////////////////
414 // IShellInit Functions
415 /////////////////////////////////////////////////////////////////////////////
416 STDMETHODIMP CShellExt::XShellInit::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
418 METHOD_PROLOGUE(CShellExt, ShellInit);
420 HRESULT hres = E_FAIL;
421 FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
424 // We must have a data object
428 // Use the given IDataObject to get a list of filenames (CF_HDROP)
429 hres = pdobj->GetData(&fmte, &medium);
433 int nNumFiles = DragQueryFile((HDROP)medium.hGlobal, 0xFFFFFFFF, NULL, 0);
437 pThis->m_bDirSelected = FALSE;
439 for (int ii = 0; ii < nNumFiles; ii++) {
442 // Get the size of the file name string
443 int nNameLen = DragQueryFile((HDROP)medium.hGlobal, ii, 0, 0);
445 // Make room for it in our string object
446 LPTSTR pszFileNameBuf = strFileName.GetBuffer(nNameLen + 1); // +1 for the terminating NULL
447 ASSERT(pszFileNameBuf);
450 DragQueryFile((HDROP)medium.hGlobal, ii, pszFileNameBuf, nNameLen + 1);
452 strFileName.ReleaseBuffer();
454 if (!IsPathInAfs(strFileName)) {
455 pThis->m_astrFileNames.RemoveAll();
459 if (IsADir(strFileName))
460 pThis->m_bDirSelected = TRUE;
462 pThis->m_astrFileNames.Add(strFileName);
465 if (pThis->m_astrFileNames.GetSize() > 0)
472 ReleaseStgMedium(&medium);