windows-shell-ext-remove-mtpt-20050420
[openafs.git] / src / WINNT / client_exp / shell_ext.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include <afxpriv.h>
16 #include "stdafx.h"
17 #include <atlconv.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include "afs_shl_ext.h"
21 #include "shell_ext.h"
22 #include "volume_info.h"
23 #include "set_afs_acl.h"
24 #include "gui2fs.h"
25 #include "make_mount_point_dlg.h"
26 #include "msgs.h"
27 #include "server_status_dlg.h"
28 #include "auth_dlg.h"
29 #include "submounts_dlg.h"
30 #include "make_symbolic_link_dlg.h"
31 #include <WINNT\afsreg.h>
32
33 #ifdef _DEBUG
34 #define new DEBUG_NEW
35 #undef THIS_FILE
36 static char THIS_FILE[] = __FILE__;
37 #endif
38
39
40 ULONG nCMRefCount = 0;  // IContextMenu ref count
41 ULONG nSERefCount = 0;  // IShellExtInit ref count
42 ULONG nICRefCount=0;
43 ULONG nTPRefCount=0;
44 ULONG nXPRefCount=0;
45
46 #define MAXSIZE 2048 /* most I'll get back from PIOCTL */
47 #define PCCHAR(str)     ((char *)(const char *)str)
48 static char space[MAXSIZE];
49
50 static BOOL IsADir(const CString& strName)
51 {
52         struct _stat statbuf;
53
54         if (_stat(strName, &statbuf) < 0)
55                 return FALSE;
56
57         return statbuf.st_mode & _S_IFDIR;
58 }
59
60 /////////////////////////////////////////////////////////////////////////////
61 // CShellExt
62
63 IMPLEMENT_DYNCREATE(CShellExt, CCmdTarget)
64 #define REG_CLIENT_PARMS_KEY    "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"
65 #define OVERLAYENABLED 1
66
67 CShellExt::CShellExt()
68 {
69         HKEY NPKey;
70         EnableAutomation();
71         nCMRefCount++;
72         HRESULT hr;
73         UINT code;
74         DWORD ShellOption,LSPsize,LSPtype;
75         hr = SHGetMalloc(&m_pAlloc);
76         m_bIsOverlayEnabled=FALSE;
77         if (FAILED(hr))
78                 m_pAlloc = NULL;
79         RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,0, KEY_QUERY_VALUE, &NPKey);
80         LSPsize=sizeof(ShellOption);
81         code=RegQueryValueEx(NPKey, "ShellOption", NULL,
82                              &LSPtype, (LPBYTE)&ShellOption, &LSPsize);
83         RegCloseKey (NPKey);
84         m_bIsOverlayEnabled=((code==0) && (LSPtype==REG_DWORD) && ((ShellOption & OVERLAYENABLED)!=0));
85         TRACE("Create CShellExt, Ref count %d/n",nCMRefCount);
86 }
87
88 CShellExt::~CShellExt()
89 {
90         if(m_pAlloc) m_pAlloc->Release();
91         nCMRefCount--;
92         TRACE("Destroy CShellExt, Ref count %d/n",nCMRefCount);
93 }
94
95
96 void CShellExt::OnFinalRelease()
97 {
98         // When the last reference for an automation object is released
99         // OnFinalRelease is called.  The base class will automatically
100         // deletes the object.  Add additional cleanup required for your
101         // object before calling the base class.
102
103         CCmdTarget::OnFinalRelease();
104 }
105
106
107 BEGIN_MESSAGE_MAP(CShellExt, CCmdTarget)
108         //{{AFX_MSG_MAP(CShellExt)
109                 // NOTE - the ClassWizard will add and remove mapping macros here.
110         //}}AFX_MSG_MAP
111 END_MESSAGE_MAP()
112
113 BEGIN_DISPATCH_MAP(CShellExt, CCmdTarget)
114         //{{AFX_DISPATCH_MAP(CShellExt)
115                 // NOTE - the ClassWizard will add and remove mapping macros here.
116         //}}AFX_DISPATCH_MAP
117 END_DISPATCH_MAP()
118
119 // Note: we add support for IID_IShellExt to support typesafe binding
120 //  from VBA.  This IID must match the GUID that is attached to the 
121 //  dispinterface in the .ODL file.
122
123 // {DC515C27-6CAC-11D1-BAE7-00C04FD140D2}
124 static const IID IID_IShellExt =
125 { 0xdc515c27, 0x6cac, 0x11d1, { 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2 } };
126
127 BEGIN_INTERFACE_MAP(CShellExt, CCmdTarget)
128         INTERFACE_PART(CShellExt, IID_IShellExt, Dispatch)
129     INTERFACE_PART(CShellExt, IID_IContextMenu, MenuExt)
130     INTERFACE_PART(CShellExt, IID_IShellExtInit, ShellInit)
131         INTERFACE_PART(CShellExt, IID_IShellIconOverlayIdentifier, IconExt)
132         INTERFACE_PART(CShellExt, IID_IQueryInfo , ToolTipExt)
133         INTERFACE_PART(CShellExt, IID_IPersistFile , PersistFileExt)
134 END_INTERFACE_MAP()
135
136 IMPLEMENT_OLECREATE(CShellExt, STR_EXT_TITLE, 0xdc515c27, 0x6cac, 0x11d1, 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2)
137
138
139 /////////////////////////////////////////////////////////////////////////////
140 // CShellExt message handlers
141 /////////////////////////////////////////////////////////////////////////////
142
143
144 /////////////////////////////////////////////////////////////////////////////
145 // IUnknown for IContextMenu
146 /////////////////////////////////////////////////////////////////////////////
147 STDMETHODIMP CShellExt::XMenuExt::QueryInterface(REFIID riid, void** ppv)
148 {
149     METHOD_PROLOGUE(CShellExt, MenuExt);
150
151     return pThis->ExternalQueryInterface(&riid, ppv);
152 }
153
154 STDMETHODIMP_(ULONG) CShellExt::XMenuExt::AddRef(void)
155 {
156         return ++nCMRefCount;
157 }
158
159 STDMETHODIMP_(ULONG) CShellExt::XMenuExt::Release(void)
160 {
161         if (nCMRefCount > 0)
162                 nCMRefCount--;
163
164         return nCMRefCount;
165 }
166
167 /////////////////////////////////////////////////////////////////////////////
168 // IConextMenu Functions
169 /////////////////////////////////////////////////////////////////////////////
170 STDMETHODIMP CShellExt::XMenuExt::QueryContextMenu(HMENU hMenu,UINT indexMenu,
171     UINT idCmdFirst, UINT idCmdLast,UINT uFlags)
172 {
173     METHOD_PROLOGUE(CShellExt, MenuExt);
174
175         // Don't add any menu items if we're being asked to deal with this file as a shortcut.
176         if (uFlags & CMF_VERBSONLY)
177                 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)0);
178
179         // Check to see if there's already an AFS menu here; if so, remove it
180         int nItemsNow = GetMenuItemCount (hMenu);
181         CString strAfsItemText = GetMessageString(IDS_AFS_ITEM);
182         LPCTSTR pszAfsItemText = (LPCTSTR)strAfsItemText;
183         for (int iItem = 0; iItem < nItemsNow; iItem++) {
184                 TCHAR szItemText[256];
185                 if (!GetMenuString (hMenu, iItem, szItemText, 256, MF_BYPOSITION))
186                         continue;
187                 if (!lstrcmp (szItemText, pszAfsItemText)) {
188                         DeleteMenu (hMenu, iItem, MF_BYPOSITION);
189                         continue;
190                 }
191                 if ((!lstrcmp(szItemText,"&Delete"))&&(pThis->m_bIsSymlink)) {  /*this is a symlink - don't present a delete menu!*/
192                         DeleteMenu (hMenu, iItem, MF_BYPOSITION);
193                         continue;
194                 }
195                 if ((!lstrcmp(szItemText,"Cu&t"))&&(pThis->m_bIsSymlink)) {             /*same for cut*/
196                         DeleteMenu (hMenu, iItem, MF_BYPOSITION);
197                         continue;
198                 }
199         }
200         int indexShellMenu = 0;
201
202         // Create the AFS submenu using the allowed ID's.
203         HMENU hAfsMenu = CreatePopupMenu();
204         int indexAfsMenu = 0;
205
206         // The Authentication item has been removed from the AFS menu because
207         // there is now a tray icon to handle authentication.
208         //
209         //::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_AUTHENTICATION, GetMessageString(IDS_AUTHENTICATION_ITEM));
210         
211         // Only enable the ACL menu item if a single directory is selected
212         int nSingleDirOnly = MF_GRAYED;
213         if (pThis->m_bDirSelected && (pThis->m_astrFileNames.GetSize() == 1))
214                 nSingleDirOnly = MF_ENABLED;
215         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_ACL_SET, GetMessageString(IDS_ACLS_ITEM));
216         
217         // Volume/Partition submenu of the AFS submenu
218         HMENU hVolPartMenu = CreatePopupMenu();
219         int indexVolPartMenu = 0;
220         ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUME_PROPERTIES, GetMessageString(IDS_VOL_PART_PROPS_ITEM));
221         ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE, GetMessageString(IDS_VOL_PART_REFRESH_ITEM));
222         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hVolPartMenu, GetMessageString(IDS_VOL_PART_ITEM));
223
224         // Mount Point submenu of the AFS submenu
225         HMENU hMountPointMenu = CreatePopupMenu();
226         int indexMountPointMenu = 0;
227         int nMountPointSelected = MF_GRAYED;
228         for (int n = pThis->m_astrFileNames.GetSize() - 1 ; n >= 0; n--) {
229             if ( IsMountPoint(pThis->m_astrFileNames[n]) ) {
230                 nMountPointSelected = MF_ENABLED;
231                 break;
232             }
233         }
234         ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_SHOW, GetMessageString(IDS_MP_SHOW_ITEM));
235         ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION | nMountPointSelected, idCmdFirst + IDM_MOUNTPOINT_REMOVE, GetMessageString(IDS_MP_REMOVE_ITEM));
236         ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_MAKE, GetMessageString(IDS_MP_MAKE_ITEM));
237         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hMountPointMenu, GetMessageString(IDS_MOUNT_POINT_ITEM));
238
239         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH, GetMessageString(IDS_FLUSH_FILE_DIR_ITEM));   
240         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH_VOLUME, GetMessageString(IDS_FLUSH_VOLUME_ITEM));
241         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOW_SERVER, GetMessageString(IDS_SHOW_FILE_SERVERS_ITEM));
242         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOWCELL, GetMessageString(IDS_SHOW_CELL_ITEM));
243         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SERVER_STATUS, GetMessageString(IDS_SHOW_SERVER_STATUS_ITEM));
244
245     HMENU hSymbolicMenu = CreatePopupMenu();
246         int indexSymbolicMenu = 0;
247     ::InsertMenu(hSymbolicMenu, indexSymbolicMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SYMBOLICLINK_ADD, GetMessageString(IDS_SYMBOLICLINK_ADD));
248     // ::InsertMenu(hSymbolicMenu, indexSymbolicMenu, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SYMBOLICLINK_EDIT, GetMessageString(IDS_SYMBOLICLINK_EDIT));
249         // ::EnableMenuItem(hSymbolicMenu,indexSymbolicMenu++,((pThis->m_bIsSymlink)?MF_ENABLED:MF_GRAYED)|MF_BYPOSITION);
250         ::InsertMenu(hSymbolicMenu, indexSymbolicMenu, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SYMBOLICLINK_REMOVE, GetMessageString(IDS_SYMBOLICLINK_REMOVE));
251         ::EnableMenuItem(hSymbolicMenu,indexSymbolicMenu++,((pThis->m_bIsSymlink)?MF_ENABLED:MF_GRAYED)|MF_BYPOSITION);
252         ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hSymbolicMenu, GetMessageString(IDS_SYMBOLIC_LINK_ITEM));
253         
254         // The Submounts menu has been removed because the AFS tray icon
255         // and control panel now support mapping drives directly to an AFS
256         // path.
257         //
258         // HMENU hSubmountMenu = CreatePopupMenu();
259         // int indexSubmountMenu = 0;
260         // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_SUBMOUNTS_CREATE, GetMessageString(IDS_SUBMOUNTS_CREATE_ITEM));
261         // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SUBMOUNTS_EDIT, GetMessageString(IDS_SUBMOUNTS_EDIT_ITEM));
262         // ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hSubmountMenu, GetMessageString(IDS_SUBMOUNTS_ITEM));
263
264         // Add a separator
265         ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
266
267         // Add the AFS submenu to the shell's menu
268         ::InsertMenu(hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hAfsMenu, GetMessageString(IDS_AFS_ITEM));
269
270         // Add a separator after us
271         ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
272         
273     return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 
274                         (USHORT)indexAfsMenu + indexVolPartMenu + indexMountPointMenu + indexShellMenu + indexSymbolicMenu);
275 }
276
277 STDMETHODIMP CShellExt::XMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
278 {
279     METHOD_PROLOGUE(CShellExt, MenuExt);
280
281     if (HIWORD(lpici->lpVerb ))
282         return E_FAIL;
283
284         AddRef();
285
286         CStringArray &files = pThis->m_astrFileNames;
287
288         switch (LOWORD(lpici->lpVerb))
289         {
290                 case IDM_AUTHENTICATION:        {
291                                                                                 CAuthDlg dlg;
292                                                                                 dlg.DoModal();
293                                                                                 break;
294                                                                         }
295                 
296                 case IDM_ACL_SET:                       { 
297                                                                                 CSetAfsAcl dlg;
298                                                                                 ASSERT(files.GetSize() == 1);
299                                                                                 dlg.SetDir(files[0]);
300                                                                                 dlg.DoModal();
301                                                                         }
302                                                                         break;
303                 
304                 case IDM_VOLUME_PROPERTIES:     {
305                                                                                 CVolumeInfo dlg;
306                                                                                 dlg.SetFiles(files);
307                                                                                 dlg.DoModal();
308                                                                         }
309                                                                         break;
310
311                 case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE:     CheckVolumes();
312                                                                                                         break;
313
314                 case IDM_MOUNTPOINT_SHOW:       ListMount(files);
315                                                                         break;
316
317                 case IDM_MOUNTPOINT_REMOVE:     {
318                                                                                 int nChoice = ShowMessageBox(IDS_REALLY_DEL_MOUNT_POINTS, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_DEL_MOUNT_POINTS);
319                                                                                 if (nChoice == IDYES)
320                                                                                         RemoveMount(files);
321                                                                         }
322                                                                         break;
323                 
324                 case IDM_MOUNTPOINT_MAKE:       {
325                                                                                 CMakeMountPointDlg dlg;
326                                                                                 ASSERT(files.GetSize() == 1);
327                                                                                 dlg.SetDir(files[0]);
328                                                                                 dlg.DoModal();
329                                                                         }
330                                                                         break;
331
332
333                 case IDM_FLUSH:                         Flush(files);
334                                                                         break;
335                 
336                 case IDM_FLUSH_VOLUME:          FlushVolume(files);
337                                                                         break;
338
339                 case IDM_SHOW_SERVER:           WhereIs(files);
340                                                                         break;
341                 
342                 case IDM_SHOWCELL:                      WhichCell(files);
343                                                                         break;
344
345                 case IDM_SERVER_STATUS:         {
346                                                                                 CServerStatusDlg dlg;
347                                                                                 dlg.DoModal();
348                                                                         }
349                                                                         break;
350
351         /*
352                 case IDM_SUBMOUNTS_EDIT:        {
353                                                                                 CSubmountsDlg dlg;
354                                                                                 dlg.DoModal();
355                                                                         }
356                                                                         break;
357
358                 case IDM_SUBMOUNTS_CREATE:      {
359                                                                                 ASSERT(files.GetSize() == 1);
360                                                                                 CSubmountsDlg dlg;
361                                                                                 dlg.SetAddOnlyMode(files[0]);
362                                                                                 dlg.DoModal();
363                                                                         }
364                                                                         break;
365         */
366         case IDM_SYMBOLICLINK_REMOVE: {
367                 if (files.GetSize()>1)
368                         break;
369                 CString msg=files.GetAt(0);
370                 int i;
371                 if ((i=msg.ReverseFind('\\'))>0)
372                         msg=msg.Left(i+1);
373                 else if ((i=msg.ReverseFind(':'))>0)
374                         msg=msg.Left(i+1)+"\\";
375                 if (!SetCurrentDirectory(msg))
376                 {
377                         MessageBeep((UINT)-1);
378                         ShowMessageBox(IDS_UNABLE_TO_SET_CURRENT_DIRECTORY,MB_OK,IDS_UNABLE_TO_SET_CURRENT_DIRECTORY);
379                         break;
380                 }
381                 msg=files.GetAt(0);
382                 if ((i=msg.ReverseFind('\\'))>0||((i=msg.ReverseFind(':'))>0))
383                         msg=msg.Right(msg.GetLength()-i-1);
384                 int nChoice = ShowMessageBox(IDS_REALLY_REMOVE_SYMLINK, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_REMOVE_SYMLINK,msg);
385                 if (nChoice == IDYES)
386                         RemoveSymlink(files.GetAt(0));
387         }
388                 break;
389
390         case IDM_SYMBOLICLINK_ADD: {
391                 CString msg=files.GetAt(0);
392                 int i;
393                 if ((i=msg.ReverseFind('\\'))>0)
394                         msg=msg.Left(i+1);
395                 else if ((i=msg.ReverseFind(':'))>0)
396                         msg=msg.Left(i+1)+"\\";
397                 CMakeSymbolicLinkDlg dlg;
398                 dlg.Setbase(msg);
399                 dlg.DoModal();
400         }
401                 break;
402                 
403         case IDM_REMOVE_SYMLINK:        {
404                 if (files.GetSize()>1)
405                         break;
406                 int nChoice = ShowMessageBox(IDS_REALLY_REMOVE_SYMLINK, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_REMOVE_SYMLINK);
407                 if (nChoice == IDYES)
408                         RemoveSymlink(files.GetAt(0));
409         }
410                 break;
411         default:
412                 ASSERT(FALSE);
413                 Release();
414                 return E_INVALIDARG;
415         }
416
417         Release();
418
419     return NOERROR;
420 }
421
422 STDMETHODIMP CShellExt::XMenuExt::GetCommandString(UINT idCmd, UINT uType,
423     UINT* pwReserved, LPSTR pszName, UINT cchMax)
424 {
425         if (uType != GCS_HELPTEXT)
426                 return NOERROR;                 // ?????????????????????????????????????????????????
427
428         UINT nCmdStrID;
429
430     AfxSetResourceHandle(theApp.m_hInstance);
431
432     switch (idCmd)
433         {
434                 case IDM_AUTHENTICATION:        nCmdStrID = ID_AUTHENTICATE;
435                                                                         break;
436                 
437                 case IDM_ACL_SET:                       nCmdStrID = ID_ACL_SET;
438                                                                         break;
439                 
440                 case IDM_VOLUME_PROPERTIES:     nCmdStrID = ID_VOLUME_PROPERTIES;
441                                                                         break;
442
443                 case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE:     nCmdStrID = ID_VOLUMEPARTITION_UPDATENAMEIDTABLE;
444                                                                                                         break;
445
446                 case IDM_MOUNTPOINT_SHOW:       nCmdStrID = ID_MOUNTPOINT_SHOW;
447                                                                         break;
448
449                 case IDM_MOUNTPOINT_REMOVE:     nCmdStrID = ID_MOUNTPOINT_REMOVE;
450                                                                         break;
451                 
452                 case IDM_MOUNTPOINT_MAKE:       nCmdStrID = ID_MOUNTPOINT_MAKE;
453                                                                         break;
454
455                 case IDM_FLUSH:                         nCmdStrID = ID_FLUSH;
456                                                                         break;
457                 
458                 case IDM_FLUSH_VOLUME:          nCmdStrID = ID_VOLUME_FLUSH;
459                                                                         break;
460
461                 case IDM_SHOW_SERVER:           nCmdStrID = ID_WHEREIS;
462                                                                         break;
463                 
464                 case IDM_SHOWCELL:                      nCmdStrID = ID_SHOWCELL;
465                                                                         break;
466
467                 case IDM_SERVER_STATUS:         nCmdStrID = ID_SERVER_STATUS;
468                                                                         break;
469
470                 case IDM_SYMBOLICLINK_ADD:      nCmdStrID = ID_SYMBOLICLINK_ADD;
471                                                                         break;
472                 
473                 case IDM_SYMBOLICLINK_REMOVE:   nCmdStrID = ID_SYMBOLICLINK_REMOVE;
474                                                                         break;
475
476                 case IDM_REMOVE_SYMLINK:        nCmdStrID= ID_REMOVE_SYMLINK;
477                                                                         break;
478                 
479                 default:
480                         ASSERT(FALSE);
481                         Release();
482                     return E_INVALIDARG;
483         }
484
485     CString strMsg;
486     LoadString (strMsg, nCmdStrID);
487
488     strncpy(pszName, strMsg, cchMax);
489
490     return NOERROR;
491 }
492
493 /////////////////////////////////////////////////////////////////////////////
494 // IUnknown for IShellExtInit
495 /////////////////////////////////////////////////////////////////////////////
496 STDMETHODIMP CShellExt::XShellInit::QueryInterface(REFIID riid, void** ppv)
497 {
498     METHOD_PROLOGUE(CShellExt, ShellInit);
499
500     return pThis->ExternalQueryInterface(&riid, ppv);
501 }
502
503 STDMETHODIMP_(ULONG) CShellExt::XShellInit::AddRef(void)
504 {
505         return ++nSERefCount;
506 }
507
508 STDMETHODIMP_(ULONG) CShellExt::XShellInit::Release(void)
509 {
510         if (nSERefCount > 0)
511                 nSERefCount--;
512         
513         return nSERefCount;
514 }
515
516 /////////////////////////////////////////////////////////////////////////////
517 // IShellInit Functions
518 /////////////////////////////////////////////////////////////////////////////
519 STDMETHODIMP CShellExt::XShellInit::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
520 {
521     METHOD_PROLOGUE(CShellExt, ShellInit);
522
523     HRESULT hres = E_FAIL;
524     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
525     STGMEDIUM medium;
526
527         // We must have a data object
528     if (pdobj == NULL)
529             return E_FAIL;
530
531     //  Use the given IDataObject to get a list of filenames (CF_HDROP)
532     hres = pdobj->GetData(&fmte, &medium);
533     if (FAILED(hres)) {
534             return E_FAIL;
535     }
536
537     int nNumFiles = DragQueryFile((HDROP)medium.hGlobal, 0xFFFFFFFF, NULL, 0);
538         if (nNumFiles == 0)
539                 hres = E_FAIL;
540         else {
541                 pThis->m_bDirSelected = FALSE;
542
543                 for (int ii = 0; ii < nNumFiles; ii++) {
544                         CString strFileName;
545
546                         // Get the size of the file name string
547                         int nNameLen = DragQueryFile((HDROP)medium.hGlobal, ii, 0, 0);
548
549                         // Make room for it in our string object
550                         LPTSTR pszFileNameBuf = strFileName.GetBuffer(nNameLen + 1);    // +1 for the terminating NULL
551                         ASSERT(pszFileNameBuf);
552                         
553                         // Get the file name
554                         DragQueryFile((HDROP)medium.hGlobal, ii, pszFileNameBuf, nNameLen + 1);
555                         
556                         strFileName.ReleaseBuffer();
557
558                         if (!IsPathInAfs(strFileName)) {
559                                 pThis->m_astrFileNames.RemoveAll();
560                                 break;
561                         } else {
562                                 pThis->m_bIsSymlink=IsSymlink(strFileName);
563                         }
564
565                         if (IsADir(strFileName))
566                                 pThis->m_bDirSelected = TRUE;
567
568                         pThis->m_astrFileNames.Add(strFileName);
569                 }
570
571                 if (pThis->m_astrFileNames.GetSize() > 0)
572                         hres = NOERROR;
573                 else
574                         hres = E_FAIL;
575     }
576  
577     //  Release the data
578     ReleaseStgMedium(&medium);
579
580     return hres;
581 }
582
583 STDMETHODIMP CShellExt::XIconExt::QueryInterface(REFIID riid, void** ppv)
584 {
585     METHOD_PROLOGUE(CShellExt, IconExt);
586     return pThis->ExternalQueryInterface(&riid, ppv);
587 }
588
589 STDMETHODIMP_(ULONG) CShellExt::XIconExt::AddRef(void)
590 {
591         return ++nICRefCount;
592 }
593
594 STDMETHODIMP_(ULONG) CShellExt::XIconExt::Release(void)
595 {
596         if (nICRefCount > 0)
597                 nICRefCount--;
598
599         return nICRefCount;
600 }
601
602
603 /////////////////////////////////////////////////////////////////////////////
604 // IIconHandler Functions
605 /////////////////////////////////////////////////////////////////////////////
606
607 STDMETHODIMP CShellExt::XIconExt::GetOverlayInfo(LPWSTR pwszIconFile
608         ,int cchMax,int* pIndex,DWORD* pdwFlags)
609 {
610         if(IsBadWritePtr(pIndex, sizeof(int)))
611                 return E_INVALIDARG;
612         if(IsBadWritePtr(pdwFlags, sizeof(DWORD)))
613                 return E_INVALIDARG;
614
615         HMODULE hModule=GetModuleHandle("shell32.dll");
616         TCHAR szModule[MAX_PATH];
617         DWORD z=GetModuleFileName(hModule,szModule,sizeof(szModule));
618         MultiByteToWideChar( CP_ACP,0,szModule,-1,pwszIconFile,cchMax); 
619         *pIndex = 30;
620         *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
621         return S_OK;
622 }
623
624 STDMETHODIMP CShellExt::XIconExt::GetPriority(int* pPriority)
625 {
626         if(IsBadWritePtr(pPriority, sizeof(int)))
627            return E_INVALIDARG;
628         *pPriority = 0;
629         return S_OK;
630 }
631
632 STDMETHODIMP CShellExt::XIconExt::IsMemberOf(LPCWSTR pwszPath,DWORD dwAttrib)
633 {
634         TCHAR szPath[MAX_PATH];
635         WideCharToMultiByte( CP_ACP,0,pwszPath,-1,szPath,MAX_PATH,NULL,NULL);
636         if (IsSymlink(szPath))
637                 return S_OK;
638         return S_FALSE;
639 }
640
641 /*          TOOL TIP INFO IMPLIMENTION   */
642
643 STDMETHODIMP CShellExt::XToolTipExt::QueryInterface(REFIID riid, void** ppv)
644 {
645     METHOD_PROLOGUE(CShellExt, ToolTipExt);
646     return pThis->ExternalQueryInterface(&riid, ppv);
647 }
648
649 STDMETHODIMP_(ULONG) CShellExt::XToolTipExt::AddRef(void)
650 {
651         return ++nTPRefCount;
652 }
653
654 STDMETHODIMP_(ULONG) CShellExt::XToolTipExt::Release(void)
655 {
656         if (nTPRefCount> 0)
657                 nTPRefCount--;
658
659         return nTPRefCount;
660 }
661
662 STDMETHODIMP CShellExt::XToolTipExt::GetInfoTip(DWORD dwFlags, LPWSTR *ppwszTip)
663 {
664     METHOD_PROLOGUE(CShellExt, ToolTipExt);
665
666         if (!IsSymlink(pThis->m_szFile))
667         {
668                 ppwszTip=NULL;
669                 return S_OK;
670         }
671         USES_CONVERSION;
672         // dwFlags is currently unused.
673         *ppwszTip = (WCHAR*) (pThis->m_pAlloc)->Alloc((1+lstrlen(pThis->m_szFile))*sizeof(WCHAR));
674         if (*ppwszTip)
675         {
676                 wcscpy(*ppwszTip, (WCHAR*)T2OLE(pThis->m_szFile));
677         }
678
679         return S_OK;
680 }
681 STDMETHODIMP CShellExt::XToolTipExt::GetInfoFlags(LPDWORD pdwFlags)
682 {
683         return S_OK;
684 }
685
686 //////////                          IPersistFile
687 ///////                            PersistFileExt
688
689 STDMETHODIMP CShellExt::XPersistFileExt::QueryInterface(REFIID riid, void** ppv)
690 {
691     METHOD_PROLOGUE(CShellExt, PersistFileExt);
692     return pThis->ExternalQueryInterface(&riid, ppv);
693 }
694
695 STDMETHODIMP_(ULONG) CShellExt::XPersistFileExt::AddRef(void)
696 {
697         return ++nXPRefCount;
698 }
699
700 STDMETHODIMP_(ULONG) CShellExt::XPersistFileExt::Release(void)
701 {
702         if (nXPRefCount> 0)
703                 nXPRefCount--;
704
705         return nXPRefCount;
706 }
707
708 STDMETHODIMP    CShellExt::XPersistFileExt::Load(LPCOLESTR wszFile, DWORD dwMode)
709 {
710     METHOD_PROLOGUE(CShellExt, PersistFileExt);
711         USES_CONVERSION;
712         _tcscpy(pThis->m_szFile, OLE2T((WCHAR*)wszFile)); 
713         return S_OK;    
714 }
715
716 STDMETHODIMP CShellExt::XPersistFileExt::GetClassID(LPCLSID)
717
718         return E_NOTIMPL;       
719 }
720
721 STDMETHODIMP CShellExt::XPersistFileExt::IsDirty(VOID)
722
723         return E_NOTIMPL; 
724 }
725
726 STDMETHODIMP CShellExt::XPersistFileExt::Save(LPCOLESTR, BOOL)
727
728         return E_NOTIMPL; 
729 }
730
731 STDMETHODIMP CShellExt::XPersistFileExt::SaveCompleted(LPCOLESTR)
732
733         return E_NOTIMPL; 
734 }
735
736 STDMETHODIMP CShellExt::XPersistFileExt::GetCurFile(LPOLESTR FAR*)
737
738         return E_NOTIMPL; 
739 }