📄 ftpobj.cpp
字号:
/*****************************************************************************
*
* ftpobj.cpp - IDataObject interface
*
*****************************************************************************/
#include "priv.h"
#include "ftpobj.h"
#include "ftpurl.h"
#include <shlwapi.h>
// CLSIDs
// {299D0193-6DAA-11d2-B679-006097DF5BD4}
const GUID CLSID_FtpDataObject = { 0x299d0193, 0x6daa, 0x11d2, 0xb6, 0x79, 0x0, 0x60, 0x97, 0xdf, 0x5b, 0xd4 };
/*****************************************************************************
*
* g_dropTypes conveniently mirrors our FORMATETCs.
*
* Hardly coincidence, of course. Enum_Fe did the real work.
*
*****************************************************************************/
/*****************************************************************************
*
* Preinitialized global data.
*
*****************************************************************************/
FORMATETC g_formatEtcOffsets;
FORMATETC g_formatPasteSucceeded;
CLIPFORMAT g_cfTargetCLSID;
FORMATETC g_dropTypes[] =
{
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_ISTREAM }, // DROP_FCont
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_FGDW
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_FGDA
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_IDList
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_URL
// { 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_Offsets
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_PrefDe
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_PerfDe
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_FTP_PRIVATE
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_OLEPERSIST - see _RenderOlePersist() for desc.
{ CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_Hdrop
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, // DROP_FNMA
{ 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } // DROP_FNMW
};
/*****************************************************************************\
GLOBAL: c_stgInit
DESCRIPTION:
Mostly straightforward. The only major weirdness is that cfURL
is delay-rendered iff the m_pflHfpl contains only one object. Otherwise,
cfURL is not supported. (URLs can refer to only one object at a time.)
\*****************************************************************************/
STGMEDIUM c_stgInit[] =
{
{ 0, 0, 0 }, // DROP_FCont
{ TYMED_HGLOBAL, 0, 0 }, // DROP_FGDW - delay-rendered
{ TYMED_HGLOBAL, 0, 0 }, // DROP_FGDA - delay-rendered
{ TYMED_HGLOBAL, 0, 0 }, // DROP_IDList - delay-rendered
{ 0, 0, 0 }, // DROP_URL - opt delay-rendered
// { 0, 0, 0 }, // DROP_Offsets
{ TYMED_HGLOBAL, 0, 0 }, // DROP_PrefDe - delay-rendered
{ 0, 0, 0 }, // DROP_PerfDe
{ TYMED_HGLOBAL, 0, 0 }, // DROP_FTP_PRIVATE
{ TYMED_HGLOBAL, 0, 0 }, // DROP_OLEPERSIST - see _RenderOlePersist() for desc.
{ 0, 0, 0 }, // DROP_Hdrop
{ 0, 0, 0 }, // DROP_FNMA
{ 0, 0, 0 } // DROP_FNMW
};
/*****************************************************************************\
FUNCTION: TraceMsgWithFormatEtc
DESCRIPTION:
\*****************************************************************************/
void TraceMsgWithFormat(DWORD dwFlags, LPCSTR pszBefore, LPFORMATETC pFormatEtc, LPCSTR pszAfter, HRESULT hr)
{
#ifdef DEBUG
TCHAR szFormatName[MAX_PATH];
TCHAR szMedium[MAX_PATH];
szFormatName[0] = 0;
szMedium[0] = 0;
if (pFormatEtc)
{
// This may fail if it's a basic format.
if (!GetClipboardFormatName(pFormatEtc->cfFormat, szFormatName, ARRAYSIZE(szFormatName)))
wnsprintf(szFormatName, ARRAYSIZE(szFormatName), TEXT("Pre-defined=%d"), pFormatEtc->cfFormat);
switch (pFormatEtc->tymed)
{
case TYMED_HGLOBAL: StrCpyN(szMedium, TEXT("HGLOBAL"), ARRAYSIZE(szMedium)); break;
case TYMED_FILE: StrCpyN(szMedium, TEXT("File"), ARRAYSIZE(szMedium)); break;
case TYMED_GDI: StrCpyN(szMedium, TEXT("GDI"), ARRAYSIZE(szMedium)); break;
case TYMED_MFPICT: StrCpyN(szMedium, TEXT("MFPICT"), ARRAYSIZE(szMedium)); break;
case TYMED_ENHMF: StrCpyN(szMedium, TEXT("ENHMF"), ARRAYSIZE(szMedium)); break;
case TYMED_ISTORAGE: StrCpyN(szMedium, TEXT("ISTORAGE"), ARRAYSIZE(szMedium)); break;
case TYMED_ISTREAM: StrCpyN(szMedium, TEXT("ISTREAM"), ARRAYSIZE(szMedium)); break;
}
}
else
{
szMedium[0] = 0;
}
TraceMsg(dwFlags, "%hs [FRMTETC: %ls, lndx: %d, %ls] hr=%#08lx, %hs", pszBefore, szFormatName, pFormatEtc->lindex, szMedium, hr, pszAfter);
#endif // DEBUG
}
/*****************************************************************************\
FUNCTION: _IsLindexOkay
DESCRIPTION:
If ife != DROP_FCont, then pfeWant->lindex must be -1.
If ife == DROP_FCont, then pfeWant->lindex must be in the range
0 ... m_pflHfpl->GetCount() - 1
\*****************************************************************************/
BOOL CFtpObj::_IsLindexOkay(int ife, FORMATETC *pfeWant)
{
BOOL fResult;
if (ife != DROP_FCont)
fResult = pfeWant->lindex == -1;
else
fResult = (LONG)pfeWant->lindex < m_pflHfpl->GetCount();
return fResult;
}
/*****************************************************************************\
FUNCTION: _FindData
DESCRIPTION:
Locate our FORMATETC/STGMEDIUM given a FORMATETC from somebody else.
On success, stores the index found into *piOut.
We do not allow clients to change the TYMED of a FORMATETC, so
in fact checking the TYMED is what we want, even on a SetData.
\*****************************************************************************/
HRESULT CFtpObj::_FindData(FORMATETC *pfe, PINT piOut)
{
int nIndex;
HRESULT hres = DV_E_FORMATETC;
*piOut = 0;
for (nIndex = DROP_FCont; nIndex < DROP_OFFERMAX; nIndex++)
{
ASSERT(0 == (g_dropTypes[nIndex]).ptd);
ASSERT(g_dropTypes[nIndex].dwAspect == DVASPECT_CONTENT);
if ((pfe->cfFormat == g_dropTypes[nIndex].cfFormat) && !ShouldSkipDropFormat(nIndex))
{
if (EVAL(g_dropTypes[nIndex].ptd == NULL))
{
if (EVAL(pfe->dwAspect == DVASPECT_CONTENT))
{
if (EVAL(g_dropTypes[nIndex].tymed & pfe->tymed))
{
if (EVAL(_IsLindexOkay(nIndex, pfe)))
{
*piOut = nIndex;
hres = S_OK;
}
else
hres = DV_E_LINDEX;
}
else
hres = DV_E_TYMED;
}
else
hres = DV_E_DVASPECT;
}
else
hres = DV_E_DVTARGETDEVICE;
break;
}
}
return hres;
}
/*****************************************************************************\
FUNCTION: _FindDataForGet
DESCRIPTION:
Locate our FORMATETC/STGMEDIUM given a FORMATETC from somebody else.
On success, stores the index found into *piOut. Unlike _FindData, we will
fail the call if the data object doesn't currently have the clipboard format.
(Delayed render counts as "currently having it". What we are filtering out
are formats for which GetData will necessarily fail.)
\*****************************************************************************/
HRESULT CFtpObj::_FindDataForGet(FORMATETC *pfe, PINT piOut)
{
HRESULT hr = _FindData(pfe, piOut);
// TODO: g_cfHIDA should return an array of pidls for each folder.
// If we do this, the caller will support creating Shortcuts
// (LNK files) that point to these pidls. We may want to do
// that later.
if (SUCCEEDED(hr))
{
if (*piOut != DROP_FCont)
{
if (m_stgCache[*piOut].tymed)
{
// Do we have data at all?
// (possibly delay-rendered)
}
else
hr = DV_E_FORMATETC; // I guess not
}
else
{
// File contents always okay
}
}
#ifdef DEBUG
if (FAILED(hr))
{
//TraceMsg(TF_FTPDRAGDROP, "CFtpObj::_FindDataForGet(FORMATETC.cfFormat=%d) Failed.", pfe->cfFormat);
*piOut = 0xBAADF00D;
}
#endif
return hr;
}
// The following are used to enumerate sub directories when creating a list of pidls for
// a directory download (Ftp->FileSys).
typedef struct tagGENPIDLLIST
{
CFtpPidlList * ppidlList;
IMalloc * pm;
IProgressDialog * ppd;
CWireEncoding * pwe;
} GENPIDLLIST;
/*****************************************************************************\
FUNCTION: ProcessItemCB
DESCRIPTION:
This function will add the specified pidl to the list. It will then
detect if it's a folder and if so, will call EnumFolder() to recursively
enum it's contents and call ProcessItemCB() for each one.
PARAMETERS:
\*****************************************************************************/
HRESULT ProcessItemCB(LPVOID pvFuncCB, HINTERNET hint, LPCITEMIDLIST pidlFull, BOOL * pfValidhinst, LPVOID pvData)
{
GENPIDLLIST * pGenPidlList = (GENPIDLLIST *) pvData;
HRESULT hr = S_OK;
// Does the user want to cancel?
if (pGenPidlList->ppd && pGenPidlList->ppd->HasUserCancelled())
{
EVAL(SUCCEEDED(pGenPidlList->ppd->StopProgressDialog()));
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
if (SUCCEEDED(hr))
{
// No, don't cancel so continue...
// Add everything except SoftLinks.
// This is because dir SoftLinks may cause infinite recurion.
// Someday, we may want to upload a shortcut but
// that's too much work for now.
if (0 != FtpPidl_GetAttributes(pidlFull))
{
// We exist to do this:
pGenPidlList->ppidlList->InsertSorted(pidlFull);
}
// Is this a dir/folder that we need to recurse into?
if (SUCCEEDED(hr) && (FILE_ATTRIBUTE_DIRECTORY & FtpPidl_GetAttributes(pidlFull)))
{
hr = EnumFolder((LPFNPROCESSITEMCB) pvFuncCB, hint, pidlFull, pGenPidlList->pwe, pfValidhinst, pvData);
}
}
return hr;
}
/*****************************************************************************\
FUNCTION: _ExpandPidlListRecursively
DESCRIPTION:
This function will take the pidl list (ppidlListSrc) and call into it
to enumerate. It will provide ProcessItemCB as the callback function.
This function will help it create a new CFtpPidlList which will not only
contain the pidls in a base folder, but also all the pidls in any subfolders
that are in the original list.
Delay-render a file group descriptor.
\*****************************************************************************/
CFtpPidlList * CFtpObj::_ExpandPidlListRecursively(CFtpPidlList * ppidlListSrc)
{
GENPIDLLIST pep = {0};
pep.ppidlList = NULL;
pep.ppd = m_ppd;
pep.pwe = m_pff->GetCWireEncoding();
if (SUCCEEDED(CFtpPidlList_Create(0, NULL, &pep.ppidlList)))
{
m_pff->GetItemAllocator(&pep.pm);
if (EVAL(m_pfd) && EVAL(pep.pm))
{
HINTERNET hint;
if (SUCCEEDED(m_pfd->GetHint(NULL, NULL, &hint, NULL, m_pff)))
{
LPITEMIDLIST pidlRoot = ILClone(m_pfd->GetPidlReference());
if (EVAL(pidlRoot))
{
HRESULT hr = ppidlListSrc->RecursiveEnum(pidlRoot, ProcessItemCB, hint, (LPVOID) &pep);
if (m_ppd)
EVAL(SUCCEEDED(m_ppd->StopProgressDialog()));
if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) && !m_fErrAlreadyDisplayed)
{
pep.ppidlList->Release();
pep.ppidlList = NULL;
// Oh, I want a real hwnd, but where or where can I get one?
DisplayWininetErrorEx(NULL, TRUE, HRESULT_CODE(hr), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_DROPFAIL, IDS_FTPERR_WININET, MB_OK, NULL, NULL);
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Wrong permissions
// We need to suppress subsequent error dlgs from this location
// because callers like to ask for FILEGROUPDESCRIPTORA and
// if that fails, ask for FILEGROUPDESCRIPTORW and we don't
// want an error dialog for each.
m_fErrAlreadyDisplayed = TRUE;
}
ILFree(pidlRoot);
}
m_pfd->ReleaseHint(hint);
pep.pm->Release();
}
}
}
return pep.ppidlList;
}
/*****************************************************************************\
FUNCTION: _DelayRender_FGD
DESCRIPTION:
Delay-render a file group descriptor
\*****************************************************************************/
HGLOBAL CFtpObj::_DelayRender_FGD(BOOL fUnicode)
{
HGLOBAL hGlobal = NULL;
if (m_fCheckSecurity &&
ZoneCheckPidlAction(SAFECAST(this, IInternetSecurityMgrSite *), URLACTION_SHELL_FILE_DOWNLOAD, m_pff->GetPrivatePidlReference(), (PUAF_DEFAULT | PUAF_WARN_IF_DENIED)))
{
m_pflHfpl->TraceDump(m_pff->GetPrivatePidlReference(), TEXT("_DelayRender_FGD() TraceDump before"));
CFtpPidlList * pPidlList;
if (!m_fFGDRendered)
{
pPidlList = _ExpandPidlListRecursively(m_pflHfpl);
if (pPidlList)
{
// We succeeded so now it's expanded.
m_fFGDRendered = TRUE;
}
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -