📄 ftpobj.cpp
字号:
DESCRIPTION:
Render the data in the requested format and put it into the
STGMEDIUM structure.
\*****************************************************************************/
HRESULT CFtpObj::GetData(LPFORMATETC pfe, LPSTGMEDIUM pstg)
{
int ife;
HRESULT hr;
hr = _FindDataForGet(pfe, &ife);
if (SUCCEEDED(hr))
{
if (ife == DROP_FCont)
hr = _RenderFileContents(pfe, pstg);
else
{
hr = _ForceRender(ife);
if (SUCCEEDED(hr)) // May not succeed for security reasons.
{
ASSERT(m_stgCache[ife].hGlobal);
// It's possible to use the hacking STGMEDIUM.pUnkForRelease to give away
// pointers to our data, but we then need massive amounts of code to babysite
// the lifetime of those pointers. This becomes more work when ::SetData() can
// replace that data, so we just take the hit of the memcpy for less code.
hr = CopyStgMediumWrap(&m_stgCache[ife], pstg);
ASSERT(SUCCEEDED(hr));
ASSERT(NULL == pstg->pUnkForRelease);
//TraceMsg(TF_FTPDRAGDROP, "CFtpObj::GetData() pstg->hGlobal=%#08lx. pstg->pUnkForRelease=%#08lx.", pstg->hGlobal, pstg->pUnkForRelease);
}
}
TraceMsgWithFormat(TF_FTPDRAGDROP, "CFtpObj::GetData()", pfe, "Format in static list", hr);
}
else
{
int nIndex = _FindExtraDataIndex(pfe);
if (-1 == nIndex)
hr = E_FAIL;
else
{
FORMATETC_STGMEDIUM fs;
DSA_GetItem(m_hdsaSetData, nIndex, &fs);
hr = CopyStgMediumWrap(&fs.medium, pstg);
}
TraceMsgWithFormat(TF_FTPDRAGDROP, "CFtpObj::GetData()", pfe, "Looking in dyn list", hr);
}
return hr;
}
/*****************************************************************************\
IDataObject::GetDataHere
Render the data in the requested format and put it into the
object provided by the caller.
\*****************************************************************************/
HRESULT CFtpObj::GetDataHere(FORMATETC *pfe, STGMEDIUM *pstg)
{
TraceMsg(TF_FTPDRAGDROP, "CFtpObj::GetDataHere() pfe->cfFormat=%d.", pfe->cfFormat);
return E_NOTIMPL;
}
/*****************************************************************************\
FUNCTION: IDataObject::QueryGetData
DESCRIPTION:
Indicate whether we could provide data in the requested format.
\*****************************************************************************/
HRESULT CFtpObj::QueryGetData(FORMATETC *pfe)
{
int ife;
HRESULT hr = _FindDataForGet(pfe, &ife);
if (FAILED(hr))
{
// If it wasn't one of the types we offer, see if it was given to us via
// IDataObject::SetData().
int nIndex = _FindExtraDataIndex(pfe);
if (-1 != nIndex)
hr = S_OK;
}
TraceMsgWithFormat(TF_FTPDRAGDROP, "CFtpObj::QueryGetData()", pfe, "", hr);
return hr;
}
/*****************************************************************************\
FUNCTION: IDataObject::GetCanonicalFormatEtc
DESCRIPTION:
Our data are not sensitive to device-specific renderings,
so we do what the book tells us to do.
Or we *try* to do what the book tells us to do.
OLE random documentation of the day:
IDataObject::GetCanonicalFormatEtc.
Turns out that the man page contradicts itself within sentences:
DATA_S_SAMEFORMATETC - The FORMATETC structures are the same
and NULL is returned in pfeOut.
If the data object never provides device-specific renderings,
the implementation of IDataObject::GetCanonicalFormatEtc
simply copies the input FORMATETC to the output FORMATETC,
stores a null in the ptd field, and returns DATA_S_SAMEFORMATETC.
And it turns out that the shell doesn't do *either* of these things.
It just returns DATA_S_SAMEFORMATETC and doesn't touch pfeOut.
The book is even more confused. Under pfeOut, it says
The value is NULL if the method returns DATA_S_SAMEFORMATETC.
This makes no sense. The caller provides the value of pfeOut.
How can the caller possibly know that the method is going to return
DATA_S_SAMEFORMATETC before it calls it? If you expect the
method to write "pfeOut = 0" before returning, you're nuts. That
communicates nothing to the caller.
I'll just do what the shell does.
\*****************************************************************************/
HRESULT CFtpObj::GetCanonicalFormatEtc(FORMATETC *pfeIn, FORMATETC *pfeOut)
{
return DATA_S_SAMEFORMATETC;
}
/*****************************************************************************\
FUNCTION: IDataObject::SetData
DESCRIPTION:
We let people change TYMED_HGLOBAL gizmos, but nothing else.
We need to do a careful two-step when replacing the HGLOBAL.
If the user gave us a plain HGLOBAL without a pUnkForRelease,
we need to invent our own pUnkForRelease to track it. But we
don't want to release the old STGMEDIUM until we're sure we
can accept the new one.
fRelease == 0 makes life doubly interesting, because we also
have to clone the HGLOBAL (and remember to free the clone on the
error path).
_SOMEDAY_/TODO -- Need to support PerformedDropEffect so we can
clean up stuff on a cut/paste.
\*****************************************************************************/
HRESULT CFtpObj::SetData(FORMATETC *pfe, STGMEDIUM *pstg, BOOL fRelease)
{
int ife;
HRESULT hr;
hr = _FindData(pfe, &ife);
if (SUCCEEDED(hr))
{
if (ife == DROP_FCont)
{
TraceMsg(TF_FTPDRAGDROP, "CFtpObj::SetData(FORMATETC.cfFormat=%d) ife == DROP_FCont", pfe->cfFormat);
hr = DV_E_FORMATETC;
}
else
{
ASSERT(g_dropTypes[ife].tymed == TYMED_HGLOBAL);
ASSERT(pstg->tymed == TYMED_HGLOBAL);
if (EVAL(pstg->hGlobal))
{
STGMEDIUM stg = {0};
hr = CopyStgMediumWrap(pstg, &stg);
if (EVAL(SUCCEEDED(hr)))
{
ReleaseStgMedium(&m_stgCache[ife]);
m_stgCache[ife] = stg;
}
}
else
{ // Tried to SetData a _DelayRender
hr = DV_E_STGMEDIUM; // You idiot you
}
}
TraceMsgWithFormat(TF_FTPDRAGDROP, "CFtpObj::SetData()", pfe, "in static list", hr);
}
else
{
hr = _SetExtraData(pfe, pstg, fRelease);
TraceMsgWithFormat(TF_FTPDRAGDROP, "CFtpObj::SetData()", pfe, "in dyn list", hr);
}
return hr;
}
/*****************************************************************************\
FUNCTION: IDataObject::EnumFormatEtc
DESCRIPTION:
_UNDOCUMENTED_: If you drag something from a DefView, it will
check the data object to see if it has a hida. If so, then it
will cook up a CFSTR_SHELLIDLISTOFFSET *for you* and SetData
the information into the data object. So in order to get
position-aware drag/drop working, you must allow DefView to change
your CFSTR_SHELLIDLISTOFFSET.
We allow all FORMATETCs to be modified except for FileContents.
\*****************************************************************************/
HRESULT CFtpObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenum)
{
HRESULT hres;
switch (dwDirection)
{
case DATADIR_GET:
hres = CFtpEfe_Create(DROP_OFFERMAX - DROP_FCont, &g_dropTypes[DROP_FCont],
&m_stgCache[DROP_FCont], this, ppenum);
TraceMsg(TF_FTPDRAGDROP, "CFtpObj::EnumFormatEtc(DATADIR_GET) CFtpEfe_Create() returned hres=%#08lx", hres);
break;
case DATADIR_SET:
hres = CFtpEfe_Create(DROP_OFFERMAX - DROP_OFFERMIN, &g_dropTypes[DROP_OFFERMIN],
&m_stgCache[DROP_OFFERMIN], NULL, ppenum);
TraceMsg(TF_FTPDRAGDROP, "CFtpObj::EnumFormatEtc(DATADIR_SET) CFtpEfe_Create() returned hres=%#08lx", hres);
break;
default:
ASSERT(0);
hres = E_NOTIMPL;
break;
}
return hres;
}
/*****************************************************************************\
FUNCTION: IDataObject::DAdvise
DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpObj::DAdvise(FORMATETC *pfe, DWORD advfl, IAdviseSink *padv, DWORD *pdwConnection)
{
return OLE_E_ADVISENOTSUPPORTED;
}
/*****************************************************************************\
FUNCTION: IDataObject::DUnadvise
DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpObj::DUnadvise(DWORD dwConnection)
{
return OLE_E_ADVISENOTSUPPORTED;
}
/*****************************************************************************\
FUNCTION: IDataObject::EnumDAdvise
DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpObj::EnumDAdvise(IEnumSTATDATA **ppeadv)
{
return OLE_E_ADVISENOTSUPPORTED;
}
/*****************************************************************************\
FUNCTION: CFtpObj_Create
DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpObj_Create(CFtpFolder * pff, CFtpPidlList * pflHfpl, REFIID riid, LPVOID * ppvObj)
{
HRESULT hres;
CFtpObj * pfo;
*ppvObj = NULL;
hres = CFtpObj_Create(pff, pflHfpl, &pfo);
if (EVAL(SUCCEEDED(hres)))
{
pfo->QueryInterface(riid, ppvObj);
pfo->Release();
}
return hres;
}
/*****************************************************************************\
FUNCTION: CFtpObj_Create
DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpObj_Create(CFtpFolder * pff, CFtpPidlList * pflHfpl, CFtpObj ** ppfo)
{
HRESULT hres = S_OK;
if (EVAL(pflHfpl->GetCount()))
{
*ppfo = new CFtpObj();
if (EVAL(*ppfo))
{
CFtpObj * pfo = *ppfo;
pfo->m_pfd = pff->GetFtpDir();
if (EVAL(pfo->m_pfd))
{
pfo->m_pff = pff;
if (pff)
pff->AddRef();
IUnknown_Set(&pfo->m_pflHfpl, pflHfpl);
if (pfo->m_pflHfpl->GetCount() == 1)
{
pfo->m_stgCache[DROP_URL].tymed = TYMED_HGLOBAL;
}
}
else
{
hres = E_FAIL;
(*ppfo)->Release();
*ppfo = NULL;
}
}
else
hres = E_OUTOFMEMORY;
}
else
{
*ppfo = NULL;
hres = E_INVALIDARG; /* Trying to get UI object of nil? */
}
return hres;
}
/*****************************************************************************\
FUNCTION: CFtpObj_Create
DESCRIPTION:
This will be called by the Class Factory when the IDataObject gets
persisted and then wants to be recreated in a new process. (Happens
after the original thread/process calls OleFlushClipboard.
\*****************************************************************************/
HRESULT CFtpObj_Create(REFIID riid, void ** ppvObj)
{
HRESULT hr = E_OUTOFMEMORY;
CFtpObj * pfo = new CFtpObj();
*ppvObj = NULL;
if (pfo)
{
hr = pfo->QueryInterface(riid, ppvObj);
pfo->Release();
}
return hr;
}
#define SETDATA_GROWSIZE 3
/****************************************************\
Constructor
\****************************************************/
CFtpObj::CFtpObj() : m_cRef(1)
{
DllAddRef();
// This needs to be allocated in Zero Inited Memory.
// Assert that all Member Variables are inited to Zero.
ASSERT(!m_pff);
ASSERT(!m_pfd);
ASSERT(!m_pflHfpl);
ASSERT(!m_fDidAsynchStart);
// NT #245306: If the user drags files from an FTP window (Thread 1)
// to a shell window (Thread 2), the shell window will do
// the dr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -