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