//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: items.cpp // //-------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include // QITAB, QISearch #include // 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]); COfflineFilesFolder::OLID_GetFileName(m_rgpolid[i], pfd->cFileName, 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 ) { // 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]; HRESULT hr = COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[lindex], szPath, ARRAYSIZE(szPath)); if (SUCCEEDED(hr)) { hr = SHCreateStreamOnFile(szPath, STGM_READ, &pstm->pstm); } return hr; } HRESULT COfflineItemsData::CreateHDROP( STGMEDIUM *pstm ) { HRESULT hr; 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'); hr = COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[i], szPath, ARRAYSIZE(szPath)); if (FAILED(hr)) { return hr; } 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++) { // We allocated enough, so this should never fail if (SUCCEEDED(COfflineFilesFolder::OLID_GetFullPath(m_rgpolid[i], pszWrite, (UINT)(pszEnd - pszWrite)))) { pszWrite += lstrlen(pszWrite) + 1; } } hr = S_OK; } else { hr = E_OUTOFMEMORY; } 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 ) { ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); if ( 0 == cRef ) { delete this; } return cRef; } // // IQueryInfo Methods ------------------------------------------------------- // HRESULT COfflineItems::GetInfoTip( DWORD dwFlags, WCHAR **ppwszTip ) { TCHAR szPath[MAX_PATH]; HRESULT hr = COfflineFilesFolder::OLID_GetFullPath(m_ppolid[0], szPath, ARRAYSIZE(szPath)); if (SUCCEEDED(hr)) { hr = SHStrDup(szPath, ppwszTip); } return hr; } 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; }