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.

545 lines
17 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "itbar.h"
  4. #include "itbdrop.h"
  5. #include "qlink.h"
  6. #include "resource.h"
  7. #include "dpastuff.h"
  8. #include "bands.h"
  9. #include "isfband.h"
  10. #include "bandprxy.h"
  11. #include "uemapp.h"
  12. #include "mluisupp.h"
  13. #define SUPERCLASS CISFBand
  14. #define DM_PERSIST DM_TRACE // trace IPS::Load, ::Save, etc.
  15. class CQuickLinks : public CISFBand
  16. {
  17. public:
  18. // *** IUnknown ***
  19. virtual STDMETHODIMP_(ULONG) AddRef(void) { return CISFBand::AddRef(); };
  20. virtual STDMETHODIMP_(ULONG) Release(void){ return CISFBand::Release(); };
  21. virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  22. // *** IPersistStream methods ***
  23. virtual STDMETHODIMP GetClassID(CLSID *pClassID);
  24. virtual STDMETHODIMP Load(IStream *pStm);
  25. virtual STDMETHODIMP Save(IStream *pstm, BOOL fClearDirty);
  26. // *** IDockingWindow methods (override) ***
  27. virtual STDMETHODIMP ShowDW(BOOL fShow);
  28. virtual STDMETHODIMP CloseDW(DWORD dw) { return CISFBand::CloseDW(dw); };
  29. // *** IObjectWithSite methods ***
  30. virtual STDMETHODIMP SetSite(IUnknown* punkSite) { return CISFBand::SetSite(punkSite); };
  31. // *** IOleCommandTarget ***
  32. virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup,
  33. DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn,
  34. VARIANTARG *pvarargOut);
  35. // *** IDeskBand methods ***
  36. virtual STDMETHODIMP GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  37. DESKBANDINFO* pdbi);
  38. // *** IDelegateDropTarget ***
  39. virtual HRESULT OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect);
  40. protected:
  41. CQuickLinks();
  42. virtual ~CQuickLinks();
  43. HRESULT _GetTitleW(LPWSTR pwzTitle, DWORD cchSize);
  44. HRESULT _InternalInit(void);
  45. virtual HRESULT _LoadOrderStream();
  46. virtual HRESULT _SaveOrderStream();
  47. virtual BOOL _AllowDropOnTitle() { return TRUE; };
  48. virtual HRESULT _GetIEnumIDList(DWORD dwEnumFlags, IEnumIDList **ppenum);
  49. private:
  50. BITBOOL _fIsInited :1;
  51. BITBOOL _fSingleLine :1;
  52. friend HRESULT CQuickLinks_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi); // for ctor
  53. };
  54. #define MAX_QL_SITES 5 // Number of Sites on the quick link bar
  55. #define SZ_REGKEY_SPECIALFOLDERS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
  56. HRESULT SHGetSpecialFolderPathEx(LPTSTR pszPath, DWORD cchSize, DWORD dwCSIDL, LPCTSTR pszFolderName)
  57. {
  58. HRESULT hr = S_OK;
  59. if (SHGetSpecialFolderPath(NULL, pszPath, CSIDL_FAVORITES, TRUE))
  60. return hr;
  61. cchSize *= sizeof(TCHAR); // Count of chars to count of bytes.
  62. if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_SPECIALFOLDERS, pszFolderName, NULL, pszPath, &cchSize))
  63. hr = E_FAIL;
  64. TraceMsg(TF_BAND|TF_GENERAL, "CQuickLinks SHGetSpecialFolderPath(CSIDL_FAVORITES), Failed so getting Fav dir from registry. Path=%s; hr=%#8lx", pszPath, hr);
  65. return hr;
  66. }
  67. #define LINKS_FOLDERNAME_KEY TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar")
  68. #define LINKS_FOLDERNAME_VALUE TEXT("LinksFolderName")
  69. // _GetTitleW and QuickLinks_GetFolder call this.
  70. // if we ever go back to ANSI days we'll get a build break
  71. // right now we are saving some space by not having A version that's not used
  72. void QuickLinks_GetName(LPTSTR pszName, DWORD cchSize, BOOL bSetup)
  73. {
  74. DWORD cb = cchSize * SIZEOF(TCHAR);
  75. // try to get the name of the folder from the registry (in case of upgrade to a different
  76. // language we cannot use the resource)
  77. if (SHGetValue(HKEY_CURRENT_USER, LINKS_FOLDERNAME_KEY, LINKS_FOLDERNAME_VALUE, NULL, (void *)pszName, &cb) != ERROR_SUCCESS)
  78. {
  79. // no luck, try the HKLM if we are doing per user registration, maybe setup stored the old links folder name there
  80. cb = cchSize * SIZEOF(TCHAR);
  81. if (!bSetup || SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion"), TEXT("LinkFolderName"), NULL, (void *)pszName, &cb) != ERROR_SUCCESS)
  82. {
  83. // if everything else fails load it from the resource
  84. MLLoadString(IDS_QLINKS, pszName, cchSize);
  85. }
  86. }
  87. }
  88. HRESULT QuickLinks_GetFolder(LPTSTR pszPath, DWORD cchSize, BOOL bSetup = FALSE)
  89. {
  90. TCHAR szQuickLinks[MAX_PATH];
  91. if (SUCCEEDED(SHGetSpecialFolderPathEx(pszPath, cchSize, CSIDL_FAVORITES, TEXT("Favorites"))))
  92. {
  93. QuickLinks_GetName(szQuickLinks, ARRAYSIZE(szQuickLinks), bSetup);
  94. if (PathCombine(pszPath, pszPath, szQuickLinks))
  95. {
  96. return S_OK;
  97. }
  98. }
  99. return E_FAIL;
  100. }
  101. #define QL_BUFFER (MAX_QL_TEXT_LENGTH + MAX_URL_STRING + MAX_TOOLTIP_STRING + 3)
  102. //
  103. // Load strings needed for quick links
  104. //
  105. // returns TRUE/FALSE if it was user specified (false used to load the default
  106. // urls, but now we leave that to branding dll
  107. BOOL QLLoadLinkName(HUSKEY hUSKey, int i, LPTSTR pszTitle, UINT cchTitle, LPTSTR pszURL, UINT cchURL)
  108. {
  109. CHAR szScratch[QL_BUFFER];
  110. DWORD dwcbData = SIZEOF(szScratch);
  111. CHAR * pszTemp;
  112. TCHAR szRegValues[12];
  113. // In IE3, links did not have its own folder. Instead, links were stored in the registry as a
  114. // set of binary streams of ANSI strings.
  115. StringCchPrintf(szRegValues, ARRAYSIZE(szRegValues), TEXT("%d"), i+1); // ok to truncate
  116. if (hUSKey &&
  117. (ERROR_SUCCESS == SHRegQueryUSValue(hUSKey, szRegValues, NULL, (LPBYTE)szScratch, &dwcbData, FALSE, NULL, 0)))
  118. {
  119. int nNULLs = 0;
  120. pszTemp = szScratch;
  121. DWORD j;
  122. for (j = 0; j < dwcbData; j++)
  123. {
  124. #ifdef MAINWIN
  125. // Because of the limitations of the MainWin registry, we'll put '*' instead of '\0'.
  126. if (*pszTemp == TEXT('*'))
  127. *pszTemp = '\0';
  128. #endif
  129. nNULLs += (UINT)(*pszTemp++ == TEXT('\0'));
  130. }
  131. // make sure we have 3 strings with a double NULL at the end
  132. if (nNULLs > 3)
  133. {
  134. pszTemp = szScratch;
  135. SHAnsiToTChar(pszTemp, pszTitle, cchTitle);
  136. pszTemp += lstrlenA(pszTemp) + 1;
  137. SHAnsiToTChar(pszTemp, pszURL, cchURL);
  138. return TRUE;
  139. }
  140. }
  141. return FALSE;
  142. }
  143. void ImportQuickLinks()
  144. {
  145. TCHAR szQuickLinksDir[MAX_PATH];
  146. if (FAILED(QuickLinks_GetFolder(szQuickLinksDir, ARRAYSIZE(szQuickLinksDir), TRUE)))
  147. return;
  148. // need to write the folder name to the registry so we can use it w/ different plug ui languages
  149. LPTSTR pszQLinks;
  150. DWORD cb;
  151. PathRemoveBackslash(szQuickLinksDir);
  152. pszQLinks = PathFindFileName(szQuickLinksDir);
  153. if (pszQLinks)
  154. {
  155. cb = (lstrlen(pszQLinks)+1) * sizeof(TCHAR);
  156. SHSetValue(HKEY_CURRENT_USER, LINKS_FOLDERNAME_KEY, LINKS_FOLDERNAME_VALUE, REG_SZ, (void *)pszQLinks, cb);
  157. }
  158. if (!PathFileExists(szQuickLinksDir) &&
  159. CreateDirectory(szQuickLinksDir, NULL))
  160. {
  161. HUSKEY hUSKey = NULL;
  162. if (ERROR_SUCCESS == SHRegOpenUSKey(TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar\\Links"), KEY_QUERY_VALUE, NULL, &hUSKey, FALSE))
  163. {
  164. // we found the key, there's something to migrate
  165. for (int i = 0; i < MAX_QL_SITES; i++)
  166. {
  167. // this was user specified... convert it
  168. LPITEMIDLIST pidl;
  169. TCHAR szURLTemp[MAX_URL_STRING];
  170. TCHAR szTitle[MAX_QL_TEXT_LENGTH];
  171. if (QLLoadLinkName(hUSKey, i, szTitle, ARRAYSIZE(szTitle), szURLTemp, ARRAYSIZE(szURLTemp)))
  172. {
  173. WCHAR szURL[MAX_URL_STRING];
  174. if (SUCCEEDED(URLSubstitution(szURLTemp, szURL, ARRAYSIZE(szURL), URLSUB_ALL)) &&
  175. SUCCEEDED(IECreateFromPath(szURL, &pidl)))
  176. {
  177. CreateShortcutInDir(pidl, szTitle, szQuickLinksDir, NULL, FALSE);
  178. ILFree(pidl);
  179. }
  180. }
  181. }
  182. SHRegCloseUSKey(hUSKey);
  183. // all converted, delete the key
  184. SHDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar\\Links"));
  185. }
  186. }
  187. else
  188. {
  189. // ie4 -> ieX upgrade
  190. // create a value in hkcu\sw\ms\ie\toolbar to indicate that we should preserve the order from the links stream
  191. // not the one from the favorites\links that we are using for links starting w/ ie5
  192. BOOL bVal = TRUE;
  193. // we don't care if this fails. if it does we'll just just favorites\links order stream
  194. SHSetValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar"),
  195. TEXT("SaveLinksOrder"), REG_BINARY, (DWORD *)&bVal, SIZEOF(bVal));
  196. }
  197. }
  198. HRESULT CQuickLinks::_InternalInit(void)
  199. {
  200. HRESULT hr = S_OK;
  201. if (!_fIsInited && !_psf)
  202. {
  203. TCHAR szPath[MAX_PATH];
  204. hr = QuickLinks_GetFolder(szPath, ARRAYSIZE(szPath));
  205. if (SUCCEEDED(hr))
  206. {
  207. LPITEMIDLIST pidlQLinks;
  208. if (!PathFileExists(szPath))
  209. CreateDirectory(szPath, NULL);
  210. if (SUCCEEDED(IECreateFromPath(szPath, &pidlQLinks)))
  211. {
  212. InitializeSFB(NULL, pidlQLinks);
  213. ILFree(pidlQLinks);
  214. }
  215. }
  216. }
  217. _fIsInited = TRUE;
  218. return hr;
  219. }
  220. CQuickLinks::CQuickLinks() :
  221. SUPERCLASS()
  222. {
  223. #ifdef DEBUG
  224. if (IsFlagSet(g_dwBreakFlags, BF_ONAPIENTER))
  225. {
  226. TraceMsg(TF_ALWAYS, "Stopping in CQuickLinks ctor");
  227. DEBUG_BREAK;
  228. }
  229. #endif
  230. ASSERT(!_fIsInited);
  231. _fCascadeFolder = TRUE;
  232. _fVariableWidth = TRUE;
  233. _pguidUEMGroup = &UEMIID_BROWSER;
  234. }
  235. CQuickLinks::~CQuickLinks()
  236. {
  237. }
  238. STDAPI CQuickLinks_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  239. {
  240. // aggregation checking is handled in class factory
  241. CQuickLinks * p = new CQuickLinks();
  242. if (p)
  243. {
  244. *ppunk = SAFECAST(p, IDeskBand *);
  245. return NOERROR;
  246. }
  247. *ppunk = NULL;
  248. return E_OUTOFMEMORY;
  249. }
  250. HRESULT CQuickLinks::_LoadOrderStream()
  251. {
  252. HRESULT hr = E_FAIL;
  253. if (_pidl && _psf) {
  254. IStream* pstm = OpenPidlOrderStream((LPCITEMIDLIST)CSIDL_FAVORITES, _pidl, REG_SUBKEY_FAVORITESA, STGM_READ);
  255. if (pstm) {
  256. OrderList_Destroy(&_hdpaOrder);
  257. hr = OrderList_LoadFromStream(pstm, &_hdpaOrder, _psf);
  258. pstm->Release();
  259. }
  260. }
  261. return hr;
  262. }
  263. HRESULT CQuickLinks::_SaveOrderStream()
  264. {
  265. HRESULT hr = E_FAIL;
  266. if (_pidl && (_hdpa || _hdpaOrder)) {
  267. IStream* pstm = OpenPidlOrderStream((LPCITEMIDLIST)CSIDL_FAVORITES, _pidl, REG_SUBKEY_FAVORITESA, STGM_CREATE | STGM_WRITE);
  268. if (pstm) {
  269. hr = OrderList_SaveToStream(pstm, (_hdpa ? _hdpa : _hdpaOrder), _psf);
  270. pstm->Release();
  271. }
  272. }
  273. if (SUCCEEDED(hr))
  274. hr = SUPERCLASS::_SaveOrderStream();
  275. return hr;
  276. }
  277. HRESULT CQuickLinks::_GetIEnumIDList(DWORD dwEnumFlags, IEnumIDList **ppenum)
  278. {
  279. HRESULT hres;
  280. ASSERT(_psf);
  281. // Pass in a NULL hwnd so the enumerator does not show any UI while
  282. // we're filling a band.
  283. hres = IShellFolder_EnumObjects(_psf, NULL, dwEnumFlags, ppenum);
  284. // we could have failed because our folder does not exist
  285. // that can happen if someone delted/renamed links while there is
  286. // stream in the registry that saves the pidl - we get the pidl and
  287. // bind to it (bind does not hit the disk so it succeeds even though
  288. // the file does not exist
  289. if (FAILED(hres) && hres != E_OUTOFMEMORY)
  290. {
  291. TCHAR szPath[MAX_PATH];
  292. ASSERT(_pidl);
  293. if (SHGetPathFromIDList(_pidl, szPath) && !PathFileExists(szPath))
  294. {
  295. hres = QuickLinks_GetFolder(szPath, ARRAYSIZE(szPath));
  296. if (SUCCEEDED(hres))
  297. {
  298. LPITEMIDLIST pidlQLinks;
  299. if (!PathFileExists(szPath))
  300. CreateDirectory(szPath, NULL);
  301. hres = IECreateFromPath(szPath, &pidlQLinks);
  302. if (SUCCEEDED(hres))
  303. {
  304. hres = InitializeSFB(NULL, pidlQLinks);
  305. if (SUCCEEDED(hres))
  306. {
  307. hres = _psf->EnumObjects(NULL, dwEnumFlags, ppenum);
  308. }
  309. ILFree(pidlQLinks);
  310. }
  311. }
  312. }
  313. }
  314. return hres;
  315. }
  316. //*** CQuickLinks::IPersistStream
  317. HRESULT CQuickLinks::Load(IStream *pstm)
  318. {
  319. HRESULT hr = S_OK;
  320. hr = SUPERCLASS::Load(pstm);
  321. // This forces a refresh
  322. _fIsInited = FALSE;
  323. ATOMICRELEASE(_psf);
  324. _InternalInit();
  325. // if we are on our first run through (i.e. this reg key exists)
  326. // we load the order stream from our old location (used in ie4) and avoid overwriting it w/ favorites stream
  327. // so user can have their custom order preserved on upgrade (they are more likely to customize links bar
  328. // order then favorites/links so we picked that one)
  329. if (SHGetValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar"),
  330. TEXT("SaveLinksOrder"), NULL, NULL, NULL) == ERROR_SUCCESS)
  331. {
  332. SHDeleteValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar"), TEXT("SaveLinksOrder"));
  333. // must persist old order stream in the new location (fav/links)
  334. _SaveOrderStream();
  335. }
  336. else
  337. {
  338. _LoadOrderStream();
  339. }
  340. return hr;
  341. }
  342. HRESULT CQuickLinks::Save(IStream *pstm, BOOL fClearDirty)
  343. {
  344. HRESULT hr = SUPERCLASS::Save(pstm, fClearDirty);
  345. _SaveOrderStream();
  346. return hr;
  347. }
  348. HRESULT CQuickLinks::GetClassID(CLSID *pClassID)
  349. {
  350. *pClassID = CLSID_QuickLinks;
  351. return S_OK;
  352. }
  353. // *** IUnknown Interface ***
  354. HRESULT CQuickLinks::QueryInterface(REFIID riid, void **ppvObj)
  355. {
  356. return SUPERCLASS::QueryInterface(riid, ppvObj);
  357. }
  358. // command target
  359. STDMETHODIMP CQuickLinks::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  360. DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  361. {
  362. HRESULT hres = S_FALSE;
  363. if (pguidCmdGroup)
  364. {
  365. if (IsEqualGUID(*pguidCmdGroup, CLSID_QuickLinks))
  366. {
  367. switch (nCmdID)
  368. {
  369. case QLCMD_SINGLELINE:
  370. _fSingleLine = (nCmdexecopt == 1);
  371. return S_OK;
  372. }
  373. }
  374. else if (IsEqualGUID(*pguidCmdGroup, CGID_ISFBand))
  375. {
  376. switch(nCmdID)
  377. {
  378. case ISFBID_SETORDERSTREAM:
  379. hres = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  380. _SaveOrderStream();
  381. break;
  382. }
  383. }
  384. }
  385. if (hres == S_FALSE)
  386. hres = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  387. return hres;
  388. }
  389. // *** IDockingWindow Interface ***
  390. HRESULT CQuickLinks::ShowDW(BOOL fShow)
  391. {
  392. if (fShow)
  393. _InternalInit();
  394. return SUPERCLASS::ShowDW(fShow);
  395. }
  396. HRESULT CQuickLinks::_GetTitleW(LPWSTR pwzTitle, DWORD cchSize)
  397. {
  398. QuickLinks_GetName(pwzTitle, cchSize, FALSE);
  399. return S_OK;
  400. }
  401. HRESULT CQuickLinks::GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi)
  402. {
  403. HRESULT hres = SUPERCLASS::GetBandInfo(dwBandID, fViewMode, pdbi);
  404. if (_hwndTB && _fSingleLine) {
  405. LRESULT lButtonSize = SendMessage(_hwndTB, TB_GETBUTTONSIZE, 0, 0L);
  406. pdbi->ptMinSize.y = HIWORD(lButtonSize);
  407. pdbi->dwModeFlags &= ~DBIMF_VARIABLEHEIGHT;
  408. }
  409. return hres;
  410. }
  411. HRESULT CQuickLinks::OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect)
  412. {
  413. HRESULT hr;
  414. BOOL fIsSafe = TRUE;
  415. // if we are not the source of the drop and the Links folder does not exist we need to create it
  416. if (_iDragSource == -1)
  417. {
  418. TCHAR szPath[MAX_PATH];
  419. hr = QuickLinks_GetFolder(szPath, ARRAYSIZE(szPath));
  420. if (SUCCEEDED(hr))
  421. {
  422. if (!PathFileExists(szPath))
  423. CreateDirectory(szPath, NULL);
  424. LPITEMIDLIST pidl;
  425. if (SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
  426. {
  427. fIsSafe = IEIsLinkSafe(_hwnd, pidl, ILS_LINK);
  428. ILFree(pidl);
  429. }
  430. }
  431. else
  432. {
  433. fIsSafe = FALSE;
  434. }
  435. }
  436. if (fIsSafe)
  437. {
  438. hr = SUPERCLASS::OnDropDDT(pdt, pdtobj, pgrfKeyState, pt, pdwEffect);
  439. }
  440. else
  441. {
  442. hr = S_FALSE;
  443. }
  444. return hr;
  445. }