windows-nt/Source/XPSP1/NT/shell/ext/cscui/items.cpp
2020-09-26 16:20:57 +08:00

641 lines
15 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: items.cpp
//
//--------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <shlwapip.h> // QITAB, QISearch
#include <shsemip.h> // ILFree(), etc
#include "folder.h"
#include "items.h"
#include "strings.h"
CLIPFORMAT COfflineItemsData::m_cfHDROP;
CLIPFORMAT COfflineItemsData::m_cfFileContents;
CLIPFORMAT COfflineItemsData::m_cfFileDesc;
CLIPFORMAT COfflineItemsData::m_cfPreferedEffect;
CLIPFORMAT COfflineItemsData::m_cfPerformedEffect;
CLIPFORMAT COfflineItemsData::m_cfLogicalPerformedEffect;
CLIPFORMAT COfflineItemsData::m_cfDataSrcClsid;
COfflineItemsData::COfflineItemsData(
LPCITEMIDLIST pidlFolder,
UINT cidl,
LPCITEMIDLIST *apidl,
HWND hwndParent,
IShellFolder *psfOwner, // Optional. Default is NULL.
IDataObject *pdtInner // Optional. Default is NULL.
) : CIDLData(pidlFolder,
cidl,
apidl,
psfOwner,
pdtInner),
m_hwndParent(hwndParent),
m_rgpolid(NULL),
m_hrCtor(NOERROR),
m_dwPreferredEffect(DROPEFFECT_COPY),
m_dwPerformedEffect(DROPEFFECT_NONE),
m_dwLogicalPerformedEffect(DROPEFFECT_NONE),
m_cItems(0)
{
if (0 == m_cfHDROP)
{
m_cfHDROP = CF_HDROP;
m_cfFileContents = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS);
m_cfFileDesc = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
m_cfPreferedEffect = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
m_cfPerformedEffect = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
m_cfLogicalPerformedEffect = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT);
m_cfDataSrcClsid = (CLIPFORMAT)RegisterClipboardFormat(c_szCFDataSrcClsid);
}
m_hrCtor = CIDLData::CtorResult();
if (SUCCEEDED(m_hrCtor))
{
m_rgpolid = new LPCOLID[cidl];
if (m_rgpolid)
{
ZeroMemory(m_rgpolid, sizeof(LPCOLID) * cidl);
m_cItems = cidl;
for (UINT i = 0; i < cidl; i++)
{
m_rgpolid[i] = (LPCOLID)ILClone(apidl[i]);
if (!m_rgpolid[i])
{
m_hrCtor = E_OUTOFMEMORY;
break;
}
}
}
else
m_hrCtor = E_OUTOFMEMORY;
}
}
COfflineItemsData::~COfflineItemsData(
void
)
{
delete[] m_rgpolid;
}
HRESULT
COfflineItemsData::CreateInstance(
COfflineItemsData **ppOut,
LPCITEMIDLIST pidlFolder,
UINT cidl,
LPCITEMIDLIST *apidl,
HWND hwndParent,
IShellFolder *psfOwner,
IDataObject *pdtInner
)
{
HRESULT hr = E_OUTOFMEMORY;
COfflineItemsData *pNew = new COfflineItemsData(pidlFolder,
cidl,
apidl,
hwndParent,
psfOwner,
pdtInner);
if (NULL != pNew)
{
hr = pNew->CtorResult();
if (SUCCEEDED(hr))
*ppOut = pNew;
else
delete pNew;
}
return hr;
}
HRESULT
COfflineItemsData::CreateInstance(
IDataObject **ppOut,
LPCITEMIDLIST pidlFolder,
UINT cidl,
LPCITEMIDLIST *apidl,
HWND hwndParent,
IShellFolder *psfOwner,
IDataObject *pdtInner
)
{
COfflineItemsData *poid;
HRESULT hr = CreateInstance(&poid,
pidlFolder,
cidl,
apidl,
hwndParent,
psfOwner,
pdtInner);
if (SUCCEEDED(hr))
{
poid->AddRef();
hr = poid->QueryInterface(IID_IDataObject, (void **)ppOut);
poid->Release();
}
return hr;
}
HRESULT
COfflineItemsData::GetData(
FORMATETC *pFEIn,
STGMEDIUM *pstm
)
{
HRESULT hr;
pstm->hGlobal = NULL;
pstm->pUnkForRelease = NULL;
if ((pFEIn->cfFormat == m_cfHDROP) && (pFEIn->tymed & TYMED_HGLOBAL))
hr = CreateHDROP(pstm);
else if ((pFEIn->cfFormat == m_cfFileDesc) && (pFEIn->tymed & TYMED_HGLOBAL))
hr = CreateFileDescriptor(pstm);
else if ((pFEIn->cfFormat == m_cfFileContents) && (pFEIn->tymed & TYMED_ISTREAM))
hr = CreateFileContents(pstm, pFEIn->lindex);
else if ((pFEIn->cfFormat == m_cfPreferedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
hr = CreatePrefDropEffect(pstm);
else if ((pFEIn->cfFormat == m_cfPerformedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
hr = CreatePerformedDropEffect(pstm);
else if ((pFEIn->cfFormat == m_cfLogicalPerformedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
hr = CreateLogicalPerformedDropEffect(pstm);
else if ((pFEIn->cfFormat == m_cfDataSrcClsid) && (pFEIn->tymed & TYMED_HGLOBAL))
hr = CreateDataSrcClsid(pstm);
else
hr = CIDLData::GetData(pFEIn, pstm);
return hr;
}
DWORD COfflineItemsData::GetDataDWORD(
FORMATETC *pfe,
STGMEDIUM *pstm,
DWORD *pdwOut
)
{
if (pfe->tymed == TYMED_HGLOBAL)
{
DWORD *pdw = (DWORD *)GlobalLock(pstm->hGlobal);
if (pdw)
{
*pdwOut = *pdw;
GlobalUnlock(pstm->hGlobal);
}
}
return *pdwOut;
}
HRESULT
COfflineItemsData::SetData(
FORMATETC *pFEIn,
STGMEDIUM *pstm,
BOOL fRelease
)
{
if (pFEIn->cfFormat == g_cfPerformedDropEffect)
{
GetDataDWORD(pFEIn, pstm, &m_dwPerformedEffect);
}
else if (pFEIn->cfFormat == g_cfLogicalPerformedDropEffect)
{
GetDataDWORD(pFEIn, pstm, &m_dwLogicalPerformedEffect);
}
else if (pFEIn->cfFormat == g_cfPreferredDropEffect)
{
GetDataDWORD(pFEIn, pstm, &m_dwPreferredEffect);
}
return CIDLData::SetData(pFEIn, pstm, fRelease);
}
HRESULT
COfflineItemsData::QueryGetData(
FORMATETC *pFEIn
)
{
if (pFEIn->cfFormat == m_cfHDROP ||
pFEIn->cfFormat == m_cfFileDesc ||
pFEIn->cfFormat == m_cfFileContents ||
pFEIn->cfFormat == m_cfPreferedEffect ||
pFEIn->cfFormat == m_cfPerformedEffect ||
pFEIn->cfFormat == m_cfLogicalPerformedEffect ||
pFEIn->cfFormat == m_cfDataSrcClsid)
{
return S_OK;
}
return CIDLData::QueryGetData(pFEIn);
}
HRESULT
COfflineItemsData::ProvideFormats(
CEnumFormatEtc *pEnumFmtEtc
)
{
FORMATETC rgFmtEtc[] = {
{ m_cfHDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
{ m_cfFileContents, NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM },
{ m_cfFileDesc, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
{ m_cfPreferedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
{ m_cfPerformedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
{ m_cfLogicalPerformedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
{ m_cfDataSrcClsid, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
};
//
// Add our formats to the CIDLData format enumerator.
//
return pEnumFmtEtc->AddFormats(ARRAYSIZE(rgFmtEtc), rgFmtEtc);
}
HRESULT
COfflineItemsData::CreateFileDescriptor(
STGMEDIUM *pstm
)
{
HRESULT hr;
pstm->tymed = TYMED_HGLOBAL;
pstm->pUnkForRelease = NULL;
// render the file descriptor
// we only allocate for m_cItems-1 file descriptors because the filegroup
// descriptor has already allocated space for 1.
FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR) + (m_cItems - 1) * sizeof(FILEDESCRIPTOR));
if (pfgd)
{
pfgd->cItems = m_cItems; // set the number of items
pfgd->fgd[0].dwFlags = FD_PROGRESSUI; // turn on progress UI
for (int i = 0; i < m_cItems; i++)
{
FILEDESCRIPTOR *pfd = &(pfgd->fgd[i]);
TCHAR szName[MAX_PATH];
StrCpyN(pfd->cFileName,
COfflineFilesFolder::OLID_GetFileName(m_rgpolid[i], szName, ARRAYSIZE(szName)),
ARRAYSIZE(pfd->cFileName));
}
pstm->hGlobal = pfgd;
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
return hr;
}
HRESULT
COfflineItemsData::CreatePrefDropEffect(
STGMEDIUM *pstm
)
{
return CreateDWORD(pstm, m_dwPreferredEffect);
}
HRESULT
COfflineItemsData::CreatePerformedDropEffect(
STGMEDIUM *pstm
)
{
return CreateDWORD(pstm, m_dwPerformedEffect);
}
HRESULT
COfflineItemsData::CreateLogicalPerformedDropEffect(
STGMEDIUM *pstm
)
{
return CreateDWORD(pstm, m_dwLogicalPerformedEffect);
}
HRESULT
COfflineItemsData::CreateDWORD(
STGMEDIUM *pstm,
DWORD dwEffect
)
{
pstm->tymed = TYMED_HGLOBAL;
pstm->pUnkForRelease = NULL;
pstm->hGlobal = GlobalAlloc(GPTR, sizeof(DWORD));
if (pstm->hGlobal)
{
*((DWORD *)pstm->hGlobal) = dwEffect;
return S_OK;
}
return E_OUTOFMEMORY;
}
HRESULT
COfflineItemsData::CreateFileContents(
STGMEDIUM *pstm,
LONG lindex
)
{
HRESULT hr;
// here's a partial fix for when ole sometimes passes in -1 for lindex
if (lindex == -1)
{
if (m_cItems == 1)
lindex = 0;
else
return E_FAIL;
}
pstm->tymed = TYMED_ISTREAM;
pstm->pUnkForRelease = NULL;
TCHAR szPath[MAX_PATH];
COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[lindex], szPath, ARRAYSIZE(szPath));
hr = SHCreateStreamOnFile(szPath, STGM_READ, &pstm->pstm);
return hr;
}
HRESULT
COfflineItemsData::CreateHDROP(
STGMEDIUM *pstm
)
{
HRESULT hr = E_OUTOFMEMORY;
int i;
//
// The extra MAX_PATH is so that the damned SHLWAPI functions (i.e.
// PathAppend) won't complain about a too-small buffer. They require
// that the destination buffer be AT LEAST MAX_PATH. So much for letting
// code being smart about buffer sizes.
//
int cbHdrop = sizeof(DROPFILES) + (MAX_PATH * sizeof(TCHAR)) + sizeof(TEXT('\0'));
TCHAR szPath[MAX_PATH];
pstm->tymed = TYMED_HGLOBAL;
pstm->pUnkForRelease = NULL;
//
// Calculate required buffer size.
//
for (i = 0; i < m_cItems; i++)
{
szPath[0] = TEXT('\0');
COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[i], szPath, ARRAYSIZE(szPath));
cbHdrop += (lstrlen(szPath) + 1) * sizeof(TCHAR);
}
pstm->hGlobal = GlobalAlloc(GPTR, cbHdrop);
if (NULL != pstm->hGlobal)
{
//
// Fill out the header and append the file paths in a
// double-nul term list.
//
LPDROPFILES pdfHdr = (LPDROPFILES)pstm->hGlobal;
pdfHdr->pFiles = sizeof(DROPFILES);
pdfHdr->fWide = TRUE;
LPTSTR pszWrite = (LPTSTR)((LPBYTE)pdfHdr + sizeof(DROPFILES));
LPTSTR pszEnd = (LPTSTR)((LPBYTE)pstm->hGlobal + cbHdrop - sizeof(TCHAR));
for (i = 0; i < m_cItems; i++)
{
COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[i], pszWrite, (UINT)(pszEnd - pszWrite));
pszWrite += lstrlen(pszWrite) + 1;
}
hr = S_OK;
}
return hr;
}
HRESULT
COfflineItemsData::CreateDataSrcClsid(
STGMEDIUM *pstm
)
{
HRESULT hr = E_OUTOFMEMORY;
pstm->tymed = TYMED_HGLOBAL;
pstm->pUnkForRelease = NULL;
pstm->hGlobal = GlobalAlloc(GPTR, sizeof(CLSID));
if (pstm->hGlobal)
{
*((CLSID *)pstm->hGlobal) = CLSID_OfflineFilesFolder;
return S_OK;
}
return E_OUTOFMEMORY;
}
COfflineItems::COfflineItems(
COfflineFilesFolder *pFolder,
HWND hwnd
) : m_cRef(1),
m_hwndBrowser(hwnd),
m_pFolder(pFolder),
m_ppolid(NULL),
m_cItems(0)
{
DllAddRef();
if (m_pFolder)
m_pFolder->AddRef();
}
COfflineItems::~COfflineItems()
{
if (m_pFolder)
m_pFolder->Release();
if (m_ppolid)
{
for (UINT i = 0; i < m_cItems; i++)
{
if (m_ppolid[i])
ILFree((LPITEMIDLIST)m_ppolid[i]);
}
LocalFree((HLOCAL)m_ppolid);
}
DllRelease();
}
HRESULT
COfflineItems::Initialize(
UINT cidl,
LPCITEMIDLIST *ppidl
)
{
HRESULT hr;
m_ppolid = (LPCOLID *)LocalAlloc(LPTR, cidl * sizeof(LPCOLID));
if (m_ppolid)
{
m_cItems = cidl;
hr = S_OK;
for (UINT i = 0; i < cidl; i++)
{
m_ppolid[i] = (LPCOLID)ILClone(ppidl[i]);
if (!m_ppolid[i])
{
hr = E_OUTOFMEMORY;
break;
}
}
}
else
hr = E_OUTOFMEMORY;
return hr;
}
HRESULT
COfflineItems::CreateInstance(
COfflineFilesFolder *pfolder,
HWND hwnd,
UINT cidl,
LPCITEMIDLIST *ppidl,
REFIID riid,
void **ppv)
{
HRESULT hr;
*ppv = NULL; // null the out param
COfflineItems *pitems = new COfflineItems(pfolder, hwnd);
if (pitems)
{
hr = pitems->Initialize(cidl, ppidl);
if (SUCCEEDED(hr))
{
hr = pitems->QueryInterface(riid, ppv);
}
pitems->Release();
}
else
hr = E_OUTOFMEMORY;
return hr;
}
HRESULT
COfflineItems::QueryInterface(
REFIID iid,
void **ppv
)
{
static const QITAB qit[] = {
QITABENT(COfflineItems, IContextMenu),
QITABENT(COfflineItems, IQueryInfo),
{ 0 },
};
return QISearch(this, qit, iid, ppv);
}
ULONG
COfflineItems::AddRef(
void
)
{
return InterlockedIncrement(&m_cRef);
}
ULONG
COfflineItems::Release(
void
)
{
if (InterlockedDecrement(&m_cRef))
return m_cRef;
delete this;
return 0;
}
//
// IQueryInfo Methods -------------------------------------------------------
//
HRESULT
COfflineItems::GetInfoTip(
DWORD dwFlags,
WCHAR **ppwszTip
)
{
TCHAR szPath[MAX_PATH];
return SHStrDup(COfflineFilesFolder::OLID_GetFullPath(m_ppolid[0], szPath, ARRAYSIZE(szPath)), ppwszTip);
}
HRESULT
COfflineItems::GetInfoFlags(
DWORD *pdwFlags
)
{
*pdwFlags = 0;
return S_OK;
}
//
// IContextMenu Methods -------------------------------------------------------
//
HRESULT
COfflineItems::QueryContextMenu(
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags
)
{
USHORT cItems = 0;
return ResultFromShort(cItems); // number of menu items
}
HRESULT
COfflineItems::InvokeCommand(
LPCMINVOKECOMMANDINFO pici
)
{
HRESULT hr = S_OK;
return hr;
}
HRESULT
COfflineItems::GetCommandString(
UINT_PTR idCmd,
UINT uFlags,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax
)
{
HRESULT hr = E_FAIL;
return hr;
}