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

319 lines
8.6 KiB
C++

/*****************************************************************************\
FILE: isfvcb.cpp
DESCRIPTION:
This is a base class that implements the default behavior of
IShellFolderViewCallBack. This allows default DefView implementation with this
callback to override specific behavior.
\*****************************************************************************/
#include "priv.h"
#include "isfvcb.h"
//===========================
// *** IShellFolderViewCB Interface ***
//===========================
/*****************************************************************************\
FUNCTION: _OnSetISFV
DESCRIPTION:
Same as ::SetSite();
\*****************************************************************************/
HRESULT CBaseFolderViewCB::_OnSetISFV(IShellFolderView * psfv)
{
IUnknown_Set((IUnknown **) &m_psfv, (IUnknown *) psfv);
return S_OK;
}
/*****************************************************************************\
FUNCTION: IShellFolderViewCB::MessageSFVCB
DESCRIPTION:
\*****************************************************************************/
#define NOTHANDLED(m) case m: hr = E_NOTIMPL; break
HRESULT CBaseFolderViewCB::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr = E_FAIL;
switch (uMsg)
{
case DVM_GETDETAILSOF:
hr = _OnGetDetailsOf((UINT)wParam, (PDETAILSINFO)lParam);
break;
case DVM_COLUMNCLICK:
hr = _OnColumnClick((UINT)wParam);
break;
case DVM_MERGEMENU:
hr = _OnMergeMenu((LPQCMINFO)lParam);
break;
case DVM_UNMERGEMENU:
hr = _OnUnMergeMenu((HMENU)lParam);
break;
case DVM_INVOKECOMMAND:
hr = _OnInvokeCommand((UINT)wParam);
break;
case DVM_GETHELPTEXT:
hr = _OnGetHelpText(lParam, wParam);
break;
case SFVM_GETHELPTOPIC:
hr = _OnGetHelpTopic((SFVM_HELPTOPIC_DATA *) lParam);
break;
case DVM_GETTOOLTIPTEXT:
// TODO: Implement
hr = E_NOTIMPL;
break;
case DVM_UPDATESTATUSBAR:
// TODO: Implement
hr = _OnUpdateStatusBar();
break;
case DVM_WINDOWCREATED:
hr = _OnWindowCreated();
break;
case SFVM_BACKGROUNDENUMDONE:
hr = _OnBackGroundEnumDone();
break;
case DVM_INITMENUPOPUP:
hr = _OnInitMenuPopup((HMENU) lParam, (UINT) HIWORD(wParam), (UINT) LOWORD(wParam));
break;
case DVM_RELEASE:
{
CBaseFolderViewCB * pfv = (CBaseFolderViewCB *) lParam;
if (pfv)
hr = pfv->Release();
}
break;
case DVM_DEFITEMCOUNT:
hr = _OnDefItemCount((LPINT)lParam);
break;
case DVM_DIDDRAGDROP:
hr = _OnDidDragDrop((DROPEFFECT)wParam, (IDataObject *)lParam);
break;
case DVM_REFRESH:
hr = _OnRefresh((BOOL) wParam);
break;
case SFVM_ADDPROPERTYPAGES:
hr = _OnAddPropertyPages((SFVM_PROPPAGE_DATA *)lParam);
break;
case DVM_BACKGROUNDENUM:
// WARNING! If we return S_OK from DVM_BACKGROUNDENUM, we also
// are promising that we support free threading on our IEnumIDList
// interface! This allows the shell to do enumeration on our
// IEnumIDList on a separate background thread.
hr = S_OK; // Always enum in background
break;
case SFVM_DONTCUSTOMIZE:
if (lParam)
*((BOOL *) lParam) = FALSE; // Yes, we are customizable.
hr = S_OK;
break;
case SFVM_GETZONE:
hr = _OnGetZone((DWORD *) lParam, wParam);
break;
case SFVM_GETPANE:
hr = _OnGetPane((DWORD) wParam, (DWORD *)lParam);
break;
case SFVM_SETISFV:
hr = _OnSetISFV((IShellFolderView *)lParam);
break;
case SFVM_GETNOTIFY:
hr = _OnGetNotify((LPITEMIDLIST *) wParam, (LONG *) lParam);
break;
case SFVM_FSNOTIFY:
hr = _OnFSNotify((LPITEMIDLIST *) wParam, (LONG *) lParam);
break;
case SFVM_QUERYFSNOTIFY:
hr = _OnQueryFSNotify((SHChangeNotifyEntry *) lParam);
break;
case SFVM_SIZE:
hr = _OnSize((LONG) wParam, (LONG) lParam);
break;
case SFVM_THISIDLIST:
hr = _OnThisIDList((LPITEMIDLIST *) lParam);
break;
// The following are some we could do.
// SFVM_HWNDMAIN
// Others that aren't currently handled.
NOTHANDLED(DVM_GETBUTTONINFO);
NOTHANDLED(DVM_GETBUTTONS);
NOTHANDLED(DVM_SELCHANGE);
NOTHANDLED(DVM_DRAWITEM);
NOTHANDLED(DVM_MEASUREITEM);
NOTHANDLED(DVM_EXITMENULOOP);
NOTHANDLED(DVM_GETCCHMAX);
NOTHANDLED(DVM_WINDOWDESTROY);
NOTHANDLED(DVM_SETFOCUS);
NOTHANDLED(DVM_KILLFOCUS);
NOTHANDLED(DVM_QUERYCOPYHOOK);
NOTHANDLED(DVM_NOTIFYCOPYHOOK);
NOTHANDLED(DVM_DEFVIEWMODE);
#if 0
NOTHANDLED(DVM_INSERTITEM); // Too verbose
NOTHANDLED(DVM_DELETEITEM);
#endif
NOTHANDLED(DVM_GETWORKINGDIR);
NOTHANDLED(DVM_GETCOLSAVESTREAM);
NOTHANDLED(DVM_SELECTALL);
NOTHANDLED(DVM_SUPPORTSIDENTIFY);
NOTHANDLED(DVM_FOLDERISPARENT);
default:
hr = E_NOTIMPL;
break;
}
return hr;
}
/****************************************************\
Constructor
\****************************************************/
CBaseFolderViewCB::CBaseFolderViewCB() : m_cRef(1), m_dwSignature(c_dwSignature)
{
DllAddRef();
// This needs to be allocated in Zero Inited Memory.
// Assert that all Member Variables are inited to Zero.
ASSERT(!m_psfv);
}
/****************************************************\
Destructor
\****************************************************/
CBaseFolderViewCB::~CBaseFolderViewCB()
{
m_dwSignature = 0; // Turn off _IShellFolderViewCallBack
IUnknown_Set((IUnknown **)&m_psfv, NULL);
DllRelease();
}
//===========================
// *** IUnknown Interface ***
//===========================
ULONG CBaseFolderViewCB::AddRef()
{
m_cRef++;
return m_cRef;
}
ULONG CBaseFolderViewCB::Release()
{
ASSERT(m_cRef > 0);
m_cRef--;
if (m_cRef > 0)
return m_cRef;
delete this;
return 0;
}
// {7982F251-C37A-11d1-9823-006097DF5BD4}
static const GUID CIID_PrivateThis = { 0x7982f251, 0xc37a, 0x11d1, { 0x98, 0x23, 0x0, 0x60, 0x97, 0xdf, 0x5b, 0xd4 } };
HRESULT CBaseFolderViewCB::QueryInterface(REFIID riid, void **ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IShellFolderViewCB))
{
*ppvObj = SAFECAST(this, IShellFolderViewCB*);
}
else
if (IsEqualIID(riid, IID_IObjectWithSite))
{
*ppvObj = SAFECAST(this, IObjectWithSite*);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
HRESULT CBaseFolderViewCB::_IShellFolderViewCallBack(IShellView * psvOuter, IShellFolder * psf, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
IShellFolderViewCB * psfvcb = NULL;
HRESULT hr = E_FAIL;
// Now this is a total hack. I am bastardizing the pszOuter param to really be the this pointer that
// is the IShellFolderViewCB interface of the CBaseFolderViewCB object. I use the SFVM_WINDOWDESTROY event to
// release the object but DefView calls us back with one more message before we completely go away
// and that message is SFVM_SETISFV. Everytime the SFVM_SETISFV is called with a NULL lParam, it's
// equivalent to calling ::SetSite(NULL). We can ignore this because we release the back pointer in our
// destructor.
if (((SFVM_SETISFV == uMsg) && !lParam) ||
(SFVM_PRERELEASE == uMsg))
{
return S_OK;
}
// psvOuter is really our CBaseFolderViewCB. Sniff around to make sure.
// Note that this casting must exactly invert the casts that we do in
// CBaseFolder::_CreateShellView.
CBaseFolderViewCB *pbfvcb = (CBaseFolderViewCB *)(IShellFolderViewCB *)psvOuter;
if (EVAL(!IsBadReadPtr(pbfvcb, sizeof(CBaseFolderViewCB))) &&
EVAL(pbfvcb->m_dwSignature == c_dwSignature))
{
// psvOuter is really our CBaseFolderViewCB and let's make sure with this QI.
hr = psvOuter->QueryInterface(IID_IShellFolderViewCB, (void **) &psfvcb);
if (EVAL(psfvcb))
{
hr = psfvcb->MessageSFVCB(uMsg, wParam, lParam);
if ((SFVM_WINDOWDESTROY == uMsg)) // (DVM_WINDOWDESTROY == SFVM_WINDOWDESTROY)
{
ASSERT(!lParam); // Sometimes callers want this to be freed.
psvOuter->Release(); // We are releasing the psvOuter that DefView is holding. We shouldn't be called again.
}
psfvcb->Release();
}
}
return hr;
}