Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
8.0 KiB

  1. #include "shellprv.h"
  2. #include "infotip.h"
  3. #include "ids.h"
  4. #include "prop.h"
  5. #include <mluisupp.h>
  6. // generic info tip object
  7. class CInfoTip : public IQueryInfo, public ICustomizeInfoTip, public IParentAndItem
  8. {
  9. public:
  10. // IUnknown
  11. STDMETHODIMP QueryInterface(REFIID, void **);
  12. STDMETHODIMP_(ULONG) AddRef(void);
  13. STDMETHODIMP_(ULONG) Release(void);
  14. // IQueryInfo methods.
  15. STDMETHODIMP GetInfoTip(DWORD dwFlags, WCHAR** ppwszTip);
  16. STDMETHODIMP GetInfoFlags(DWORD *pdwFlags);
  17. // ICustomizeInfoTip
  18. STDMETHODIMP SetPrefixText(LPCWSTR pszPrefix);
  19. STDMETHODIMP SetExtraProperties(const SHCOLUMNID *pscid, UINT cscid);
  20. // IParentAndItem
  21. STDMETHODIMP SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidlChild);
  22. STDMETHODIMP GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidlChild);
  23. CInfoTip(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPCWSTR pszProp);
  24. private:
  25. ~CInfoTip();
  26. HRESULT _GetInfoTipFromItem(WCHAR **ppszText);
  27. BOOL _InExtraList(const SHCOLUMNID *pscid);
  28. LONG _cRef;
  29. IShellFolder2 *_psf;
  30. LPITEMIDLIST _pidl;
  31. TCHAR _szText[INFOTIPSIZE];
  32. LPWSTR _pszPrefix;
  33. SHCOLUMNID _rgcols[8];
  34. UINT _cscid;
  35. };
  36. #define PROP_PREFIX TEXT("prop:")
  37. #define PROP_PREFIX_LEN (ARRAYSIZE(PROP_PREFIX) - 1)
  38. CInfoTip::CInfoTip(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPCWSTR pszText) : _cRef(1)
  39. {
  40. if (IS_INTRESOURCE(pszText))
  41. LoadString(HINST_THISDLL, LOWORD((UINT_PTR)pszText), _szText, ARRAYSIZE(_szText));
  42. else
  43. SHUnicodeToTChar(pszText, _szText, ARRAYSIZE(_szText));
  44. if (psf && pidl && (StrCmpNI(_szText, PROP_PREFIX, PROP_PREFIX_LEN) == 0))
  45. {
  46. // list of properties, we need the psf and pidl for this
  47. psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf));
  48. _pidl = ILClone(pidl);
  49. }
  50. }
  51. CInfoTip::~CInfoTip()
  52. {
  53. if (_psf)
  54. _psf->Release();
  55. ILFree(_pidl);
  56. Str_SetPtr(&_pszPrefix, NULL);
  57. }
  58. HRESULT CInfoTip::QueryInterface(REFIID riid, void **ppv)
  59. {
  60. static const QITAB qit[] = {
  61. QITABENT(CInfoTip, IQueryInfo),
  62. QITABENT(CInfoTip, ICustomizeInfoTip),
  63. QITABENT(CInfoTip, IParentAndItem),
  64. { 0 },
  65. };
  66. return QISearch(this, qit, riid, ppv);
  67. }
  68. ULONG CInfoTip::AddRef()
  69. {
  70. return InterlockedIncrement(&_cRef);
  71. }
  72. ULONG CInfoTip::Release()
  73. {
  74. ASSERT( 0 != _cRef );
  75. ULONG cRef = InterlockedDecrement(&_cRef);
  76. if ( 0 == cRef )
  77. {
  78. delete this;
  79. }
  80. return cRef;
  81. }
  82. BOOL CInfoTip::_InExtraList(const SHCOLUMNID *pscid)
  83. {
  84. for (UINT i = 0; i < _cscid; i++)
  85. {
  86. if (IsEqualSCID(*pscid, _rgcols[i]))
  87. return TRUE;
  88. }
  89. return FALSE;
  90. }
  91. void _AppendTipText(LPTSTR pszBuf, int cch, LPCTSTR pszCRLF, LPCTSTR pszPropName, LPCTSTR pszValue)
  92. {
  93. TCHAR szFmt[64], szProp[128];
  94. if (*pszPropName)
  95. LoadString(g_hinst, IDS_EXCOL_TEMPLATE, szFmt, SIZECHARS(szFmt));
  96. else
  97. lstrcpyn(szFmt, TEXT("%s%s%s"), ARRAYSIZE(szFmt));
  98. wnsprintf(szProp, ARRAYSIZE(szProp), szFmt, pszCRLF, pszPropName, pszValue);
  99. StrCatBuff(pszBuf, szProp, cch);
  100. }
  101. HRESULT CInfoTip::_GetInfoTipFromItem(WCHAR **ppszText)
  102. {
  103. TCHAR szTip[INFOTIPSIZE];
  104. szTip[0] = 0;
  105. IPropertyUI *ppui;
  106. if (SUCCEEDED(CoCreateInstance(CLSID_PropertiesUI, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPropertyUI, &ppui))))
  107. {
  108. LPCTSTR pszCRLF = TEXT("");
  109. if (_pszPrefix)
  110. {
  111. _AppendTipText(szTip, ARRAYSIZE(szTip), pszCRLF, TEXT(""), _pszPrefix);
  112. pszCRLF = TEXT("\n");
  113. }
  114. UINT iCurrentExtra = 0;
  115. BOOL bContinue = TRUE;
  116. ULONG chEaten = 0; // gets incremented by ParsePropertyName
  117. while (bContinue)
  118. {
  119. SHCOLUMNID scid;
  120. BOOL bDoThisOne = TRUE;
  121. if (iCurrentExtra < _cscid)
  122. {
  123. scid = _rgcols[iCurrentExtra++];
  124. }
  125. else
  126. {
  127. if (SUCCEEDED(ppui->ParsePropertyName(_szText, &scid.fmtid, &scid.pid, &chEaten)))
  128. {
  129. bDoThisOne = !_InExtraList(&scid);
  130. }
  131. else
  132. {
  133. bContinue = FALSE;
  134. }
  135. }
  136. if (bContinue)
  137. {
  138. VARIANT v = {0};
  139. if (bDoThisOne && (S_OK == _psf->GetDetailsEx(_pidl, &scid, &v)))
  140. {
  141. TCHAR szPropName[128], szValue[128];
  142. ppui->FormatForDisplay(scid.fmtid, scid.pid, (PROPVARIANT*)&v, PUIFFDF_DEFAULT, szValue, ARRAYSIZE(szValue));
  143. if (IsEqualSCID(scid, SCID_Comment))
  144. {
  145. szPropName[0] = 0; // comment property, don't use the label
  146. }
  147. else
  148. {
  149. ppui->GetDisplayName(scid.fmtid, scid.pid, PUIFNF_DEFAULT, szPropName, ARRAYSIZE(szPropName));
  150. }
  151. // if we got a value, and that value is different from
  152. // the prefix of the current tip string we append it.
  153. // that is don't dupe the same string where the comment == name
  154. if (szValue[0] && (0 != StrCmpNI(szTip, szValue, lstrlen(szValue))))
  155. {
  156. _AppendTipText(szTip, ARRAYSIZE(szTip), pszCRLF, szPropName, szValue);
  157. pszCRLF = TEXT("\n");
  158. }
  159. VariantClear(&v);
  160. }
  161. }
  162. }
  163. ppui->Release();
  164. }
  165. return SHStrDup(szTip, ppszText);
  166. }
  167. STDMETHODIMP CInfoTip::GetInfoTip(DWORD dwFlags, WCHAR** ppszText)
  168. {
  169. HRESULT hr;
  170. if (_psf && _pidl)
  171. hr = _GetInfoTipFromItem(ppszText);
  172. else if (_szText[0])
  173. hr = SHStrDup(_szText, ppszText);
  174. else
  175. hr = E_FAIL;
  176. return hr;
  177. }
  178. STDMETHODIMP CInfoTip::GetInfoFlags(DWORD *pdwFlags)
  179. {
  180. *pdwFlags = 0;
  181. return E_NOTIMPL;
  182. }
  183. // ICustomizeInfoTip
  184. STDMETHODIMP CInfoTip::SetPrefixText(LPCWSTR pszPrefix)
  185. {
  186. Str_SetPtr(&_pszPrefix, pszPrefix);
  187. return S_OK;
  188. }
  189. // IParentAndItem
  190. STDMETHODIMP CInfoTip::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidl)
  191. {
  192. if (psf)
  193. {
  194. ATOMICRELEASE(_psf);
  195. psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf));
  196. }
  197. if (pidl)
  198. Pidl_Set(&_pidl, pidl);
  199. return _psf && _pidl ? S_OK : E_FAIL;
  200. }
  201. STDMETHODIMP CInfoTip::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl)
  202. {
  203. return E_NOTIMPL;
  204. }
  205. STDMETHODIMP CInfoTip::SetExtraProperties(const SHCOLUMNID *pscid, UINT cscid)
  206. {
  207. _cscid = min(cscid, ARRAYSIZE(_rgcols));
  208. CopyMemory(_rgcols, pscid, _cscid * sizeof(_rgcols[0]));
  209. return S_OK;
  210. }
  211. // in:
  212. // pszText - description of info tip. either
  213. // 1) a semi separated list of property names, "Author;Size" or "{fmtid},pid;{fmtid},pid"
  214. // 2) if no semis the tip to create
  215. // MAKEINTRESOURCE(id) of a resource ID
  216. STDAPI CreateInfoTipFromItem(IShellFolder2 *psf, LPCITEMIDLIST pidl, LPCWSTR pszText, REFIID riid, void **ppv)
  217. {
  218. HRESULT hr;
  219. CInfoTip* pit = new CInfoTip(psf, pidl, pszText);
  220. if (pit)
  221. {
  222. hr = pit->QueryInterface(riid, ppv);
  223. pit->Release();
  224. }
  225. else
  226. {
  227. hr = E_OUTOFMEMORY;
  228. *ppv = NULL;
  229. }
  230. return hr;
  231. }
  232. STDAPI CreateInfoTipFromText(LPCTSTR pszText, REFIID riid, void **ppv)
  233. {
  234. if (IS_INTRESOURCE(pszText))
  235. return CreateInfoTipFromItem(NULL, NULL, (LPCWSTR)pszText, riid, ppv);
  236. else
  237. {
  238. WCHAR szBuf[INFOTIPSIZE];
  239. SHTCharToUnicode(pszText, szBuf, ARRAYSIZE(szBuf));
  240. return CreateInfoTipFromItem(NULL, NULL, szBuf, riid, ppv);
  241. }
  242. }