797 lines
29 KiB
C
797 lines
29 KiB
C
|
//
|
||
|
// Win32 window that hosts a pane on the desktop.
|
||
|
//
|
||
|
// You are expected to derive from this class and implement the virtual
|
||
|
// methods.
|
||
|
//
|
||
|
#ifndef __SFTHOST_H__
|
||
|
#define __SFTHOST_H__
|
||
|
|
||
|
#include "uemapp.h"
|
||
|
#include "runtask.h"
|
||
|
#include "hostutil.h"
|
||
|
#include "dobjutil.h"
|
||
|
|
||
|
//****************************************************************************
|
||
|
//
|
||
|
// Miscellaneous helper functions
|
||
|
//
|
||
|
|
||
|
STDAPI_(HFONT) LoadControlFont(HTHEME hTheme, int iPart, BOOL fUnderline, DWORD dwSizePercentage);
|
||
|
|
||
|
STDAPI_(HRESULT)
|
||
|
IDataObject_DragQueryFile(IDataObject *pdto, UINT iFile, LPTSTR pszBuf, UINT cch, UINT *puFiles);
|
||
|
|
||
|
STDAPI_(LPITEMIDLIST)
|
||
|
ConvertToLogIL(LPITEMIDLIST pidl);
|
||
|
|
||
|
LRESULT _SendNotify(HWND hwndFrom, UINT code, OPTIONAL NMHDR *pnm = NULL);
|
||
|
|
||
|
BOOL GetFileCreationTime(LPCTSTR pszFile, LPFILETIME pftCreate);
|
||
|
|
||
|
/* Simple wrapper - the string needs to be freed with SHFree */
|
||
|
LPTSTR _DisplayNameOf(IShellFolder *psf, LPCITEMIDLIST pidl, UINT shgno);
|
||
|
|
||
|
HICON _IconOf(IShellFolder *psf, LPCITEMIDLIST pidl, int cxIcon);
|
||
|
|
||
|
BOOL ShowInfoTip();
|
||
|
|
||
|
//****************************************************************************
|
||
|
|
||
|
// The base class uses the following properties in the initializing
|
||
|
// property bag:
|
||
|
//
|
||
|
//
|
||
|
// "type" - type of host to use (see HOSTTYPE array)
|
||
|
// "asyncEnum" - 1 = enumerate in background; 0 = foreground
|
||
|
// "iconSize" - 0 = small, 1 = large
|
||
|
// "horizontal" - 0 = vertical (default), n = horizontal
|
||
|
// n = number of items to show
|
||
|
|
||
|
class PaneItem;
|
||
|
|
||
|
class PaneItem
|
||
|
{
|
||
|
public:
|
||
|
PaneItem() : _iPos(-1), _iPinPos(PINPOS_UNPINNED) {}
|
||
|
virtual ~PaneItem() { SHFree(_pszAccelerator); }
|
||
|
static int CALLBACK DPAEnumCallback(PaneItem *self, LPVOID pData)
|
||
|
{ delete self; return TRUE; }
|
||
|
|
||
|
BOOL IsPinned() const { return _iPinPos >= 0; }
|
||
|
BOOL IsSeparator() const { return _iPinPos == PINPOS_SEPARATOR; }
|
||
|
BOOL GetPinPos() const { return _iPinPos; }
|
||
|
BOOL IsCascade() const { return _dwFlags & ITEMFLAG_CASCADE; }
|
||
|
void EnableCascade() { _dwFlags |= ITEMFLAG_CASCADE; }
|
||
|
BOOL HasSubtitle() const { return _dwFlags & ITEMFLAG_SUBTITLE; }
|
||
|
void EnableSubtitle() { _dwFlags |= ITEMFLAG_SUBTITLE; }
|
||
|
BOOL IsDropTarget() const { return _dwFlags & ITEMFLAG_DROPTARGET; }
|
||
|
void EnableDropTarget() { _dwFlags |= ITEMFLAG_DROPTARGET; }
|
||
|
BOOL HasAccelerator() { return _pszAccelerator != NULL; }
|
||
|
|
||
|
virtual BOOL IsEqual(PaneItem *pItem) const { return FALSE; }
|
||
|
|
||
|
enum {
|
||
|
PINPOS_UNPINNED = -1,
|
||
|
PINPOS_SEPARATOR = -2,
|
||
|
};
|
||
|
|
||
|
enum {
|
||
|
ITEMFLAG_CASCADE = 0x0001,
|
||
|
ITEMFLAG_SUBTITLE = 0x0002,
|
||
|
ITEMFLAG_DROPTARGET = 0x0004,
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
friend class SFTBarHost;
|
||
|
int _iPos; /* Position on screen (or garbage if not on screen) */
|
||
|
public:
|
||
|
int _iPinPos; /* Pin position (or special PINPOS value) */
|
||
|
DWORD _dwFlags; /* ITEMFLAG_* values */
|
||
|
LPTSTR _pszAccelerator;/* Text with ampersand (for keyboard accelerator) */
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Note: Since this is a base class, we can't use ATL because the base
|
||
|
// class's CreateInstance won't know how to construct the derived classes.
|
||
|
//
|
||
|
class SFTBarHost
|
||
|
: public IDropTarget
|
||
|
, public IDropSource
|
||
|
, public CAccessible
|
||
|
{
|
||
|
public:
|
||
|
static BOOL Register();
|
||
|
static BOOL Unregister();
|
||
|
|
||
|
// Would normally be "protected" except that proglist.cpp actually implements
|
||
|
// in a separate class and forwards.
|
||
|
public:
|
||
|
/*
|
||
|
* Classes which derive from this class are expected to implement
|
||
|
* the following methods.
|
||
|
*/
|
||
|
|
||
|
/* Constructor with return code */
|
||
|
virtual HRESULT Initialize() PURE;
|
||
|
|
||
|
/* Destructor */
|
||
|
virtual ~SFTBarHost();
|
||
|
|
||
|
/* Enumerate the objects and call AddItem for each one you find */
|
||
|
// TODO: Maybe the EnumItems should be moved to a background thread
|
||
|
virtual void EnumItems() PURE;
|
||
|
|
||
|
virtual BOOL NeedBackgroundEnum() { return FALSE; }
|
||
|
virtual BOOL HasDynamicContent() { return FALSE; }
|
||
|
|
||
|
/* Compare two objects, tell me which one should come first */
|
||
|
virtual int CompareItems(PaneItem *p1, PaneItem *p2) PURE;
|
||
|
|
||
|
/*
|
||
|
* Given a PaneItem, produce the pidl and IShellFolder associated with it.
|
||
|
* The IShellFolder will be Release()d when no longer needed.
|
||
|
*/
|
||
|
virtual HRESULT GetFolderAndPidl(PaneItem *pitem, IShellFolder **ppsfOut, LPCITEMIDLIST *ppidlOut) PURE;
|
||
|
|
||
|
// An over-ridable method to add an image to our private imagelist for an item (virtual but not pure)
|
||
|
virtual int AddImageForItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidl, int iPos);
|
||
|
|
||
|
/*
|
||
|
* Dispatch a shell notification. Default handler ignores.
|
||
|
*/
|
||
|
virtual void OnChangeNotify(UINT id, LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { }
|
||
|
|
||
|
/*
|
||
|
* Allows derived classes to control their own icon size.
|
||
|
*/
|
||
|
enum ICONSIZE {
|
||
|
ICONSIZE_SMALL, // typically 16x16
|
||
|
ICONSIZE_LARGE, // typically 32x32
|
||
|
ICONSIZE_MEDIUM, // typically 24x24
|
||
|
};
|
||
|
|
||
|
virtual int ReadIconSize() PURE;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Optional hook into window procedure.
|
||
|
*
|
||
|
* Default behavior is just to call DefWindowProc.
|
||
|
*/
|
||
|
virtual LRESULT OnWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Required if AdjustDeleteMenuItem is customized.
|
||
|
* Invoked when a context menu command is invoked.
|
||
|
* Host must intercept the
|
||
|
* "delete" command. Other commands can also be intercepted as
|
||
|
* necessary.
|
||
|
*/
|
||
|
virtual HRESULT ContextMenuInvokeItem(PaneItem *pitem, IContextMenu *pcm, CMINVOKECOMMANDINFOEX *pici, LPCTSTR pszVerb);
|
||
|
|
||
|
/*
|
||
|
* Required if HOSTF_CANRENAME is passed: Invoked when an item
|
||
|
* is renamed.
|
||
|
*
|
||
|
* Note: The client is allowed to change the pidl associated with an
|
||
|
* item during a rename. (In fact, it's expected to!) So callers
|
||
|
* which have called GetFolderAndPidl need to call it again after the
|
||
|
* rename to get the correct post-rename pidl.
|
||
|
*/
|
||
|
virtual HRESULT ContextMenuRenameItem(PaneItem *pitem, LPCTSTR ptszNewName) { return E_NOTIMPL; }
|
||
|
|
||
|
/*
|
||
|
* Optional hook for obtaining the display name of an item.
|
||
|
* The default implementation calls IShellFolder::GetDisplayNameOf.
|
||
|
* If hooked, the returned string should be allocated by SHAlloc().
|
||
|
*/
|
||
|
virtual LPTSTR DisplayNameOfItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidlItem, SHGNO shgno)
|
||
|
{
|
||
|
return _DisplayNameOf(psf, pidlItem, shgno);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Required if pinnned items are created. Invoked when the user moves
|
||
|
* a pinned item.
|
||
|
*/
|
||
|
virtual HRESULT MovePinnedItem(PaneItem *pitem, int iInsert) { return E_NOTIMPL; }
|
||
|
|
||
|
/*
|
||
|
* Optional hook into the SMN_INITIALUPDATE notification.
|
||
|
*/
|
||
|
virtual void PrePopulate() { }
|
||
|
|
||
|
/*
|
||
|
* Optional handler that says whether an item is still valid.
|
||
|
*/
|
||
|
virtual BOOL IsItemStillValid(PaneItem *pitem) { return TRUE; }
|
||
|
|
||
|
/*
|
||
|
* Required if HOSTF_CASCADEMENU. Invoked when user wants to view
|
||
|
* a cascaded menu.
|
||
|
*/
|
||
|
virtual HRESULT GetCascadeMenu(PaneItem *pitem, IShellMenu **ppsm) { return E_FAIL; }
|
||
|
|
||
|
/*
|
||
|
* Required if any items have subtitles. Returns the subtitle of the item.
|
||
|
*/
|
||
|
virtual LPTSTR SubtitleOfItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidlItem) { return NULL; }
|
||
|
|
||
|
/*
|
||
|
* Optionally over-ridable method to ge the infotip for an item. Default does a GetFolderAndPidl/GetInfoTip.
|
||
|
*/
|
||
|
virtual void GetItemInfoTip(PaneItem *pitem, LPTSTR pszText, DWORD cch);
|
||
|
|
||
|
/*
|
||
|
* Specify whether the data object can be inserted into the pin list.
|
||
|
* (Default: No.)
|
||
|
*/
|
||
|
virtual BOOL IsInsertable(IDataObject *pdto) { return FALSE; }
|
||
|
|
||
|
/*
|
||
|
* If you say that something is insertable, they you may be asked to
|
||
|
* insert it.
|
||
|
*/
|
||
|
virtual HRESULT InsertPinnedItem(IDataObject *pdto, int iInsert)
|
||
|
{
|
||
|
ASSERT(FALSE); // You must implement this if you implement IsInsertable
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* An over-ridable method to allow hooking into keyboard accelerators.
|
||
|
*/
|
||
|
virtual TCHAR GetItemAccelerator(PaneItem *pitem, int iItemStart);
|
||
|
|
||
|
/*
|
||
|
* Specify whether the item should be displayed as bold.
|
||
|
* Default is to boldface if pinned.
|
||
|
*/
|
||
|
virtual BOOL IsBold(PaneItem *pitem) { return pitem->IsPinned(); }
|
||
|
|
||
|
/*
|
||
|
* Notify the client that a system imagelist index has changed.
|
||
|
* Default is to re-extract icons for any matching listview items.
|
||
|
*/
|
||
|
virtual void UpdateImage(int iImage);
|
||
|
|
||
|
/*
|
||
|
* Optional method to allow clients to specify how "Delete"
|
||
|
* should be exposed (if at all). Return 0 to disallow "Delete".
|
||
|
* Return the string ID of the string to show for the command.
|
||
|
* Set *puiFlags to any additional flags to pass to ModifyMenu.
|
||
|
* Default is to disallow delete.
|
||
|
*/
|
||
|
virtual UINT AdjustDeleteMenuItem(PaneItem *pitem, UINT *puiFlags) { return 0; }
|
||
|
|
||
|
/*
|
||
|
* Allow client to reject/over-ride the IContextMenu on a per-item basis
|
||
|
*/
|
||
|
|
||
|
virtual HRESULT _GetUIObjectOfItem(PaneItem *pitem, REFIID riid, LPVOID *ppv);
|
||
|
|
||
|
protected:
|
||
|
/*
|
||
|
* Classes which derive from this class may call the following
|
||
|
* helper methods.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Add a PaneItem to the list - if add fails, item will be delete'd.
|
||
|
*
|
||
|
* CLEANUP psf must be NULL; pidl must be the absolute pidl to the item
|
||
|
* being added. Leftover from dead HOSTF_PINITEMSBYFOLDER feature.
|
||
|
* Needs to be cleaned up.
|
||
|
*
|
||
|
* Passing psf and pidlChild are for perf.
|
||
|
*/
|
||
|
BOOL AddItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidlChild);
|
||
|
|
||
|
/*
|
||
|
* Use AddImage when you already have a HICON that needs to go to the private image list.
|
||
|
*/
|
||
|
int AddImage(HICON hIcon);
|
||
|
|
||
|
/*
|
||
|
* Hooking into change notifications
|
||
|
*/
|
||
|
enum {
|
||
|
SFTHOST_MAXCLIENTNOTIFY = 7, // Clients get this many notifications
|
||
|
SFTHOST_MAXHOSTNOTIFY = 1, // We use this many ourselves
|
||
|
SFTHOST_HOSTNOTIFY_UPDATEIMAGE = SFTHOST_MAXCLIENTNOTIFY,
|
||
|
SFTHOST_MAXNOTIFY = SFTHOST_MAXCLIENTNOTIFY + SFTHOST_MAXHOSTNOTIFY,
|
||
|
};
|
||
|
|
||
|
BOOL RegisterNotify(UINT id, LONG lEvents, LPCITEMIDLIST pidl, BOOL fRecursive)
|
||
|
{
|
||
|
ASSERT(id < SFTHOST_MAXCLIENTNOTIFY);
|
||
|
return _RegisterNotify(id, lEvents, pidl, fRecursive);
|
||
|
}
|
||
|
|
||
|
BOOL UnregisterNotify(UINT id);
|
||
|
|
||
|
/*
|
||
|
* Forcing a re-enumeration.
|
||
|
*/
|
||
|
void Invalidate() { _fEnumValid = FALSE; }
|
||
|
|
||
|
/*
|
||
|
* Informing host of desired size.
|
||
|
*/
|
||
|
void SetDesiredSize(int cPinned, int cNormal)
|
||
|
{
|
||
|
_cPinnedDesired = cPinned;
|
||
|
_cNormalDesired = cNormal;
|
||
|
}
|
||
|
|
||
|
BOOL AreNonPinnedItemsDesired()
|
||
|
{
|
||
|
return _cNormalDesired;
|
||
|
}
|
||
|
|
||
|
void StartRefreshTimer() { SetTimer(_hwnd, IDT_REFRESH, 5000, NULL); }
|
||
|
|
||
|
void ForceChange() { _fForceChange = TRUE; }
|
||
|
protected:
|
||
|
/*
|
||
|
* The constructor must be marked "protected" so people can derive
|
||
|
* from us.
|
||
|
*/
|
||
|
|
||
|
enum {
|
||
|
HOSTF_FIREUEMEVENTS = 0x00000001,
|
||
|
HOSTF_CANDELETE = 0x00000002,
|
||
|
HOSTF_Unused = 0x00000004, // recycle me!
|
||
|
HOSTF_CANRENAME = 0x00000008,
|
||
|
HOSTF_REVALIDATE = 0x00000010,
|
||
|
HOSTF_RELOADTEXT = 0x00000020, // requires HOSTF_REVALIDATE
|
||
|
HOSTF_CASCADEMENU = 0x00000040,
|
||
|
};
|
||
|
|
||
|
SFTBarHost(DWORD dwFlags = 0)
|
||
|
: _dwFlags(dwFlags)
|
||
|
, _lRef(1)
|
||
|
, _iInsert(-1)
|
||
|
, _clrBG(CLR_INVALID)
|
||
|
, _iCascading(-1)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
enum {
|
||
|
SFTBM_REPOPULATE = WM_USER,
|
||
|
SFTBM_CHANGENOTIFY,
|
||
|
SFTBM_REFRESH = SFTBM_CHANGENOTIFY + SFTHOST_MAXNOTIFY,
|
||
|
SFTBM_CASCADE,
|
||
|
SFTBM_ICONUPDATE,
|
||
|
};
|
||
|
|
||
|
public:
|
||
|
/*
|
||
|
* Interface stuff...
|
||
|
*/
|
||
|
|
||
|
// *** IUnknown ***
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvOut);
|
||
|
STDMETHODIMP_(ULONG) AddRef();
|
||
|
STDMETHODIMP_(ULONG) Release();
|
||
|
|
||
|
// *** IDropTarget ***
|
||
|
STDMETHODIMP DragEnter(IDataObject *pdto, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
|
||
|
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
|
||
|
STDMETHODIMP DragLeave();
|
||
|
STDMETHODIMP Drop(IDataObject *pdto, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
|
||
|
|
||
|
// *** IDropSource ***
|
||
|
STDMETHODIMP GiveFeedback(DWORD dwEffect);
|
||
|
STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
|
||
|
|
||
|
// *** IAccessible overridden methods ***
|
||
|
STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole);
|
||
|
STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState);
|
||
|
STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut);
|
||
|
STDMETHODIMP get_accDefaultAction(VARIANT varChild, BSTR *pszDefAction);
|
||
|
STDMETHODIMP accDoDefaultAction(VARIANT varChild);
|
||
|
|
||
|
// Helpers
|
||
|
|
||
|
//
|
||
|
// It is pointless to move an object to a place adjacent to itself,
|
||
|
// because the end result is that nothing happens.
|
||
|
//
|
||
|
inline IsInsertMarkPointless(int iInsert)
|
||
|
{
|
||
|
return _fDragToSelf &&
|
||
|
IsInRange(iInsert, _iPosDragOut, _iPosDragOut + 1);
|
||
|
}
|
||
|
|
||
|
void _PurgeDragDropData();
|
||
|
HRESULT _DragEnter(IDataObject *pdto, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
|
||
|
HRESULT _TryInnerDropTarget(int iItem, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect);
|
||
|
void _ClearInnerDropTarget();
|
||
|
void _SetDragOver(int iItem);
|
||
|
|
||
|
// Insert mark stuff
|
||
|
void _SetInsertMarkPosition(int iInsert);
|
||
|
void _InvalidateInsertMark();
|
||
|
BOOL _GetInsertMarkRect(LPRECT prc);
|
||
|
BOOL _IsInsertionMarkActive() { return _iInsert >= 0; }
|
||
|
void _DrawInsertionMark(LPNMLVCUSTOMDRAW plvcd);
|
||
|
|
||
|
/*
|
||
|
* End of drag/drop stuff...
|
||
|
*/
|
||
|
|
||
|
private:
|
||
|
/*
|
||
|
* Background enumeration stuff...
|
||
|
*/
|
||
|
class CBGEnum : public CRunnableTask {
|
||
|
public:
|
||
|
CBGEnum(SFTBarHost *phost, BOOL fUrgent)
|
||
|
: CRunnableTask(RTF_DEFAULT)
|
||
|
, _fUrgent(fUrgent)
|
||
|
, _phost(phost) { phost->AddRef(); }
|
||
|
~CBGEnum()
|
||
|
{
|
||
|
// We should not be the last release or else we are going to deadlock here, when _phost
|
||
|
// tries to release the scheduler
|
||
|
ASSERT(_phost->_lRef > 1);
|
||
|
_phost->Release();
|
||
|
}
|
||
|
STDMETHODIMP RunInitRT()
|
||
|
{
|
||
|
_phost->_EnumerateContentsBackground();
|
||
|
if (_phost->_hwnd) PostMessage(_phost->_hwnd, SFTBM_REPOPULATE, _fUrgent, 0);
|
||
|
return S_OK;
|
||
|
}
|
||
|
private:
|
||
|
SFTBarHost *_phost;
|
||
|
BOOL _fUrgent;
|
||
|
};
|
||
|
|
||
|
friend class SFTBarHost::CBGEnum;
|
||
|
|
||
|
private:
|
||
|
/* Window procedure helpers */
|
||
|
|
||
|
static LRESULT CALLBACK _WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
static LRESULT _OnNcCreate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnCreate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnNcDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
LRESULT _OnNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnSize(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnContextMenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnCtlColorStatic(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnMenuMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnEraseBackground(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnTimer(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnSetFocus(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnSysColorChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnForwardMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnUpdateUIState(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
LRESULT _OnRepopulate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnChangeNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnRefresh(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnCascade(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT _OnIconUpdate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
LRESULT _OnLVCustomDraw(LPNMLVCUSTOMDRAW plvcd);
|
||
|
LRESULT _OnLVNItemActivate(LPNMITEMACTIVATE pnmia);
|
||
|
LRESULT _OnLVNGetInfoTip(LPNMLVGETINFOTIP plvn);
|
||
|
LRESULT _OnLVNGetEmptyText(NMLVDISPINFO *plvdi);
|
||
|
LRESULT _OnLVNBeginDrag(LPNMLISTVIEW plv);
|
||
|
LRESULT _OnLVNBeginLabelEdit(NMLVDISPINFO *pldvi);
|
||
|
LRESULT _OnLVNEndLabelEdit(NMLVDISPINFO *pldvi);
|
||
|
LRESULT _OnLVNKeyDown(LPNMLVKEYDOWN pkd);
|
||
|
LRESULT _OnSMNGetMinSize(PSMNGETMINSIZE pgms);
|
||
|
LRESULT _OnSMNFindItem(PSMNDIALOGMESSAGE pdm);
|
||
|
LRESULT _OnSMNFindItemWorker(PSMNDIALOGMESSAGE pdm);
|
||
|
LRESULT _OnSMNDismiss();
|
||
|
LRESULT _OnHover();
|
||
|
|
||
|
/* Custom draw helpers */
|
||
|
LRESULT _OnLVPrePaint(LPNMLVCUSTOMDRAW plvcd);
|
||
|
LRESULT _OnLVItemPrePaint(LPNMLVCUSTOMDRAW plvcd);
|
||
|
LRESULT _OnLVSubItemPrePaint(LPNMLVCUSTOMDRAW plvcd);
|
||
|
LRESULT _OnLVItemPostPaint(LPNMLVCUSTOMDRAW plvcd);
|
||
|
LRESULT _OnLVPostPaint(LPNMLVCUSTOMDRAW plvcd);
|
||
|
|
||
|
/* Custom draw push/pop */
|
||
|
void _CustomDrawPush(BOOL fReal);
|
||
|
BOOL _IsRealCustomDraw();
|
||
|
void _CustomDrawPop();
|
||
|
|
||
|
/* Other helpers */
|
||
|
void _SetMaxShow(int cx, int cy);
|
||
|
void _EnumerateContents(BOOL fUrgent);
|
||
|
void _EnumerateContentsBackground();
|
||
|
void _RevalidateItems();
|
||
|
void _RevalidatePostPopup();
|
||
|
void _ReloadText();
|
||
|
static int CALLBACK _SortItemsAfterEnum(PaneItem *p1, PaneItem *p2, SFTBarHost *self);
|
||
|
void _RepopulateList();
|
||
|
void _InternalRepopulateList();
|
||
|
int _InsertListViewItem(int iPos, PaneItem *pitem);
|
||
|
void _ComputeListViewItemPosition(int iItem, POINT *pptOut);
|
||
|
int _AppendEnumPaneItem(PaneItem *pitem);
|
||
|
void _RepositionItems();
|
||
|
void _ComputeTileMetrics();
|
||
|
void _SetTileWidth(int cxTile);
|
||
|
BOOL _CreateMarlett();
|
||
|
void _CreateBoldFont();
|
||
|
int _GetLVCurSel() {
|
||
|
return ListView_GetNextItem(_hwndList, -1, LVNI_FOCUSED);
|
||
|
}
|
||
|
BOOL _OnCascade(int iItem, DWORD dwFlags);
|
||
|
BOOL _IsPrivateImageList() const { return _iconsize == ICONSIZE_MEDIUM; }
|
||
|
BOOL _CanHaveSubtitles() const { return _iconsize == ICONSIZE_LARGE; }
|
||
|
int _ExtractImageForItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidl);
|
||
|
void _ClearListView();
|
||
|
void _EditLabel(int iItem);
|
||
|
BOOL _RegisterNotify(UINT id, LONG lEvents, LPCITEMIDLIST pidl, BOOL fRecursive);
|
||
|
void _OnUpdateImage(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExtra);
|
||
|
|
||
|
/* Returns E_FAIL for separators; otherwise calls client */
|
||
|
HRESULT _GetFolderAndPidl(PaneItem *pitem, IShellFolder **ppsfOut, LPCITEMIDLIST *ppidlOut);
|
||
|
|
||
|
/* Simple wrappers - the string needs to be freed with SHFree */
|
||
|
LPTSTR _DisplayNameOfItem(PaneItem *pitem, UINT shgno);
|
||
|
HRESULT _GetUIObjectOfItem(int iItem, REFIID riid, LPVOID *ppv);
|
||
|
|
||
|
inline PaneItem *_GetItemFromLVLParam(LPARAM lParam)
|
||
|
{ return reinterpret_cast<PaneItem*>(lParam); }
|
||
|
PaneItem *_GetItemFromLV(int iItem);
|
||
|
|
||
|
enum {
|
||
|
AIF_KEYBOARD = 1,
|
||
|
};
|
||
|
|
||
|
int _ContextMenuCoordsToItem(LPARAM lParam, POINT *pptOut);
|
||
|
LRESULT _ActivateItem(int iItem, DWORD dwFlags); // AIF_* values
|
||
|
HRESULT _InvokeDefaultCommand(int iItem, IShellFolder *psf, LPCITEMIDLIST pidl);
|
||
|
void _OfferDeleteBrokenItem(PaneItem *pitem, IShellFolder *psf, LPCITEMIDLIST pidl);
|
||
|
|
||
|
// If you hover the mouse for this much time, we will open it if it
|
||
|
// cascades. This is the same value that USER uses for auto-cascading
|
||
|
// menus.
|
||
|
DWORD _GetCascadeHoverTime() { return GetDoubleClickTime() * 4 / 5; }
|
||
|
|
||
|
static void CALLBACK SetIconAsync(LPCITEMIDLIST pidl, LPVOID pvData, LPVOID pvHint, INT iIconIndex, INT iOpenIconIndex);
|
||
|
|
||
|
/*
|
||
|
* Custom commands we add to the context menu.
|
||
|
*/
|
||
|
enum {
|
||
|
IDM_REMOVEFROMLIST = 1,
|
||
|
// Insert private menu items here
|
||
|
|
||
|
// range used for client QueryContextMenu
|
||
|
IDM_QCM_MIN = 0x0100,
|
||
|
IDM_QCM_MAX = 0x7000,
|
||
|
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Timer IDs
|
||
|
*/
|
||
|
enum {
|
||
|
IDT_ASYNCENUM = 1,
|
||
|
IDT_RELOADTEXT = 2,
|
||
|
IDT_REFRESH = 3,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Miscellaneous settings.
|
||
|
*/
|
||
|
enum {
|
||
|
MAX_SEPARATORS = 3, /* Maximum number of separators allowed */
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Pinning helpers...
|
||
|
*/
|
||
|
BOOL NeedSeparator() const { return _cPinned; }
|
||
|
BOOL _HasSeparators() const { return _rgiSep[0] >= 0; }
|
||
|
void _DrawSeparator(HDC hdc, int x, int y);
|
||
|
void _DrawSeparators(LPNMLVCUSTOMDRAW plvcd);
|
||
|
|
||
|
/*
|
||
|
* Bookkeeping.
|
||
|
*/
|
||
|
int _PosToItemNo(int iPos);
|
||
|
int _ItemNoToPos(int iItem);
|
||
|
|
||
|
/*
|
||
|
* Accessibility helpers...
|
||
|
*/
|
||
|
PaneItem *_GetItemFromAccessibility(const VARIANT& varChild);
|
||
|
|
||
|
/*
|
||
|
* Debugging helpers...
|
||
|
*/
|
||
|
#if defined(DEBUG) && defined(FULL_DEBUG)
|
||
|
void _DebugConsistencyCheck();
|
||
|
#else
|
||
|
inline void _DebugConsistencyCheck() { }
|
||
|
#endif
|
||
|
BOOL _AreChangesRestricted()
|
||
|
{
|
||
|
return (IsRestrictedOrUserSetting(HKEY_CURRENT_USER, REST_NOCHANGESTARMENU, TEXT("Advanced"), TEXT("Start_EnableDragDrop"), ROUS_DEFAULTALLOW | ROUS_KEYALLOWS));
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
HTHEME _hTheme; // theme handle, can be NULL
|
||
|
int _iThemePart; // SPP_PROGLIST SPP_PLACESLIST
|
||
|
int _iThemePartSep; // theme part for the separator
|
||
|
HWND _hwnd; /* Our window handle */
|
||
|
HIMAGELIST _himl; // Imagelist handle
|
||
|
int _cxIcon; /* Icon size for imagelist */
|
||
|
int _cyIcon; /* Icon size for imagelist */
|
||
|
ICONSIZE _iconsize; /* ICONSIZE_* value */
|
||
|
|
||
|
private:
|
||
|
HWND _hwndList; /* Handle of inner listview */
|
||
|
|
||
|
MARGINS _margins; // margins for children (listview and oobe static) valid in theme and non-theme case
|
||
|
|
||
|
int _cPinned; /* Number of those items that are pinned */
|
||
|
|
||
|
DWORD _dwFlags; /* Misc flags that derived classes can set */
|
||
|
|
||
|
// _dpaEnum is the DPA of enumerated items, sorted in the
|
||
|
// _SortItemsAfterEnum sense, which prepares them for _RepopulateList.
|
||
|
// When _dpaEnum is destroyed, its pointers must be delete'd.
|
||
|
CDPA<PaneItem> _dpaEnum;
|
||
|
CDPA<PaneItem> _dpaEnumNew; // Used during background enumerations
|
||
|
|
||
|
int _rgiSep[MAX_SEPARATORS]; /* Only _cSep elements are meaningful */
|
||
|
int _cSep; /* Number of separators */
|
||
|
|
||
|
//
|
||
|
// Context menu handling
|
||
|
//
|
||
|
IContextMenu2 * _pcm2Pop; /* Currently popped-up context menu */
|
||
|
IContextMenu3 * _pcm3Pop; /* Currently popped-up context menu */
|
||
|
|
||
|
IDropTargetHelper * _pdth; /* For cool-looking drag/drop */
|
||
|
IDragSourceHelper * _pdsh; /* For cool-looking drag/drop */
|
||
|
IDataObject * _pdtoDragOut; /* Data object being dragged out */
|
||
|
IDataObject * _pdtoDragIn; /* Data object being dragged in */
|
||
|
IDropTarget * _pdtDragOver; /* Object being dragged over (if any) */
|
||
|
|
||
|
IShellTaskScheduler * _psched; /* Task scheduler */
|
||
|
|
||
|
int _iDragOut; /* The item being dragged out (-1 if none) */
|
||
|
int _iPosDragOut; /* The position of item _iDragOut */
|
||
|
int _iDragOver; /* The item being dragged over (-1 if none) */
|
||
|
DWORD _tmDragOver; /* Time the dragover started (to see if we need to auto-open) */
|
||
|
|
||
|
int _iInsert; /* Where the insert mark should be drawn (-1 if none) */
|
||
|
BOOL _fForceArrowCursor; /* Should we force a regular cursor during drag/drop? */
|
||
|
BOOL _fDragToSelf; /* Are we dragging an object to ourselves? */
|
||
|
BOOL _fInsertable; /* Is item being dragged pinnable? */
|
||
|
DWORD _grfKeyStateLast; /* Last grfKeyState passed to DragOver */
|
||
|
|
||
|
int _cyTile; /* Height of a tile */
|
||
|
int _cxTile; /* Width of a tile */
|
||
|
int _cyTilePadding; /* Extra vertical space between tiles */
|
||
|
int _cySepTile; /* Height of a separator tile */
|
||
|
int _cySep; /* Height of a separator line */
|
||
|
|
||
|
int _cxMargin; /* Left margin */
|
||
|
int _cyMargin; /* Top margin */
|
||
|
int _cxIndent; /* So bonus texts line up with listview text */
|
||
|
COLORREF _clrBG; /* Color for background */
|
||
|
COLORREF _clrHot; /* Color for hot text*/
|
||
|
COLORREF _clrSubtitle; /* Color for subtitle text*/
|
||
|
|
||
|
|
||
|
LONG _lRef; /* Reference count */
|
||
|
BOOL _fBGTask; /* Is a background task already scheduled? */
|
||
|
BOOL _fRestartEnum; /* Should in-progress enumeration be restarted? */
|
||
|
BOOL _fRestartUrgent;/* Is the _fRestartEnum urgent? */
|
||
|
BOOL _fEnumValid; /* Is the list of items all fine? */
|
||
|
BOOL _fNeedsRepopulate; /* Do we need to call _RepopulateList ? */
|
||
|
BOOL _fForceChange; /* Should we act as if there was a change even if there didn't seem to be one? */
|
||
|
ULONG _rguChangeNotify[SFTHOST_MAXNOTIFY];
|
||
|
/* Outstanding change notification (if any) */
|
||
|
|
||
|
BOOL _fAllowEditLabel; /* Is this an approved label-editing state? */
|
||
|
|
||
|
HFONT _hfList; /* Custom listview font (if required) */
|
||
|
HFONT _hfBold; /* Bold listview font (if required) */
|
||
|
HFONT _hfMarlett; /* Marlett font (if required) */
|
||
|
int _cxMarlett; /* Width of the menu cascade glyph */
|
||
|
int _tmAscentMarlett; /* Font ascent for Marlett */
|
||
|
|
||
|
HWND _hwndAni; /* Handle of flashlight animation, if present */
|
||
|
UINT _idtAni; /* Animation timer handle */
|
||
|
HBRUSH _hBrushAni; /* Background brush for the Ani window */
|
||
|
|
||
|
int _cPinnedDesired;/* SetDesiredSize */
|
||
|
int _cNormalDesired;/* SetDesiredSize */
|
||
|
|
||
|
int _iCascading; /* Which item is the cascade menu appearing over? */
|
||
|
DWORD _dwCustomDrawState; /* Keeps track of whether customdraw is real or fake */
|
||
|
#ifdef DEBUG
|
||
|
BOOL _fEnumerating; /* Are we enumerating client items? */
|
||
|
BOOL _fPopulating; /* Are we populating the listview? */
|
||
|
BOOL _fListUnstable; /* The listview is unstable; don't get upset */
|
||
|
|
||
|
//
|
||
|
// To verify that we manage the inner drop target correctly.
|
||
|
//
|
||
|
enum {
|
||
|
DRAGSTATE_UNINITIALIZED = 0,
|
||
|
DRAGSTATE_ENTERED = 1,
|
||
|
};
|
||
|
int _iDragState; /* for debugging */
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* Large structures go at the end */
|
||
|
};
|
||
|
|
||
|
_inline SMPANEDATA* PaneDataFromCreateStruct(LPARAM lParam)
|
||
|
{
|
||
|
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
||
|
return reinterpret_cast<SMPANEDATA*>(lpcs->lpCreateParams);
|
||
|
}
|
||
|
|
||
|
//****************************************************************************
|
||
|
//
|
||
|
// Helper functions for messing with UEM info
|
||
|
//
|
||
|
|
||
|
void _GetUEMInfo(const GUID *pguidGrp, int eCmd, WPARAM wParam, LPARAM lParam, UEMINFO *pueiOut);
|
||
|
|
||
|
#define _GetUEMPidlInfo(psf, pidl, pueiOut) \
|
||
|
_GetUEMInfo(&UEMIID_SHELL, UEME_RUNPIDL, \
|
||
|
reinterpret_cast<WPARAM>(psf), \
|
||
|
reinterpret_cast<LPARAM>(pidl), pueiOut)
|
||
|
|
||
|
#define _GetUEMPathInfo(pszPath, pueiOut) \
|
||
|
_GetUEMInfo(&UEMIID_SHELL, UEME_RUNPATH, (WPARAM)-1, \
|
||
|
reinterpret_cast<LPARAM>(pszPath), pueiOut)
|
||
|
|
||
|
#define _SetUEMPidlInfo(psf, pidl, pueiInOut) \
|
||
|
UEMSetEvent(&UEMIID_SHELL, UEME_RUNPIDL, \
|
||
|
reinterpret_cast<WPARAM>(psf), \
|
||
|
reinterpret_cast<LPARAM>(pidl), pueiInOut)
|
||
|
|
||
|
#define _SetUEMPathInfo(pszPath, pueiInOut) \
|
||
|
UEMSetEvent(&UEMIID_SHELL, UEME_RUNPATH, (WPARAM)-1, \
|
||
|
reinterpret_cast<LPARAM>(pszPath), pueiInOut)
|
||
|
|
||
|
// SOMEDAY: Figure out what UEMF_XEVENT means. I just stole the code
|
||
|
// from startmnu.cpp.
|
||
|
|
||
|
#define _FireUEMPidlEvent(psf, pidl) \
|
||
|
UEMFireEvent(&UEMIID_SHELL, UEME_RUNPIDL, UEMF_XEVENT, \
|
||
|
reinterpret_cast<WPARAM>(psf), \
|
||
|
reinterpret_cast<LPARAM>(pidl))
|
||
|
|
||
|
|
||
|
//****************************************************************************
|
||
|
//
|
||
|
// Constructors for derived classes
|
||
|
//
|
||
|
|
||
|
typedef SFTBarHost *(CALLBACK *PFNHOSTCONSTRUCTOR)(void);
|
||
|
|
||
|
STDAPI_(SFTBarHost *) ByUsage_CreateInstance();
|
||
|
STDAPI_(SFTBarHost *) SpecList_CreateInstance();
|
||
|
STDAPI_(SFTBarHost *) RecentDocs_CreateInstance();
|
||
|
|
||
|
#define RECTWIDTH(rc) ((rc).right-(rc).left)
|
||
|
#define RECTHEIGHT(rc) ((rc).bottom-(rc).top)
|
||
|
|
||
|
#endif // __SFTHOST_H__
|