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