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.

917 lines
27 KiB

  1. /**************************************************************\
  2. FILE: mrulist.cpp
  3. DESCRIPTION:
  4. CMRUList implements the Shell Name Space List or DriveList.
  5. This will store a pidl and be able to populate the AddressBand
  6. combobox with the shell name space that includes that PIDL.
  7. \**************************************************************/
  8. #include "priv.h"
  9. #include "addrlist.h"
  10. #include "itbar.h"
  11. #include "itbdrop.h"
  12. #include "util.h"
  13. #include "autocomp.h"
  14. #include <urlhist.h>
  15. #include <winbase.h>
  16. #include <wininet.h>
  17. #define SUPERCLASS CAddressList
  18. ///////////////////////////////////////////////////////////////////
  19. // #DEFINEs
  20. #define MRU_LIST_MAX_CONST 25
  21. ///////////////////////////////////////////////////////////////////
  22. // Data Structures
  23. typedef struct tagSIZESTRCOMBO
  24. {
  25. DWORD dwStringSize; // Size in Characters (not bytes)
  26. LPTSTR lpszString;
  27. int iImage;
  28. int iSelectedImage;
  29. } SIZESTRCOMBO;
  30. ///////////////////////////////////////////////////////////////////
  31. // Prototypes
  32. /**************************************************************\
  33. CLASS: CMRUList
  34. DESCRIPTION:
  35. The MRU List will contain the type MRU history for the
  36. browser. This is an IAddressList used by the Address Band/Bar.
  37. \**************************************************************/
  38. class CMRUList : public CAddressList
  39. , public IMRU
  40. , public IPersistStream
  41. {
  42. public:
  43. //////////////////////////////////////////////////////
  44. // Public Interfaces
  45. //////////////////////////////////////////////////////
  46. // *** IUnknown ***
  47. virtual STDMETHODIMP_(ULONG) AddRef(void);
  48. virtual STDMETHODIMP_(ULONG) Release(void);
  49. virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  50. // *** IAddressList methods ***
  51. virtual STDMETHODIMP Connect(BOOL fConnect, HWND hwnd, IBrowserService * pbs, IBandProxy * pbp, IAutoComplete * pac);
  52. virtual STDMETHODIMP Refresh(DWORD dwType);
  53. virtual STDMETHODIMP Save(void);
  54. // *** IPersistStream methods ***
  55. virtual STDMETHODIMP GetClassID(CLSID *pClassID){ *pClassID = CLSID_MRUList; return S_OK; }
  56. virtual STDMETHODIMP Load(IStream *pStm) { return S_OK; }
  57. virtual STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty);
  58. virtual STDMETHODIMP IsDirty(void) { return S_FALSE; }
  59. virtual STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize) { return E_NOTIMPL; }
  60. // *** IMRU methods ***
  61. virtual STDMETHODIMP AddEntry(LPCWSTR pszEntry);
  62. // IWinEventHandler
  63. virtual STDMETHODIMP OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres);
  64. protected:
  65. //////////////////////////////////////////////////////
  66. // Private Member Functions
  67. //////////////////////////////////////////////////////
  68. // Constructor / Destructor
  69. CMRUList();
  70. ~CMRUList(void); // This is now an OLE Object and cannot be used as a normal Class.
  71. // Address List Modification Functions
  72. HRESULT _UpdateMRUEntry(LPCTSTR szNewValue, int nIndex, int iImage , int iISelectedImage);
  73. HRESULT _LoadList(void);
  74. HKEY _GetRegKey(BOOL fCreate);
  75. HRESULT _UpdateMRU(void);
  76. int _FindInMRU(LPCTSTR szURL);
  77. HRESULT _MRUMerge(HKEY kKey);
  78. BOOL _MoveAddressToTopOfMRU(int nMRUIndex);
  79. HRESULT _PopulateOneItem(void);
  80. HRESULT _Populate(void);
  81. void _InitCombobox(void);
  82. HRESULT _SetTopItem(void);
  83. // Friend Functions
  84. friend IAddressList * CMRUList_Create(void);
  85. //////////////////////////////////////////////////////
  86. // Private Member Variables
  87. //////////////////////////////////////////////////////
  88. BOOL _fDropDownPopulated;// Have we populated the drop down yet?
  89. BOOL _fListLoaded; // Have we loaded the Type-in MRU?
  90. BOOL _fMRUUptodate; // Is it necessary to update the MRU?
  91. BOOL _fNeedToSave; // Do we need to update the registry?
  92. SIZESTRCOMBO _szMRU[MRU_LIST_MAX_CONST]; // MRU list.
  93. int _nMRUSize; // Number of entries in MRU used.
  94. };
  95. //=================================================================
  96. // Implementation of CMRUList
  97. //=================================================================
  98. /****************************************************\
  99. FUNCTION: CMRUList_Create
  100. DESCRIPTION:
  101. This function will create an instance of the
  102. CMRUList COM object.
  103. \****************************************************/
  104. IAddressList * CMRUList_Create(void)
  105. {
  106. CMRUList *p = new CMRUList();
  107. return p;
  108. }
  109. /****************************************************\
  110. Address Band Constructor
  111. \****************************************************/
  112. CMRUList::CMRUList()
  113. {
  114. }
  115. /****************************************************\
  116. Address Band destructor
  117. \****************************************************/
  118. CMRUList::~CMRUList()
  119. {
  120. // loop through every potential saved URL in registry.
  121. if (_fListLoaded)
  122. {
  123. for (int nIndex = 0; (nIndex < MRU_LIST_MAX_CONST) && (_szMRU[nIndex].lpszString); nIndex++)
  124. {
  125. LocalFree(_szMRU[nIndex].lpszString);
  126. }
  127. }
  128. }
  129. //===========================
  130. // *** IUnknown Interface ***
  131. HRESULT CMRUList::QueryInterface(REFIID riid, void **ppvObj)
  132. {
  133. if (IsEqualIID(riid, IID_IMRU))
  134. {
  135. *ppvObj = SAFECAST(this, IMRU*);
  136. }
  137. else if (IsEqualIID(riid, IID_IPersistStream))
  138. {
  139. *ppvObj = SAFECAST(this, IPersistStream*);
  140. }
  141. else
  142. {
  143. return SUPERCLASS::QueryInterface(riid,ppvObj);
  144. }
  145. AddRef();
  146. return S_OK;
  147. }
  148. ULONG CMRUList::AddRef()
  149. {
  150. return SUPERCLASS::AddRef();
  151. }
  152. ULONG CMRUList::Release()
  153. {
  154. return SUPERCLASS::Release();
  155. }
  156. //================================
  157. // *** IAddressList Interface ***
  158. /****************************************************\
  159. FUNCTION: Connect
  160. DESCRIPTION:
  161. We are either becoming the selected list for
  162. the AddressBand's combobox, or lossing this status.
  163. We need to populate or unpopulate the combobox
  164. as appropriate.
  165. \****************************************************/
  166. HRESULT CMRUList::Connect(BOOL fConnect, HWND hwnd, IBrowserService * pbs, IBandProxy * pbp, IAutoComplete * pac)
  167. {
  168. HRESULT hr = S_OK;
  169. _fVisible = fConnect;
  170. if (!_hwnd)
  171. _hwnd = hwnd;
  172. ASSERT(_hwnd);
  173. if (fConnect)
  174. {
  175. // This needs to come before because it setups up
  176. // pointers that we need.
  177. SUPERCLASS::Connect(fConnect, hwnd, pbs, pbp, pac);
  178. // Initial combobox parameters.
  179. if (_pbp && _pbp->IsConnected() == S_FALSE)
  180. {
  181. // Do these tasks only the first time and only if
  182. // we are not in a browser window (because it will come
  183. // from the navigation complete).
  184. _PopulateOneItem();
  185. }
  186. }
  187. else
  188. {
  189. _UpdateMRU(); // Save contents of MRU because the ComboBox will be purged.
  190. _fDropDownPopulated = FALSE;
  191. // This call needs to come after _UpdateMRU() because
  192. // it releases pointers that we need.
  193. SUPERCLASS::Connect(fConnect, hwnd, pbs, pbp, pac);
  194. }
  195. return hr;
  196. }
  197. /****************************************************\
  198. FUNCTION: _SetTopItem
  199. DESCRIPTION:
  200. TODO.
  201. \****************************************************/
  202. HRESULT CMRUList::_SetTopItem(void)
  203. {
  204. COMBOBOXEXITEM cbexItem = {0};
  205. LPCTSTR pszData = _szMRU[0].lpszString;
  206. if (pszData) {
  207. cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  208. cbexItem.iItem = -1;
  209. cbexItem.pszText =(LPTSTR)pszData;
  210. cbexItem.cchTextMax = lstrlen(pszData);
  211. if(_szMRU[0].iImage == -1 || _szMRU[0].iSelectedImage == -1) {
  212. _GetUrlUI(NULL,pszData, &(_szMRU[0].iImage),\
  213. &(_szMRU[0].iSelectedImage));
  214. }
  215. cbexItem.iImage =_szMRU[0].iImage;
  216. cbexItem.iSelectedImage = _szMRU[0].iSelectedImage;
  217. SendMessage(_hwnd, CBEM_SETITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem);
  218. }
  219. return S_OK;
  220. }
  221. //================================
  222. // *** IMRU Interface ***
  223. /*******************************************************************
  224. FUNCTION: AddEntry
  225. DESCRIPTION:
  226. Adds the specified URL to the top of the address bar
  227. combo box. Limits the number of URLs in combo box to
  228. MRU_LIST_MAX_CONST.
  229. ********************************************************************/
  230. HRESULT CMRUList::AddEntry(LPCWSTR pszEntry)
  231. {
  232. HRESULT hr = S_OK;
  233. _fNeedToSave = TRUE;
  234. if (_fDropDownPopulated)
  235. {
  236. _ComboBoxInsertURL(pszEntry, MAX_URL_STRING, MRU_LIST_MAX_CONST);
  237. _fMRUUptodate = FALSE;
  238. }
  239. else
  240. {
  241. int nMRUIndex;
  242. if (!_fListLoaded)
  243. _LoadList();
  244. // Since we don't own the ComboBox, we need to add it to
  245. // the end of our MRU data.
  246. nMRUIndex = _FindInMRU(pszEntry); // Now make it the top most.
  247. if (-1 != nMRUIndex)
  248. {
  249. // We already have this entry in our list, so all we need
  250. // to do is move it to the top.
  251. _MoveAddressToTopOfMRU(nMRUIndex);
  252. return hr;
  253. }
  254. for (nMRUIndex = 0; nMRUIndex < MRU_LIST_MAX_CONST; nMRUIndex++)
  255. {
  256. if (!_szMRU[nMRUIndex].lpszString)
  257. { // We found an empty spot.
  258. _UpdateMRUEntry(pszEntry, nMRUIndex, -1, -1);
  259. break; // We are done.
  260. }
  261. }
  262. if (MRU_LIST_MAX_CONST == nMRUIndex)
  263. {
  264. // The MRU is full so we will replace the last entry.
  265. _UpdateMRUEntry(pszEntry, --nMRUIndex, -1, -1);
  266. }
  267. _MoveAddressToTopOfMRU(nMRUIndex); // Now make it the top most.
  268. }
  269. TraceMsg(TF_BAND|TF_GENERAL, "CMRUList: AddEntry(), URL=%s", pszEntry);
  270. return hr;
  271. }
  272. //================================
  273. // *** IPersistStream Interface ***
  274. /****************************************************\
  275. FUNCTION: Save
  276. DESCRIPTION:
  277. TODO.
  278. \****************************************************/
  279. HRESULT CMRUList::Save(IStream *pstm, BOOL fClearDirty)
  280. {
  281. // APPCOMPAT: There currently is a bug in the shell that it leaks
  282. // an object. This causes CAddressBand to never be
  283. // destructed when hosted in the TaskBar.
  284. // Since we normally call IAddressList::SaveList() in the
  285. // destructor, we will now need to call it
  286. // from here in that case.
  287. if (_pbp && _pbp->IsConnected() == S_FALSE)
  288. {
  289. Save();
  290. }
  291. return S_OK;
  292. }
  293. /****************************************************\
  294. FUNCTION: _InitCombobox
  295. DESCRIPTION:
  296. Prepare the combo box for this list. This normally
  297. means that the indenting and icon are either turned
  298. on or off.
  299. \****************************************************/
  300. void CMRUList::_InitCombobox()
  301. {
  302. HIMAGELIST himlSysSmall;
  303. Shell_GetImageLists(NULL, &himlSysSmall);
  304. SendMessage(_hwnd, CBEM_SETIMAGELIST, 0, (LPARAM)himlSysSmall);
  305. SendMessage(_hwnd, CBEM_SETEXTENDEDSTYLE, 0,0);
  306. SUPERCLASS::_InitCombobox();
  307. }
  308. HKEY CMRUList::_GetRegKey(BOOL fCreate)
  309. {
  310. BOOL fIsConnected = FALSE;
  311. HKEY hKey;
  312. DWORD result;
  313. LPCTSTR pszKey;
  314. if (_pbp)
  315. fIsConnected = (_pbp->IsConnected() == S_OK);
  316. if (fIsConnected)
  317. pszKey = SZ_REGKEY_TYPEDURLMRU;
  318. else
  319. pszKey = SZ_REGKEY_TYPEDCMDMRU;
  320. if (fCreate)
  321. result = RegCreateKey(HKEY_CURRENT_USER, pszKey, &hKey);
  322. else
  323. result = RegOpenKey(HKEY_CURRENT_USER, pszKey, &hKey);
  324. if (result != ERROR_SUCCESS)
  325. return NULL;
  326. return hKey;
  327. }
  328. /****************************************************\
  329. FUNCTION: _LoadList
  330. DESCRIPTION:
  331. When the ComboBox is switched to this MRU
  332. AddressList, the contents need to be populated. Before
  333. that happens, we copy the data to the combobox
  334. from the registry.
  335. \****************************************************/
  336. HRESULT CMRUList::_LoadList(void)
  337. {
  338. HRESULT hr = S_OK;
  339. HKEY hKey;
  340. DWORD dwCount;
  341. TCHAR szAddress[MAX_URL_STRING+1];
  342. ASSERT(!_fListLoaded);
  343. ASSERT(_hwnd);
  344. hKey = _GetRegKey(TRUE);
  345. ASSERT(hKey);
  346. if (!hKey)
  347. return E_FAIL;
  348. for (dwCount = 0; dwCount < MRU_LIST_MAX_CONST ; dwCount++)
  349. {
  350. hr = GetMRUEntry(hKey, dwCount, szAddress, SIZECHARS(szAddress), NULL);
  351. if (SUCCEEDED(hr))
  352. _UpdateMRUEntry(szAddress, (int)dwCount, -1, -1);
  353. else
  354. {
  355. _szMRU[dwCount].lpszString = NULL;
  356. _szMRU[dwCount].iImage = -1;
  357. _szMRU[dwCount].iSelectedImage = -1;
  358. }
  359. }
  360. RegCloseKey(hKey);
  361. _fListLoaded = TRUE;
  362. return hr;
  363. }
  364. /****************************************************\
  365. FUNCTION: Save
  366. DESCRIPTION:
  367. When this object is closed, we save the contents
  368. to the registry.
  369. \****************************************************/
  370. HRESULT CMRUList::Save(void)
  371. {
  372. HRESULT hr = S_OK;
  373. HKEY hKey;
  374. DWORD result;
  375. TCHAR szValueName[10]; // big enough for "url99"
  376. int nCount;
  377. int nItems = (_fDropDownPopulated) ? ComboBox_GetCount(_hwnd) : _nMRUSize;
  378. if (!_fListLoaded || !_fNeedToSave) // Don't save the registry if we don't need to.
  379. return S_OK;
  380. if (!_fMRUUptodate)
  381. hr = _UpdateMRU();
  382. hKey = _GetRegKey(TRUE);
  383. ASSERT(hKey);
  384. if (!hKey)
  385. return E_FAIL;
  386. hr = _MRUMerge(hKey); // Merge if the list has been modified.
  387. // loop through every potential saved URL in registry.
  388. for (nCount = 0; nCount < MRU_LIST_MAX_CONST; nCount++)
  389. {
  390. // make a value name a la "url1" (1-based for historical reasons)
  391. wnsprintf(szValueName, ARRAYSIZE(szValueName), SZ_REGVAL_MRUENTRY, nCount+1);
  392. // for every combo box item we have, get the corresponding
  393. // text and save it in the registry
  394. if (nCount < nItems && _szMRU[nCount].lpszString)
  395. {
  396. // store it in registry and off to the next one.
  397. result = SHSetValue(hKey, NULL, szValueName, REG_SZ, (CONST BYTE *) _szMRU[nCount].lpszString,
  398. _szMRU[nCount].dwStringSize*SIZEOF(TCHAR));
  399. }
  400. else
  401. {
  402. // if we get here, we've run out of combo box items (or
  403. // failed to retrieve text for one of them). Delete any
  404. // extra items that may be lingering in the registry.
  405. SHDeleteValue(hKey, NULL, szValueName);
  406. }
  407. }
  408. _fNeedToSave = FALSE;
  409. RegCloseKey(hKey);
  410. return hr;
  411. }
  412. /****************************************************\
  413. FUNCTION: _MRUMerge
  414. DESCRIPTION:
  415. This function will merge the current contents
  416. of the saved MRU. This means that if the Address
  417. Band is being closed, it will load the MRU again
  418. because it could have been saved by a AddressBar
  419. that was recently closed down. The merge happens
  420. like this: If the MRU is not full, items
  421. in the registry will be appended to the end
  422. of the MRU if they don't currently exist in the
  423. MRU.
  424. \****************************************************/
  425. HRESULT CMRUList::_MRUMerge(HKEY hKey)
  426. {
  427. HRESULT hr = S_OK;
  428. UINT nCount;
  429. UINT nNextFreeSlot = _nMRUSize;
  430. long lResult;
  431. TCHAR szValueName[10]; // big enough for "url99"
  432. TCHAR szAddress[MAX_URL_STRING+1];
  433. DWORD dwAddress;
  434. ASSERT(_fListLoaded);
  435. ASSERT(hKey);
  436. for (nCount = 0; (nCount < MRU_LIST_MAX_CONST) && (nNextFreeSlot < MRU_LIST_MAX_CONST); nCount++)
  437. {
  438. // make a value name a la "url1" (1-based for historical reasons)
  439. wnsprintf(szValueName, ARRAYSIZE(szValueName), SZ_REGVAL_MRUENTRY, nCount+1);
  440. dwAddress = SIZEOF(szAddress);
  441. lResult = SHQueryValueEx(hKey, szValueName, NULL, NULL, (LPBYTE) szAddress, &dwAddress);
  442. if (ERROR_SUCCESS == lResult)
  443. {
  444. if (-1 == _FindInMRU(szAddress))
  445. {
  446. // We found a unique item. Add it to our free slot.
  447. _UpdateMRUEntry(szAddress, nNextFreeSlot++, -1, -1);
  448. }
  449. }
  450. else
  451. break;
  452. }
  453. // REARCHITECT: Because the AddressBand is always closed after all
  454. // AddressBars when the shell is shut down, anything
  455. // new in the AddressBars will be ignored if the
  456. // MRU in the AddressBand is full. Revisit.
  457. return hr;
  458. }
  459. /****************************************************\
  460. FUNCTION: _UpdateMRU
  461. DESCRIPTION:
  462. Save the contents of the Combobox because
  463. it will be purged for the next AddressList.
  464. \****************************************************/
  465. HRESULT CMRUList::_UpdateMRU(void)
  466. {
  467. HRESULT hr = S_OK;
  468. TCHAR szAddress[MAX_URL_STRING+1];
  469. // get the number of items in combo box
  470. int nItems;
  471. int nCount;
  472. if (!_hwnd)
  473. return S_OK;
  474. if (!_fDropDownPopulated)
  475. return S_OK; // Nothing to update.
  476. nItems = ComboBox_GetCount(_hwnd);
  477. ASSERT(_hwnd);
  478. // loop through every potential saved URL in registry.
  479. for (nCount = 0; nCount < MRU_LIST_MAX_CONST; nCount++)
  480. {
  481. // for every combo box item we have, get the corresponding
  482. // text and save it in our local array.
  483. if (nCount < nItems)
  484. {
  485. COMBOBOXEXITEM cbexItem = {0};
  486. cbexItem.mask = CBEIF_TEXT|CBEIF_IMAGE|CBEIF_SELECTEDIMAGE;
  487. cbexItem.pszText = szAddress;
  488. cbexItem.cchTextMax = ARRAYSIZE(szAddress);
  489. cbexItem.iItem = nCount;
  490. if (SendMessage(_hwnd, CBEM_GETITEM, 0, (LPARAM) &cbexItem))
  491. {
  492. hr = _UpdateMRUEntry(szAddress, nCount, cbexItem.iImage, cbexItem.iSelectedImage);
  493. }
  494. }
  495. else
  496. {
  497. if (_szMRU[nCount].lpszString)
  498. {
  499. // Free this array entry because it's not being used.
  500. LocalFree(_szMRU[nCount].lpszString);
  501. _szMRU[nCount].lpszString = NULL;
  502. _szMRU[nCount].iImage = -1;
  503. _szMRU[nCount].iSelectedImage = -1;
  504. _nMRUSize--;
  505. }
  506. }
  507. }
  508. _fMRUUptodate = TRUE;
  509. TraceMsg(TF_BAND|TF_GENERAL, "CMRUList: _UpdateMRU().");
  510. return hr;
  511. }
  512. /****************************************************\
  513. FUNCTION: _UpdateMRUEntry
  514. DESCRIPTION:
  515. When the ComboBox is switched to this MRU
  516. AddressList, the contents need to be populated. Before
  517. that happens, we copy the data to the combobox
  518. from the registry.
  519. \****************************************************/
  520. HRESULT CMRUList::_UpdateMRUEntry(LPCTSTR szNewValue, int nIndex, int iImage , int iSelectedImage)
  521. {
  522. DWORD dwStrSize = lstrlen(szNewValue);
  523. if (!szNewValue)
  524. {
  525. // The caller wants us to free the string.
  526. if (_szMRU[nIndex].lpszString)
  527. {
  528. // We have a string that needs freeing.
  529. LocalFree(_szMRU[nIndex].lpszString);
  530. _szMRU[nIndex].lpszString = NULL;
  531. _nMRUSize--;
  532. }
  533. return S_OK;
  534. }
  535. if (!(_szMRU[nIndex].lpszString))
  536. {
  537. // We need to create the string buffer
  538. _szMRU[nIndex].dwStringSize = dwStrSize+1;
  539. _szMRU[nIndex].lpszString = (LPTSTR) LocalAlloc(LPTR, _szMRU[nIndex].dwStringSize*SIZEOF(TCHAR));
  540. if (!(_szMRU[nIndex].lpszString))
  541. return E_FAIL;
  542. _nMRUSize++;
  543. }
  544. if (dwStrSize + 1 > _szMRU[nIndex].dwStringSize)
  545. {
  546. // We need to increase the size of the buffer.
  547. LocalFree(_szMRU[nIndex].lpszString);
  548. _szMRU[nIndex].dwStringSize = dwStrSize+1;
  549. _szMRU[nIndex].lpszString = (LPTSTR) LocalAlloc(LPTR, _szMRU[nIndex].dwStringSize*SIZEOF(TCHAR));
  550. if (!(_szMRU[nIndex].lpszString))
  551. return E_FAIL;
  552. }
  553. lstrcpyn(_szMRU[nIndex].lpszString, szNewValue, _szMRU[nIndex].dwStringSize);
  554. _szMRU[nIndex].iImage = iImage;
  555. _szMRU[nIndex].iSelectedImage = iSelectedImage;
  556. return S_OK;
  557. }
  558. /****************************************************\
  559. FUNCTION: _Populate
  560. DESCRIPTION:
  561. fills in the entire combo.
  562. WARNING!!!!!!!!:
  563. This is expensive, don't do it unless absolutely
  564. necessary!
  565. \****************************************************/
  566. HRESULT CMRUList::_Populate(void)
  567. {
  568. HRESULT hr = S_OK;
  569. CShellUrl *psu;
  570. if (!_fListLoaded)
  571. hr = _LoadList(); // Load Data
  572. if (_fDropDownPopulated)
  573. return S_OK; // We are already populated.
  574. psu = new CShellUrl();
  575. if (psu)
  576. {
  577. // We need to set the "Shell Path" so that we can find
  578. // the correct icons for items in "desktop" and in
  579. // Desktop/My Computer".
  580. SetDefaultShellPath(psu);
  581. // Give it a parent for displaying message boxes
  582. psu->SetMessageBoxParent(_hwnd);
  583. // read values from registry and put them in combo box
  584. COMBOBOXEXITEM cbexItem = {0};
  585. cbexItem.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  586. for (cbexItem.iItem = 0; cbexItem.iItem < MRU_LIST_MAX_CONST ; cbexItem.iItem++)
  587. {
  588. if (_szMRU[cbexItem.iItem].lpszString)
  589. {
  590. cbexItem.pszText = _szMRU[cbexItem.iItem].lpszString;
  591. cbexItem.cchTextMax = _szMRU[cbexItem.iItem].dwStringSize;
  592. //Do Image creation when we actually populate
  593. if(_szMRU[cbexItem.iItem].iImage == -1 || _szMRU[cbexItem.iItem].iSelectedImage == -1) {
  594. _GetUrlUI(psu,_szMRU[cbexItem.iItem].lpszString, &(_szMRU[cbexItem.iItem].iImage),\
  595. &(_szMRU[cbexItem.iItem].iSelectedImage));
  596. }
  597. // initialize the image indexes
  598. cbexItem.iImage = _szMRU[cbexItem.iItem].iImage;
  599. cbexItem.iSelectedImage = _szMRU[cbexItem.iItem].iSelectedImage;
  600. SendMessage(_hwnd, CBEM_INSERTITEM, (WPARAM)0, (LPARAM)(LPVOID)&cbexItem);
  601. }
  602. else
  603. break; // Stop populating when we hit the max.
  604. }
  605. _fDropDownPopulated = TRUE;
  606. //Delete the shell url object
  607. delete psu;
  608. } else {
  609. // low mem
  610. hr = E_OUTOFMEMORY;
  611. }
  612. TraceMsg(TF_BAND|TF_GENERAL, "CMRUList: _Populate(). This is a VERY EXPENSIVE operation.");
  613. return hr;
  614. }
  615. /****************************************************\
  616. FUNCTION: _PopulateOneItem
  617. DESCRIPTION:
  618. This just files the ComboBox's edit control.
  619. We do this when we want to postpone populating
  620. the entire drop down list.
  621. \****************************************************/
  622. HRESULT CMRUList::_PopulateOneItem(void)
  623. {
  624. HRESULT hr = S_OK;
  625. if (!_fListLoaded)
  626. hr = _LoadList(); // Load Data
  627. if (_fDropDownPopulated)
  628. return S_OK; // We are already populated.
  629. hr = _SetTopItem();
  630. return hr;
  631. }
  632. /****************************************************\
  633. FUNCTION: Refresh
  634. DESCRIPTION:
  635. Update the URL in the Top of the list.
  636. \****************************************************/
  637. HRESULT CMRUList::Refresh(DWORD dwType)
  638. {
  639. HRESULT hr = S_OK;
  640. if (OLECMD_REFRESH_ENTIRELIST == dwType)
  641. {
  642. // Force a refresh. We don't move the contents
  643. // of the of the Combobox to the MRU because the
  644. // user wanted to refresh the Combobox because
  645. // it's contents may be tainted.
  646. SendMessage(_hwnd, CB_RESETCONTENT, 0, 0L);
  647. _fDropDownPopulated = FALSE;
  648. }
  649. return hr;
  650. }
  651. //================================
  652. // *** Internal/Private Methods ***
  653. /*******************************************************************
  654. FUNCTION: _MoveAddressToTopOfMRU
  655. PARAMETERS:
  656. nMRUIndex - index of be moved to top.
  657. DESCRIPTION:
  658. This function will move the specified index to the top of
  659. the list.
  660. ********************************************************************/
  661. BOOL CMRUList::_MoveAddressToTopOfMRU(int nMRUIndex)
  662. {
  663. int nCurrent;
  664. SIZESTRCOMBO sscNewTopItem;
  665. _fNeedToSave = TRUE;
  666. ASSERT(nMRUIndex < MRU_LIST_MAX_CONST);
  667. // Save off new top item info.
  668. sscNewTopItem.dwStringSize = _szMRU[nMRUIndex].dwStringSize;
  669. sscNewTopItem.lpszString = _szMRU[nMRUIndex].lpszString;
  670. sscNewTopItem.iImage = _szMRU[nMRUIndex].iImage;
  671. sscNewTopItem.iSelectedImage = _szMRU[nMRUIndex].iSelectedImage;
  672. for (nCurrent = nMRUIndex; nCurrent > 0; nCurrent--)
  673. {
  674. // Move item down in list.
  675. _szMRU[nCurrent].dwStringSize = _szMRU[nCurrent-1].dwStringSize;
  676. _szMRU[nCurrent].lpszString = _szMRU[nCurrent-1].lpszString;
  677. _szMRU[nCurrent].iImage = _szMRU[nCurrent-1].iImage;
  678. _szMRU[nCurrent].iSelectedImage = _szMRU[nCurrent-1].iSelectedImage;
  679. }
  680. // Set new top item.
  681. _szMRU[0].dwStringSize = sscNewTopItem.dwStringSize;
  682. _szMRU[0].lpszString = sscNewTopItem.lpszString;
  683. _szMRU[0].iImage = sscNewTopItem.iImage;
  684. _szMRU[0].iSelectedImage = sscNewTopItem.iSelectedImage;
  685. return TRUE;
  686. }
  687. /*******************************************************************
  688. FUNCTION: _FindInMRU
  689. PARAMETERS:
  690. szURL - URL to see if it exists in list.
  691. DESCRIPTION:
  692. Search through MRU for URL. Return value will be -1 if not
  693. found or index if found.
  694. ********************************************************************/
  695. int CMRUList::_FindInMRU(LPCTSTR szURL)
  696. {
  697. int nCurrent;
  698. for (nCurrent = 0; (nCurrent < MRU_LIST_MAX_CONST) && _szMRU[nCurrent].lpszString; nCurrent++)
  699. {
  700. if (0 == StrCmpN(_szMRU[nCurrent].lpszString, szURL, _szMRU[nCurrent].dwStringSize))
  701. {
  702. // We found it.
  703. return nCurrent;
  704. }
  705. }
  706. return -1;
  707. }
  708. HRESULT CMRUList::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  709. {
  710. switch(uMsg) {
  711. case WM_WININICHANGE:
  712. {
  713. HKEY hkey = _GetRegKey(FALSE);
  714. if (hkey) {
  715. RegCloseKey(hkey);
  716. } else {
  717. // reset if the key is gone
  718. if (_fVisible) {
  719. SendMessage(_hwnd, CB_RESETCONTENT, 0, 0L);
  720. }
  721. _fDropDownPopulated = FALSE;
  722. _fListLoaded = FALSE;
  723. }
  724. }
  725. break;
  726. }
  727. return SUPERCLASS::OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  728. }