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.

1318 lines
41 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;
  755. if(SUCCEEDED(StringCchPrintf(pnmTT->pszText, cchMax, szFormat, szAddress)))
  756. {
  757. cch = lstrlen(pnmTT->pszText);
  758. // Append ellipses?
  759. if (cch == cchMax - 1)
  760. {
  761. // Note that Japan has a single character for ellipses, so we load
  762. // as a resource.
  763. WCHAR szEllipses[10];
  764. cch = MLLoadString(IDS_ELLIPSES, szEllipses, ARRAYSIZE(szEllipses));
  765. StringCchCopy(pnmTT->pszText + cchMax - cch - 1, cch + 1, szEllipses);
  766. }
  767. }
  768. }
  769. else if (pnmTT->cchTextMax > 0)
  770. {
  771. // Use button text for tooltip
  772. *pnmTT->pszText = L'\0';
  773. }
  774. }
  775. //+-------------------------------------------------------------------------
  776. // Subclassed window procedure of the combobox Edit control in the address band
  777. //--------------------------------------------------------------------------
  778. LRESULT CALLBACK CAddressBand::_ComboExEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  779. {
  780. CAddressBand* pThis = (CAddressBand*)GetProp(hwnd, c_szAddressBandProp);
  781. if (!pThis)
  782. return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
  783. WNDPROC pfnOldEditProc = pThis->_pfnOldEditProc;
  784. switch (uMsg)
  785. {
  786. case WM_KILLFOCUS :
  787. SetModeBias(MODEBIASMODE_DEFAULT);
  788. break;
  789. case WM_SETFOCUS:
  790. SetModeBias(MODEBIASMODE_URLHISTORY);
  791. break;
  792. case WM_DESTROY:
  793. //
  794. // Unsubclass myself.
  795. //
  796. RemoveProp(hwnd, c_szAddressBandProp);
  797. if (pfnOldEditProc)
  798. {
  799. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldEditProc);
  800. pThis->_pfnOldEditProc = NULL;
  801. }
  802. break;
  803. default:
  804. break;
  805. }
  806. return CallWindowProc(pfnOldEditProc, hwnd, uMsg, wParam, lParam);
  807. }
  808. //+-------------------------------------------------------------------------
  809. // Subclassed window procedure of the combobox in the address band
  810. //--------------------------------------------------------------------------
  811. LRESULT CALLBACK CAddressBand::_ComboExWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  812. {
  813. CAddressBand* pThis = (CAddressBand*)GetProp(hwnd, c_szAddressBandProp);
  814. if (!pThis)
  815. return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
  816. WNDPROC pfnOldWndProc = pThis->_pfnOldWndProc;
  817. switch (uMsg)
  818. {
  819. case WM_NOTIFYFORMAT:
  820. if (NF_QUERY == lParam)
  821. {
  822. return (DLL_IS_UNICODE ? NFR_UNICODE : NFR_ANSI);
  823. }
  824. break;
  825. case WM_WINDOWPOSCHANGING:
  826. {
  827. // Break out if the go button is hidden
  828. if (!pThis->_fGoButton)
  829. break;
  830. //
  831. // Make room for the go button on the right side
  832. //
  833. LPWINDOWPOS pwp = (LPWINDOWPOS)lParam;
  834. pwp->flags |= SWP_NOCOPYBITS;
  835. WINDOWPOS wp = *(LPWINDOWPOS)lParam;
  836. // Get the dimensions of our 'go' button
  837. RECT rc;
  838. SendMessage(pThis->_hwndTools, TB_GETITEMRECT, 0, (LPARAM)&rc);
  839. int cxGo = RECTWIDTH(rc);
  840. int cyGo = RECTHEIGHT(rc);
  841. // Make room for the go button on the right side
  842. wp.cx -= cxGo + 2;
  843. CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, (LPARAM)&wp);
  844. // Paint underneath the 'go' button
  845. RECT rcGo = {wp.cx, 0, wp.cx + cxGo + 2, wp.cy};
  846. InvalidateRect(pThis->_hwnd, &rcGo, TRUE);
  847. // The outer window can be much higher than the internal combobox.
  848. // We want to center the go button on the combobox
  849. int y;
  850. if (pThis->_hwndCombo)
  851. {
  852. // Center vertically with inner combobox
  853. RECT rcCombo;
  854. GetWindowRect(pThis->_hwndCombo, &rcCombo);
  855. y = (rcCombo.bottom - rcCombo.top - cyGo)/2;
  856. }
  857. else
  858. {
  859. y = (wp.cy - cyGo)/2;
  860. }
  861. // Position the 'go' button on the right. Note that the height will always be ok
  862. // because the addressbar displays 16x16 icons within it.
  863. SetWindowPos(pThis->_hwndTools, NULL, wp.cx + 2, y, cxGo, cyGo, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  864. // Adjust the drop-down width
  865. SendMessage(pThis->_hwndCombo, CB_SETDROPPEDWIDTH, MIN_DROPWIDTH, 0L);
  866. return 0;
  867. }
  868. case WM_SIZE:
  869. {
  870. // Break out if the go button is hidden
  871. if (!pThis->_fGoButton)
  872. break;
  873. //
  874. // Make room for the go button on the right side
  875. //
  876. int cx = LOWORD(lParam);
  877. int cy = HIWORD(lParam);
  878. // Get the dimensions of our 'go' button
  879. RECT rc;
  880. SendMessage(pThis->_hwndTools, TB_GETITEMRECT, 0, (LPARAM)&rc);
  881. int cxGo = RECTWIDTH(rc);
  882. int cyGo = RECTHEIGHT(rc);
  883. // Make room for the go button on the right side
  884. LPARAM lParamTemp = MAKELONG(cx - cxGo - 2, cy);
  885. CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParamTemp);
  886. // Paint underneath the 'go' button
  887. RECT rcGo = {cx-cxGo, 0, cx, cy};
  888. InvalidateRect(pThis->_hwnd, &rcGo, TRUE);
  889. // The outer window can be much higher than the internal combobox.
  890. // We want to center the go button on the combobox
  891. int y;
  892. if (pThis->_hwndCombo)
  893. {
  894. // Center vertically with inner combobox
  895. RECT rcCombo;
  896. GetWindowRect(pThis->_hwndCombo, &rcCombo);
  897. y = (rcCombo.bottom - rcCombo.top - cyGo)/2;
  898. }
  899. else
  900. {
  901. y = (cy - cyGo)/2;
  902. }
  903. // Position the 'go' button on the right. Note that the height will always be ok
  904. // because the addressbar displays 16x16 icons within it.
  905. SetWindowPos(pThis->_hwndTools, NULL, cx - cxGo, y, cxGo, cyGo, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  906. // Adjust the drop-down width
  907. SendMessage(pThis->_hwndCombo, CB_SETDROPPEDWIDTH, MIN_DROPWIDTH, 0L);
  908. return 0;
  909. }
  910. case WM_NOTIFY:
  911. {
  912. LPNMHDR pnm = (LPNMHDR)lParam;
  913. if (pnm->hwndFrom == pThis->_hwndTools)
  914. {
  915. switch (pnm->code)
  916. {
  917. case NM_CLICK:
  918. // Simulate an enter key press in the combobox
  919. SendMessage(pThis->_hwndEdit, WM_KEYDOWN, VK_RETURN, 0);
  920. SendMessage(pThis->_hwndEdit, WM_KEYUP, VK_RETURN, 0);
  921. // n.b. we also got a NAVADDRESS from the simulate
  922. UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVGO);
  923. break;
  924. case NM_TOOLTIPSCREATED:
  925. {
  926. //
  927. // Make the tooltip show up even when the app is nit active
  928. //
  929. NMTOOLTIPSCREATED* pnmTTC = (NMTOOLTIPSCREATED*)pnm;
  930. SHSetWindowBits(pnmTTC->hwndToolTips, GWL_STYLE, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX);
  931. }
  932. break;
  933. case TBN_GETINFOTIP:
  934. pThis->_OnGetInfoTip((LPNMTBGETINFOTIP)pnm);
  935. break;
  936. }
  937. return 0;
  938. }
  939. break;
  940. }
  941. case WM_ERASEBKGND:
  942. {
  943. // Break out if the go button is hidden
  944. if (!pThis->_fGoButton)
  945. break;
  946. //
  947. // Forward the erase background to the parent so that
  948. // we appear transparent under the go button
  949. //
  950. HDC hdc = (HDC)wParam;
  951. HWND hwndParent = GetParent(hwnd);
  952. LRESULT lres = 0;
  953. if (hwndParent)
  954. {
  955. // Adjust the origin so the parent paints in the right place
  956. POINT pt = {0,0};
  957. MapWindowPoints(hwnd, hwndParent, &pt, 1);
  958. OffsetWindowOrgEx(hdc,
  959. pt.x,
  960. pt.y,
  961. &pt);
  962. lres = SendMessage(hwndParent, WM_ERASEBKGND, (WPARAM)hdc, 0L);
  963. SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
  964. }
  965. if (lres != 0)
  966. {
  967. // We handled it
  968. return lres;
  969. }
  970. break;
  971. }
  972. case WM_DESTROY:
  973. //
  974. // Unsubclass myself.
  975. //
  976. RemoveProp(hwnd, c_szAddressBandProp);
  977. if (pfnOldWndProc)
  978. {
  979. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) pfnOldWndProc);
  980. pThis->_pfnOldWndProc = NULL;
  981. }
  982. break;
  983. default:
  984. break;
  985. }
  986. return CallWindowProc(pfnOldWndProc, hwnd, uMsg, wParam, lParam);
  987. }
  988. //+-------------------------------------------------------------------------
  989. // Creates and shows the go button
  990. //--------------------------------------------------------------------------
  991. BOOL CAddressBand::_CreateGoButton()
  992. {
  993. ASSERT(_hwndTools == NULL);
  994. BOOL fRet = FALSE;
  995. BOOL bUseClassicGlyphs = SHUseClassicToolbarGlyphs();
  996. COLORREF crMask = RGB(255, 0, 255);
  997. if (_himlDefault == NULL)
  998. {
  999. if (bUseClassicGlyphs)
  1000. {
  1001. _himlDefault = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_GO), 16, 0, crMask,
  1002. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  1003. }
  1004. else
  1005. {
  1006. _himlDefault = ImageList_LoadImage(GetModuleHandle(TEXT("shell32.dll")), MAKEINTRESOURCE(IDB_TB_GO_DEF_20), 20, 0, crMask,
  1007. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  1008. }
  1009. }
  1010. if (_himlHot == NULL)
  1011. {
  1012. if (bUseClassicGlyphs)
  1013. {
  1014. _himlHot = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_GOHOT), 16, 0, crMask,
  1015. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  1016. }
  1017. else
  1018. {
  1019. _himlHot = ImageList_LoadImage(GetModuleHandle(TEXT("shell32.dll")), MAKEINTRESOURCE(IDB_TB_GO_HOT_20), 20, 0, crMask,
  1020. IMAGE_BITMAP, LR_CREATEDIBSECTION);
  1021. }
  1022. }
  1023. // If we have the image lists, go ahead and create the toolbar control for the go button
  1024. if (_himlDefault && _himlHot)
  1025. {
  1026. //
  1027. // Subclass the comboboxex so that we can place the go botton within it. The toolbad class
  1028. // assumes one window per band, so this trick allows us to add the button using existing windows.
  1029. // Note that comboex controls have a separate window used to wrap the internal combobox. This
  1030. // is the window that we use to host our "go" button. We must subclass before creating the
  1031. // go button so that we respond to WM_NOTIFYFORMAT with NFR_UNICODE.
  1032. //
  1033. //
  1034. if (SetProp(_hwnd, c_szAddressBandProp, this))
  1035. {
  1036. _pfnOldWndProc = (WNDPROC) SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR) _ComboExWndProc);
  1037. }
  1038. // Create the toolbar control for the go button
  1039. _hwndTools = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
  1040. WS_CHILD | TBSTYLE_FLAT |
  1041. TBSTYLE_TOOLTIPS |
  1042. TBSTYLE_LIST |
  1043. WS_CLIPCHILDREN |
  1044. WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN |
  1045. CCS_NORESIZE,
  1046. 0, 0, 0, 0, _hwnd, NULL, HINST_THISDLL, NULL);
  1047. }
  1048. if (_hwndTools)
  1049. {
  1050. // Init the toolbar control
  1051. SendMessage(_hwndTools, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
  1052. SendMessage(_hwndTools, TB_SETMAXTEXTROWS, 1, 0L);
  1053. SendMessage(_hwndTools, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, 500));
  1054. SendMessage(_hwndTools, TB_SETIMAGELIST, 0, (LPARAM)_himlDefault);
  1055. SendMessage(_hwndTools, TB_SETHOTIMAGELIST, 0, (LPARAM)_himlHot);
  1056. LRESULT nRet = SendMessage(_hwndTools, TB_ADDSTRING, (WPARAM)MLGetHinst(), (LPARAM)IDS_ADDRESS_TB_LABELS);
  1057. ASSERT(nRet == 0);
  1058. static const TBBUTTON tbb[] =
  1059. {
  1060. {0, 1, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0},
  1061. };
  1062. SendMessage(_hwndTools, TB_ADDBUTTONS, ARRAYSIZE(tbb), (LPARAM)tbb);
  1063. fRet = TRUE;
  1064. }
  1065. else
  1066. {
  1067. // If no toolbar control, don't subclass the comboboxex
  1068. if (_pfnOldWndProc)
  1069. {
  1070. RemoveProp(_hwnd, c_szAddressBandProp);
  1071. SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR) _pfnOldWndProc);
  1072. _pfnOldWndProc = NULL;
  1073. }
  1074. }
  1075. return fRet;
  1076. }
  1077. //+-------------------------------------------------------------------------
  1078. // Shows/hides the go button depending on the current registry settings
  1079. //--------------------------------------------------------------------------
  1080. void CAddressBand::_InitGoButton()
  1081. {
  1082. BOOL fUpdate = FALSE;
  1083. //
  1084. // Create the go button if it's enabled
  1085. //
  1086. // down-level client fix: only show Go in shell areas when NT5 or greater
  1087. // or on a window that was originally IE
  1088. BOOL fShowGoButton = SHRegGetBoolUSValue(REGSTR_PATH_MAIN,
  1089. TEXT("ShowGoButton"), FALSE, /*default*/TRUE)
  1090. && (WasOpenedAsBrowser(_punkSite) || GetUIVersion() >= 5);
  1091. if (fShowGoButton && (_hwndTools || _CreateGoButton()))
  1092. {
  1093. ShowWindow(_hwndTools, SW_SHOW);
  1094. _fGoButton = TRUE;
  1095. fUpdate = TRUE;
  1096. }
  1097. else if (_hwndTools && IsWindowVisible(_hwndTools))
  1098. {
  1099. ShowWindow(_hwndTools, SW_HIDE);
  1100. _fGoButton = FALSE;
  1101. fUpdate = TRUE;
  1102. }
  1103. // If the go button was hidden or shown, get the combobox to adjust itself
  1104. if (fUpdate)
  1105. {
  1106. // Resetting the item height gets the combobox to update the size of the editbox
  1107. LRESULT iHeight = SendMessage(_hwnd, CB_GETITEMHEIGHT, -1, 0);
  1108. if (iHeight != CB_ERR)
  1109. {
  1110. SendMessage(_hwnd, CB_SETITEMHEIGHT, -1, iHeight);
  1111. }
  1112. }
  1113. }