📄 ftpcm.cpp
字号:
return (((nRoot + 1) >= nCurrent) ? TRUE : FALSE);
}
/*****************************************************************************\
FUNCTION: DeleteItemCB
DESCRIPTION:
This function will download the specified item and it's contents if it
is a directory. Since this is in the line of recursion, we need to have the
stack be as small as possible. Therefore, we call _DeleteItemPrep() to use
as much stack as needed to do the majority of the work and the clean up the
stack before we do the recursion. The only information we need from it is
pszUrlPath which we put on the stack and heap and clean up our selves.
\*****************************************************************************/
HRESULT DeleteItemCB(LPVOID pvFuncCB, HINTERNET hint, LPCITEMIDLIST pidlFull, BOOL * pfValidhinst, LPVOID pvData)
{
DELETESTRUCT * pDelete = (DELETESTRUCT *) pvData;
BOOL fIsTopLevel = _IsTopLevel(pDelete->pidlRoot, pidlFull);
HRESULT hr = _DeleteItemPrep(hint, pidlFull, fIsTopLevel, pDelete);
if (SUCCEEDED(hr) && (FILE_ATTRIBUTE_DIRECTORY & FtpPidl_GetAttributes(pidlFull)))
{
hr = EnumFolder((LPFNPROCESSITEMCB) pvFuncCB, hint, pidlFull, pDelete->pff->GetCWireEncoding(), pfValidhinst, pvData);
if (SUCCEEDED(hr))
{
if (pDelete->fInDeletePass)
{
hr = FtpRemoveDirectoryWithCN(pDelete->hwnd, hint, pDelete->pff, pidlFull, fIsTopLevel);
// TraceMsg(TF_FTPOPERATION, "DeleteItemCB() FtpRemoveDirectoryA() returned hr=%#08lx.", hr);
pDelete->dwDeletedFiles++;
}
else
pDelete->dwTotalFiles++;
}
}
hr = _DeleteItemCleanUp(hr, pDelete);
return hr;
}
/*****************************************************************************\
FUNCTION: _InvokeLoginAsVerb
DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpMenu::_InvokeLoginAsVerb(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr = E_FAIL;
if (EVAL(m_pfd))
hr = LoginAs(pici->hwnd, m_pff, m_pfd, _punkSite);
return hr;
}
/*****************************************************************************\
FUNCTION: _InvokeNewFolderVerb
DESCRIPTION:
The user just selected "New Folder", so we need to create a new folder.
\*****************************************************************************/
HRESULT CFtpMenu::_InvokeNewFolderVerb(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr = E_FAIL;
if (m_pfd)
hr = CreateNewFolder(m_hwnd, m_pff, m_pfd, _punkSite, (m_uFlags & CMF_DVFILE), m_ptNewItem);
return hr;
}
/*****************************************************************************\
FUNCTION: _InvokeDeleteVerb
DESCRIPTION:
The user just selected file(s) and/or folder(s) and selected the
"download" verb. We need to:
1. Display UI to ask the user for the destination directory.
2. Download each item (pidl) into that directory.
\*****************************************************************************/
HRESULT CFtpMenu::_InvokeDeleteVerb(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr = S_OK;
if (EVAL(m_pfd))
{
if (m_sfgao & SFGAO_CANDELETE)
{
if (!(pici->fMask & CMIC_MASK_FLAG_NO_UI))
{
ASSERT(pici->hwnd);
switch (FtpConfirmDeleteDialog(ChooseWindow(pici->hwnd, m_hwnd), m_pflHfpl, m_pff))
{
case IDC_REPLACE_YES:
hr = S_OK;
break;
default:
// FALLTHROUGH
case IDC_REPLACE_CANCEL:
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Cancel all copies.
break;
case IDC_REPLACE_NO:
hr = S_FALSE;
break;
}
}
else
hr = S_OK;
if (hr == S_OK)
{
CStatusBar * psb = _GetStatusBar();
IProgressDialog * ppd = CProgressDialog_CreateInstance(IDS_DELETE_TITLE, IDA_FTPDELETE);
LPITEMIDLIST pidlRoot = ILClone(m_pfd->GetPidlReference());
DELETESTRUCT delStruct = {pidlRoot, m_pff, m_pff->m_pm, pici, ChooseWindow(pici->hwnd, m_hwnd), psb, ppd, 0, 0, FALSE};
if (EVAL(SUCCEEDED(hr)))
{
HINTERNET hint;
m_pfd->GetHint(NULL, NULL, &hint, _punkSite, m_pff);
if (EVAL(hint))
{
HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (EVAL(ppd))
{
WCHAR wzProgressDialogStr[MAX_PATH];
HWND hwndParent = NULL;
// BUGBUG: DefView (defview.cpp CDefView::QueryInterface()) doesn't support IOleWindow so our
// progress dialog isn't correctly parented.
// If the caller was nice enough to SetSite() with their punk, I will be nice enough to make
// their window may progress dialog's parent window.
IUnknown_GetWindow(_punkSite, &hwndParent);
if (!hwndParent)
hwndParent = m_hwnd;
// Normally we always want UI, but in one case we don't. If the
// user does a DROPEFFECT_MOVE, it really is a DROPEFFECT_COPY
// and then a IContextMenu::InvokeCommand(SZ_VERB_DELETEA).
// The progress was done in the copy thread and isn't needed
// in the delete thread.
// ASSERT(hwndParent);
// We give a NULL punkEnableModless because we don't want to go modal.
EVAL(SUCCEEDED(ppd->StartProgressDialog(hwndParent, NULL, PROGDLG_AUTOTIME, NULL)));
// Tell the user we are calculating how long it will take.
if (EVAL(LoadStringW(HINST_THISDLL, IDS_PROGRESS_DELETETIMECALC, wzProgressDialogStr, ARRAYSIZE(wzProgressDialogStr))))
EVAL(SUCCEEDED(ppd->SetLine(2, wzProgressDialogStr, FALSE, NULL)));
}
// Tell the user we are calculating how long it will take.
hr = m_pflHfpl->RecursiveEnum(pidlRoot, DeleteItemCB, hint, (LPVOID) &delStruct);
if (ppd)
{
// Reset because RecursiveEnum(DeleteItemCB) can take a long time and the estimated time
// is based on the time between ::StartProgressDialog() and the first
// ::SetProgress() call.
EVAL(SUCCEEDED(ppd->Timer(PDTIMER_RESET, NULL)));
}
delStruct.fInDeletePass = TRUE;
if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) // This is the only error we care about.
{
m_pflHfpl->UseCachedDirListings(TRUE); // Get the perf advantage now because we just updated the cache a few lines up.
hr = m_pflHfpl->RecursiveEnum(pidlRoot, DeleteItemCB, hint, (LPVOID) &delStruct);
}
if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr))
{
DisplayWininetError(pici->hwnd, TRUE, HRESULT_CODE(hr), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_DELETE, IDS_FTPERR_WININET, MB_OK, ppd);
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Wrong permissions
}
if (psb)
psb->SetStatusMessage(IDS_EMPTY, NULL);
if (ppd)
{
ppd->StopProgressDialog();
ppd->Release();
}
ILFree(pidlRoot);
SetCursor(hCursorOld); // Restore old cursor.
}
m_pfd->ReleaseHint(hint);
}
}
}
else
{
DisplayWininetError(pici->hwnd, TRUE, ResultFromScode(E_ACCESSDENIED), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_DELETE, IDS_FTPERR_WININET, MB_OK, NULL);
hr = E_ACCESSDENIED; // Wrong permissions
}
}
return hr;
}
/*****************************************************************************\
FUNCTION: _GetStatusBar
DESCRIPTION:
\*****************************************************************************/
CStatusBar * CFtpMenu::_GetStatusBar(void)
{
return GetCStatusBarFromDefViewSite(_punkSite);
}
/*****************************************************************************\
FUNCTION: FileSizeCountItemCB
DESCRIPTION:
This function will download the specified item and it's contents if it
is a directory.
\*****************************************************************************/
HRESULT FileSizeCountItemCB(LPVOID pvFuncCB, HINTERNET hint, LPCITEMIDLIST pidlFull, BOOL * pfValidhinst, LPVOID pvData)
{
PROGRESSINFO * pProgInfo = (PROGRESSINFO *) pvData;
HRESULT hr = S_OK;
if (pProgInfo->ppd && pProgInfo->ppd->HasUserCancelled())
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
if (SUCCEEDED(hr))
{
// Is this a dir/folder that we need to recurse into?
if (FILE_ATTRIBUTE_DIRECTORY & FtpPidl_GetAttributes(pidlFull))
hr = EnumFolder((LPFNPROCESSITEMCB) pvFuncCB, hint, pidlFull, NULL, pfValidhinst, pvData);
else
pProgInfo->uliBytesTotal.QuadPart += FtpPidl_GetFileSize(pidlFull);
}
return hr;
}
HRESULT UpdateDownloadProgress(PROGRESSINFO * pProgInfo, LPCITEMIDLIST pidlFull, LPCWSTR pwzTo, LPCWSTR pwzFileName)
{
HRESULT hr;
WCHAR wzTemplate[MAX_PATH];
WCHAR wzStatusText[MAX_PATH];
WCHAR wzFrom[MAX_PATH];
LPITEMIDLIST pidlParent = ILClone(pidlFull);
if (pidlParent)
{
ILRemoveLastID(pidlParent);
FtpPidl_GetDisplayName(pidlParent, wzFrom, ARRAYSIZE(wzFrom));
ILFree(pidlParent);
}
// Give the directories some weight because the user may be copying tons of empty directories.
EVAL(SUCCEEDED(pProgInfo->ppd->SetProgress64(pProgInfo->uliBytesCompleted.QuadPart, pProgInfo->uliBytesTotal.QuadPart)));
// Generate the string "Downloading <FileName>..." status string
EVAL(LoadStringW(HINST_THISDLL, IDS_DOWNLOADING, wzTemplate, ARRAYSIZE(wzTemplate)));
wnsprintfW(wzStatusText, ARRAYSIZE(wzStatusText), wzTemplate, pwzFileName);
EVAL(SUCCEEDED(pProgInfo->ppd->SetLine(1, wzStatusText, FALSE, NULL)));
// Generate the string "From <SrcFtpUrlDir> to <DestFileDir>" status string
if (EVAL(SUCCEEDED(hr = CreateFromToStr(wzStatusText, ARRAYSIZE(wzStatusText), wzFrom, pwzTo))))
EVAL(SUCCEEDED(hr = pProgInfo->ppd->SetLine(2, wzStatusText, FALSE, NULL))); // Line one is the file being copied.
return hr;
}
/*****************************************************************************\
ConfirmDownloadReplace
Callback procedure that checks if this file really ought to be
copied.
Returns S_OK if the file should be copied.
Returns S_FALSE if the file should not be copied.
- If the user cancelled, then say S_FALSE from now on.
- If the user said Yes to All, then say S_OK.
- If there is no conflict, then say S_OK.
- If the user said No to All, then say S_FALSE.
- Else, ask the user what to do.
Note that the order of the tests above means that if you say
"Yes to All", then we don't waste our time doing overwrite checks.
_GROSS_: NOTE! that we don't try to uniquify the name, because
WinINet doesn't support the STOU (store unique) command, and
there is no way to know what filenames are valid on the server.
\*****************************************************************************/
HRESULT ConfirmDownloadReplace(LPCWSTR pwzDestPath, LPCITEMIDLIST pidlSrcFTP, OPS * pOps, HWND hwnd, CFtpFolder * pff, CFtpDir * pfd, int nObjs, BOOL * pfDeleteRequired)
{
HRESULT hr = S_OK;
ASSERT(hwnd);
*pfDeleteRequired = FALSE;
if (*pOps == opsCancel)
hr = S_FALSE;
else if (*pOps == opsYesToAll)
{
*pfDeleteRequired = PathFileExistsW(pwzDestPath);
hr = S_OK;
}
else
{
if (PathFileExistsW(pwzDestPath))
{
// It exists, so worry.
if (*pOps == opsNoToAll)
hr = S_FALSE;
else
{
FTP_FIND_DATA wfdSrc;
WIN32_FIND_DATA wfdDest;
HANDLE hfindDest;
FILETIME ftUTC;
*pfDeleteRequired = TRUE;
hfindDest = FindFirstFileW(pwzDestPath, &wfdDest);
ftUTC = wfdDest.ftLastWriteTime;
FileTimeToLocalFileTime(&ftUTC, &wfdDest.ftLastWriteTime); // UTC->LocalTime
EVAL(S_OK == Win32FindDataFromPidl(pidlSrcFTP, (LPWIN32_FIND_DATA)&wfdSrc, FALSE, FALSE));
if (EVAL(hfindDest != INVALID_HANDLE_VALUE))
{
// BUGBUG/TODO: Do we need to set modal?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -