|
|
#include "shellprv.h"
#include "infotip.h"
#include "ids.h"
#include "prop.h"
#include <mluisupp.h>
// generic info tip object
class CInfoTip : public IQueryInfo, public ICustomizeInfoTip, public IParentAndItem { public: // IUnknown
STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void);
// IQueryInfo methods.
STDMETHODIMP GetInfoTip(DWORD dwFlags, WCHAR** ppwszTip); STDMETHODIMP GetInfoFlags(DWORD *pdwFlags);
// ICustomizeInfoTip
STDMETHODIMP SetPrefixText(LPCWSTR pszPrefix); STDMETHODIMP SetExtraProperties(const SHCOLUMNID *pscid, UINT cscid);
// IParentAndItem
STDMETHODIMP SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidlChild); STDMETHODIMP GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidlChild);
CInfoTip(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPCWSTR pszProp);
private: ~CInfoTip(); HRESULT _GetInfoTipFromItem(WCHAR **ppszText); BOOL _InExtraList(const SHCOLUMNID *pscid);
LONG _cRef;
IShellFolder2 *_psf; LPITEMIDLIST _pidl; TCHAR _szText[INFOTIPSIZE]; LPWSTR _pszPrefix; SHCOLUMNID _rgcols[8]; UINT _cscid; };
#define PROP_PREFIX TEXT("prop:")
#define PROP_PREFIX_LEN (ARRAYSIZE(PROP_PREFIX) - 1)
CInfoTip::CInfoTip(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPCWSTR pszText) : _cRef(1) { if (IS_INTRESOURCE(pszText)) LoadString(HINST_THISDLL, LOWORD((UINT_PTR)pszText), _szText, ARRAYSIZE(_szText)); else SHUnicodeToTChar(pszText, _szText, ARRAYSIZE(_szText));
if (psf && pidl && (StrCmpNI(_szText, PROP_PREFIX, PROP_PREFIX_LEN) == 0)) { // list of properties, we need the psf and pidl for this
psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf)); _pidl = ILClone(pidl); } }
CInfoTip::~CInfoTip() { if (_psf) _psf->Release();
ILFree(_pidl);
Str_SetPtr(&_pszPrefix, NULL); }
HRESULT CInfoTip::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CInfoTip, IQueryInfo), QITABENT(CInfoTip, ICustomizeInfoTip), QITABENT(CInfoTip, IParentAndItem), { 0 }, }; return QISearch(this, qit, riid, ppv); }
ULONG CInfoTip::AddRef() { return InterlockedIncrement(&_cRef); }
ULONG CInfoTip::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
BOOL CInfoTip::_InExtraList(const SHCOLUMNID *pscid) { for (UINT i = 0; i < _cscid; i++) { if (IsEqualSCID(*pscid, _rgcols[i])) return TRUE; } return FALSE; }
void _AppendTipText(LPTSTR pszBuf, int cch, LPCTSTR pszCRLF, LPCTSTR pszPropName, LPCTSTR pszValue) { TCHAR szFmt[64], szProp[128];
if (*pszPropName) LoadString(g_hinst, IDS_EXCOL_TEMPLATE, szFmt, SIZECHARS(szFmt)); else lstrcpyn(szFmt, TEXT("%s%s%s"), ARRAYSIZE(szFmt));
wnsprintf(szProp, ARRAYSIZE(szProp), szFmt, pszCRLF, pszPropName, pszValue); StrCatBuff(pszBuf, szProp, cch); }
HRESULT CInfoTip::_GetInfoTipFromItem(WCHAR **ppszText) { TCHAR szTip[INFOTIPSIZE]; szTip[0] = 0;
IPropertyUI *ppui; if (SUCCEEDED(CoCreateInstance(CLSID_PropertiesUI, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPropertyUI, &ppui)))) { LPCTSTR pszCRLF = TEXT("");
if (_pszPrefix) { _AppendTipText(szTip, ARRAYSIZE(szTip), pszCRLF, TEXT(""), _pszPrefix); pszCRLF = TEXT("\n"); }
UINT iCurrentExtra = 0;
BOOL bContinue = TRUE; ULONG chEaten = 0; // gets incremented by ParsePropertyName
while (bContinue) { SHCOLUMNID scid; BOOL bDoThisOne = TRUE;
if (iCurrentExtra < _cscid) { scid = _rgcols[iCurrentExtra++]; } else { if (SUCCEEDED(ppui->ParsePropertyName(_szText, &scid.fmtid, &scid.pid, &chEaten))) { bDoThisOne = !_InExtraList(&scid); } else { bContinue = FALSE; } }
if (bContinue) { VARIANT v = {0};
if (bDoThisOne && (S_OK == _psf->GetDetailsEx(_pidl, &scid, &v))) { TCHAR szPropName[128], szValue[128];
ppui->FormatForDisplay(scid.fmtid, scid.pid, (PROPVARIANT*)&v, PUIFFDF_DEFAULT, szValue, ARRAYSIZE(szValue));
if (IsEqualSCID(scid, SCID_Comment)) { szPropName[0] = 0; // comment property, don't use the label
} else { ppui->GetDisplayName(scid.fmtid, scid.pid, PUIFNF_DEFAULT, szPropName, ARRAYSIZE(szPropName)); }
// if we got a value, and that value is different from
// the prefix of the current tip string we append it.
// that is don't dupe the same string where the comment == name
if (szValue[0] && (0 != StrCmpNI(szTip, szValue, lstrlen(szValue)))) { _AppendTipText(szTip, ARRAYSIZE(szTip), pszCRLF, szPropName, szValue); pszCRLF = TEXT("\n"); }
VariantClear(&v); } } } ppui->Release(); } return SHStrDup(szTip, ppszText); }
STDMETHODIMP CInfoTip::GetInfoTip(DWORD dwFlags, WCHAR** ppszText) { HRESULT hr; if (_psf && _pidl) hr = _GetInfoTipFromItem(ppszText); else if (_szText[0]) hr = SHStrDup(_szText, ppszText); else hr = E_FAIL; return hr; }
STDMETHODIMP CInfoTip::GetInfoFlags(DWORD *pdwFlags) { *pdwFlags = 0; return E_NOTIMPL; }
// ICustomizeInfoTip
STDMETHODIMP CInfoTip::SetPrefixText(LPCWSTR pszPrefix) { Str_SetPtr(&_pszPrefix, pszPrefix); return S_OK; }
// IParentAndItem
STDMETHODIMP CInfoTip::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidl) { if (psf) { ATOMICRELEASE(_psf); psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf)); }
if (pidl) Pidl_Set(&_pidl, pidl); return _psf && _pidl ? S_OK : E_FAIL; }
STDMETHODIMP CInfoTip::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl) { return E_NOTIMPL; }
STDMETHODIMP CInfoTip::SetExtraProperties(const SHCOLUMNID *pscid, UINT cscid) { _cscid = min(cscid, ARRAYSIZE(_rgcols)); CopyMemory(_rgcols, pscid, _cscid * sizeof(_rgcols[0])); return S_OK; }
// in:
// pszText - description of info tip. either
// 1) a semi separated list of property names, "Author;Size" or "{fmtid},pid;{fmtid},pid"
// 2) if no semis the tip to create
// MAKEINTRESOURCE(id) of a resource ID
STDAPI CreateInfoTipFromItem(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPCWSTR pszText, REFIID riid, void **ppv) { HRESULT hr; CInfoTip* pit = new CInfoTip(psf, pidl, pszText); if (pit) { hr = pit->QueryInterface(riid, ppv); pit->Release(); } else { hr = E_OUTOFMEMORY; *ppv = NULL; } return hr; }
STDAPI CreateInfoTipFromText(LPCTSTR pszText, REFIID riid, void **ppv) { if (IS_INTRESOURCE(pszText)) return CreateInfoTipFromItem(NULL, NULL, (LPCWSTR)pszText, riid, ppv); else { WCHAR szBuf[INFOTIPSIZE]; SHTCharToUnicode(pszText, szBuf, ARRAYSIZE(szBuf)); return CreateInfoTipFromItem(NULL, NULL, szBuf, riid, ppv); } }
|