|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995 - 1995.
//
// File: sfolder.cxx
//
// Contents: Implementation of IShellFolder
//
// History: 13-Dec-95 BruceFo Created
//
//----------------------------------------------------------------------------
#include "headers.hxx"
#pragma hdrstop
#include "dutil.hxx"
#include "enum.hxx"
#include "menuutil.hxx"
#include "menu.hxx"
#include "menusp.hxx"
#include "menubg.hxx"
#include "sdetails.hxx"
#include "sfolder.hxx"
#include "shares.h"
#include "shares.hxx"
#include "util.hxx"
#include "xicon.hxx"
#include "resource.h"
//////////////////////////////////////////////////////////////////////////////
void FSSetStatusText( HWND hwndOwner, LPTSTR* ppszText, int iStart, int iEnd);
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CSharesSF::ParseDisplayName( HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG* pchEaten, LPITEMIDLIST* ppidlOutm, ULONG* pdwAttributes ) { return E_NOTIMPL; }
STDMETHODIMP CSharesSF::GetAttributesOf( UINT cidl, LPCITEMIDLIST* apidl, ULONG* pdwInOut ) { // There are four types of object: New object, View NetWare, View Mac,
// and regular share. If there is a single selection, then the operations
// possible are:
// New share: open, create shortcut
// View NetWare: open, create shortcut
// View Mac: open, create shortcut
// a share: delete, properties
// If there are different types of objects multiply selected, then
// the items must all be shares, or there are no allowed operations.
// For shares, the only multiple-select operation allowed is delete.
ULONG fMask = 0;
if (cidl == 0) { // What things in general can be done in the folder? Return a
// mask of everything possible.
fMask = SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_LINK; } else if (cidl == 1) { LPIDSHARE pids = (LPIDSHARE)apidl[0]; if (Share_IsShare(pids)) { fMask = SFGAO_CANDELETE | SFGAO_HASPROPSHEET; if (!(Share_GetType(pids) & STYPE_SPECIAL)) { fMask |= SFGAO_CANRENAME; } } else { fMask = SFGAO_CANLINK; } } else if (cidl > 1) { UINT i; for (i = 0; i < cidl; i++) { LPIDSHARE pids = (LPIDSHARE)apidl[i]; if (!Share_IsShare(pids)) { break; } }
if (i == cidl) { fMask |= SFGAO_CANDELETE; } }
*pdwInOut &= fMask; return S_OK; }
STDMETHODIMP CSharesSF::GetUIObjectOf( HWND hwndOwner, UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT* prgfInOut, LPVOID* ppvOut ) { CShares* This = IMPL(CShares,m_ShellFolder,this); HRESULT hr = E_NOINTERFACE;
*ppvOut = NULL;
if (cidl == 1 && IsEqualIID(riid, IID_IExtractIcon)) { LPIDSHARE pids = (LPIDSHARE)apidl[0];
CSharesEI* pObj = new CSharesEI(Share_GetFlags(pids), Share_GetType(pids)); if (NULL == pObj) { return E_OUTOFMEMORY; }
hr = pObj->QueryInterface(riid, ppvOut); pObj->Release(); } #ifdef UNICODE
else if (cidl == 1 && IsEqualIID(riid, IID_IExtractIconA)) { LPIDSHARE pids = (LPIDSHARE)apidl[0];
CSharesEIA* pObj = new CSharesEIA(Share_GetFlags(pids), Share_GetType(pids)); if (NULL == pObj) { return E_OUTOFMEMORY; }
hr = pObj->QueryInterface(riid, ppvOut); pObj->Release(); } #endif // UNICODE
else if (cidl > 0 && IsEqualIID(riid, IID_IContextMenu)) { // Create a context menu for selected items. If there is only one
// item, then the context menu is based on that object and is
// CSharesCM for shares and CSharesCMSpecial for special objects.
// If there is a multiple selection, then the selection must all be
// shares, in which case the context-menu is CSharesCM, else there
// is no context menu!
if (This->m_level < 2) { // user has insufficient privilege to perform any operations.
return E_NOINTERFACE; }
IUnknown* punk = NULL; if (cidl == 1) { LPIDSHARE pids = (LPIDSHARE)apidl[0]; if (Share_IsShare(pids)) { CSharesCM* pObj = new CSharesCM(hwndOwner); if (NULL == pObj) { return E_OUTOFMEMORY; }
hr = pObj->InitInstance(This->m_pszMachine, cidl, apidl, this); if (FAILED(hr)) { return hr; }
punk = (IUnknown*)pObj; } #ifdef WIZARDS
else { CSharesCMSpecial* pObj = new CSharesCMSpecial(hwndOwner); if (NULL == pObj) { return E_OUTOFMEMORY; }
hr = pObj->InitInstance(This->m_pszMachine, apidl[0], this); if (FAILED(hr)) { return hr; }
punk = (IUnknown*)pObj; } #endif // WIZARDS
} else if (cidl > 1) { UINT i; for (i = 0; i < cidl; i++) { LPIDSHARE pids = (LPIDSHARE)apidl[i]; if (!Share_IsShare(pids)) { break; } }
if (i == cidl) { CSharesCM* pObj = new CSharesCM(hwndOwner); if (NULL == pObj) { return E_OUTOFMEMORY; }
hr = pObj->InitInstance(This->m_pszMachine, cidl, apidl, this); if (FAILED(hr)) { return hr; }
punk = (IUnknown*)pObj; } else { return E_FAIL; } }
appAssert(NULL != punk); hr = punk->QueryInterface(riid, ppvOut); punk->Release(); } else if (cidl > 0 && IsEqualIID(riid, IID_IDataObject)) { hr = CIDLData_CreateFromIDArray( This->m_pidl, cidl, apidl, (LPDATAOBJECT *)ppvOut); }
return hr; }
STDMETHODIMP CSharesSF::EnumObjects( HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST* ppenumUnknown ) { CShares* This = IMPL(CShares,m_ShellFolder,this); HRESULT hr = E_FAIL;
*ppenumUnknown = NULL;
if (!(grfFlags & SHCONTF_NONFOLDERS)) { return hr; }
appAssert(0 != This->m_level); CSharesEnum* pEnum = new CSharesEnum(This->m_pszMachine, This->m_level); if (NULL == pEnum) { return E_OUTOFMEMORY; }
hr = pEnum->Init(grfFlags); if (FAILED(hr)) { return hr; }
hr = pEnum->QueryInterface(IID_IEnumIDList, (LPVOID*)ppenumUnknown); pEnum->Release(); return hr; }
STDMETHODIMP CSharesSF::BindToObject( LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, LPVOID* ppvOut ) { //
// Shares folder doesn't contain sub-folders
//
*ppvOut = NULL; return E_FAIL; }
// not used in Win95
STDMETHODIMP CSharesSF::BindToStorage( LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID* ppvOut ) { *ppvOut = NULL; return E_NOTIMPL; }
#define PlusMinus(x) (((x) < 0) ? -1 : ( ((x) > 0) ? 1 : 0 ))
int CSharesSF::_CompareOne( DWORD iCol, LPIDSHARE pids1, LPIDSHARE pids2 ) { switch (iCol) { case ICOL2_NAME: return lstrcmpi(Share_GetName(pids1), Share_GetName(pids2));
case ICOL2_COMMENT: return lstrcmpi(Share_GetComment(pids1), Share_GetComment(pids2));
case ICOL2_PATH: return lstrcmpi(Share_GetPath(pids1), Share_GetPath(pids2));
case ICOL2_MAXUSES: { DWORD max1 = Share_GetMaxUses(pids1); DWORD max2 = Share_GetMaxUses(pids2); if (max1 == SHI_USES_UNLIMITED && max2 == SHI_USES_UNLIMITED) { return 0; } else if (max1 == SHI_USES_UNLIMITED) { return 1; } else if (max2 == SHI_USES_UNLIMITED) { return -1; } else { return max1 - max2; } }
default: appAssert(!"Illegal column"); return 0; } }
STDMETHODIMP CSharesSF::CompareIDs( LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2 ) { CShares* This = IMPL(CShares,m_ShellFolder,this);
// If one item is a special item, then put it ahead of the other one.
// If they are both special items, sort on name.
LPIDSHARE pids1 = (LPIDSHARE)pidl1; LPIDSHARE pids2 = (LPIDSHARE)pidl2; int iCmp;
#ifdef WIZARDS
if (Share_IsSpecial(pids1)) { if (Share_IsSpecial(pids2)) { // both special; sort on name
return ResultFromShort(lstrcmpi(Share_GetName(pids1), Share_GetName(pids2))); } else { return ResultFromShort(-1); } } else if (Share_IsSpecial(pids2)) { return ResultFromShort(1); } #endif // WIZARDS
// Documentation says iCol is always zero, but that is wrong! It will
// be non-zero in case the user has clicked on a column heading to sort
// the column. In general, we want the entire item to be equal before we
// return 0 for equality. To do this, we first check the chosen element.
// If it is not equal, return the value. Otherwise, check all elements in
// this standard order:
// name
// comment
// path
// max uses
// current uses
// Only after all these checks return 0 (equality) do we return 0 (equality)
iCmp = _CompareOne((ULONG)iCol, pids1, pids2); if (iCmp != 0) { return ResultFromShort(PlusMinus(iCmp)); }
// now, check each in turn
iCmp = _CompareOne(ICOL2_NAME, pids1, pids2); if (iCmp != 0) { return ResultFromShort(PlusMinus(iCmp)); }
iCmp = _CompareOne(ICOL2_COMMENT, pids1, pids2); if (iCmp != 0) { return ResultFromShort(PlusMinus(iCmp)); }
if (This->m_level == 2) { iCmp = _CompareOne(ICOL2_PATH, pids1, pids2); if (iCmp != 0) { return ResultFromShort(PlusMinus(iCmp)); }
iCmp = _CompareOne(ICOL2_MAXUSES, pids1, pids2); if (iCmp != 0) { return ResultFromShort(PlusMinus(iCmp)); } }
return 0; // the same!
}
STDMETHODIMP CSharesSF::CreateViewObject( HWND hwnd, REFIID riid, LPVOID* ppvOut ) { CShares* This = IMPL(CShares,m_ShellFolder,this); HRESULT hr = E_NOINTERFACE;
*ppvOut = NULL;
if (IsEqualIID(riid, IID_IShellView)) { CSFV csfv = { sizeof(CSFV), // cbSize
(IShellFolder*)this, // pshf
NULL, // psvOuter
NULL, // pidl to monitor (NULL == all)
SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_UPDATEITEM, // events
_SFVCallBack, // pfnCallback
FVM_DETAILS };
hr = SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut); } else if (IsEqualIID(riid, IID_IShellDetails)) { appAssert(This->m_level != 0); CSharesSD* pObj = new CSharesSD(hwnd, This->m_level); if (NULL == pObj) { return E_OUTOFMEMORY; }
hr = pObj->QueryInterface(riid, ppvOut); pObj->Release(); } else if (IsEqualIID(riid, IID_IContextMenu)) { // Create a context menu for the background
CSharesCMBG* pObj = new CSharesCMBG(hwnd, This->m_pszMachine, This->m_level); if (NULL == pObj) { return E_OUTOFMEMORY; }
hr = pObj->QueryInterface(riid, ppvOut); pObj->Release(); }
return hr; }
STDMETHODIMP CSharesSF::GetDisplayNameOf( LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName ) { CShares* This = IMPL(CShares,m_ShellFolder,this);
LPIDSHARE pids = (LPIDSHARE)pidl; if (uFlags == SHGDN_FORPARSING) { return E_NOTIMPL; // don't support parsing.
} else if (uFlags == SHGDN_INFOLDER) { return STRRETCopy(Share_GetName(pids), lpName); } else if (uFlags == SHGDN_NORMAL) { if (NULL == This->m_pszMachine) { return STRRETCopy(Share_GetName(pids), lpName); } else { LPWSTR pszMachine = This->m_pszMachine; if (pszMachine[0] == TEXT('\\') && pszMachine[1] == TEXT('\\')) { pszMachine += 2; }
WCHAR szBuf[MAX_PATH]; szBuf[0] = L'\0'; MyFormatMessage( MSG_TEMPLATE_WITH_ON, szBuf, ARRAYLEN(szBuf), pszMachine, Share_GetName(pids)); #ifdef UNICODE
LPTSTR pszCopy = (LPTSTR)SHAlloc((lstrlen(szBuf)+1) * sizeof(TCHAR)); if (pszCopy) { wcscpy(pszCopy, szBuf); lpName->uType = STRRET_OLESTR; lpName->pOleStr = pszCopy; } else { lpName->uType = STRRET_CSTR; lpName->cStr[0] = '\0'; } #else
lpName->uType = STRRET_CSTR; lstrcpyn(lpName->cStr, szBuf, ARRAYSIZE(lpName->cStr)); SHFree(pszRet); #endif
return S_OK; } } else { return E_INVALIDARG; } }
STDMETHODIMP CSharesSF::SetNameOf( HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags, LPITEMIDLIST* ppidlOut ) { CShares* This = IMPL(CShares,m_ShellFolder,this);
if (uFlags != SHGDN_INFOLDER) { return E_NOTIMPL; }
if (NULL == lpszName || L'\0' == *lpszName) { // can't change name to nothing
MessageBeep(0); return E_FAIL; }
NET_API_STATUS ret; WCHAR szBuf[MAX_PATH]; LPSHARE_INFO_502 pInfo; LPIDSHARE pids = (LPIDSHARE)pidl;
// Get information about the existing share before deleting it.
ret = NetShareGetInfo(This->m_pszMachine, Share_GetName(pids), 502, (LPBYTE*)&pInfo); if (ret != NERR_Success) { DisplayError(hwndOwner, IERR_CANT_DEL_SHARE, ret, Share_GetName(pids)); return HRESULT_FROM_WIN32(ret); }
// Validate the new share name
// Trying to create a reserved share?
if ( (0 == _wcsicmp(g_szIpcShare, lpszName)) || (0 == _wcsicmp(g_szAdminShare, lpszName))) { MyErrorDialog(hwndOwner, MSG_ADDSPECIAL2); NetApiBufferFree(pInfo); return E_FAIL; }
HRESULT hrTemp; if (!IsValidShareName(lpszName, &hrTemp)) { MyErrorDialog(hwndOwner, hrTemp); NetApiBufferFree(pInfo); return E_FAIL; }
// Check to see that the same share isn't already used, for either the
// same path or for another path.
SHARE_INFO_2* pInfo2; ret = NetShareGetInfo(This->m_pszMachine, (LPWSTR)lpszName, 2, (LPBYTE*)&pInfo2); if (ret == NERR_Success) { // Is it already shared for the same path?
if (0 == _wcsicmp(pInfo2->shi2_path, pInfo->shi502_path)) { MyErrorDialog(hwndOwner, IERR_AlreadyExists, lpszName); NetApiBufferFree(pInfo); NetApiBufferFree(pInfo2); return TRUE; }
// Shared for a different path. Ask the user if they wish to delete
// the old share and create the new one using the name.
DWORD id = ConfirmReplaceShare(hwndOwner, lpszName, pInfo2->shi2_path, pInfo->shi502_path); if (id == IDNO || id == IDCANCEL) // FEATURE: should be only yes/no
{ NetApiBufferFree(pInfo); NetApiBufferFree(pInfo2); return E_FAIL; }
// User said to replace the old share. Do it.
ret = NetShareDel(This->m_pszMachine, (LPWSTR)lpszName, 0); if (ret != NERR_Success) { DisplayError(hwndOwner, IERR_CANT_DEL_SHARE, ret, (LPWSTR)lpszName); NetApiBufferFree(pInfo); NetApiBufferFree(pInfo2); return FALSE; } else { SHChangeNotify(SHCNE_NETUNSHARE, SHCNF_PATH, pInfo2->shi2_path, NULL); }
NetApiBufferFree(pInfo2); }
// Check for downlevel accessibility
ULONG nType; if (NERR_Success != NetpPathType(NULL, (LPWSTR)lpszName, &nType, INPT_FLAGS_OLDPATHS)) { DWORD id = MyConfirmationDialog( hwndOwner, IERR_InaccessibleByDos, MB_YESNO | MB_ICONEXCLAMATION, lpszName); if (id == IDNO) { return TRUE; } }
// delete the existing share
ret = NetShareDel(This->m_pszMachine, Share_GetName(pids), 0); if (ret != NERR_Success) { NetApiBufferFree(pInfo); DisplayError(hwndOwner, IERR_CANT_DEL_SHARE, ret, Share_GetName(pids)); return HRESULT_FROM_WIN32(ret); }
// Create a new share with the new name.
LPWSTR ptmp = pInfo->shi502_netname; pInfo->shi502_netname = (LPWSTR)lpszName; // cast away const
ret = NetShareAdd(This->m_pszMachine, 502, (LPBYTE)pInfo, NULL); if (ret != NERR_Success) { pInfo->shi502_netname = ptmp; NetApiBufferFree(pInfo); DisplayError(hwndOwner, IERR_CANT_ADD_SHARE, ret, (LPWSTR)lpszName); // cast away const
return HRESULT_FROM_WIN32(ret); }
// Ok, now I've renamed it. So, fill an ID list with the new guy, and
// return it in *ppidlOut.
HRESULT hr = S_OK; if (NULL != ppidlOut) { IDSHARE ids; FillID2(&ids, (LPSHARE_INFO_2)pInfo); // ignore security at end of level 502
*ppidlOut = ILClone((LPCITEMIDLIST)(&ids)); if (NULL == *ppidlOut) { hr = E_OUTOFMEMORY; } }
// force a view refresh
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, NULL, 0);
pInfo->shi502_netname = ptmp; NetApiBufferFree(pInfo); return hr; }
//
// Callback from SHCreateShellFolderViewEx
//
HRESULT CALLBACK CSharesSF::_SFVCallBack( LPSHELLVIEW psvOuter, LPSHELLFOLDER psf, HWND hwndOwner, UINT uMsg, WPARAM wParam, LPARAM lParam ) { CShares* This = IMPL(CShares,m_ShellFolder,psf); HRESULT hr = S_OK; // assume no error
switch (uMsg) { case DVM_UPDATESTATUSBAR: { IShellBrowser* psb = FileCabinet_GetIShellBrowser(hwndOwner); UINT cidl = ShellFolderView_GetSelectedCount(hwndOwner); if (cidl == 1) { LPITEMIDLIST *apidl; LPIDSHARE pids; LPTSTR lpsz = TEXT("");
ShellFolderView_GetSelectedObjects(hwndOwner, &apidl); if (apidl) { pids = (LPIDSHARE)apidl[0]; if (Share_IsShare(pids)) { lpsz = Share_GetComment(pids); } FSSetStatusText(hwndOwner, &lpsz, 0, 0); LocalFree(apidl); } } else { hr = E_FAIL; } break; }
case DVM_MERGEMENU: { appDebugOut((DEB_TRACE, "DVM_MERGEMENU\n")); appAssert(This->m_pMenuBg == NULL); hr = psf->CreateViewObject(hwndOwner, IID_IContextMenu, (LPVOID*)&This->m_pMenuBg); if (SUCCEEDED(hr)) { LPQCMINFO pqcm = (LPQCMINFO)lParam; hr = This->m_pMenuBg->QueryContextMenu( pqcm->hmenu, pqcm->indexMenu, pqcm->idCmdFirst, pqcm->idCmdLast, CMF_DVFILE); } break; }
case DVM_UNMERGEMENU: { appDebugOut((DEB_TRACE, "DVM_UNMERGEMENU\n")); if (NULL != This->m_pMenuBg) { This->m_pMenuBg->Release(); This->m_pMenuBg = NULL; } break; }
case DVM_INVOKECOMMAND: { appDebugOut((DEB_TRACE, "DVM_INVOKECOMMAND\n")); appAssert(This->m_pMenuBg != NULL); CMINVOKECOMMANDINFO ici = { sizeof(ici), 0, // mask
hwndOwner, (LPCSTR)wParam, NULL, NULL, 0, 0, NULL }; hr = This->m_pMenuBg->InvokeCommand(&ici); break; }
case DVM_GETHELPTEXT: { appDebugOut((DEB_TRACE, "DVM_GETHELPTEXT\n")); hr = This->m_pMenuBg->GetCommandString(LOWORD(wParam), GCS_HELPTEXT, NULL, (LPSTR)lParam, HIWORD(wParam)); break; }
case DVM_DEFITEMCOUNT: //
// If DefView times out enumerating items, let it know we probably only
// have about 20 items
//
*(int *)lParam = 20; break;
case DVM_FSNOTIFY: { LPCITEMIDLIST* ppidl = (LPCITEMIDLIST*)wParam;
switch (lParam) { case SHCNE_NETSHARE: case SHCNE_NETUNSHARE: // a share was added, removed, or changed. Force a view refresh.
// SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, NULL, 0);
return S_OK; } break; }
default: hr = E_FAIL; } return hr; }
|