📄 ftpcm.cpp
字号:
{
ASSERT(ILIsSimple(pidl));
if (GetAsyncKeyState(VK_ESCAPE) >= 0)
{
if (EVAL(SUCCEEDED(peii->hres)))
peii->hres = peii->pfn(peii->pfcm, peii->pici, peii->ptszCmd, pidl);
}
else
peii->hres = HRESULT_FROM_WIN32(ERROR_CANCELLED);
return SUCCEEDED(peii->hres);
}
/*****************************************************************************\
*
* _EnumInvoke
*
* Invoke the command on each object in the list, assuming that
* permissions are properly set. (We need to check the permissions
* in case somebody randomly threw the verb at us.)
*
\*****************************************************************************/
STDMETHODIMP CFtpMenu::_EnumInvoke(LPCMINVOKECOMMANDINFO pici, INVOKEPROC pfn, LPCTSTR pszCmd)
{
EII eii;
eii.pfcm = this;
eii.pici = pici;
eii.pfn = pfn;
eii.ptszCmd = pszCmd;
eii.hres = S_OK;
if (m_pflHfpl->GetCount())
m_pflHfpl->Enum(_InvokeOneCB, (LPVOID) &eii);
else
_InvokeOne(c_pidlNil, &eii);
return eii.hres;
}
/*****************************************************************************\
*
* _InvokeRename
*
* Rename the object to the indicated name.
*
* The rename verb should have been enabled only if the pidl list
* is singleton. Of course, that doesn't prevent some random bozo
* from throwing the word "rename" at us from out of the blue, so
* we need to remain on guard.
*
* _UNOBVIOUS_: If the user does an in-place rename, we don't get
* a "rename" command invoked against our context menu. Instead,
* the shell goes straight for the SetNameOf method in the ShellFolder.
* Which means that we cannot put UI in the context menu (which is the
* obvious place for it, because it has a CMIC_MASK_FLAG_NO_UI bit);
* we must put it into SetNameOf, which is annoying because it means
* there is no way to programmatically perform a SetNameOf without UI.
*
* _SOMEDAY_
* We fix this unobvious-ness by passing the CMIC_MASK_FLAG_NO_UI bit
* through to our SetNameOf backdoor, so you can programmatically
* rename a file without UI by going through the IContextMenu.
*
\*****************************************************************************/
HRESULT CFtpMenu::_InvokeRename(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr;
if (EVAL((m_sfgao & SFGAO_CANRENAME) && m_pfd))
{
ASSERT(m_pflHfpl->GetCount() == 1);
if (EVAL(pici->lpParameters))
{
TCHAR szParams[MAX_URL_STRING];
ASSERT(pici->hwnd);
SHAnsiToTChar(pici->lpParameters, szParams, ARRAYSIZE(szParams));
hr = m_pfd->SetNameOf(m_pff, pici->hwnd, m_pflHfpl->GetPidl(0), szParams, SHGDN_INFOLDER, 0);
}
else
hr = E_INVALIDARG; // Arguments required
}
else
hr = E_ACCESSDENIED; // Can't rename this
return hr;
}
/*****************************************************************************\
* _InvokeCutCopy
*
* Cut or copy the selection to the OLE clipboard. No big deal.
*
* Note that GetUIObjectOfHfpl(IID_IDataObject) will fail if we
* are talking about ourself. Maybe it shouldn't but it does today.
\*****************************************************************************/
HRESULT CFtpMenu::_InvokeCutCopy(UINT_PTR id, LPCMINVOKECOMMANDINFO pici)
{
IDataObject * pdo;
HRESULT hr;
hr = m_pff->GetUIObjectOfHfpl(pici->hwnd, m_pflHfpl, IID_IDataObject, (LPVOID *)&pdo, m_fBackground);
if (EVAL(SUCCEEDED(hr)))
{
DWORD dwEffect = ((DFM_CMD_COPY == id) ? DROPEFFECT_COPY : DROPEFFECT_MOVE);
EVAL(SUCCEEDED(DataObj_SetPreferredEffect(pdo, dwEffect)));
ShellFolderView_SetPoints(m_hwnd, pdo);
hr = OleSetClipboard(pdo); // Will do its own AddRef
ShellFolderView_SetClipboard(m_hwnd, id);
if (pdo)
pdo->Release();
}
else
ASSERT(0); // BUGBUG -- error UI
return hr;
}
/*****************************************************************************\
FUNCTION: _DoDrop
DESCRIPTION:
The user just did a Paste on FTP so we want to do the operation.
We will use our Drag & Drop code to carry out the operation. We don't
currently support optimized FTP operations but a lot could be done if
we did.
First we need to find out if the caller did "Cut" or "Copy" to create
the IDataObject. We can find out by asking the IDataObject for the
CFSTR_PREFERREDDROPEFFECT.
\*****************************************************************************/
HRESULT CFtpMenu::_DoDrop(IDropTarget * pdt, IDataObject * pdo)
{
POINTL pt = {0, 0};
DWORD dwEffect = DROPEFFECT_COPY; // Default
HRESULT hr = DataObj_GetDWORD(pdo, g_dropTypes[DROP_PrefDe].cfFormat, &dwEffect);
#ifndef FEATURE_CUT_MOVE
dwEffect = DROPEFFECT_COPY; // Forcibly remove the MOVE effect
#endif // FEATURE_CUT_MOVE
hr = pdt->DragEnter(pdo, MK_LBUTTON, pt, &dwEffect);
if (EVAL(SUCCEEDED(hr)) && dwEffect)
{
#ifndef FEATURE_CUT_MOVE
dwEffect = DROPEFFECT_COPY; // Forcibly remove the MOVE effect
#endif // FEATURE_CUT_MOVE
hr = pdt->Drop(pdo, MK_LBUTTON, pt, &dwEffect);
}
else
pdt->DragLeave();
return hr;
}
/*****************************************************************************\
*
* _InvokePaste
*
* Copy from the OLE clipboard into the selcted folder (which might
* be ourselves).
*
\*****************************************************************************/
HRESULT CFtpMenu::_InvokePaste(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hres = E_FAIL;
if (EVAL(m_sfgao & SFGAO_DROPTARGET))
{
IDataObject *pdto;
hres = OleGetClipboard(&pdto);
if (EVAL(SUCCEEDED(hres)))
{
IDropTarget *pdt;
hres = m_pff->GetUIObjectOfHfpl(pici->hwnd, m_pflHfpl, IID_IDropTarget, (LPVOID *)&pdt, m_fBackground);
if (EVAL(SUCCEEDED(hres)))
{
hres = _DoDrop(pdt, pdto);
if (pdt)
pdt->Release();
}
else
{
// BUGBUG -- error UI
}
if (pdto)
pdto->Release();
}
else
{
// BUGBUG -- error UI
}
}
else
{
// BUGBUG -- error UI
}
return hres;
}
//===========================
// *** IContextMenu Interface ***
//===========================
/*****************************************************************************\
FUNCTION: _ContainsForgroundItems
DESCRIPTION:
We want to know if the user selected items in the view and then invoked
some menu (Context Menu, File Menu, CaptionBar icon menu, etc.). Normally
this is as simple as seeing if (0 == m_pflHfpl->GetCount()). However,
there is one other nasty case where (1 == m_pflHfpl->GetCount()) and
the user still didn't select anything. This case happens when the user
is at the root of a FTP share and the CaptionBar menu is dropped down.
In that case, the single pidl is the pidl to the ftp root.
\*****************************************************************************/
BOOL CFtpMenu::_ContainsForgroundItems(void)
{
BOOL fIsForground = (0 != m_pflHfpl->GetCount());
if (fIsForground && (1 == m_pflHfpl->GetCount()))
{
LPITEMIDLIST pidl = m_pflHfpl->GetPidl(0);
if (FtpID_IsServerItemID(pidl) && ILIsEmpty(_ILNext(pidl)))
{
if (!m_pfd)
{
CFtpSite * pfs;
// In this strange case, our m_pfd is NULL, so we need
// to create it from pidl.
if (EVAL(SUCCEEDED(SiteCache_PidlLookup(pidl, FALSE, m_pff->GetItemAllocatorDirect(), &pfs))))
{
EVAL(SUCCEEDED(pfs->GetFtpDir(pidl, &m_pfd)));
pfs->Release();
}
}
fIsForground = FALSE;
}
}
return fIsForground;
}
BOOL CFtpMenu::_IsCallerCaptionBar(UINT indexMenu, UINT uFlags)
{
BOOL fFromCaptionBar;
if ((0 == uFlags) && (1 == indexMenu))
fFromCaptionBar = TRUE;
else
fFromCaptionBar = FALSE;
return fFromCaptionBar;
}
/*****************************************************************************\
FUNCTION: IContextMenu::QueryContextMenu
DESCRIPTION:
Given an existing context menu hmenu, insert new context menu
items at location indexMenu (indexMenu = index to menu indexMenu), returning the
number of menu items added.
The incoming flags control how much goop we add to the menu.
It is important not to add "Delete", "Rename", etc., to context
menus that come from shortcuts, else the user gets hit with
two "Delete" verbs, one to delete the object from the FTP site,
and the other to delete the shortcut. How confusing...
hmenu - destination menu
indexMenu - location at which menu items should be inserted
idCmdFirst - first available menu identifier
idCmdLast - first unavailable menu identifier
_UNDOCUMENTED_: The "shared" menu items are not documented.
Particularly gruesome, because the "shared" menu items are the
only way to get Rename, Delete, etc. to work. You can't roll
your own, because those magics are handled partly in the
enclosing shell view.
_UNOBVIOUS_: The context menu for the folder itself is
extremely squirly. It's not like a normal context menu.
Rather, you add the "New" verb, and any custom verbs, but
none of the standard folder verbs.
PARAMS:
Often, we need to key off strange parameter heiristicts to
determine who our caller is so we don't enable certain items.
"Rename" from the from CaptionBar is one example. Here are what
we are passed in the different situations:
CaptionBar:
QCM(hmenu, 1, idCmdFirst, idCmdLast, 0) m_pflHfpl contains 1
FileMenu w/1 Selected:
QCM(hmenu, 0, idCmdFirst, idCmdLast, CMF_DVFILE | CMF_NODEFAULT) m_pflHfpl contains 1
0 Items Selected:
QCM(hmenu, -1, idCmdFirst, idCmdLast, 0) m_pflHfpl contains 0
1 Items Selected:
QCM(hmenu, 0, idCmdFirst, idCmdLast, CMF_CANRENAME) m_pflHfpl contains 1
2 Items Selected:
QCM(hmenu, 0, idCmdFirst, idCmdLast, CMF_CANRENAME) m_pflHfpl contains 2
\*****************************************************************************/
HRESULT CFtpMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
HRESULT hr = S_OK;
// HACK: I assume that they are querying during a WM_INITMENUPOPUP or equivelant
GetCursorPos(&m_ptNewItem);
m_uFlags = uFlags;
if (!m_fBackground)
{
BOOL fAllFolders = m_pflHfpl->AreAllFolders();
// _UNDOCUMENTED_: CMF_DVFILE is not a documented flag.
if (!(uFlags & (CMF_DVFILE | CMF_VERBSONLY)))
{
DWORD sfgao = m_sfgao;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -