/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ extern "C" { #include #include } #include #include "stdafx.h" #include #include #include #include "afs_shl_ext.h" #include "shell_ext.h" #include "volume_info.h" #include "set_afs_acl.h" #include "gui2fs.h" #include "make_mount_point_dlg.h" #include "msgs.h" #include "server_status_dlg.h" #include "auth_dlg.h" #include "submounts_dlg.h" #include "make_symbolic_link_dlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ULONG nCMRefCount = 0; // IContextMenu ref count ULONG nSERefCount = 0; // IShellExtInit ref count ULONG nICRefCount=0; ULONG nTPRefCount=0; ULONG nXPRefCount=0; #define MAXSIZE 2048 /* most I'll get back from PIOCTL */ #define PCCHAR(str) ((char *)(const char *)str) static char space[MAXSIZE]; static BOOL IsADir(const CString& strName) { struct _stat statbuf; if (_stat(strName, &statbuf) < 0) return FALSE; return statbuf.st_mode & _S_IFDIR; } ///////////////////////////////////////////////////////////////////////////// // CShellExt IMPLEMENT_DYNCREATE(CShellExt, CCmdTarget) #define REG_CLIENT_PARMS_KEY "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters" #define OVERLAYENABLED 1 CShellExt::CShellExt() { HKEY NPKey; EnableAutomation(); nCMRefCount++; HRESULT hr; UINT code; DWORD ShellOption,LSPsize,LSPtype; hr = SHGetMalloc(&m_pAlloc); m_bIsOverlayEnabled=FALSE; if (FAILED(hr)) m_pAlloc = NULL; RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,0, KEY_QUERY_VALUE, &NPKey); LSPsize=sizeof(ShellOption); code=RegQueryValueEx(NPKey, "ShellOption", NULL, &LSPtype, (LPBYTE)&ShellOption, &LSPsize); RegCloseKey (NPKey); m_bIsOverlayEnabled=((code==0) && (LSPtype==REG_DWORD) && ((ShellOption & OVERLAYENABLED)!=0)); TRACE("Create CShellExt, Ref count %d/n",nCMRefCount); } CShellExt::~CShellExt() { if(m_pAlloc) m_pAlloc->Release(); nCMRefCount--; TRACE("Destroy CShellExt, Ref count %d/n",nCMRefCount); } void CShellExt::OnFinalRelease() { // When the last reference for an automation object is released // OnFinalRelease is called. The base class will automatically // deletes the object. Add additional cleanup required for your // object before calling the base class. CCmdTarget::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CShellExt, CCmdTarget) //{{AFX_MSG_MAP(CShellExt) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CShellExt, CCmdTarget) //{{AFX_DISPATCH_MAP(CShellExt) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_DISPATCH_MAP END_DISPATCH_MAP() // Note: we add support for IID_IShellExt to support typesafe binding // from VBA. This IID must match the GUID that is attached to the // dispinterface in the .ODL file. // {DC515C27-6CAC-11D1-BAE7-00C04FD140D2} static const IID IID_IShellExt = { 0xdc515c27, 0x6cac, 0x11d1, { 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2 } }; BEGIN_INTERFACE_MAP(CShellExt, CCmdTarget) INTERFACE_PART(CShellExt, IID_IShellExt, Dispatch) INTERFACE_PART(CShellExt, IID_IContextMenu, MenuExt) INTERFACE_PART(CShellExt, IID_IShellExtInit, ShellInit) INTERFACE_PART(CShellExt, IID_IShellIconOverlayIdentifier, IconExt) INTERFACE_PART(CShellExt, IID_IQueryInfo , ToolTipExt) INTERFACE_PART(CShellExt, IID_IPersistFile , PersistFileExt) END_INTERFACE_MAP() IMPLEMENT_OLECREATE(CShellExt, STR_EXT_TITLE, 0xdc515c27, 0x6cac, 0x11d1, 0xba, 0xe7, 0x0, 0xc0, 0x4f, 0xd1, 0x40, 0xd2) ///////////////////////////////////////////////////////////////////////////// // CShellExt message handlers ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // IUnknown for IContextMenu ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CShellExt::XMenuExt::QueryInterface(REFIID riid, void** ppv) { METHOD_PROLOGUE(CShellExt, MenuExt); return pThis->ExternalQueryInterface(&riid, ppv); } STDMETHODIMP_(ULONG) CShellExt::XMenuExt::AddRef(void) { return ++nCMRefCount; } STDMETHODIMP_(ULONG) CShellExt::XMenuExt::Release(void) { if (nCMRefCount > 0) nCMRefCount--; return nCMRefCount; } ///////////////////////////////////////////////////////////////////////////// // IConextMenu Functions ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CShellExt::XMenuExt::QueryContextMenu(HMENU hMenu,UINT indexMenu, UINT idCmdFirst, UINT idCmdLast,UINT uFlags) { METHOD_PROLOGUE(CShellExt, MenuExt); // Don't add any menu items if we're being asked to deal with this file as a shortcut. if (uFlags & CMF_VERBSONLY) return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)0); // Check to see if there's already an AFS menu here; if so, remove it int nItemsNow = GetMenuItemCount (hMenu); CString strAfsItemText = GetMessageString(IDS_AFS_ITEM); LPCTSTR pszAfsItemText = (LPCTSTR)strAfsItemText; for (int iItem = 0; iItem < nItemsNow; iItem++) { TCHAR szItemText[256]; if (!GetMenuString (hMenu, iItem, szItemText, 256, MF_BYPOSITION)) continue; if (!lstrcmp (szItemText, pszAfsItemText)) { DeleteMenu (hMenu, iItem, MF_BYPOSITION); continue; } if ((!lstrcmp(szItemText,"&Delete"))&&(pThis->m_bIsSymlink)) { /*this is a symlink - don't present a delete menu!*/ DeleteMenu (hMenu, iItem, MF_BYPOSITION); continue; } if ((!lstrcmp(szItemText,"Cu&t"))&&(pThis->m_bIsSymlink)) { /*same for cut*/ DeleteMenu (hMenu, iItem, MF_BYPOSITION); continue; } } int indexShellMenu = 0; // Create the AFS submenu using the allowed ID's. HMENU hAfsMenu = CreatePopupMenu(); int indexAfsMenu = 0; // The Authentication item has been removed from the AFS menu because // there is now a tray icon to handle authentication. // //::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_AUTHENTICATION, GetMessageString(IDS_AUTHENTICATION_ITEM)); // Only enable the ACL menu item if a single directory is selected int nSingleDirOnly = MF_GRAYED; if (pThis->m_bDirSelected && (pThis->m_astrFileNames.GetSize() == 1)) nSingleDirOnly = MF_ENABLED; ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_ACL_SET, GetMessageString(IDS_ACLS_ITEM)); // Volume/Partition submenu of the AFS submenu HMENU hVolPartMenu = CreatePopupMenu(); int indexVolPartMenu = 0; ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUME_PROPERTIES, GetMessageString(IDS_VOL_PART_PROPS_ITEM)); ::InsertMenu(hVolPartMenu, indexVolPartMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE, GetMessageString(IDS_VOL_PART_REFRESH_ITEM)); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hVolPartMenu, GetMessageString(IDS_VOL_PART_ITEM)); // Mount Point submenu of the AFS submenu HMENU hMountPointMenu = CreatePopupMenu(); int indexMountPointMenu = 0; ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_SHOW, GetMessageString(IDS_MP_SHOW_ITEM)); ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_REMOVE, GetMessageString(IDS_MP_REMOVE_ITEM)); ::InsertMenu(hMountPointMenu, indexMountPointMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_MOUNTPOINT_MAKE, GetMessageString(IDS_MP_MAKE_ITEM)); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hMountPointMenu, GetMessageString(IDS_MOUNT_POINT_ITEM)); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH, GetMessageString(IDS_FLUSH_FILE_DIR_ITEM)); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_FLUSH_VOLUME, GetMessageString(IDS_FLUSH_VOLUME_ITEM)); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOW_SERVER, GetMessageString(IDS_SHOW_FILE_SERVERS_ITEM)); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHOWCELL, GetMessageString(IDS_SHOW_CELL_ITEM)); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SERVER_STATUS, GetMessageString(IDS_SHOW_SERVER_STATUS_ITEM)); HMENU hSymbolicMenu = CreatePopupMenu(); int indexSymbolicMenu = 0; ::InsertMenu(hSymbolicMenu, indexSymbolicMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SYMBOLICLINK_ADD, GetMessageString(IDS_SYMBOLICLINK_ADD)); // ::InsertMenu(hSymbolicMenu, indexSymbolicMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SYMBOLICLINK_EDIT, GetMessageString(IDS_SYMBOLICLINK_EDIT)); ::InsertMenu(hSymbolicMenu, indexSymbolicMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SYMBOLICLINK_REMOVE, GetMessageString(IDS_SYMBOLICLINK_REMOVE)); ::EnableMenuItem(hSymbolicMenu,1,((pThis->m_bIsSymlink)?MF_ENABLED:MF_GRAYED)|MF_BYPOSITION); // ::EnableMenuItem(hSymbolicMenu,2,((pThis->m_bIsSymlink)?MF_ENABLED:MF_GRAYED)|MF_BYPOSITION); ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hSymbolicMenu, GetMessageString(IDS_SYMBOLIC_LINK_ITEM)); // The Submounts menu has been removed because the AFS tray icon // and control panel now support mapping drives directly to an AFS // path. // // HMENU hSubmountMenu = CreatePopupMenu(); // int indexSubmountMenu = 0; // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION | nSingleDirOnly, idCmdFirst + IDM_SUBMOUNTS_CREATE, GetMessageString(IDS_SUBMOUNTS_CREATE_ITEM)); // ::InsertMenu(hSubmountMenu, indexSubmountMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SUBMOUNTS_EDIT, GetMessageString(IDS_SUBMOUNTS_EDIT_ITEM)); // ::InsertMenu(hAfsMenu, indexAfsMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hSubmountMenu, GetMessageString(IDS_SUBMOUNTS_ITEM)); // Add a separator ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT("")); // Add the AFS submenu to the shell's menu ::InsertMenu(hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT)hAfsMenu, GetMessageString(IDS_AFS_ITEM)); // Add a separator after us ::InsertMenu (hMenu, indexMenu + indexShellMenu++, MF_STRING | MF_BYPOSITION | MF_SEPARATOR, 0, TEXT("")); return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)indexAfsMenu + indexVolPartMenu + indexMountPointMenu + indexShellMenu + indexSymbolicMenu); } STDMETHODIMP CShellExt::XMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) { METHOD_PROLOGUE(CShellExt, MenuExt); if (HIWORD(lpici->lpVerb )) return E_FAIL; AddRef(); CStringArray &files = pThis->m_astrFileNames; switch (LOWORD(lpici->lpVerb)) { case IDM_AUTHENTICATION: { CAuthDlg dlg; dlg.DoModal(); break; } case IDM_ACL_SET: { CSetAfsAcl dlg; ASSERT(files.GetSize() == 1); dlg.SetDir(files[0]); dlg.DoModal(); } break; case IDM_VOLUME_PROPERTIES: { CVolumeInfo dlg; dlg.SetFiles(files); dlg.DoModal(); } break; case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE: CheckVolumes(); break; case IDM_MOUNTPOINT_SHOW: ListMount(files); break; case IDM_MOUNTPOINT_REMOVE: { int nChoice = ShowMessageBox(IDS_REALLY_DEL_MOUNT_POINTS, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_DEL_MOUNT_POINTS); if (nChoice == IDYES) RemoveMount(files); } break; case IDM_MOUNTPOINT_MAKE: { CMakeMountPointDlg dlg; ASSERT(files.GetSize() == 1); dlg.SetDir(files[0]); dlg.DoModal(); } break; case IDM_FLUSH: Flush(files); break; case IDM_FLUSH_VOLUME: FlushVolume(files); break; case IDM_SHOW_SERVER: WhereIs(files); break; case IDM_SHOWCELL: WhichCell(files); break; case IDM_SERVER_STATUS: { CServerStatusDlg dlg; dlg.DoModal(); } break; /* case IDM_SUBMOUNTS_EDIT: { CSubmountsDlg dlg; dlg.DoModal(); } break; case IDM_SUBMOUNTS_CREATE: { ASSERT(files.GetSize() == 1); CSubmountsDlg dlg; dlg.SetAddOnlyMode(files[0]); dlg.DoModal(); } break; */ case IDM_SYMBOLICLINK_REMOVE: { if (files.GetSize()>1) break; CString msg=files.GetAt(0); int i; if ((i=msg.ReverseFind('\\'))>0) msg=msg.Left(i+1); else if ((i=msg.ReverseFind(':'))>0) msg=msg.Left(i+1)+"\\"; if (!SetCurrentDirectory(msg)) { MessageBeep((UINT)-1); ShowMessageBox(IDS_UNABLE_TO_SET_CURRENT_DIRECTORY,MB_OK,IDS_UNABLE_TO_SET_CURRENT_DIRECTORY); break; } msg=files.GetAt(0); if ((i=msg.ReverseFind('\\'))>0||((i=msg.ReverseFind(':'))>0)) msg=msg.Right(msg.GetLength()-i-1); int nChoice = ShowMessageBox(IDS_REALLY_REMOVE_SYMLINK, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_REMOVE_SYMLINK,msg); if (nChoice == IDYES) RemoveSymlink(files.GetAt(0)); } break; case IDM_SYMBOLICLINK_ADD: { CString msg=files.GetAt(0); int i; if ((i=msg.ReverseFind('\\'))>0) msg=msg.Left(i+1); else if ((i=msg.ReverseFind(':'))>0) msg=msg.Left(i+1)+"\\"; CMakeSymbolicLinkDlg dlg; dlg.Setbase(msg); dlg.DoModal(); } break; case IDM_REMOVE_SYMLINK: { if (files.GetSize()>1) break; int nChoice = ShowMessageBox(IDS_REALLY_REMOVE_SYMLINK, MB_ICONQUESTION | MB_YESNO, IDS_REALLY_REMOVE_SYMLINK); if (nChoice == IDYES) RemoveSymlink(files.GetAt(0)); } break; default: ASSERT(FALSE); Release(); return E_INVALIDARG; } Release(); return NOERROR; } STDMETHODIMP CShellExt::XMenuExt::GetCommandString(UINT idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax) { if (uType != GCS_HELPTEXT) return NOERROR; // ????????????????????????????????????????????????? UINT nCmdStrID; AfxSetResourceHandle(theApp.m_hInstance); switch (idCmd) { case IDM_AUTHENTICATION: nCmdStrID = ID_AUTHENTICATE; break; case IDM_ACL_SET: nCmdStrID = ID_ACL_SET; break; case IDM_VOLUME_PROPERTIES: nCmdStrID = ID_VOLUME_PROPERTIES; break; case IDM_VOLUMEPARTITION_UPDATENAMEIDTABLE: nCmdStrID = ID_VOLUMEPARTITION_UPDATENAMEIDTABLE; break; case IDM_MOUNTPOINT_SHOW: nCmdStrID = ID_MOUNTPOINT_SHOW; break; case IDM_MOUNTPOINT_REMOVE: nCmdStrID = ID_MOUNTPOINT_REMOVE; break; case IDM_MOUNTPOINT_MAKE: nCmdStrID = ID_MOUNTPOINT_MAKE; break; case IDM_FLUSH: nCmdStrID = ID_FLUSH; break; case IDM_FLUSH_VOLUME: nCmdStrID = ID_VOLUME_FLUSH; break; case IDM_SHOW_SERVER: nCmdStrID = ID_WHEREIS; break; case IDM_SHOWCELL: nCmdStrID = ID_SHOWCELL; break; case IDM_SERVER_STATUS: nCmdStrID = ID_SERVER_STATUS; break; case IDM_SYMBOLICLINK_ADD: nCmdStrID = ID_SYMBOLICLINK_ADD; break; case IDM_SYMBOLICLINK_REMOVE: nCmdStrID = ID_SYMBOLICLINK_REMOVE; break; case IDM_REMOVE_SYMLINK: nCmdStrID= ID_REMOVE_SYMLINK; break; default: ASSERT(FALSE); Release(); return E_INVALIDARG; } CString strMsg; LoadString (strMsg, nCmdStrID); strncpy(pszName, strMsg, cchMax); return NOERROR; } ///////////////////////////////////////////////////////////////////////////// // IUnknown for IShellExtInit ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CShellExt::XShellInit::QueryInterface(REFIID riid, void** ppv) { METHOD_PROLOGUE(CShellExt, ShellInit); return pThis->ExternalQueryInterface(&riid, ppv); } STDMETHODIMP_(ULONG) CShellExt::XShellInit::AddRef(void) { return ++nSERefCount; } STDMETHODIMP_(ULONG) CShellExt::XShellInit::Release(void) { if (nSERefCount > 0) nSERefCount--; return nSERefCount; } ///////////////////////////////////////////////////////////////////////////// // IShellInit Functions ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CShellExt::XShellInit::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID) { METHOD_PROLOGUE(CShellExt, ShellInit); HRESULT hres = E_FAIL; FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM medium; // We must have a data object if (pdobj == NULL) return E_FAIL; // Use the given IDataObject to get a list of filenames (CF_HDROP) hres = pdobj->GetData(&fmte, &medium); if (FAILED(hres)) { return E_FAIL; } int nNumFiles = DragQueryFile((HDROP)medium.hGlobal, 0xFFFFFFFF, NULL, 0); if (nNumFiles == 0) hres = E_FAIL; else { pThis->m_bDirSelected = FALSE; for (int ii = 0; ii < nNumFiles; ii++) { CString strFileName; // Get the size of the file name string int nNameLen = DragQueryFile((HDROP)medium.hGlobal, ii, 0, 0); // Make room for it in our string object LPTSTR pszFileNameBuf = strFileName.GetBuffer(nNameLen + 1); // +1 for the terminating NULL ASSERT(pszFileNameBuf); // Get the file name DragQueryFile((HDROP)medium.hGlobal, ii, pszFileNameBuf, nNameLen + 1); strFileName.ReleaseBuffer(); if (!IsPathInAfs(strFileName)) { pThis->m_astrFileNames.RemoveAll(); break; } else { pThis->m_bIsSymlink=IsSymlink(strFileName); } if (IsADir(strFileName)) pThis->m_bDirSelected = TRUE; pThis->m_astrFileNames.Add(strFileName); } if (pThis->m_astrFileNames.GetSize() > 0) hres = NOERROR; else hres = E_FAIL; } // Release the data ReleaseStgMedium(&medium); return hres; } STDMETHODIMP CShellExt::XIconExt::QueryInterface(REFIID riid, void** ppv) { METHOD_PROLOGUE(CShellExt, IconExt); return pThis->ExternalQueryInterface(&riid, ppv); } STDMETHODIMP_(ULONG) CShellExt::XIconExt::AddRef(void) { return ++nICRefCount; } STDMETHODIMP_(ULONG) CShellExt::XIconExt::Release(void) { if (nICRefCount > 0) nICRefCount--; return nICRefCount; } ///////////////////////////////////////////////////////////////////////////// // IIconHandler Functions ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CShellExt::XIconExt::GetOverlayInfo(LPWSTR pwszIconFile ,int cchMax,int* pIndex,DWORD* pdwFlags) { if(IsBadWritePtr(pIndex, sizeof(int))) return E_INVALIDARG; if(IsBadWritePtr(pdwFlags, sizeof(DWORD))) return E_INVALIDARG; HMODULE hModule=GetModuleHandle("shell32.dll"); TCHAR szModule[MAX_PATH]; DWORD z=GetModuleFileName(hModule,szModule,sizeof(szModule)); MultiByteToWideChar( CP_ACP,0,szModule,-1,pwszIconFile,cchMax); *pIndex = 30; *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX; return S_OK; } STDMETHODIMP CShellExt::XIconExt::GetPriority(int* pPriority) { if(IsBadWritePtr(pPriority, sizeof(int))) return E_INVALIDARG; *pPriority = 0; return S_OK; } STDMETHODIMP CShellExt::XIconExt::IsMemberOf(LPCWSTR pwszPath,DWORD dwAttrib) { TCHAR szPath[MAX_PATH]; WideCharToMultiByte( CP_ACP,0,pwszPath,-1,szPath,MAX_PATH,NULL,NULL); if (IsSymlink(szPath)) return S_OK; return S_FALSE; } /* TOOL TIP INFO IMPLIMENTION */ STDMETHODIMP CShellExt::XToolTipExt::QueryInterface(REFIID riid, void** ppv) { METHOD_PROLOGUE(CShellExt, ToolTipExt); return pThis->ExternalQueryInterface(&riid, ppv); } STDMETHODIMP_(ULONG) CShellExt::XToolTipExt::AddRef(void) { return ++nTPRefCount; } STDMETHODIMP_(ULONG) CShellExt::XToolTipExt::Release(void) { if (nTPRefCount> 0) nTPRefCount--; return nTPRefCount; } STDMETHODIMP CShellExt::XToolTipExt::GetInfoTip(DWORD dwFlags, LPWSTR *ppwszTip) { METHOD_PROLOGUE(CShellExt, ToolTipExt); if (!IsSymlink(pThis->m_szFile)) { ppwszTip=NULL; return S_OK; } USES_CONVERSION; // dwFlags is currently unused. *ppwszTip = (WCHAR*) (pThis->m_pAlloc)->Alloc((1+lstrlen(pThis->m_szFile))*sizeof(WCHAR)); if (*ppwszTip) { wcscpy(*ppwszTip, (WCHAR*)T2OLE(pThis->m_szFile)); } return S_OK; } STDMETHODIMP CShellExt::XToolTipExt::GetInfoFlags(LPDWORD pdwFlags) { return S_OK; } ////////// IPersistFile /////// PersistFileExt STDMETHODIMP CShellExt::XPersistFileExt::QueryInterface(REFIID riid, void** ppv) { METHOD_PROLOGUE(CShellExt, PersistFileExt); return pThis->ExternalQueryInterface(&riid, ppv); } STDMETHODIMP_(ULONG) CShellExt::XPersistFileExt::AddRef(void) { return ++nXPRefCount; } STDMETHODIMP_(ULONG) CShellExt::XPersistFileExt::Release(void) { if (nXPRefCount> 0) nXPRefCount--; return nXPRefCount; } STDMETHODIMP CShellExt::XPersistFileExt::Load(LPCOLESTR wszFile, DWORD dwMode) { METHOD_PROLOGUE(CShellExt, PersistFileExt); USES_CONVERSION; _tcscpy(pThis->m_szFile, OLE2T((WCHAR*)wszFile)); return S_OK; } STDMETHODIMP CShellExt::XPersistFileExt::GetClassID(LPCLSID) { return E_NOTIMPL; } STDMETHODIMP CShellExt::XPersistFileExt::IsDirty(VOID) { return E_NOTIMPL; } STDMETHODIMP CShellExt::XPersistFileExt::Save(LPCOLESTR, BOOL) { return E_NOTIMPL; } STDMETHODIMP CShellExt::XPersistFileExt::SaveCompleted(LPCOLESTR) { return E_NOTIMPL; } STDMETHODIMP CShellExt::XPersistFileExt::GetCurFile(LPOLESTR FAR*) { return E_NOTIMPL; }