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