Source code of Windows XP (NT5)
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.

1314 lines
40 KiB

  1. /**************************************************************\
  2. FILE: address.cpp
  3. DESCRIPTION:
  4. The Class CAddressBand exists to support the Address
  5. ToolBand in either the main browser toolbar or as a
  6. ShellToolBand.
  7. \**************************************************************/
  8. #include "priv.h"
  9. #include "sccls.h"
  10. #include "addrlist.h"
  11. #include "itbar.h"
  12. #include "itbdrop.h"
  13. #include "util.h"
  14. #include "aclhist.h"
  15. #include "aclmulti.h"
  16. #include "autocomp.h"
  17. #include "address.h"
  18. #include "shellurl.h"
  19. #include "resource.h"
  20. #include "uemapp.h"
  21. #include <tb_ids.h>
  22. #include "apithk.h"
  23. #include "mluisupp.h"
  24. #define SUPERCLASS CToolBand
  25. #define MIN_DROPWIDTH 200
  26. const static TCHAR c_szAddressBandProp[] = TEXT("CAddressBand_This");
  27. //=================================================================
  28. // Implementation of CAddressBand
  29. //=================================================================
  30. //===========================
  31. // *** IUnknown Interface ***
  32. HRESULT CAddressBand::QueryInterface(REFIID riid, void **ppvObj)
  33. {
  34. if (IsEqualIID(riid, IID_IWinEventHandler))
  35. {
  36. *ppvObj = SAFECAST(this, IWinEventHandler*);
  37. }
  38. else if (IsEqualIID(riid, IID_IAddressBand))
  39. {
  40. *ppvObj = SAFECAST(this, IAddressBand*);
  41. }
  42. else if (IsEqualIID(riid, IID_IPersistStream))
  43. {
  44. *ppvObj = SAFECAST(this, IPersistStream*);
  45. }
  46. else if (IsEqualIID(riid, IID_IServiceProvider))
  47. {
  48. *ppvObj = SAFECAST(this, IServiceProvider*);
  49. }
  50. else if (IsEqualIID(riid, IID_IInputObjectSite))
  51. {
  52. *ppvObj = SAFECAST(this, IInputObjectSite*);
  53. }
  54. else
  55. {
  56. return SUPERCLASS::QueryInterface(riid, ppvObj);
  57. }
  58. AddRef();
  59. return S_OK;
  60. }
  61. //================================
  62. // *** IDockingWindow Interface ***
  63. /****************************************************\
  64. FUNCTION: ShowDW
  65. DESCRIPTION:
  66. fShow == TRUE means show the window, FALSE means
  67. remove the window from the view. The window will
  68. be created if needed.
  69. \****************************************************/
  70. HRESULT CAddressBand::ShowDW(BOOL fShow)
  71. {
  72. if (!_hwnd)
  73. return S_FALSE; // The window needs to be created first.
  74. ShowWindow(_hwnd, fShow ? SW_SHOW : SW_HIDE);
  75. // Refresh if we are becoming visible because we could have
  76. // received and ignored FileSysChange() events while
  77. // we where hidden.
  78. if (fShow && !_fVisible)
  79. Refresh(NULL);
  80. _fVisible = BOOLIFY(fShow);
  81. return SUPERCLASS::ShowDW(fShow);
  82. }
  83. HRESULT CAddressBand::CloseDW(DWORD dw)
  84. {
  85. if(_paeb)
  86. _paeb->Save(0);
  87. return SUPERCLASS::CloseDW(dw);
  88. }
  89. /****************************************************\
  90. FUNCTION: SetSite
  91. DESCRIPTION:
  92. This function will be called to have this
  93. Toolband try to obtain enough information about its
  94. parent Toolbar to create the Band window and maybe
  95. connect to a Browser Window.
  96. \****************************************************/
  97. HRESULT CAddressBand::SetSite(IUnknown *punkSite)
  98. {
  99. HRESULT hr;
  100. BOOL fSameHost = punkSite == _punkSite;
  101. if (!punkSite && _paeb)
  102. {
  103. IShellService * pss;
  104. hr = _paeb->QueryInterface(IID_IShellService, (LPVOID *)&pss);
  105. if (SUCCEEDED(hr))
  106. {
  107. hr = pss->SetOwner(NULL);
  108. pss->Release();
  109. }
  110. }
  111. hr = SUPERCLASS::SetSite(punkSite);
  112. if (punkSite && !fSameHost)
  113. {
  114. hr = _CreateAddressBand(punkSite);
  115. // This call failing is expected when the host doesn't have a Browser Window.
  116. }
  117. // Set or reset the AddressEditBox's Browser IUnknown.
  118. if (_paeb)
  119. {
  120. IShellService * pss;
  121. hr = _paeb->QueryInterface(IID_IShellService, (LPVOID *)&pss);
  122. if (SUCCEEDED(hr))
  123. {
  124. // CAddressBand and the BandSite(host) have a ref count cycle. This cycle
  125. // is broken when BandSite calls SetSite(NULL) which will cause
  126. // CAddressBand to break the cycle by releasing it's punk to the BandSite.
  127. //
  128. // CAddressEditBox and CAddressBand have the same method of breaking the
  129. // cycle. This is accomplished by passing NULL to IAddressEditBox(NULL, NULL)
  130. // if our caller is breaking the cycle. This will cause CAddressEditBox to
  131. // release it's ref count on CAddressBand.
  132. hr = pss->SetOwner((punkSite ? SAFECAST(this, IAddressBand *) : NULL));
  133. pss->Release();
  134. }
  135. }
  136. // setsite must succeed
  137. return S_OK;
  138. }
  139. //================================
  140. // *** IInputObject Methods ***
  141. HRESULT CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg)
  142. {
  143. BOOL fForwardToView = FALSE;
  144. static CHAR szAccel[2] = "\0"; // Alt-D needs to be localizable
  145. switch (lpMsg->message)
  146. {
  147. case WM_KEYDOWN: // process these
  148. if (IsVK_TABCycler(lpMsg))
  149. {
  150. // If we are tabbing away, let the edit box know so
  151. // that it clears its dirty flag.
  152. SendMessage(_hwndEdit, WM_KEYDOWN, VK_TAB, 0);
  153. }
  154. else
  155. {
  156. fForwardToView = TRUE;
  157. }
  158. switch (lpMsg->wParam)
  159. {
  160. case VK_F1: // help
  161. {
  162. //
  163. // FEATURE: Should add and accelerator for this and simply return S_FALSE, but that
  164. // causes two instances of the help dialog to come up when focus is in Trident.
  165. // This is the quick fix for IE5B2.
  166. //
  167. IOleCommandTarget* poct;
  168. IServiceProvider* psp;
  169. if (_punkSite && SUCCEEDED(_punkSite->QueryInterface(IID_IServiceProvider, (void**)&psp)))
  170. {
  171. if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser, IID_IOleCommandTarget, (LPVOID*)&poct)))
  172. {
  173. poct->Exec(&CGID_ShellBrowser, DVIDM_HELPSEARCH, 0, NULL, NULL);
  174. poct->Release();
  175. }
  176. psp->Release();
  177. }
  178. return S_FALSE;
  179. }
  180. case VK_F11: // fullscreen
  181. {
  182. return S_FALSE;
  183. }
  184. case VK_F4:
  185. {
  186. if (_fVisible)
  187. {
  188. if (HasFocusIO() == S_FALSE)
  189. SetFocus(_hwnd);
  190. // toggle the dropdown state
  191. SendMessage(_hwnd, CB_SHOWDROPDOWN,
  192. !SendMessage(_hwnd, CB_GETDROPPEDSTATE, 0, 0L), 0);
  193. // Leave focus in the edit box so you can keep typing
  194. if (_hwndEdit)
  195. SetFocus(_hwndEdit);
  196. }
  197. else
  198. {
  199. ASSERT(0); // Should this really be ignored?
  200. }
  201. return S_OK;
  202. }
  203. case VK_TAB:
  204. {
  205. // See if the editbox wants the tab character
  206. if (SendMessage(_hwndEdit, WM_GETDLGCODE, lpMsg->wParam, (LPARAM)lpMsg) == DLGC_WANTTAB)
  207. {
  208. // We want the tab character
  209. return S_OK;
  210. }
  211. break;
  212. }
  213. case VK_RETURN:
  214. {
  215. //
  216. // Ctrl-enter is used for quick complete, so pass it through
  217. //
  218. if (GetKeyState(VK_CONTROL) & 0x80000000)
  219. {
  220. TranslateMessage(lpMsg);
  221. DispatchMessage(lpMsg);
  222. return S_OK;
  223. }
  224. break;
  225. }
  226. }
  227. break;
  228. case WM_KEYUP: // eat any that WM_KEYDOWN processes
  229. switch (lpMsg->wParam)
  230. {
  231. case VK_F1: // help
  232. case VK_F11: // fullscreen
  233. return S_FALSE;
  234. case VK_RETURN:
  235. case VK_F4:
  236. case VK_TAB:
  237. return S_OK;
  238. default:
  239. break;
  240. }
  241. break;
  242. case WM_SYSCHAR:
  243. {
  244. CHAR szChar [2] = "\0";
  245. if ('\0' == szAccel[0]) {
  246. MLLoadStringA(IDS_ADDRBAND_ACCELLERATOR,szAccel,ARRAYSIZE(szAccel));
  247. }
  248. szChar[0] = (CHAR)lpMsg->wParam;
  249. if (lstrcmpiA(szChar,szAccel) == 0)
  250. {
  251. ASSERT(_fVisible);
  252. if (_fVisible && (HasFocusIO() == S_FALSE))
  253. {
  254. SetFocus(_hwnd);
  255. }
  256. return S_OK;
  257. }
  258. }
  259. break;
  260. case WM_SYSKEYUP: // eat any that WM_SYSKEYDOWN processes
  261. if ('\0' == szAccel[0]) {
  262. MLLoadStringA(IDS_ADDRBAND_ACCELLERATOR,szAccel,ARRAYSIZE(szAccel));
  263. }
  264. if ((CHAR)lpMsg->wParam == szAccel[0]) {
  265. return S_OK;
  266. }
  267. break;
  268. }
  269. HRESULT hres = EditBox_TranslateAcceleratorST(lpMsg);
  270. if (hres == S_FALSE && fForwardToView)
  271. {
  272. IShellBrowser *psb;
  273. // we did not process this try the view before we return
  274. if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_STopLevelBrowser, IID_IShellBrowser, (void **)&psb)))
  275. {
  276. IShellView *psv;
  277. if (SUCCEEDED(psb->QueryActiveShellView(&psv)))
  278. {
  279. hres = psv->TranslateAccelerator(lpMsg);
  280. psv->Release();
  281. }
  282. psb->Release();
  283. }
  284. }
  285. return hres;
  286. }
  287. HRESULT CAddressBand::HasFocusIO()
  288. {
  289. if ((_hwndEdit&& (GetFocus() == _hwndEdit)) ||
  290. SendMessage(_hwnd, CB_GETDROPPEDSTATE, 0, 0))
  291. return S_OK;
  292. return S_FALSE;
  293. }
  294. //=====================================
  295. // *** IInputObjectSite Interface ***
  296. HRESULT CAddressBand::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
  297. {
  298. HRESULT hr;
  299. ASSERT(_punkSite);
  300. hr = IUnknown_OnFocusChangeIS(_punkSite, punk, fSetFocus);
  301. return hr;
  302. }
  303. //=====================================
  304. // *** IOleCommandTarget Interface ***
  305. HRESULT CAddressBand::QueryStatus(const GUID *pguidCmdGroup,
  306. ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  307. {
  308. ASSERT(_paeb);
  309. return IUnknown_QueryStatus(_paeb, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  310. }
  311. HRESULT CAddressBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
  312. VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  313. {
  314. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  315. if (pguidCmdGroup == NULL)
  316. {
  317. // nothing
  318. }
  319. else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  320. {
  321. switch (nCmdID)
  322. {
  323. case SBCMDID_GETADDRESSBARTEXT:
  324. hr = S_OK;
  325. TCHAR wz[MAX_URL_STRING];
  326. UINT cb = 0;
  327. BSTR bstr = NULL;
  328. VariantInit(pvarargOut);
  329. if (_hwndEdit)
  330. cb = Edit_GetText(_hwndEdit, (TCHAR *)&wz, ARRAYSIZE(wz));
  331. if (cb)
  332. bstr = SysAllocStringLen(NULL, cb);
  333. if (bstr)
  334. {
  335. SHTCharToUnicode(wz, bstr, cb);
  336. pvarargOut->vt = VT_BSTR|VT_BYREF;
  337. pvarargOut->byref = bstr;
  338. }
  339. else
  340. {
  341. // VariantInit() might do this for us.
  342. pvarargOut->vt = VT_EMPTY;
  343. pvarargOut->byref = NULL;
  344. return E_FAIL; // Edit_GetText gave us nothing
  345. }
  346. break;
  347. }
  348. }
  349. else if (IsEqualGUID(CGID_DeskBand, *pguidCmdGroup))
  350. {
  351. switch (nCmdID)
  352. {
  353. case DBID_SETWINDOWTHEME:
  354. if (pvarargIn && pvarargIn->vt == VT_BSTR)
  355. {
  356. if (_hwnd)
  357. {
  358. Comctl32_SetWindowTheme(_hwnd, pvarargIn->bstrVal);
  359. Comctl32_SetWindowTheme(_hwndTools, pvarargIn->bstrVal);
  360. _BandInfoChanged();
  361. }
  362. }
  363. hr = S_OK;
  364. break;
  365. }
  366. }
  367. if (FAILED(hr))
  368. {
  369. hr = IUnknown_Exec(_paeb, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  370. }
  371. return(hr);
  372. }
  373. extern HRESULT IsDesktopBrowser(IUnknown *punkSite);
  374. //================================
  375. // *** IDeskBand Interface ***
  376. /****************************************************\
  377. FUNCTION: GetBandInfo
  378. DESCRIPTION:
  379. This function will give the caller information
  380. about this Band, mainly the size of it.
  381. \****************************************************/
  382. HRESULT CAddressBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  383. DESKBANDINFO* pdbi)
  384. {
  385. HRESULT hr = S_OK;
  386. _dwBandID = dwBandID;
  387. _fVertical = ((fViewMode & (DBIF_VIEWMODE_VERTICAL | DBIF_VIEWMODE_FLOATING)) != 0);
  388. pdbi->dwModeFlags = DBIMF_FIXEDBMP;
  389. pdbi->ptMinSize.x = 0;
  390. pdbi->ptMinSize.y = 0;
  391. if (_fVertical) {
  392. pdbi->ptMinSize.y = GetSystemMetrics(SM_CXSMICON);
  393. pdbi->ptMaxSize.y = -1; // random
  394. pdbi->ptIntegral.y = 1;
  395. pdbi->dwModeFlags |= DBIMF_VARIABLEHEIGHT;
  396. } else {
  397. if (_hwnd) {
  398. HWND hwndCombo;
  399. RECT rcCombo;
  400. hwndCombo = (HWND)SendMessage(_hwnd, CBEM_GETCOMBOCONTROL, 0, 0);
  401. ASSERT(hwndCombo);
  402. GetWindowRect(hwndCombo, &rcCombo);
  403. pdbi->ptMinSize.y = RECTHEIGHT(rcCombo);
  404. }
  405. ASSERT(pdbi->ptMinSize.y < 200);
  406. }
  407. MLLoadStringW(IDS_BAND_ADDRESS2, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle));
  408. if (IsDesktopBrowser(_punkSite) != S_FALSE) {
  409. // non- shell browser host (e.g. desktop or tray)
  410. //
  411. // this is slightly (o.k., very) hoaky. the only time we want to
  412. // show a mnemonic is when we're in a browser app. arguably we
  413. // should generalize this to all bands/bandsites by having a
  414. // DBIMF_WITHMNEMONIC or somesuch, but that would mean adding a
  415. // CBandSite::_dwModeFlag=0 and overriding it in itbar::CBandSite.
  416. // that seems like a lot of work for a special case so instead we
  417. // hack it in here based on knowledge of our host.
  418. TraceMsg(DM_TRACE, "cab.gbi: nuke Address mnemonic");
  419. MLLoadStringW(IDS_BAND_ADDRESS, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle));
  420. }
  421. return hr;
  422. }
  423. //================================
  424. // ** IWinEventHandler Interface ***
  425. /****************************************************\
  426. FUNCTION: OnWinEvent
  427. DESCRIPTION:
  428. This function will give receive events from
  429. the parent ShellToolbar.
  430. \****************************************************/
  431. HRESULT CAddressBand::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  432. {
  433. switch (uMsg)
  434. {
  435. case WM_WININICHANGE:
  436. if (SHIsExplorerIniChange(wParam, lParam) & (EICH_KINET | EICH_KINETMAIN))
  437. {
  438. _InitGoButton();
  439. }
  440. if (wParam == SPI_SETNONCLIENTMETRICS)
  441. {
  442. // Tell the combobox so that it can update its font
  443. SendMessage(_hwnd, uMsg, wParam, lParam);
  444. // Inform the band site that our height may have changed
  445. _BandInfoChanged();
  446. }
  447. break;
  448. case WM_COMMAND:
  449. {
  450. UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam);
  451. if (idCmd == FCIDM_VIEWGOBUTTON)
  452. {
  453. // Toggle the go-button visibility
  454. BOOL fShowGoButton = !SHRegGetBoolUSValue(REGSTR_PATH_MAIN,
  455. TEXT("ShowGoButton"), FALSE, /*default*/TRUE);
  456. SHRegSetUSValue(REGSTR_PATH_MAIN,
  457. TEXT("ShowGoButton"),
  458. REG_SZ,
  459. (LPVOID)(fShowGoButton ? L"yes" : L"no"),
  460. (fShowGoButton ? 4 : 3)*sizeof(TCHAR),
  461. SHREGSET_FORCE_HKCU);
  462. // Tell the world that something has changed
  463. SendShellIEBroadcastMessage(WM_WININICHANGE, 0, (LPARAM)REGSTR_PATH_MAIN, 3000);
  464. }
  465. }
  466. }
  467. if (_pweh)
  468. return _pweh->OnWinEvent(_hwnd, uMsg, wParam, lParam, plres);
  469. else
  470. return S_OK;
  471. }
  472. /****************************************************\
  473. FUNCTION: IsWindowOwner
  474. DESCRIPTION:
  475. This function will return TRUE if the HWND
  476. passed in is a HWND owned by this band.
  477. \****************************************************/
  478. HRESULT CAddressBand::IsWindowOwner(HWND hwnd)
  479. {
  480. if (_pweh)
  481. return _pweh->IsWindowOwner(hwnd);
  482. else
  483. return S_FALSE;
  484. }
  485. //================================
  486. // *** IAddressBand Interface ***
  487. /****************************************************\
  488. FUNCTION: FileSysChange
  489. DESCRIPTION:
  490. This function will handle file system change
  491. notifications.
  492. \****************************************************/
  493. HRESULT CAddressBand::FileSysChange(DWORD dwEvent, LPCITEMIDLIST * ppidl)
  494. {
  495. HRESULT hr = S_OK;
  496. if (_fVisible)
  497. {
  498. hr = IUnknown_FileSysChange(_paeb, dwEvent, ppidl);
  499. }
  500. return hr;
  501. }
  502. /****************************************************\
  503. FUNCTION: Refresh
  504. PARAMETERS:
  505. pvarType - NULL for a refress of everything.
  506. OLECMD_REFRESH_TOPMOST will only update the top most.
  507. DESCRIPTION:
  508. This function will force a refress of part
  509. or all of the AddressBand.
  510. \****************************************************/
  511. HRESULT CAddressBand::Refresh(VARIANT * pvarType)
  512. {
  513. HRESULT hr = S_OK;
  514. IAddressBand * pab;
  515. if (_paeb)
  516. {
  517. hr = _paeb->QueryInterface(IID_IAddressBand, (LPVOID *)&pab);
  518. if (SUCCEEDED(hr))
  519. {
  520. hr = pab->Refresh(pvarType);
  521. pab->Release();
  522. }
  523. }
  524. return hr;
  525. }
  526. /****************************************************\
  527. Address Band Constructor
  528. \****************************************************/
  529. CAddressBand::CAddressBand()
  530. {
  531. TraceMsg(TF_SHDLIFE, "ctor CAddressBand %x", this);
  532. // This needs to be allocated in Zero Inited Memory.
  533. // ASSERT that all Member Variables are inited to Zero.
  534. ASSERT(!_hwndEdit);
  535. ASSERT(!_paeb);
  536. ASSERT(!_pweh);
  537. _fCanFocus = TRUE; // we accept focus (see CToolBand::UIActivateIO)
  538. }
  539. /****************************************************\
  540. Address Band destructor
  541. \****************************************************/
  542. CAddressBand::~CAddressBand()
  543. {
  544. ATOMICRELEASE(_paeb);
  545. ATOMICRELEASE(_pweh);
  546. //
  547. // Make sure the toolbar is destroyed before we free
  548. // the image lists
  549. //
  550. if (_hwndTools && IsWindow(_hwndTools))
  551. {
  552. DestroyWindow(_hwndTools);
  553. }
  554. if (_himlDefault) ImageList_Destroy(_himlDefault);
  555. if (_himlHot) ImageList_Destroy(_himlHot);
  556. //
  557. // Our window must be destroyed before we are freed
  558. // so that the window doesn't try to reference us.
  559. //
  560. if (_hwnd && IsWindow(_hwnd))
  561. {
  562. DestroyWindow(_hwnd);
  563. // Null out base classes window handle because
  564. // its destructor is next
  565. _hwnd = NULL;
  566. }
  567. TraceMsg(TF_SHDLIFE, "dtor CAddressBand %x", this);
  568. }
  569. /****************************************************\
  570. FUNCTION: CAddressBand_CreateInstance
  571. DESCRIPTION:
  572. This function will create an instance of the
  573. AddressBand COM object.
  574. \****************************************************/
  575. HRESULT CAddressBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  576. {
  577. // aggregation checking is handled in class factory
  578. *ppunk = NULL;
  579. CAddressBand * p = new CAddressBand();
  580. if (p)
  581. {
  582. *ppunk = SAFECAST(p, IDeskBand *);
  583. return NOERROR;
  584. }
  585. return E_OUTOFMEMORY;
  586. }
  587. /****************************************************\
  588. FUNCTION: _CreateAddressBand
  589. DESCRIPTION:
  590. This function will create the AddressBand window
  591. with the ComboBox.
  592. \****************************************************/
  593. HRESULT CAddressBand::_CreateAddressBand(IUnknown * punkSite)
  594. {
  595. HRESULT hr = S_OK;
  596. if (_hwnd)
  597. {
  598. IShellService * pss;
  599. if (_hwndTools)
  600. {
  601. DestroyWindow(_hwndTools);
  602. _hwndTools = NULL;
  603. }
  604. DestroyWindow(_hwnd);
  605. _hwnd = NULL;
  606. ASSERT(_punkSite);
  607. if (_paeb)
  608. {
  609. hr = _paeb->QueryInterface(IID_IShellService, (LPVOID *)&pss);
  610. if (SUCCEEDED(hr))
  611. {
  612. hr = pss->SetOwner(NULL);
  613. pss->Release();
  614. }
  615. }
  616. ATOMICRELEASE(_paeb);
  617. ATOMICRELEASE(_pweh);
  618. }
  619. //
  620. // Create address window.
  621. //
  622. ASSERT(_hwndParent); // Call us after SetSite()
  623. if (!_hwndParent)
  624. {
  625. // The caller hasn't called SetSite(), so we can't
  626. // create our window because we can't find out our parent's
  627. // HWND.
  628. return E_FAIL;
  629. }
  630. _InitComCtl32(); // don't check result, if this fails our CreateWindows will fail
  631. DWORD dwWindowStyles = WS_TABSTOP | WS_CHILD | WS_CLIPCHILDREN | WS_TABSTOP | CBS_DROPDOWN | CBS_AUTOHSCROLL;
  632. // WARNING: MSN and other Rooted Explorers may not have implemented all
  633. // of the ParseDisplayName and other IShellFolder members
  634. // If we want to continue to support MSN, we will need to turn on the
  635. // CBS_DROPDOWNLIST if ISROOTEDCLASS() and the clsid is equal to the MSN clsid.
  636. // dwWindowStyles |= CBS_DROPDOWNLIST; // (This turns off the ComboBox's Editbox)
  637. DWORD dwExStyle = WS_EX_TOOLWINDOW;
  638. if (IS_WINDOW_RTL_MIRRORED(_hwndParent))
  639. {
  640. // If the parent window is mirrored then the ComboBox window will inheret the mirroring flag
  641. // And we need the reading order to be Left to right, which is the right to left in the mirrored mode.
  642. dwExStyle |= WS_EX_RTLREADING;
  643. }
  644. _hwnd = CreateWindowEx(dwExStyle, WC_COMBOBOXEX, NULL, dwWindowStyles,
  645. 0, 0, 100, 250, _hwndParent,
  646. (HMENU) FCIDM_VIEWADDRESS, HINST_THISDLL, NULL);
  647. if (_hwnd)
  648. {
  649. // Initial combobox parameters.
  650. SendMessage(_hwnd, CBEM_SETEXTENDEDSTYLE,
  651. CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE,
  652. CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE);
  653. // NOTE: _hwndEdit will be NULL if the CBS_DROPDOWNLIST flag has been turned on
  654. _hwndEdit = (HWND)SendMessage(_hwnd, CBEM_GETEDITCONTROL, 0, 0L);
  655. _hwndCombo = (HWND)SendMessage(_hwnd, CBEM_GETCOMBOCONTROL, 0, 0L);
  656. // Subclass the Edit control's procedure to handle ModeBias issue.
  657. if ( _hwndEdit && SetProp(_hwndEdit, c_szAddressBandProp, this))
  658. {
  659. _pfnOldEditProc = (WNDPROC) SetWindowLongPtr(_hwndEdit, GWLP_WNDPROC, (LONG_PTR) _ComboExEditProc);
  660. }
  661. ASSERT(!_paeb && !_pweh);
  662. hr = CoCreateInstance(CLSID_AddressEditBox, NULL, CLSCTX_INPROC_SERVER, IID_IAddressEditBox, (void **)&_paeb);
  663. // If this object fails to initialize, it won't work!!! Make sure you REGSVR32ed and RUNDLL32ed shdocvw.dll
  664. if (SUCCEEDED(hr))
  665. {
  666. hr = _paeb->QueryInterface(IID_IWinEventHandler, (LPVOID *)&_pweh);
  667. ASSERT(SUCCEEDED(hr));
  668. hr = _paeb->Init(_hwnd, _hwndEdit, AEB_INIT_AUTOEXEC, SAFECAST(this, IAddressBand *));
  669. }
  670. // Create the go button if it's enabled
  671. _InitGoButton();
  672. }
  673. else
  674. {
  675. hr = E_OUTOFMEMORY;
  676. }
  677. return hr;
  678. }
  679. //================================
  680. // *** IPersistStream Interface ***
  681. /****************************************************\
  682. FUNCTION: Load
  683. DESCRIPTION:
  684. This function will currently only persist the
  685. CAddressEditBox object.
  686. HISTORY:
  687. Ver 1: Contains the CAddressEditBox::Save() stream.
  688. \****************************************************/
  689. #define STREAM_VERSION_CADDRESSBAND 0x00000001
  690. HRESULT CAddressBand::Load(IStream *pstm)
  691. {
  692. HRESULT hr;
  693. DWORD dwSize;
  694. DWORD dwVersion;
  695. hr = LoadStreamHeader(pstm, STREAMHEADER_SIG_CADDRESSBAND, STREAM_VERSION_CADDRESSBAND,
  696. STREAM_VERSION_CADDRESSBAND, &dwSize, &dwVersion);
  697. ASSERT(SUCCEEDED(hr));
  698. if (S_OK == hr)
  699. {
  700. switch (dwVersion)
  701. {
  702. case 1: // Ver 1.
  703. // Nothing.
  704. break;
  705. default:
  706. ASSERT(0); // Should never get here.
  707. break;
  708. }
  709. }
  710. else if (S_FALSE == hr)
  711. hr = S_OK; // We already have our default data set.
  712. return hr;
  713. }
  714. /****************************************************\
  715. FUNCTION: Save
  716. DESCRIPTION:
  717. This function will currently only persist the
  718. CAddressEditBox object.
  719. HISTORY:
  720. Ver 1: Contains the CAddressEditBox::Save() stream.
  721. \****************************************************/
  722. HRESULT CAddressBand::Save(IStream *pstm, BOOL fClearDirty)
  723. {
  724. HRESULT hr;
  725. hr = SaveStreamHeader(pstm, STREAMHEADER_SIG_CADDRESSBAND,
  726. STREAM_VERSION_CADDRESSBAND, 0);
  727. ASSERT(SUCCEEDED(hr));
  728. if (SUCCEEDED(hr))
  729. {
  730. IPersistStream * pps;
  731. ASSERT(_paeb);
  732. if (_paeb)
  733. {
  734. hr = _paeb->QueryInterface(IID_IPersistStream, (LPVOID *)&pps);
  735. if(EVAL(SUCCEEDED(hr)))
  736. {
  737. hr = pps->Save(pstm, fClearDirty);
  738. pps->Release();
  739. }
  740. }
  741. }
  742. return hr;
  743. }
  744. void CAddressBand::_OnGetInfoTip(LPNMTBGETINFOTIP pnmTT)
  745. {
  746. // Format a tooltip: "go to <contents of address bar>"
  747. WCHAR szAddress[MAX_PATH];
  748. if (GetWindowText(_hwndEdit, szAddress, ARRAYSIZE(szAddress)))
  749. {
  750. WCHAR szFormat[MAX_PATH];
  751. const int MAX_TOOLTIP_LENGTH = 100;
  752. int cchMax = (pnmTT->cchTextMax < MAX_TOOLTIP_LENGTH) ? pnmTT->cchTextMax : MAX_TOOLTIP_LENGTH;
  753. MLLoadString(IDS_GO_TOOLTIP, szFormat, ARRAYSIZE(szFormat));
  754. int cch = wnsprintf(pnmTT->pszText, cchMax, szFormat, szAddress);
  755. // Append ellipses?
  756. if (cch == cchMax - 1)
  757. {
  758. // Note that Japan has a single character for ellipses, so we load
  759. // as a resource.
  760. WCHAR szEllipses[10];
  761. cch = MLLoadString(IDS_ELLIPSES, szEllipses, ARRAYSIZE(szEllipses));
  762. StrCpyN(pnmTT->pszText + cchMax - cch - 1, szEllipses, cch + 1);
  763. }
  764. }
  765. else if (pnmTT->cchTextMax > 0)
  766. {
  767. // Use button text for tooltip
  768. *pnmTT->pszText = L'\0';
  769. }
  770. }
  771. //+-------------------------------------------------------------------------
  772. // Subclassed window procedure of the combobox Edit control in the address band
  773. //--------------------------------------------------------------------------
  774. LRESULT CALLBACK CAddressBand::_ComboExEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  775. {
  776. CAddressBand* pThis = (CAddressBand*)GetProp(hwnd, c_szAddressBandProp);
  777. if (!pThis)
  778. return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
  779. WNDPROC pfnOldEditProc = pThis->_pfnOldEditProc;
  780. switch (uMsg)
  781. {
  782. case WM_KILLFOCUS :
  783. SetModeBias(MODEBIASMODE_DEFAULT);
  784. break;
  785. case WM_SETFOCUS:
  786. SetModeBias(MODEBIASMODE_URLHISTORY);
  787. break;
  788. case WM_DESTROY:
  789. //
  790. // Unsubclass myself.
  791. //
  792. RemoveProp(hwnd, c_szAddressBandProp);
  793. if (pfnOldEditProc)
  794. {
  795. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldEditProc);
  796. pThis->_pfnOldEditProc = NULL;
  797. }
  798. break;
  799. default:
  800. break;
  801. }
  802. return CallWindowProc(pfnOldEditProc, hwnd, uMsg, wParam, lParam);
  803. }
  804. //+-------------------------------------------------------------------------
  805. // Subclassed window procedure of the combobox in the address band
  806. //--------------------------------------------------------------------------
  807. LRESULT CALLBACK CAddressBand::_ComboExWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  808. {
  809. CAddressBand* pThis = (CAddressBand*)GetProp(hwnd, c_szAddressBandProp);
  810. if (!pThis)
  811. return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
  812. WNDPROC pfnOldWndProc = pThis->_pfnOldWndProc;
  813. switch (uMsg)
  814. {
  815. case WM_NOTIFYFORMAT:
  816. if (NF_QUERY == lParam)
  817. {
  818. return (DLL_IS_UNICODE ? NFR_UNICODE : NFR_ANSI);
  819. }
  820. break;
  821. case WM_WINDOWPOSCHANGING:
  822. {
  823. // Break out if the go button is hidden
  824. if (!pThis->_fGoButton)
  825. break;
  826. //
  827. // Make room for the go button on the right side
  828. //
  829. LPWINDOWPOS pwp = (LPWINDOWPOS)lParam;
  830. pwp->flags |= SWP_NOCOPYBITS;
  831. WINDOWPOS wp = *(LPWINDOWPOS)lParam;
  832. // Get the dimensions of our 'go' button
  833. RECT rc;
  834. SendMessage(pThis->_hwndTools, TB_GETITEMRECT, 0, (LPARAM)&rc);
  835. int cxGo = RECTWIDTH(rc);
  836. int cyGo = RECTHEIGHT(rc);
  837. // Make room for the go button on the right side
  838. wp.cx -= cxGo + 2;
  839. CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, (LPARAM)&wp);
  840. // Paint underneath the 'go' button
  841. RECT rcGo = {wp.cx, 0, wp.cx + cxGo + 2, wp.cy};
  842. InvalidateRect(pThis->_hwnd, &rcGo, TRUE);
  843. // The outer window can be much higher than the internal combobox.
  844. // We want to center the go button on the combobox
  845. int y;
  846. if (pThis->_hwndCombo)
  847. {
  848. // Center vertically with inner combobox
  849. RECT rcCombo;
  850. GetWindowRect(pThis->_hwndCombo, &rcCombo);
  851. y = (rcCombo.bottom - rcCombo.top - cyGo)/2;
  852. }
  853. else
  854. {
  855. y = (wp.cy - cyGo)/2;
  856. }
  857. // Position the 'go' button on the right. Note that the height will always be ok
  858. // because the addressbar displays 16x16 icons within it.
  859. SetWindowPos(pThis->_hwndTools, NULL, wp.cx + 2, y, cxGo, cyGo, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  860. // Adjust the drop-down width
  861. SendMessage(pThis->_hwndCombo, CB_SETDROPPEDWIDTH, MIN_DROPWIDTH, 0L);
  862. return 0;
  863. }
  864. case WM_SIZE:
  865. {
  866. // Break out if the go button is hidden
  867. if (!pThis->_fGoButton)
  868. break;
  869. //
  870. // Make room for the go button on the right side
  871. //
  872. int cx = LOWORD(lParam);
  873. int cy = HIWORD(lParam);
  874. // Get the dimensions of our 'go' button
  875. RECT rc;
  876. SendMessage(pThis->_hwndTools, TB_GETITEMRECT, 0, (LPARAM)&rc);
  877. int cxGo = RECTWIDTH(rc);
  878. int cyGo = RECTHEIGHT(rc);
  879. // Make room for the go button on the right side
  880. LPARAM lParamTemp = MAKELONG(cx - cxGo - 2, cy);
  881. CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParamTemp);
  882. // Paint underneath the 'go' button
  883. RECT rcGo = {cx-cxGo, 0, cx, cy};
  884. InvalidateRect(pThis->_hwnd, &rcGo, TRUE);
  885. // The outer window can be much higher than the internal combobox.
  886. // We want to center the go button on the combobox
  887. int y;
  888. if (pThis->_hwndCombo)
  889. {
  890. // Center vertically with inner combobox
  891. RECT rcCombo;
  892. GetWindowRect(pThis->_hwndCombo, &rcCombo);
  893. y = (rcCombo.bottom - rcCombo.top - cyGo)/2;
  894. }
  895. else
  896. {
  897. y = (cy - cyGo)/2;
  898. }
  899. // Position the 'go' button on the right. Note that the height will always be ok
  900. // because the addressbar displays 16x16 icons within it.
  901. SetWindowPos(pThis->_hwndTools, NULL, cx - cxGo, y, cxGo, cyGo, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  902. // Adjust the drop-down width
  903. SendMessage(pThis->_hwndCombo, CB_SETDROPPEDWIDTH, MIN_DROPWIDTH, 0L);
  904. return 0;
  905. }
  906. case WM_NOTIFY:
  907. {
  908. LPNMHDR pnm = (LPNMHDR)lParam;
  909. if (pnm->hwndFrom == pThis->_hwndTools)
  910. {
  911. switch (pnm->code)
  912. {
  913. case NM_CLICK:
  914. // Simulate an enter key press in the combobox
  915. SendMessage(pThis->_hwndEdit, WM_KEYDOWN, VK_RETURN, 0);
  916. SendMessage(pThis->_hwndEdit, WM_KEYUP, VK_RETURN, 0);
  917. // n.b. we also got a NAVADDRESS from the simulate
  918. UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVGO);
  919. break;
  920. case NM_TOOLTIPSCREATED:
  921. {
  922. //
  923. // Make the tooltip show up even when the app is nit active
  924. //
  925. NMTOOLTIPSCREATED* pnmTTC = (NMTOOLTIPSCREATED*)pnm;
  926. SHSetWindowBits(pnmTTC->hwndToolTips, GWL_STYLE, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX);
  927. }
  928. break;
  929. case TBN_GETINFOTIP:
  930. pThis->_OnGetInfoTip((LPNMTBGETINFOTIP)pnm);
  931. break;
  932. }
  933. return 0;
  934. }
  935. break;
  936. }
  937. case WM_ERASEBKGND:
  938. {
  939. // Break out if the go button is hidden
  940. if (!pThis->_fGoButton)
  941. break;
  942. //
  943. // Forward the erase background to the parent so that
  944. // we appear transparent under the go button
  945. //
  946. HDC hdc = (HDC)wParam;
  947. HWND hwndParent = GetParent(hwnd);
  948. LRESULT lres = 0;
  949. if (hwndParent)
  950. {
  951. // Adjust the origin so the parent paints in the right place
  952. POINT pt = {0,0};
  953. MapWindowPoints(hwnd, hwndParent, &pt, 1);
  954. OffsetWindowOrgEx(hdc,
  955. pt.x,
  956. pt.y,
  957. &pt);
  958. lres = SendMessage(hwndParent, WM_ERASEBKGND, (WPARAM)hdc, 0L);
  959. SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
  960. }
  961. if (lres != 0)
  962. {
  963. // We handled it
  964. return lres;
  965. }
  966. break;
  967. }
  968. case WM_DESTROY:
  969. //
  970. // Unsubclass myself.
  971. //
  972. RemoveProp(hwnd, c_szAddressBandProp);
  973. if (pfnOldWndProc)
  974. {
  975. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldWndProc);
  976. pThis->_pfnOldWndProc = NULL;
  977. }
  978. break;
  979. default:
  980. break;
  981. }
  982. return CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParam);
  983. }
  984. //+-------------------------------------------------------------------------
  985. // Creates and shows the go button
  986. //--------------------------------------------------------------------------
  987. BOOL CAddressBand::_CreateGoButton()
  988. {
  989. ASSERT(_hwndTools == NULL);
  990. BOOL fRet = FALSE;
  991. BOOL bUseClassicGlyphs = SHUseClassicToolbarGlyphs();
  992. COLORREF crMask = RGB(255, 0, 255);
  993. if (_himlDefault == NULL)
  994. {
  995. if (bUseClassicGlyphs)
  996. {
  997. _himlDefault = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_GO), 16, 0, crMask,
  998. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  999. }
  1000. else
  1001. {
  1002. _himlDefault = ImageList_LoadImage(GetModuleHandle(TEXT("shell32.dll")), MAKEINTRESOURCE(IDB_TB_GO_DEF_20), 20, 0, crMask,
  1003. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  1004. }
  1005. }
  1006. if (_himlHot == NULL)
  1007. {
  1008. if (bUseClassicGlyphs)
  1009. {
  1010. _himlHot = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_GOHOT), 16, 0, crMask,
  1011. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  1012. }
  1013. else
  1014. {
  1015. _himlHot = ImageList_LoadImage(GetModuleHandle(TEXT("shell32.dll")), MAKEINTRESOURCE(IDB_TB_GO_HOT_20), 20, 0, crMask,
  1016. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  1017. }
  1018. }
  1019. // If we have the image lists, go ahead and create the toolbar control for the go button
  1020. if (_himlDefault && _himlHot)
  1021. {
  1022. //
  1023. // Subclass the comboboxex so that we can place the go botton within it. The toolbad class
  1024. // assumes one window per band, so this trick allows us to add the button using existing windows.
  1025. // Note that comboex controls have a separate window used to wrap the internal combobox. This
  1026. // is the window that we use to host our "go" button. We must subclass before creating the
  1027. // go button so that we respond to WM_NOTIFYFORMAT with NFR_UNICODE.
  1028. //
  1029. //
  1030. if (SetProp(_hwnd, c_szAddressBandProp, this))
  1031. {
  1032. _pfnOldWndProc = (WNDPROC) SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR) _ComboExWndProc);
  1033. }
  1034. // Create the toolbar control for the go button
  1035. _hwndTools = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
  1036. WS_CHILD | TBSTYLE_FLAT |
  1037. TBSTYLE_TOOLTIPS |
  1038. TBSTYLE_LIST |
  1039. WS_CLIPCHILDREN |
  1040. WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN |
  1041. CCS_NORESIZE,
  1042. 0, 0, 0, 0, _hwnd, NULL, HINST_THISDLL, NULL);
  1043. }
  1044. if (_hwndTools)
  1045. {
  1046. // Init the toolbar control
  1047. SendMessage(_hwndTools, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
  1048. SendMessage(_hwndTools, TB_SETMAXTEXTROWS, 1, 0L);
  1049. SendMessage(_hwndTools, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, 500));
  1050. SendMessage(_hwndTools, TB_SETIMAGELIST, 0, (LPARAM)_himlDefault);
  1051. SendMessage(_hwndTools, TB_SETHOTIMAGELIST, 0, (LPARAM)_himlHot);
  1052. LRESULT nRet = SendMessage(_hwndTools, TB_ADDSTRING, (WPARAM)MLGetHinst(), (LPARAM)IDS_ADDRESS_TB_LABELS);
  1053. ASSERT(nRet == 0);
  1054. static const TBBUTTON tbb[] =
  1055. {
  1056. {0, 1, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0},
  1057. };
  1058. SendMessage(_hwndTools, TB_ADDBUTTONS, ARRAYSIZE(tbb), (LPARAM)tbb);
  1059. fRet = TRUE;
  1060. }
  1061. else
  1062. {
  1063. // If no toolbar control, don't subclass the comboboxex
  1064. if (_pfnOldWndProc)
  1065. {
  1066. RemoveProp(_hwnd, c_szAddressBandProp);
  1067. SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR) _pfnOldWndProc);
  1068. _pfnOldWndProc = NULL;
  1069. }
  1070. }
  1071. return fRet;
  1072. }
  1073. //+-------------------------------------------------------------------------
  1074. // Shows/hides the go button depending on the current registry settings
  1075. //--------------------------------------------------------------------------
  1076. void CAddressBand::_InitGoButton()
  1077. {
  1078. BOOL fUpdate = FALSE;
  1079. //
  1080. // Create the go button if it's enabled
  1081. //
  1082. // down-level client fix: only show Go in shell areas when NT5 or greater
  1083. // or on a window that was originally IE
  1084. BOOL fShowGoButton = SHRegGetBoolUSValue(REGSTR_PATH_MAIN,
  1085. TEXT("ShowGoButton"), FALSE, /*default*/TRUE)
  1086. && (WasOpenedAsBrowser(_punkSite) || GetUIVersion() >= 5);
  1087. if (fShowGoButton && (_hwndTools || _CreateGoButton()))
  1088. {
  1089. ShowWindow(_hwndTools, SW_SHOW);
  1090. _fGoButton = TRUE;
  1091. fUpdate = TRUE;
  1092. }
  1093. else if (_hwndTools && IsWindowVisible(_hwndTools))
  1094. {
  1095. ShowWindow(_hwndTools, SW_HIDE);
  1096. _fGoButton = FALSE;
  1097. fUpdate = TRUE;
  1098. }
  1099. // If the go button was hidden or shown, get the combobox to adjust itself
  1100. if (fUpdate)
  1101. {
  1102. // Resetting the item height gets the combobox to update the size of the editbox
  1103. LRESULT iHeight = SendMessage(_hwnd, CB_GETITEMHEIGHT, -1, 0);
  1104. if (iHeight != CB_ERR)
  1105. {
  1106. SendMessage(_hwnd, CB_SETITEMHEIGHT, -1, iHeight);
  1107. }
  1108. }
  1109. }