📄 ftpcm.cpp
字号:
// We don't support Delete or Rename from the Caption Bar
if (_IsCallerCaptionBar(indexMenu, uFlags))
sfgao &= ~(SFGAO_CANDELETE | SFGAO_CANRENAME); // Clear these two.
// Not on the "File" menu, and not from a shortcut.
// Add the "Delete", "Rename", etc. stuff, then go
// enable/disable them as needed.
AddToPopupMenu(hmenu, IDM_ITEMCONTEXT, IDM_M_SHAREDVERBS, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
_RemoveContextMenuItems(hmenu, idCmdFirst, sfgao);
}
// Add Download if there is anything inside.
// The assertion makes sure that idCmdLast is set properly.
ASSERT(IDC_ITEM_DOWNLOAD > IDC_ITEM_OPEN);
if (!_IsCallerCaptionBar(indexMenu, uFlags))
{
// Don't add "Copy To Folder" in the caption bar because it doesn't work for the root of
// an ftp server. We aren't going to support it in subdirectories.
AddToPopupMenu(hmenu, IDM_ITEMCONTEXT, IDM_M_VERBS, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
}
if (!(uFlags & CMF_NODEFAULT))
SetMenuDefaultItem(hmenu, IDC_ITEM_DOWNLOAD + idCmdFirst, MM_ADDSEPARATOR);
AddToPopupMenu(hmenu, IDM_ITEMCONTEXT, (fAllFolders ? IDM_M_FOLDERVERBS : IDM_M_FILEVERBS), indexMenu, idCmdFirst,
idCmdLast, (_IsCallerCaptionBar(indexMenu, uFlags) ? 0 : MM_ADDSEPARATOR));
if (fAllFolders && (SHELL_VERSION_W95NT4 == GetShellVersion()))
{
// On shell32 v3 (Win95 & NT4) I remove the 'Explore' verb because the shell has bugs
// that aren't fixable are easy to fix.
EVAL(DeleteMenu(hmenu, (IDC_ITEM_EXPLORE + idCmdFirst), MF_BYCOMMAND));
TraceMsg(TF_FTPOPERATION, "QueryContextMenu() Removing 'Explorer' because it's shell v3");
SetMenuDefaultItem(hmenu, idCmdFirst + IDC_ITEM_OPEN, 0);
}
else if (!(uFlags & CMF_NODEFAULT))
SetMenuDefaultItem(hmenu, idCmdFirst + (((uFlags & CMF_EXPLORE) && fAllFolders)? IDC_ITEM_EXPLORE : IDC_ITEM_OPEN), 0);
}
else
{ // Folder background menu
AddToPopupMenu(hmenu, IDM_ITEMCONTEXT, IDM_M_BACKGROUNDVERBS, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
// Did the menu come from the file menu?
if (CMF_DVFILE == (CMF_DVFILE & uFlags))
{
// Yes, then we want to delete the "Properties" background menu item because one
// was already merged in for the selected files. The other Properties will
// be there but grayed out if nothing was selected.
EVAL(DeleteMenu(hmenu, (IDC_ITEM_BKGNDPROP + idCmdFirst), MF_BYCOMMAND));
}
MergeInToPopupMenu(hmenu, IDM_M_BACKGROUND_POPUPMERGE, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
}
if (EVAL(SUCCEEDED(hr)))
hr = ResultFromShort(IDC_ITEM_MAX);
_SHPrettyMenu(hmenu);
return hr;
}
/*****************************************************************************\
*
* IContextMenu::GetCommandString
*
* Somebody wants to convert a command id into a string of some sort.
*
\*****************************************************************************/
HRESULT CFtpMenu::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwRsv, LPSTR pszName, UINT cchMax)
{
HRESULT hr = E_FAIL;
BOOL fUnicode = FALSE;
if (idCmd < IDC_ITEM_MAX)
{
switch (uFlags)
{
case GCS_HELPTEXTW:
fUnicode = TRUE;
// Fall thru...
case GCS_HELPTEXTA:
GetHelpText:
if (EVAL(cchMax))
{
BOOL fResult;
pszName[0] = '\0';
if (fUnicode)
fResult = LoadStringW(HINST_THISDLL, IDS_ITEM_HELP((UINT)idCmd), (LPWSTR)pszName, cchMax);
else
fResult = LoadStringA(HINST_THISDLL, IDS_ITEM_HELP((UINT)idCmd), pszName, cchMax);
if (EVAL(fResult))
hr = S_OK;
else
hr = E_INVALIDARG;
}
else
hr = E_INVALIDARG;
break;
case GCS_VALIDATEW:
case GCS_VALIDATEA:
hr = S_OK;
break;
case GCS_VERBW:
fUnicode = TRUE;
// Fall thru...
case GCS_VERBA:
{
int ivi;
for (ivi = 0; ivi < IVI_MAX; ivi++)
{
if (c_rgvi[ivi].idc == idCmd)
{
if (fUnicode)
SHTCharToUnicode(c_rgvi[ivi].ptszCmd, (LPWSTR)pszName, cchMax);
else
SHTCharToAnsi(c_rgvi[ivi].ptszCmd, pszName, cchMax);
hr = S_OK;
break;
}
}
if (!EVAL(ivi < IVI_MAX))
hr = E_INVALIDARG;
break;
}
default:
hr = E_NOTIMPL;
break;
}
}
else
{
// _UNOBVIOUS_: Another place where PASTE rears its ugly head.
// We must generate the help text for it ourselves, even though
// the menu item "sort of" belongs to the shell.
if ((idCmd == SHARED_EDIT_PASTE) &&
((uFlags == GCS_HELPTEXTW) || (uFlags == GCS_HELPTEXTA)))
{
goto GetHelpText;
}
hr = E_INVALIDARG;
}
return hr;
}
HRESULT UpdateDeleteProgressStr(IProgressDialog * ppd, LPCTSTR pszFileName)
{
HRESULT hr = E_FAIL;
TCHAR szTemplate[MAX_PATH];
if (EVAL(LoadString(HINST_THISDLL, IDS_DELETING, szTemplate, ARRAYSIZE(szTemplate))))
{
TCHAR szStatusStr[MAX_PATH];
WCHAR wzStatusStr[MAX_PATH];
wnsprintf(szStatusStr, ARRAYSIZE(szStatusStr), szTemplate, pszFileName);
SHTCharToUnicode(szStatusStr, wzStatusStr, ARRAYSIZE(wzStatusStr));
EVAL(SUCCEEDED(hr = ppd->SetLine(2, wzStatusStr, FALSE, NULL)));
}
return hr;
}
HRESULT FtpChangeNotifyDirPatch(HWND hwnd, LONG wEventId, CFtpFolder * pff, LPCITEMIDLIST pidlFull, LPCITEMIDLIST pidl2, BOOL fTopLevel)
{
HRESULT hr = S_OK;
LPITEMIDLIST pidlParent = ILClone(pidlFull);
if (pidlParent)
{
ILRemoveLastID(pidlParent);
CFtpDir * pfd = pff->GetFtpDirFromPidl(pidlParent);
if (pfd)
{
FtpChangeNotify(hwnd, wEventId, pff, pfd, ILFindLastID(pidlFull), pidl2, fTopLevel);
pfd->Release();
}
ILFree(pidlParent);
}
return hr;
}
// The following struct is used when recursively downloading
// files/dirs from the FTP server after a "Download" verb.
typedef struct tagDELETESTRUCT
{
LPCITEMIDLIST pidlRoot; // Base URL of the Download Source
CFtpFolder * pff; // Allocator to create temp pidls.
IMalloc * pm; // Allocator to create temp pidls.
LPCMINVOKECOMMANDINFO pdoi; // Our call.
HWND hwnd; // HWND for UI
CStatusBar * psb; // Used to display info during the delete
IProgressDialog * ppd; // Used to display progress during the delete.
DWORD dwTotalFiles; // How many files are there to delete total.
DWORD dwDeletedFiles; // How many files have already been deleted.
BOOL fInDeletePass; // Are we in the 'Count Files to Delete' or 'Delete Files' pass?
} DELETESTRUCT;
/*****************************************************************************\
FUNCTION: DeleteItemCB
DESCRIPTION:
This function will download the specified item and it's contents if it
is a directory.
\*****************************************************************************/
HRESULT _DeleteItemPrep(HINTERNET hint, LPCITEMIDLIST pidlFull, BOOL fIsTopLevel, DELETESTRUCT * pDelete)
{
HRESULT hr = S_OK;
if (pDelete->ppd && pDelete->ppd->HasUserCancelled())
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
if (SUCCEEDED(hr)) // May have been cancelled
{
DWORD dwError = 0;
if (pDelete->fInDeletePass && pDelete->psb)
pDelete->psb->SetStatusMessage(IDS_DELETING, FtpPidl_GetLastFileDisplayName(pidlFull));
if (pDelete->fInDeletePass && pDelete->ppd)
EVAL(SUCCEEDED(UpdateDeleteProgressStr(pDelete->ppd, FtpPidl_GetLastFileDisplayName(pidlFull))));
// Is this a dir/folder that we need to recurse into? OR
// Is this a SoftLink?
if ((FILE_ATTRIBUTE_DIRECTORY & FtpPidl_GetAttributes(pidlFull)) ||
(0 == FtpPidl_GetAttributes(pidlFull)))
{
// This is the head of the recursion. We will do nothing now and we will
// wait to delete the dir in the recursion tail because we need to wait
// until all the files are gone.
// Don't delete softlinks because of the recursion problem.
}
else
{
if (pDelete->fInDeletePass)
{
if (pDelete->ppd)
EVAL(SUCCEEDED(pDelete->ppd->SetProgress(pDelete->dwDeletedFiles, pDelete->dwTotalFiles)));
// Contemplate adding a callback function in order to feed the status bar.
hr = FtpDeleteFileWrap(hint, TRUE, FtpPidl_GetLastItemWireName(pidlFull));
if (FAILED(hr))
{
// We need to display the error now while the extended error info is still valid.
// This is because as we walk out of the resursive call, we will be calling
// FtpSetCurrentDirectory() which will wipe clean the extended error msg.
if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr))
{
DisplayWininetError(pDelete->hwnd, TRUE, HRESULT_CODE(hr), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_DELETE, IDS_FTPERR_WININET, MB_OK, pDelete->ppd);
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Wrong permissions
}
}
else
FtpChangeNotifyDirPatch(pDelete->hwnd, SHCNE_DELETE, pDelete->pff, pidlFull, NULL, fIsTopLevel);
pDelete->dwDeletedFiles++;
TraceMsg(TF_FTPOPERATION, "DeleteItemCB() FtpDeleteFileA() returned dwError=%#08lx. File=%s", dwError, FtpPidl_GetLastFileDisplayName(pidlFull));
}
else
pDelete->dwTotalFiles++;
}
}
return hr;
}
HRESULT _DeleteItemCleanUp(HRESULT hr, DELETESTRUCT * pDelete)
{
if (pDelete->ppd && pDelete->ppd->HasUserCancelled())
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
if (pDelete->fInDeletePass) // Only display errors and fire ChangeNotify if in Delete pass.
{
if ((FAILED(hr)) && (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr))
{
int nResult = DisplayWininetError(pDelete->hwnd, TRUE, HRESULT_CODE(hr), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_DELETE, IDS_FTPERR_WININET, MB_OK, pDelete->ppd);
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Don't display any more error dialogs.
}
}
return hr;
}
HRESULT FtpRemoveDirectoryWithCN(HWND hwnd, HINTERNET hint, CFtpFolder * pff, LPCITEMIDLIST pidlFull, BOOL fIsTopLevel)
{
HRESULT hr = S_OK;
hr = FtpRemoveDirectoryWrap(hint, TRUE, FtpPidl_GetLastItemWireName(pidlFull));
if (SUCCEEDED(hr))
{
hr = FtpChangeNotifyDirPatch(hwnd, SHCNE_RMDIR, pff, pidlFull, NULL, fIsTopLevel);
TraceMsg(TF_WININET_DEBUG, "FtpRemoveDirectoryWithCN() FtpRemoveDirectory(%hs) returned %#08lx", FtpPidl_GetLastItemWireName(pidlFull), hr);
}
return hr;
}
INT ILCountItemIDs(LPCITEMIDLIST pidl)
{
INT nCount = 0;
if (pidl)
{
while (!ILIsEmpty(pidl))
{
pidl = _ILNext(pidl);
nCount++;
}
}
return nCount;
}
/*****************************************************************************\
FUNCTION: _IsTopLevel
DESCRIPTION:
\*****************************************************************************/
BOOL _IsTopLevel(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidlCurrent)
{
INT nRoot = ILCountItemIDs(pidlRoot);
INT nCurrent = ILCountItemIDs(pidlCurrent);
// It is the root if nCurrent has no more than 1 more than nRoot
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -