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