📄 ftpfoldr.cpp
字号:
IMalloc * CFtpFolder::GetIMalloc(void)
{
IMalloc * pm = NULL;
IUnknown_Set(&pm, m_pm);
ASSERT(pm);
return pm;
}
/*****************************************************************************\
FUNCTION: IShellFolder::EnumObjects
DESCRIPTION:
Design subtlety: If we couldn't create an enumeration on the server,
succeed, but return an enumerator that shows no objects.
This is necessary so that our IShellView callback can put
up error UI. If we failed the create, the shell would
destroy the view without giving us a chance to say what's
up.
It's also important for write-only directories like /incoming,
so that the user can drag files into the directory without
necessarily being able to drag files out.
\*****************************************************************************/
HRESULT CFtpFolder::EnumObjects(HWND hwndOwner, DWORD grfFlags, IEnumIDList ** ppenumIDList)
{
HRESULT hres = E_FAIL;
CFtpDir * pfd = GetFtpDir();
// This will happen if some TARD tries to just CoCreateInstance our
// Name Space extension and see what contents we have. TweakUI
// is an example of one such abuser. Since we can only populate
// our contents after we navigate to a FTP server, we are empty.
*ppenumIDList = NULL;
if (pfd)
{
// Create a new enumeration object for the caller.
ASSERT(m_pm);
hres = CFtpEidl_Create(pfd, this, hwndOwner, grfFlags, ppenumIDList);
TraceMsg(TF_FTPISF, "CFtpFolder::EnumObjects() CFtpEidl_Create() returned hres=%#08lx", hres);
if (!EVAL(SUCCEEDED(hres)))
{
ASSERT(*ppenumIDList); // We failed, so free what we have.
}
pfd->Release();
}
ASSERT_POINTER_MATCHES_HRESULT(*ppenumIDList, hres);
return hres;
}
BOOL CFtpFolder::_NeedToFallBackRelative(LPCITEMIDLIST pidl, BOOL * pfDisplayProxyFallBackDlg)
{
LPITEMIDLIST pidlFull = CreateFullPrivatePidl(pidl);
BOOL fFallBack = FALSE;
if (pidlFull)
{
fFallBack = _NeedToFallBack(pidl, pfDisplayProxyFallBackDlg);
ILFree(pidlFull);
}
return fFallBack;
}
/*****************************************************************************\
FUNCTION: _NeedToFallBack
DESCRIPTION:
We need to fall back to the old URLMON support in these cases:
#1 It's a file, we let the old code use URLMON to do the download.
#2 The app (WebOC host) has bugs that cause us to fail.
#3 The user turned off the New FTP UI. (For whatever reason)
#4 The proxy is a web proxy and allows URLMON but not WININET access,
so fall back to the old support.
#5 WININET doesn't support VMS servers, so we need to fall back in that case.
NOTE: The order is important because we always need to calc
fIsProxyBlockingFTP so we only display the fallback dlg
in the correct case.
\*****************************************************************************/
BOOL CFtpFolder::_NeedToFallBack(LPCITEMIDLIST pidlFull, BOOL * pfDisplayProxyFallBackDlg)
{
BOOL fNeedToFallBack = TRUE;
*pfDisplayProxyFallBackDlg = FALSE;
// TweakUI sends us an Empty pidls so don't fault. NT #396234.
if (pidlFull && !ILIsEmpty(pidlFull))
{
BOOL fIsDirectory;
if (IsFtpPidlQuestionable(pidlFull))
_FixQuestionablePidl(pidlFull);
fIsDirectory = (!FtpPidl_HasPath(pidlFull) || FtpPidl_IsDirectory(pidlFull, FALSE));
if (fIsDirectory) // #1
{
if (IsAppFTPCompatible()) // #2
{
if (!SHRegGetBoolUSValue(SZ_REGKEY_FTPFOLDER, SZ_REGKEY_USE_OLD_UI, FALSE, FALSE)) // #3
{
// The binding code passes us a bind context and that would be a good
// key to determine if were are about to navigate to the site. The
// problem is that we can't skip the proxy checking because we will
// fail later.
//
// #224285 is an example where navigating from ftp://ftp.microsoft.com/ to
// "www.microsoft.com" will cause CShellUrl to call :: BindToObject and then
// our IEnumIDList::Next() which will give an error message.
//
// Are we unable to get access to the server because there is
// a CERN type proxy blocking us?
// PERF: Only check for the proxy if we have a bind context because
// the only place we are called from to navigate is
// CDocObjectFolder:: BindToObject() and we are guaranteed that they
// pass it to us.
if (!_IsProxyBlockingSite(pidlFull)) // #4
{
// Is this a VMS Server? If yes, fallback
// to URLMON support because wininet doesn't work with this kind of server.
if (!_IsServerVMS(pidlFull))
{
// Only continue if the user didn't turn the new UI Off.
fNeedToFallBack = FALSE;
}
}
else
*pfDisplayProxyFallBackDlg = TRUE;
}
}
}
}
return fNeedToFallBack;
}
/*****************************************************************************\
FUNCTION: IShellFolder:: BindToObject
DESCRIPTION:
First thing we need to do, is see if we want to over ride the default
IE FTP support. If we do, we call otherwise, we just fallback to the old
support. We want the new UI if: a) it's a directory, b) the web proxy doesn't
block us, and c) the user didn't turn us off.
PERF/TODO:
OrderItem_GetSystemImageListIndexFromCache (\shell\lib\dpastuff.cpp)
uses riid=IShellFolder when trying to find out the icon. We don't want
to hit the net in that case, so force them to pass a pbc to indicate skipping
the net in that case.
\*****************************************************************************/
HRESULT CFtpFolder::BindToObject(LPCITEMIDLIST pidl, IBindCtx * pbc, REFIID riid, LPVOID * ppvObj)
{
HRESULT hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Indicate we want the old functionality to kick in.
if (ppvObj)
*ppvObj = NULL;
if (!pidl || ILIsEmpty(pidl) || !_IsValidPidlParameter(pidl))
{
// Caller, are you smoking crack? What's the idea of passing
// an empty pidl. (Comdlg32 is known to do this)
hr = E_INVALIDARG;
}
else
{
BOOL fDisplayProxyFallBackDlg = FALSE;
LPITEMIDLIST pidlFull = CreateFullPrivatePidl(pidl);
// We need to handle it.
hr = _BindToObject(pidl, pidlFull, pbc, riid, ppvObj);
// Maybe we still need to handle it if
ASSERT(HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr);
ILFree(pidlFull);
}
ASSERT_POINTER_MATCHES_HRESULT(*ppvObj, hr);
return hr;
}
/*****************************************************************************\
FUNCTION: IShellFolder::BindToStorage
DESCRIPTION:
We need to implement this so the user can Open and Save files in
the standard Open Dialog and Save Dialog.
\*****************************************************************************/
HRESULT CFtpFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, LPVOID * ppvObj)
{
HRESULT hr = E_INVALIDARG;
if (!EVAL(_IsValidPidlParameter(pidl)))
return E_INVALIDARG;
*ppvObj = 0;
if (EVAL(pidl))
{
IMoniker * pmk;
hr = _PidlToMoniker(pidl, &pmk);
if (SUCCEEDED(hr))
{
hr = pmk->BindToStorage(pbc, NULL, riid, ppvObj);
pmk->Release();
}
}
ASSERT_POINTER_MATCHES_HRESULT(*ppvObj, hr);
TraceMsg(TF_FTPISF, "CFtpFolder::BindToStorage() hr=%#08lx", hr);
return hr;
}
/*****************************************************************************\
FUNCTION: IShellFolder::CompareIDs
DESCRIPTION:
ici - column on which to sort. Note! that we rely on the fact that
IShellFolders are uniform; we do not need to bind to the shell folder in
order to compare its sub-itemids.
_UNDOCUMENTED_: The documentation does not say whether or not
complex pidls can be received. In fact, they can.
\*****************************************************************************/
HRESULT CFtpFolder::CompareIDs(LPARAM ici, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
ASSERT(IsValidPIDL(pidl1));
ASSERT(IsValidPIDL(pidl2));
return FtpItemID_CompareIDs(ici, pidl1, pidl2, FCMP_GROUPDIRS);
}
HRESULT CFtpFolder::_CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvObj)
{
HRESULT hr = E_FAIL;
CFtpDir * pfd = GetFtpDir();
*ppvObj = NULL; // Explorer relies on this
//TraceMsg(TF_FTPISF, "CFtpObj::CreateViewObject() ");
if (pfd)
{
if (IsEqualIID(riid, IID_IDropTarget))
{
// Don't create a drop target for the root FTP folder.
if (IsRoot())
hr = E_NOINTERFACE;
else
{
CFtpDrop * pfm;
hr = CFtpDrop_Create(this, hwndOwner, &pfm);
if (EVAL(SUCCEEDED(hr)))
{
hr = pfm->QueryInterface(riid, ppvObj);
pfm->Release();
}
}
}
else
hr = E_NOINTERFACE;
// TODO: IID_IShellDetails
pfd->Release();
}
else
hr = E_FAIL; // Can't do that yet - Never _Initialize'd
ASSERT_POINTER_MATCHES_HRESULT(*ppvObj, hr);
if (FAILED(hr))
hr = CBaseFolder::CreateViewObject(hwndOwner, riid, ppvObj);
return hr;
}
IShellFolder * CFtpFolder::_GetLegacyShellFolder(void)
{
IShellFolder * psfLegacy = NULL;
// I assert that this succeeds because I need to make
// sure every install case has this CLSID publicly available.
if (EVAL(SUCCEEDED(CoCreateInstance(CLSID_CDocObjectFolder, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder, (void **)&psfLegacy))))
{
LPITEMIDLIST pidl = GetPrivatePidlClone();
if (pidl && !ILIsEmpty(pidl))
{
LPITEMIDLIST pidlLast = (LPITEMIDLIST) ILGetLastID(pidl);
LPITEMIDLIST pidlLegacy;
if (!FtpID_IsServerItemID(pidlLast))
{
// NT #291513: We want to force the last item to always be marked as a file
// because then it will not have the trailing '/' in the URL when we
// pass it to URLMON. This way, we leave wether it's a file or dir
// ambigious for URLMON to figure out. This is because we can't
// disambiguate because the proxy blocks us but URLMON handles it
// correctly.
FtpPidl_SetFileItemType(pidlLast, FALSE);
FtpPidl_SetAttributes(pidl, FILE_ATTRIBUTE_NORMAL);
}
if (SUCCEEDED(_GetLegacyPidl(pidl, &pidlLegacy)))
{
if (FAILED(_InitLegacyShellFolder(psfLegacy, pidlLegacy)))
ATOMICRELEASE(psfLegacy);
ILFree(pidlLegacy);
}
ILFree(pidl);
}
}
return psfLegacy;
}
/*****************************************************************************\
FUNCTION: IShellFolder:: CreateViewObject
DESCRIPTION:
_UNDOCUMENTED_: This entire method is not documented.
_UNDOCUMENTED_: It is not documented that you need to
provide an IDropTarget object if you want the view to
act as a drop target.
IDropTarget produces a droptarget for the folder itself.
_UNDOCUMENTED_: The IShellView interface is not documented.
IShellView produces a shell view for the folder itself.
_UNOBVIOUS_: Not obvious that this is how the shell gets
a context menu for the folder itself. (You might think it
comes from GetUIObjectOf...)
IContextMenu produces a context menu for the folder itself.
This is important for supporting things like New and Paste.
IShellDetails (undocumented) is the direct interface to
GetDetailsOf and ColumnClick, which is now obsolete, replaced
by the DVM_GETDETAILSOF and DVM_COLUMNCLICK notifications.
_UNDOCUMENTED_: SHCreateShellFolderViewEx is not documented.
Yes, it's annoy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -