📄 ftpfoldr.cpp
字号:
This means it will be: [TheINet][FtpServerID][...]
*ppidlWithVRoot [OUT]: This will be the same public pidl that was passed in except
any ItemIDs that come from pfs->GetVirtualRootReference() will be inserted
between the ServerID and ItemIDs.
\*****************************************************************************/
HRESULT CFtpFolder::_ConvertPidlForRootedFix(LPCITEMIDLIST pidlBefore, LPITEMIDLIST * ppidlWithVRoot)
{
CFtpSite * pfs;
HRESULT hr = SiteCache_PidlLookup(pidlBefore, FALSE, m_pm, &pfs);
*ppidlWithVRoot = NULL;
if (EVAL(SUCCEEDED(hr) && pfs))
{
if (pfs->HasVirtualRoot())
{
LPCITEMIDLIST pidlVirtualRoot = pfs->GetVirtualRootReference();
LPITEMIDLIST pidlUrlPath = (LPITEMIDLIST)pidlBefore;
// Skip past non-FTP Server/ItemIDs. (TheInternet)
while (pidlUrlPath && !ILIsEmpty(pidlUrlPath) && !FtpID_IsServerItemID(pidlUrlPath))
pidlUrlPath = _ILNext(pidlUrlPath);
if (FtpID_IsServerItemID(pidlUrlPath))
pidlUrlPath = _ILNext(pidlUrlPath);
if (EVAL(pidlUrlPath))
{
LPITEMIDLIST pidlFullWithVRoot;
USHORT cb = pidlUrlPath->mkid.cb;
pidlUrlPath->mkid.cb = 0;
pidlFullWithVRoot = ILCombine(pidlBefore, pidlVirtualRoot);
pidlUrlPath->mkid.cb = cb;
if (EVAL(pidlFullWithVRoot))
{
FtpPidl_InsertVirtualRoot(pidlFullWithVRoot, pidlUrlPath, ppidlWithVRoot);
ILFree(pidlFullWithVRoot);
}
}
else
hr = E_OUTOFMEMORY;
}
else
hr = E_FAIL;
pfs->Release();
}
if (FAILED(hr))
{
*ppidlWithVRoot = ILClone(pidlBefore);
if (*ppidlWithVRoot)
hr = S_OK;
}
return hr;
}
BOOL CFtpFolder::IsUTF8Supported(void)
{
if (EVAL(m_pfs))
return m_pfs->IsUTF8Supported();
return FALSE;
}
/*****************************************************************************\
FUNCTION: IShellFolder::_PidlToMoniker
DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpFolder::_PidlToMoniker(LPCITEMIDLIST pidl, IMoniker ** ppmk)
{
HRESULT hr = E_INVALIDARG;
*ppmk = NULL;
if (EVAL(pidl))
{
IBindCtx * pbc;
hr = _GetBindCtx(&pbc);
if (SUCCEEDED(hr))
{
WCHAR wzUrl[MAX_URL_STRING];
// URLMON expects incorrectly formatted URLs (where the virtual
// root is included in the url path). We need to fix that
// here.
hr = _GetLegacyURL(pidl, pbc, wzUrl, ARRAYSIZE(wzUrl));
if (SUCCEEDED(hr))
{
hr = CreateURLMoniker(NULL, wzUrl, ppmk);
}
pbc->Release();
}
}
ASSERT_POINTER_MATCHES_HRESULT(*ppmk, hr);
return hr;
}
HRESULT CFtpFolder::_CreateShellView(HWND hwndOwner, void ** ppvObj)
{
IShellFolderViewCB * psfvCallBack;
HRESULT hr = CFtpView_Create(this, hwndOwner, IID_IShellFolderViewCB, (LPVOID *) &psfvCallBack);
if (EVAL(SUCCEEDED(hr)))
{
// GetPublicTargetPidlReference() is used because it's passed to SFVM_GETNOTIFY
// to synch ChangeNotify messages.
hr = CBaseFolder::_CreateShellView(hwndOwner, ppvObj, FTP_SHCNE_EVENTS,
FVM_DETAILS, psfvCallBack, GetPublicTargetPidlReference(), CBaseFolderViewCB::_IShellFolderViewCallBack);
psfvCallBack->Release();
}
ASSERT_POINTER_MATCHES_HRESULT(*ppvObj, hr);
return hr;
}
HKEY ClassKeyFromExtension(LPCWIRESTR pszExt)
{
HKEY hkey = NULL;
WIRECHAR szProgID[MAX_PATH];
DWORD cbProgID = sizeof(szProgID);
if (ERROR_SUCCESS == SHGetValueA(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, (void *)szProgID, &cbProgID))
{
// the entension points to a ProgID, use that.
RegOpenKeyA(HKEY_CLASSES_ROOT, szProgID, &hkey);
}
else
{
// No ProgID, use the extension as the program ID.
RegOpenKeyA(HKEY_CLASSES_ROOT, pszExt, &hkey);
}
return hkey;
}
#define SZ_REGVALUE_DOCOBJECT TEXT("DocObject")
#define SZ_REGVALUE_BROWSEINPLACE TEXT("BrowseInPlace")
BOOL _IsDocObjViewerInstalled(LPCITEMIDLIST pidl)
{
BOOL fResult = FALSE;
// Return FALSE if it's just pointing to an FTP server.
if (!FtpID_IsServerItemID(ILFindLastID(pidl)))
{
LPCWIRESTR pwWireFileName = FtpPidl_GetLastItemWireName(pidl);
LPCWIRESTR pszExt = PathFindExtensionA(pwWireFileName);
if (pszExt)
{
HKEY hkey = ClassKeyFromExtension(pszExt);
if (hkey)
{
if ((ERROR_SUCCESS == RegQueryValue(hkey, SZ_REGVALUE_DOCOBJECT, 0, NULL)) ||
(ERROR_SUCCESS == RegQueryValue(hkey, SZ_REGVALUE_BROWSEINPLACE, 0, NULL)))
{
fResult = TRUE;
}
RegCloseKey(hkey);
}
}
}
return fResult;
}
ULONG FtpGetAttributesOf(LPCITEMIDLIST pidl)
{
ASSERT(IsValidPIDL(pidl));
DWORD dwAttributes = FtpPidl_GetAttributes(pidl); // Get File based attributes.
ULONG rgfInOut = Misc_SfgaoFromFileAttributes(dwAttributes); // Turn them into IShellFolder attributes.
return rgfInOut;
}
//===========================
// *** IShellFolder2 Interface ***
//===========================
STDAPI InitVariantFromBuffer(VARIANT *pvar, const void *pv, UINT cb)
{
HRESULT hres;
SAFEARRAY *psa = SafeArrayCreateVector(VT_UI1, 0, cb); // create a one-dimensional safe array
if (psa)
{
memcpy(psa->pvData, pv, cb);
memset(pvar, 0, sizeof(*pvar)); // VariantInit()
pvar->vt = VT_ARRAY | VT_UI1;
pvar->parray = psa;
hres = S_OK;
}
else
hres = E_OUTOFMEMORY;
return hres;
}
/*****************************************************************************\
FUNCTION: IShellFolder2::GetDetailsEx
DESCRIPTION:
This function will be called when the caller wants detailed info about
and item. SHGetDataFromIDList() is one such caller and that is commonly
called by the Shell Object model when using CSDFldrItem::get_Size(LONG *pul)
and other such APIs.
\*****************************************************************************/
HRESULT CFtpFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
HRESULT hr = S_OK;
if (IsEqualGUID(pscid->fmtid, FMTID_ShellDetails) && (PID_FINDDATA == pscid->pid))
{
WIN32_FIND_DATAW wfd;
// I can handle this.
LPITEMIDLIST pidlFull = CreateFullPrivatePidl(pidl);
if (pidlFull)
{
hr = Win32FindDataFromPidl(pidlFull, &wfd, TRUE, TRUE);
ILFree(pidlFull);
}
if (SUCCEEDED(hr))
{
hr = InitVariantFromBuffer(pv, (PVOID)&wfd, sizeof(wfd));
}
}
else
hr = CBaseFolder::GetDetailsEx(pidl, pscid, pv);
return hr;
}
//===========================
// *** IShellFolder Interface ***
//===========================
/*****************************************************************************\
FUNCTION: IShellFolder:: ParseDisplayName
DESCRIPTION:
The incoming name is %-encoded, but if we see an illegal %-sequence,
just leave the % alone.
For now, we disallow backslash, "*" and "?" from filenames.
Backslashes don't sit well with wininet, and wildcards
screw up the "quick FindFirst to see if the file exists".
We also disallow encoded slashes, because they screw up the way
we manage subpidls.
Annoying feature: You can't pass -1 as the output buffer size.
NLS returns ERROR_INVALID_PARAMETER if you try. So you have to pass
the actual size. Sigh.
\*****************************************************************************/
HRESULT CFtpFolder::ParseDisplayName(HWND hwnd, LPBC pbcReserved, LPOLESTR pwszDisplayName,
ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
{
HRESULT hr = S_OK;
*ppidl = NULL;
if (pchEaten)
*pchEaten = 0;
// PERF: log 2 (sizeof(m_pflHfpl))
hr = _GetCachedPidlFromDisplayName(pwszDisplayName, ppidl);
if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr))
{
// Are we are rooted within an FTP Server?
if (IsRoot())
{
// No, so parse the entire thing
// There is only one case where we want to hide the password,
// and that is when the user entered it into the "Login"
// dialog. Since we entering it into the dialog will cause a
// redirect to an URL with that password in it, we need to determie
// if we are being called during this redirect. If so,
// the password just came from the Login dialog and we need to hide it.
// This will work for fully qualified Ftp URLs
hr = CreateFtpPidlFromUrl(pwszDisplayName, GetCWireEncoding(), pchEaten, ppidl, m_pm, FALSE);
if (SUCCEEDED(hr))
{
CFtpSite * pfs;
hr = SiteCache_PidlLookup(*ppidl, TRUE, m_pm, &pfs);
if (EVAL(SUCCEEDED(hr)))
{
// If we are using a hidden password, then ::GetDisplayNameOf() hands out
// these "ftp://user@server/dir/" URLs and the password is hidden. If
// ::ParseDisplayName() is given one of these URLs and we are currently in
// that server w/that user name, then ::ParseDisplayNameOf() needs to hand
// out a pidl with the correct hidden password cookie.
//
// Is pidlNav the same as GetPublicPidlReference() except pidlNav doesn't
// have a password. The same means that the servers match, and the user names
// match.
EVAL(SUCCEEDED(pfs->UpdateHiddenPassword(*ppidl)));
pfs->Release();
}
}
}
else
{
// Yes, so do a relative parse
// Sometimes the user will enter incorrect information without knowing.
// We would catch this if we verified everything that was entered, but
// we don't, we just take it on faith until we do the IEnumIDList.
// This is great for perf but sucks for catching these kinds of things.
// An example of this is the user using the File.Open dialog and going to
// "ftp://myserver/dir/". They then enter "ftp://myserver/dir/file.txt"
// which will try to parse relative but it's an absolute path.
hr = _FilterBadInput(pwszDisplayName, ppidl);
if (SUCCEEDED(hr))
{
CFtpDir * pfd = GetFtpDir();
hr = CreateFtpPidlFromDisplayPath(pwszDisplayName, pfd->GetFtpSite()->GetCWireEncoding(), pchEaten, ppidl, FALSE, FALSE);
pfd->Release();
}
}
}
if (SUCCEEDED(hr) && pdwAttributes)
{
hr = GetAttributesOf(1, (LPCITEMIDLIST *) ppidl, pdwAttributes);
if (FAILED(hr))
ILFree(*ppidl);
}
#ifdef DEBUG
TCHAR szUrlDebug[MAX_URL_STRING];
szUrlDebug[0] = 0;
if (*ppidl)
UrlCreateFromPidl(*ppidl, SHGDN_FORPARSING, szUrlDebug, ARRAYSIZE(szUrlDebug), ICU_USERNAME, FALSE);
TraceMsg(TF_FTPISF, "CFtpFolder::ParseDisplayName(%ls) CreateFtpPidlFromUrl() returned hres=%#08lx %ls", pwszDisplayName, hr, szUrlDebug);
ASSERT(FAILED(hr) || IsValidPIDL(*ppidl));
#endif // DEBUG
ASSERT_POINTER_MATCHES_HRESULT(*ppidl, hr);
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -