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.

425 lines
12 KiB

  1. #include "shellprv.h"
  2. #include "common.h"
  3. #include "resource.h"
  4. #include "dpastuff.h"
  5. #include "bands.h"
  6. #include "isfband.h"
  7. #include "legacy.h"
  8. #include "uemapp.h"
  9. #define SUPERCLASS CISFBand
  10. #define DM_PERSIST DM_TRACE // trace IPS::Load, ::Save, etc.
  11. class CQuickLinks : public CISFBand
  12. {
  13. public:
  14. // *** IUnknown ***
  15. virtual STDMETHODIMP_(ULONG) AddRef(void) { return CISFBand::AddRef(); };
  16. virtual STDMETHODIMP_(ULONG) Release(void){ return CISFBand::Release(); };
  17. virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  18. // *** IPersistStream methods ***
  19. virtual STDMETHODIMP GetClassID(CLSID *pClassID);
  20. virtual STDMETHODIMP Load(IStream *pStm);
  21. virtual STDMETHODIMP Save(IStream *pstm, BOOL fClearDirty);
  22. // *** IDockingWindow methods (override) ***
  23. virtual STDMETHODIMP ShowDW(BOOL fShow);
  24. virtual STDMETHODIMP CloseDW(DWORD dw) { return CISFBand::CloseDW(dw); };
  25. // *** IObjectWithSite methods ***
  26. virtual STDMETHODIMP SetSite(IUnknown* punkSite) { return CISFBand::SetSite(punkSite); };
  27. // *** IOleCommandTarget ***
  28. virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup,
  29. DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn,
  30. VARIANTARG *pvarargOut);
  31. // *** IDeskBand methods ***
  32. virtual STDMETHODIMP GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  33. DESKBANDINFO* pdbi);
  34. // *** IDelegateDropTarget ***
  35. virtual HRESULT OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect);
  36. protected:
  37. CQuickLinks();
  38. virtual ~CQuickLinks();
  39. HRESULT _GetTitleW(LPWSTR pwzTitle, DWORD cchSize);
  40. HRESULT _InternalInit(void);
  41. virtual HRESULT _LoadOrderStream();
  42. virtual HRESULT _SaveOrderStream();
  43. virtual BOOL _AllowDropOnTitle() { return TRUE; };
  44. virtual HRESULT _GetIEnumIDList(DWORD dwEnumFlags, IEnumIDList **ppenum);
  45. private:
  46. BITBOOL _fIsInited :1;
  47. BITBOOL _fSingleLine :1;
  48. friend HRESULT CQuickLinks_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv); // for ctor
  49. };
  50. #define MAX_QL_SITES 5 // Number of Sites on the quick link bar
  51. #define SZ_REGKEY_SPECIALFOLDERS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
  52. HRESULT SHGetSpecialFolderPathEx(LPTSTR pszPath, DWORD cchSize, DWORD dwCSIDL, LPCTSTR pszFolderName)
  53. {
  54. HRESULT hr = S_OK;
  55. if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL, 0, pszPath)))
  56. return hr;
  57. cchSize *= sizeof(TCHAR); // Count of chars to count of bytes.
  58. if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_SPECIALFOLDERS, pszFolderName, NULL, pszPath, &cchSize))
  59. hr = E_FAIL;
  60. TraceMsg(TF_BAND|TF_GENERAL, "CQuickLinks SHGetSpecialFolderPath(CSIDL_FAVORITES), Failed so getting Fav dir from registry. Path=%s; hr=%#8lx", pszPath, hr);
  61. return hr;
  62. }
  63. #define LINKS_FOLDERNAME_KEY TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar")
  64. #define LINKS_FOLDERNAME_VALUE TEXT("LinksFolderName")
  65. // _GetTitleW and QuickLinks_GetFolder call this.
  66. // if we ever go back to ANSI days we'll get a build break
  67. // right now we are saving some space by not having A version that's not used
  68. void QuickLinks_GetName(LPTSTR pszName, DWORD cchSize, BOOL bSetup)
  69. {
  70. DWORD cb = cchSize * SIZEOF(TCHAR);
  71. // try to get the name of the folder from the registry (in case of upgrade to a different
  72. // language we cannot use the resource)
  73. if (SHGetValue(HKEY_CURRENT_USER, LINKS_FOLDERNAME_KEY, LINKS_FOLDERNAME_VALUE, NULL, (void *)pszName, &cb) != ERROR_SUCCESS)
  74. {
  75. // no luck, try the HKLM if we are doing per user registration, maybe setup stored the old links folder name there
  76. cb = cchSize * SIZEOF(TCHAR);
  77. if (!bSetup || SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion"), TEXT("LinkFolderName"), NULL, (void *)pszName, &cb) != ERROR_SUCCESS)
  78. {
  79. // if everything else fails load it from the resource
  80. LoadString(HINST_THISDLL, IDS_QLINKS, pszName, cchSize);
  81. }
  82. }
  83. }
  84. HRESULT QuickLinks_GetFolder(LPTSTR pszPath, DWORD cchSize, BOOL bSetup = FALSE)
  85. {
  86. TCHAR szQuickLinks[MAX_PATH];
  87. if ((cchSize >= MAX_PATH) &&
  88. SUCCEEDED(SHGetSpecialFolderPathEx(pszPath, cchSize, CSIDL_FAVORITES, TEXT("Favorites"))))
  89. {
  90. QuickLinks_GetName(szQuickLinks, ARRAYSIZE(szQuickLinks), bSetup);
  91. PathCombine(pszPath, pszPath, szQuickLinks);
  92. return S_OK;
  93. }
  94. return E_FAIL;
  95. }
  96. // Length of the text under each quick links
  97. #define MAX_QL_TEXT_LENGTH 256
  98. #define MAX_QL_WIDTH 92
  99. #define QL_BUFFER (MAX_QL_TEXT_LENGTH + MAX_URL_STRING + MAX_TOOLTIP_STRING + 3)
  100. HRESULT CQuickLinks::_InternalInit(void)
  101. {
  102. if (!_fIsInited && !_psf)
  103. {
  104. LPITEMIDLIST pidlQLinks;
  105. TCHAR szPath[MAX_PATH];
  106. QuickLinks_GetFolder(szPath, ARRAYSIZE(szPath));
  107. if (!PathFileExists(szPath))
  108. CreateDirectory(szPath, NULL);
  109. if (SUCCEEDED(IECreateFromPath(szPath, &pidlQLinks)))
  110. {
  111. InitializeSFB(NULL, pidlQLinks);
  112. ILFree(pidlQLinks);
  113. }
  114. }
  115. _fIsInited = TRUE;
  116. return S_OK;
  117. }
  118. CQuickLinks::CQuickLinks() :
  119. SUPERCLASS()
  120. {
  121. #ifdef DEBUG
  122. if (IsFlagSet(g_dwBreakFlags, BF_ONAPIENTER))
  123. {
  124. TraceMsg(TF_ALWAYS, "Stopping in CQuickLinks ctor");
  125. DEBUG_BREAK;
  126. }
  127. #endif
  128. ASSERT(!_fIsInited);
  129. _fCascadeFolder = TRUE;
  130. _fVariableWidth = TRUE;
  131. _pguidUEMGroup = &UEMIID_BROWSER;
  132. }
  133. CQuickLinks::~CQuickLinks()
  134. {
  135. }
  136. HRESULT CQuickLinks_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  137. {
  138. // aggregation checking is handled in class factory
  139. HRESULT hr = E_OUTOFMEMORY;
  140. CQuickLinks *pObj = new CQuickLinks();
  141. if (pObj)
  142. {
  143. hr = pObj->QueryInterface(riid, ppv);
  144. pObj->Release();
  145. }
  146. return hr;
  147. }
  148. HRESULT CQuickLinks::_LoadOrderStream()
  149. {
  150. HRESULT hr = E_FAIL;
  151. if (_pidl && _psf)
  152. {
  153. IStream* pstm = OpenPidlOrderStream((LPCITEMIDLIST)CSIDL_FAVORITES, _pidl, REG_SUBKEY_FAVORITESA, STGM_READ);
  154. if (pstm)
  155. {
  156. OrderList_Destroy(&_hdpaOrder);
  157. hr = OrderList_LoadFromStream(pstm, &_hdpaOrder, _psf);
  158. pstm->Release();
  159. }
  160. }
  161. return hr;
  162. }
  163. HRESULT CQuickLinks::_SaveOrderStream()
  164. {
  165. HRESULT hr = E_FAIL;
  166. if (_pidl && (_hdpa || _hdpaOrder))
  167. {
  168. IStream* pstm = OpenPidlOrderStream((LPCITEMIDLIST)CSIDL_FAVORITES, _pidl, REG_SUBKEY_FAVORITESA, STGM_CREATE | STGM_WRITE);
  169. if (pstm)
  170. {
  171. hr = OrderList_SaveToStream(pstm, (_hdpa ? _hdpa : _hdpaOrder), _psf);
  172. pstm->Release();
  173. }
  174. }
  175. if (SUCCEEDED(hr))
  176. hr = SUPERCLASS::_SaveOrderStream();
  177. return hr;
  178. }
  179. HRESULT CQuickLinks::_GetIEnumIDList(DWORD dwEnumFlags, IEnumIDList **ppenum)
  180. {
  181. HRESULT hres;
  182. ASSERT(_psf);
  183. // Pass in a NULL hwnd so the enumerator does not show any UI while
  184. // we're filling a band.
  185. hres = IShellFolder_EnumObjects(_psf, NULL, dwEnumFlags, ppenum);
  186. // we could have failed because our folder does not exist
  187. // that can happen if someone delted/renamed links while there is
  188. // stream in the registry that saves the pidl - we get the pidl and
  189. // bind to it (bind does not hit the disk so it succeeds even though
  190. // the file does not exist
  191. if (FAILED(hres) && hres != E_OUTOFMEMORY)
  192. {
  193. TCHAR szPath[MAX_PATH];
  194. ASSERT(_pidl);
  195. if (SHGetPathFromIDList(_pidl, szPath) && !PathFileExists(szPath))
  196. {
  197. LPITEMIDLIST pidlQLinks;
  198. QuickLinks_GetFolder(szPath, ARRAYSIZE(szPath));
  199. if (!PathFileExists(szPath))
  200. CreateDirectory(szPath, NULL);
  201. if (SUCCEEDED(IECreateFromPath(szPath, &pidlQLinks)))
  202. {
  203. if (SUCCEEDED(InitializeSFB(NULL, pidlQLinks)))
  204. {
  205. hres = _psf->EnumObjects(NULL, dwEnumFlags, ppenum);
  206. }
  207. ILFree(pidlQLinks);
  208. }
  209. }
  210. }
  211. return hres;
  212. }
  213. //*** CQuickLinks::IPersistStream
  214. HRESULT CQuickLinks::Load(IStream *pstm)
  215. {
  216. HRESULT hr = S_OK;
  217. hr = SUPERCLASS::Load(pstm);
  218. // This forces a refresh
  219. _fIsInited = FALSE;
  220. ATOMICRELEASE(_psf);
  221. _InternalInit();
  222. // if we are on our first run through (i.e. this reg key exists)
  223. // we load the order stream from our old location (used in ie4) and avoid overwriting it w/ favorites stream
  224. // so user can have their custom order preserved on upgrade (they are more likely to customize links bar
  225. // order then favorites/links so we picked that one)
  226. if (SHGetValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar"),
  227. TEXT("SaveLinksOrder"), NULL, NULL, NULL) == ERROR_SUCCESS)
  228. {
  229. SHDeleteValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar"), TEXT("SaveLinksOrder"));
  230. // must persist old order stream in the new location (fav/links)
  231. _SaveOrderStream();
  232. }
  233. else
  234. {
  235. _LoadOrderStream();
  236. }
  237. return hr;
  238. }
  239. HRESULT CQuickLinks::Save(IStream *pstm, BOOL fClearDirty)
  240. {
  241. HRESULT hr = SUPERCLASS::Save(pstm, fClearDirty);
  242. _SaveOrderStream();
  243. return hr;
  244. }
  245. HRESULT CQuickLinks::GetClassID(CLSID *pClassID)
  246. {
  247. *pClassID = CLSID_QuickLinks;
  248. return S_OK;
  249. }
  250. // *** IUnknown Interface ***
  251. HRESULT CQuickLinks::QueryInterface(REFIID riid, void **ppvObj)
  252. {
  253. return SUPERCLASS::QueryInterface(riid, ppvObj);
  254. }
  255. // command target
  256. STDMETHODIMP CQuickLinks::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  257. DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  258. {
  259. HRESULT hres = S_FALSE;
  260. if (pguidCmdGroup)
  261. {
  262. if (IsEqualGUID(*pguidCmdGroup, CLSID_QuickLinks))
  263. {
  264. switch (nCmdID)
  265. {
  266. case QLCMD_SINGLELINE:
  267. _fSingleLine = (nCmdexecopt == 1);
  268. return S_OK;
  269. }
  270. }
  271. else if (IsEqualGUID(*pguidCmdGroup, CGID_ISFBand))
  272. {
  273. switch(nCmdID)
  274. {
  275. case ISFBID_SETORDERSTREAM:
  276. hres = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  277. _SaveOrderStream();
  278. break;
  279. }
  280. }
  281. }
  282. if (hres == S_FALSE)
  283. hres = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  284. return hres;
  285. }
  286. // *** IDockingWindow Interface ***
  287. HRESULT CQuickLinks::ShowDW(BOOL fShow)
  288. {
  289. if (fShow)
  290. _InternalInit();
  291. return SUPERCLASS::ShowDW(fShow);
  292. }
  293. HRESULT CQuickLinks::_GetTitleW(LPWSTR pwzTitle, DWORD cchSize)
  294. {
  295. QuickLinks_GetName(pwzTitle, cchSize, FALSE);
  296. return S_OK;
  297. }
  298. HRESULT CQuickLinks::GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi)
  299. {
  300. HRESULT hres = SUPERCLASS::GetBandInfo(dwBandID, fViewMode, pdbi);
  301. if (_hwndTB && _fSingleLine)
  302. {
  303. LRESULT lButtonSize = SendMessage(_hwndTB, TB_GETBUTTONSIZE, 0, 0L);
  304. pdbi->ptMinSize.y = HIWORD(lButtonSize);
  305. pdbi->dwModeFlags &= ~DBIMF_VARIABLEHEIGHT;
  306. }
  307. return hres;
  308. }
  309. HRESULT CQuickLinks::OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect)
  310. {
  311. HRESULT hr;
  312. BOOL fIsSafe = TRUE;
  313. // if we are not the source of the drop and the Links folder does not exist we need to create it
  314. if (_iDragSource == -1)
  315. {
  316. TCHAR szPath[MAX_PATH];
  317. QuickLinks_GetFolder(szPath, ARRAYSIZE(szPath));
  318. if (!PathFileExists(szPath))
  319. CreateDirectory(szPath, NULL);
  320. LPITEMIDLIST pidl;
  321. if (SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
  322. {
  323. fIsSafe = IEIsLinkSafe(_hwnd, pidl, ILS_LINK);
  324. ILFree(pidl);
  325. }
  326. }
  327. if (fIsSafe)
  328. {
  329. hr = SUPERCLASS::OnDropDDT(pdt, pdtobj, pgrfKeyState, pt, pdwEffect);
  330. }
  331. else
  332. {
  333. hr = S_FALSE;
  334. }
  335. return hr;
  336. }