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

645 lines
15 KiB
C++

//*******************************************************************************************
//
// Filename : Sfview.cpp
//
// Implementation file for CSFView
//
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//
//*******************************************************************************************
#include "Pch.H"
#include "SFView.H"
#include "SFVWnd.H"
#include "Resource.H"
#include "ThisGuid.H"
#include "SFView.H"
struct SFSTATE_HDR
{
CLSID clsThis;
SFSTATE sfState;
UINT nCols;
} ;
CSFView::CSFView(IShellFolder *psf, IShellFolderViewCallback *psfvcb) :
m_psf(psf), m_erFolder(psf), m_erCB(psfvcb), m_pCDB(NULL), m_cView(this),
m_uState(SVUIA_DEACTIVATE), m_pcmSel(NULL), m_cAccel(IDA_MAIN)
{
m_psfvcb = psfvcb;
if (psfvcb)
{
psfvcb->AddRef();
}
psf->AddRef();
m_aParamSort = DPA_Create(4);
m_sfState.lParamSort = 0;
}
CSFView::~CSFView()
{
ReleaseSelContextMenu();
}
STDMETHODIMP CSFView::QueryInterface(REFIID riid, void ** ppvObj)
{
static const IID *apiid[] = { &IID_IShellView, NULL };
LPUNKNOWN aobj[] = { (IShellView *)this };
return(QIHelper(riid, ppvObj, apiid, aobj));
}
STDMETHODIMP_(ULONG) CSFView::AddRef()
{
return(AddRefHelper());
}
STDMETHODIMP_(ULONG) CSFView::Release()
{
return(ReleaseHelper());
}
STDMETHODIMP CSFView::GetWindow(HWND * lphwnd)
{
return(E_NOTIMPL);
}
STDMETHODIMP CSFView::ContextSensitiveHelp(BOOL fEnterMode)
{
return(E_NOTIMPL);
}
//*****************************************************************************
//
// CSFView::TranslateAccelerator
//
// Purpose:
// Handle the accelerator keystrokes
//
//
// Parameters:
// LPMSG lpmsg - message structure
//
//
// Comments:
//
//*****************************************************************************
STDMETHODIMP CSFView::TranslateAccelerator(LPMSG lpmsg)
{
return(m_cAccel.TranslateAccelerator(m_cView, lpmsg) ? S_OK : S_FALSE);
}
STDMETHODIMP CSFView::EnableModeless(BOOL fEnable)
{
return(E_NOTIMPL);
}
//*****************************************************************************
//
// CSFView:UIActivate
//
// Purpose:
// The explorer calls this member function whenever the activation
// state of the view window is changed by a certain event that is
// NOT caused by the shell view itself.
//
//
// Parameters:
//
// UINT uState - UI activate flag
//
// Comments:
//
//*****************************************************************************
STDMETHODIMP CSFView::UIActivate(UINT uState)
{
if (uState)
{
OnActivate(uState);
}
else
{
OnDeactivate();
}
return S_OK;
}
STDMETHODIMP CSFView::Refresh()
{
FillList(FALSE);
return S_OK;// yes, this is potentially bad, but we risk app compat problems if we change it. 2000/02/10 -ccooney
}
//*****************************************************************************
//
// CSFView::CreateViewWindow
//
// Purpose:
//
// called by IShellBrowser to create a contents pane window
//
// Parameters:
//
// IShellView *lpPrevView - previous view
// LPCFOLDERSETTINGS lpfs - folder settings for the view
// IShellBrowser *psb - pointer to the shell browser
// RECT * prcView - view Rectangle
// HWND * phWnd - pointer to Window handle
//
//
// Comments:
//
//*****************************************************************************
STDMETHODIMP CSFView::CreateViewWindow(IShellView *lpPrevView,
LPCFOLDERSETTINGS lpfs, IShellBrowser * psb,
RECT * prcView, HWND *phWnd)
{
*phWnd = NULL;
if ((HWND)m_cView)
{
return(E_UNEXPECTED);
}
m_fs = *lpfs;
m_psb = psb;
// get the main window handle from shell browser
psb->GetWindow(&m_hwndMain);
// bring up the contents pane
if (!m_cView.DoModeless(IDD_VIEW, m_hwndMain))
{
return(E_OUTOFMEMORY);
}
*phWnd = m_cView;
// map the current view mode into menu id and set the contents pane
// view mode accordingly
OnCommand(NULL, GET_WM_COMMAND_MPS(GetMenuIDFromViewMode(), 0, 0));
AddColumns();
RestoreViewState();
// size the contents pane
SetWindowPos(m_cView, NULL, prcView->left, prcView->top,
prcView->right-prcView->left, prcView->bottom-prcView->top,
SWP_NOZORDER|SWP_SHOWWINDOW);
FillList(TRUE);
return(NOERROR);
}
STDMETHODIMP CSFView::DestroyViewWindow()
{
if (!(HWND)m_cView)
{
return(E_UNEXPECTED);
}
m_cView.DestroyWindow();
return(NOERROR);
}
STDMETHODIMP CSFView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
{
*lpfs = m_fs;
return(NOERROR);
}
STDMETHODIMP CSFView::AddPropertySheetPages(DWORD dwReserved,
LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
{
return(E_NOTIMPL);
}
STDMETHODIMP CSFView::SaveViewState()
{
SFSTATE_HDR hdr;
LPSTREAM pstm;
HRESULT hres = m_psb->GetViewStateStream(STGM_WRITE, &pstm);
if (FAILED(hres))
{
return(hres);
}
CEnsureRelease erStr(pstm);
pstm->Write(&hdr, sizeof(hdr), NULL);
hdr.clsThis = CLSID_ThisDll;
hdr.sfState = m_sfState;
hdr.nCols = SaveColumns(pstm);
ULARGE_INTEGER libCurPosition;
LARGE_INTEGER dlibMove;
dlibMove.HighPart = 0;
dlibMove.LowPart = 0;
pstm->Seek(dlibMove, STREAM_SEEK_SET, &libCurPosition);
hres = pstm->Write(&hdr, sizeof(hdr), NULL);
return(hres);
}
STDMETHODIMP CSFView::SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags)
{
return(E_NOTIMPL);
}
STDMETHODIMP CSFView::GetItemObject(UINT uItem, REFIID riid,
void **ppv)
{
return(E_NOTIMPL);
}
int CSFView::AddObject(LPCITEMIDLIST pidl)
{
// Check the commdlg hook to see if we should include this
// object.
if (IncludeObject(pidl) != S_OK)
{
return(-1);
}
return(m_cView.AddObject(pidl));
}
int CALLBACK CSFView::CompareIDs(LPVOID p1, LPVOID p2, LPARAM lParam)
{
PFNDPACOMPARE pfnCheckAPI = CompareIDs;
CSFView *pThis = (CSFView *)lParam;
HRESULT hres = pThis->m_psf->CompareIDs(pThis->m_sfState.lParamSort,
(LPITEMIDLIST)p1, (LPITEMIDLIST)p2);
return (hres);
}
//*****************************************************************************
//
// CSFView::FillList
//
// Purpose:
//
// Enumerates the objects in the namespace and fills up the
// data structures
//
//
// Comments:
//
//*****************************************************************************
HRESULT CSFView::FillList(BOOL bInteractive)
{
m_cView.DeleteAllItems();
// Setup the enum flags.
DWORD dwEnumFlags = SHCONTF_NONFOLDERS;
if (ShowAllObjects())
{
dwEnumFlags |= SHCONTF_INCLUDEHIDDEN ;
}
if (!(m_fs.fFlags & FWF_NOSUBFOLDERS))
{
dwEnumFlags |= SHCONTF_FOLDERS;
}
// Create an enum object and get the IEnumIDList ptr
LPENUMIDLIST peIDL;
HRESULT hres = m_psf->EnumObjects(bInteractive ? m_hwndMain : NULL,
dwEnumFlags, &peIDL);
// Note the return may be S_FALSE which indicates no enumerator.
// That's why we shouldn't use if (FAILED(hres))
if (hres != S_OK)
{
if (hres == S_FALSE)
{
return(NOERROR);
}
return(hres);
}
CEnsureRelease erEnum(peIDL);
HDPA hdpaNew = DPA_Create(16);
if (!hdpaNew)
{
return(E_OUTOFMEMORY);
}
LPITEMIDLIST pidl;
ULONG celt;
// Enumerate the idlist and insert into the DPA
while (peIDL->Next(1, &pidl, &celt) == S_OK)
{
if (DPA_InsertPtr(hdpaNew, 0x7fff, pidl) == -1)
{
m_cMalloc.Free(pidl);
}
}
DPA_Sort(hdpaNew, CompareIDs, (LPARAM)this);
int cNew = DPA_GetPtrCount(hdpaNew);
for (int i=0; i<cNew; ++i)
{
LPITEMIDLIST pidl = (LPITEMIDLIST)DPA_GetPtr(hdpaNew, i);
if (AddObject(pidl) < 0)
{
m_cMalloc.Free(pidl);
}
}
return(NOERROR);
}
//*****************************************************************************
//
// CSFView::AddColumns
//
// Purpose:
//
// Adds columns to the contents pane listview
//
// Comments:
//
//*****************************************************************************
void CSFView::AddColumns()
{
UINT cxChar = m_cView.CharWidth();
// add columns to the listview in the contents pane
for (int i=0; ; ++i)
{
SFVCB_GETDETAILSOF_DATA gdo;
gdo.pidl = NULL;
// get the first column
HRESULT hres = CallCB(SFVCB_GETDETAILSOF, i, (LPARAM)&gdo);
if (hres != S_OK)
{
if (i != 0)
{
break;
}
// If there is no first column, fake one up
gdo.fmt = LVCFMT_LEFT;
gdo.cChar = 40;
gdo.lParamSort = 0;
gdo.str.uType = STRRET_CSTR;
LoadString(g_ThisDll.GetInstance(), IDS_NAME, gdo.str.cStr, sizeof(gdo.str.cStr));
}
char szText[MAX_PATH];
// init the column info for the details view ...
LV_COLUMN col;
col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
col.fmt = gdo.fmt;
col.cx = gdo.cChar * cxChar;
col.pszText = szText;
col.cchTextMax = sizeof(szText);
col.iSubItem = i;
StrRetToStr(szText, sizeof(szText), &gdo.str, NULL);
// insert the column into the list view
if (m_cView.InsertColumn(i, &col)>=0 && m_aParamSort)
{
DPA_InsertPtr(m_aParamSort, 0x7fff, (LPVOID)gdo.lParamSort);
}
if (hres != S_OK)
{
break;
}
}
}
//
// Save (and check) column header information
// Returns TRUE if the columns are the default width, FALSE otherwise
// Side effect: the stream pointer is left right after the last column
//
BOOL CSFView::SaveColumns(LPSTREAM pstm)
{
UINT cxChar = m_cView.CharWidth();
BOOL bDefaultCols = TRUE;
for (int i=0; ; ++i)
{
SFVCB_GETDETAILSOF_DATA gdo;
gdo.pidl = NULL;
if (CallCB(SFVCB_GETDETAILSOF, i, (LPARAM)&gdo) != S_OK)
{
break;
}
LV_COLUMN col;
col.mask = LVCF_WIDTH;
if (!m_cView.GetColumn(i, &col))
{
// There is some problem, so just assume
// default column widths
bDefaultCols = TRUE;
break;
}
if (col.cx != (int)(gdo.cChar * cxChar))
{
bDefaultCols = FALSE;
}
// HACK: I don't really care about column widths larger
// than 64K
if (FAILED(pstm->Write(&col.cx, sizeof(USHORT), NULL)))
{
// There is some problem, so just assume
// default column widths
bDefaultCols = TRUE;
break;
}
}
return(bDefaultCols ? 0 : i);
}
void CSFView::RestoreColumns(LPSTREAM pstm, int nCols)
{
for (int i=0; i<nCols; ++i)
{
LV_COLUMN col;
col.mask = LVCF_WIDTH;
if (FAILED(pstm->Read(&col.cx, sizeof(USHORT), NULL)))
{
break;
}
m_cView.SetColumn(i, &col);
}
}
void CSFView::RestoreViewState()
{
SFSTATE_HDR hdr;
LPSTREAM pstm;
MergeToolBar();
// get the stream for storing view specific info
if (FAILED(m_psb->GetViewStateStream(STGM_READ, &pstm)))
{
return;
}
CEnsureRelease erStr(pstm);
if (FAILED(pstm->Read(&hdr, sizeof(hdr), NULL)))
{
return;
}
// Validate the header
if (hdr.clsThis != CLSID_ThisDll)
{
return;
}
m_sfState = hdr.sfState;
RestoreColumns(pstm, hdr.nCols);
}
void CSFView::CheckToolbar()
{
UINT idCmdCurView = GetMenuIDFromViewMode();
for (UINT idCmd=IDC_VIEW_ICON; idCmd<=IDC_VIEW_DETAILS; ++idCmd)
{
m_psb->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON, idCmd,
(LPARAM)(idCmd == idCmdCurView), NULL);
}
}
void CSFView::MergeToolBar()
{
enum
{
IN_STD_BMP = 0x4000,
IN_VIEW_BMP = 0x8000,
} ;
static const TBBUTTON c_tbDefault[] =
{
{ STD_COPY | IN_STD_BMP, IDC_EDIT_COPY, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 },
// the bitmap indexes here are relative to the view bitmap
{ VIEW_LARGEICONS | IN_VIEW_BMP, IDC_VIEW_ICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
{ VIEW_SMALLICONS | IN_VIEW_BMP, IDC_VIEW_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
{ VIEW_LIST | IN_VIEW_BMP, IDC_VIEW_LIST, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
{ VIEW_DETAILS | IN_VIEW_BMP, IDC_VIEW_DETAILS, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
} ;
LRESULT iStdBMOffset;
LRESULT iViewBMOffset;
TBADDBITMAP ab;
ab.hInst = HINST_COMMCTRL; // hinstCommctrl
ab.nID = IDB_STD_SMALL_COLOR; // std bitmaps
m_psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &iStdBMOffset);
ab.nID = IDB_VIEW_SMALL_COLOR; // std view bitmaps
m_psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &iViewBMOffset);
TBBUTTON tbActual[ARRAYSIZE(c_tbDefault)];
for (int i=0; i<ARRAYSIZE(c_tbDefault); ++i)
{
tbActual[i] = c_tbDefault[i];
if (!(tbActual[i].fsStyle & TBSTYLE_SEP))
{
if (tbActual[i].iBitmap & IN_VIEW_BMP)
{
tbActual[i].iBitmap = (tbActual[i].iBitmap & ~IN_VIEW_BMP) + iViewBMOffset;
}
else if (tbActual[i].iBitmap & IN_STD_BMP)
{
tbActual[i].iBitmap = (tbActual[i].iBitmap & ~IN_STD_BMP) + iStdBMOffset;
}
}
}
m_psb->SetToolbarItems(tbActual, ARRAYSIZE(c_tbDefault), FCT_MERGE);
CheckToolbar();
}
HRESULT CreateShellFolderView(IShellFolder *psf, IShellFolderViewCallback *psfvcb,
LPSHELLVIEW * ppsv)
{
CSFView *pSFView = new CSFView(psf, psfvcb);
if (!pSFView)
{
return(E_OUTOFMEMORY);
}
pSFView->AddRef();
HRESULT hRes = pSFView->QueryInterface(IID_IShellView, (void **)ppsv);
pSFView->Release();
return(hRes);
}