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