|
|
/*****************************************************************************\
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; }
|