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.

2975 lines
95 KiB

  1. /**************************************************************\
  2. FILE: aeditbox.cpp
  3. DESCRIPTION:
  4. The Class CAddressEditBox exists to support a typical
  5. set of functionality used in Editboxes or ComboBoxes. This
  6. object will add AutoComplete functionality to the EditBox and
  7. specify default "AutoComplete" Lists. If the control is a
  8. ComboBoxEd, this object will populate the drop down list
  9. appropriately.
  10. \**************************************************************/
  11. #include "priv.h"
  12. #include "sccls.h"
  13. #include "addrlist.h"
  14. #include "itbar.h"
  15. #include "itbdrop.h"
  16. #include "util.h"
  17. #include "aclhist.h"
  18. #include "aclmulti.h"
  19. #include "autocomp.h"
  20. #include "address.h"
  21. #include "shellurl.h"
  22. #include "bandprxy.h"
  23. #include "uemapp.h"
  24. #include "apithk.h"
  25. #include "accdel.h"
  26. #include "resource.h"
  27. #include "mluisupp.h"
  28. #ifdef UNIX
  29. #include "unixstuff.h"
  30. #include "shalias.h"
  31. #endif
  32. extern DWORD g_dwStopWatchMode;
  33. // Needed in order to track down NTRAID#187504-Bryanst-Tracking Winsta for corruption
  34. HWINSTA g_hWinStationBefore = NULL;
  35. HWINSTA g_hWinStationAfter = NULL;
  36. HWINSTA g_hWinStationAfterEx = NULL;
  37. // Internal message for async processing of the IDList when navigating
  38. UINT g_nAEB_AsyncNavigation = 0;
  39. ///////////////////////////////////////////////////////////////////
  40. // #DEFINEs
  41. #define SZ_ADDRESSCOMBO_PROP TEXT("CAddressCombo_This")
  42. #define SZ_ADDRESSCOMBOEX_PROP TEXT("CAddressComboEx_This")
  43. #define SEL_ESCAPE_PRESSED (-2)
  44. ///////////////////////////////////////////////////////////////////
  45. // Data Structures
  46. enum ENUMLISTTYPE
  47. {
  48. LT_NONE,
  49. LT_SHELLNAMESPACE,
  50. LT_TYPEIN_MRU,
  51. };
  52. ///////////////////////////////////////////////////////////////////
  53. // class AsyncNav: this object contains all the necessary information
  54. // to execute an asynchronous navigation task, so that
  55. // the user doesn't have to wait for navigation to
  56. // finish before doing anything, and the navigation
  57. // can be canceled if it takes too long.
  58. class AsyncNav
  59. {
  60. public:
  61. // Public Functions ***************************************
  62. AsyncNav()
  63. {
  64. _cRef = 1;
  65. _pShellUrl = NULL;
  66. _pszUrl = NULL;
  67. }
  68. LONG AddRef()
  69. {
  70. return InterlockedIncrement(&_cRef);
  71. }
  72. LONG Release()
  73. {
  74. if (InterlockedDecrement(&_cRef))
  75. return _cRef;
  76. delete this;
  77. return 0;
  78. }
  79. // Data members ***************************************
  80. CShellUrl * _pShellUrl;
  81. DWORD _dwParseFlags;
  82. BOOL _fWasCorrected;
  83. BOOL _fPidlCheckOnly;
  84. HRESULT _hr;
  85. LPTSTR _pszUrl;
  86. HWND _hwnd; // HWND that receives the message when processing is done.
  87. BOOL _fReady; // This ensures that we will not try to use the object before it's ready
  88. // CONSIDER: the memory can be released and then re-used by the same object
  89. // CONSIDER: which would have us believe that the navigation should be done.
  90. // CONSIDER: But if the navigation had been canceled and the memory re-used by the next AsyncNav alloc
  91. // CONSIDER: we would handle the message g_nAEB_AsyncNavigation with an
  92. // CONSIDER: unprocessed AsyncNav object. (See the handler for g_nAEB_AsyncNavigation).
  93. private:
  94. LONG _cRef;
  95. ~AsyncNav()
  96. {
  97. delete _pShellUrl;
  98. _pShellUrl = NULL;
  99. Str_SetPtr(&_pszUrl, NULL);
  100. }
  101. };
  102. ///////////////////////////////////////////////////////////////////
  103. // Prototypes
  104. /**************************************************************\
  105. CLASS: CAddressEditBox
  106. \**************************************************************/
  107. class CAddressEditBox
  108. : public IWinEventHandler
  109. , public IDispatch
  110. , public IAddressBand
  111. , public IAddressEditBox
  112. , public IOleCommandTarget
  113. , public IPersistStream
  114. , public IShellService
  115. {
  116. public:
  117. //////////////////////////////////////////////////////
  118. // Public Interfaces
  119. //////////////////////////////////////////////////////
  120. // *** IUnknown ***
  121. virtual STDMETHODIMP_(ULONG) AddRef(void);
  122. virtual STDMETHODIMP_(ULONG) Release(void);
  123. virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  124. // *** IOleCommandTarget methods ***
  125. virtual STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
  126. OLECMD rgCmds[], OLECMDTEXT *pcmdtext);
  127. virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
  128. VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
  129. // *** IWinEventHandler methods ***
  130. virtual STDMETHODIMP OnWinEvent (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plre);
  131. virtual STDMETHODIMP IsWindowOwner(HWND hwnd);
  132. // *** IDispatch methods ***
  133. virtual STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) {return E_NOTIMPL;}
  134. virtual STDMETHODIMP GetTypeInfo(UINT itinfo,LCID lcid,ITypeInfo **pptinfo) {return E_NOTIMPL;}
  135. virtual STDMETHODIMP GetIDsOfNames(REFIID riid,OLECHAR **rgszNames,UINT cNames, LCID lcid, DISPID * rgdispid) {return E_NOTIMPL;}
  136. virtual STDMETHODIMP Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,
  137. DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,UINT * puArgErr);
  138. // *** IPersistStream methods ***
  139. virtual STDMETHODIMP GetClassID(CLSID *pClassID){ *pClassID = CLSID_AddressEditBox; return S_OK; }
  140. virtual STDMETHODIMP Load(IStream *pStm) {return S_OK;}
  141. virtual STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty) { Save(0); return S_OK;}
  142. virtual STDMETHODIMP IsDirty(void) {return S_OK;} // Indicate that we are dirty and ::Save() needs to be called.
  143. virtual STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize) {return E_NOTIMPL;}
  144. // *** IAddressBand methods ***
  145. virtual STDMETHODIMP FileSysChange(DWORD dwEvent, LPCITEMIDLIST *ppidl);
  146. virtual STDMETHODIMP Refresh(VARIANT * pvarType);
  147. // *** IAddressEditBox methods ***
  148. virtual STDMETHODIMP Init(HWND hwndComboBox, HWND hwndEditBox, DWORD dwFlags, IUnknown * punkParent);
  149. virtual STDMETHODIMP SetCurrentDir(LPCOLESTR pwzDir);
  150. virtual STDMETHODIMP ParseNow(DWORD dwFlags);
  151. virtual STDMETHODIMP Execute(DWORD dwExecFlags);
  152. virtual STDMETHODIMP Save(DWORD dwReserved);
  153. // *** IShellService methods ***
  154. STDMETHODIMP SetOwner(IUnknown* punkOwner);
  155. protected:
  156. //////////////////////////////////////////////////////
  157. // Private Member Functions
  158. //////////////////////////////////////////////////////
  159. // Constructor / Destructor
  160. CAddressEditBox();
  161. ~CAddressEditBox(void); // This is now an OLE Object and cannot be used as a normal Class.
  162. LRESULT _OnNotify(LPNMHDR pnm);
  163. LRESULT _OnCommand(WPARAM wParam, LPARAM lParam);
  164. LRESULT _OnBeginEdit(LPNMHDR pnm) ;
  165. LRESULT _OnEndEditW(LPNMCBEENDEDITW pnmW);
  166. LRESULT _OnEndEditA(LPNMCBEENDEDITA pnmA);
  167. HRESULT _ConnectToBrwsrConnectionPoint(BOOL fConnect, IUnknown * punk);
  168. HRESULT _ConnectToBrwsrWnd(IUnknown* punk);
  169. HRESULT _UseNewList(ENUMLISTTYPE eltNew);
  170. HRESULT _CreateCShellUrl(void);
  171. HRESULT _HandleUserAction(LPCTSTR pszUrl, int iNewSelection);
  172. HRESULT _NavigationComplete(LPCTSTR pszUrl, BOOL fChangeLists, BOOL fAddToMRU);
  173. void _SetAutocompleteOptions();
  174. void _GetUrlAndCache(void);
  175. BOOL _IsShellUrl(void);
  176. static HRESULT _NavigateToUrlCB(LPARAM lParam, LPTSTR lpUrl);
  177. static LRESULT CALLBACK _ComboSubclassWndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
  178. // Functions for keeping dirty contents from getting clobbered
  179. BOOL _IsDirty();
  180. void _ClearDirtyFlag();
  181. void _InstallHookIfDirty();
  182. void _RemoveHook();
  183. LRESULT _MsgHook(int nCode, WPARAM wParam, MOUSEHOOKSTRUCT *pmhs);
  184. static LRESULT CALLBACK CAddressEditBox::_MsgHook(int nCode, WPARAM wParam, LPARAM lParam);
  185. static LRESULT CALLBACK _ComboExSubclassWndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
  186. static LRESULT CALLBACK _EditSubclassWndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
  187. static BOOL CALLBACK _EnumFindWindow(HWND hwnd, LPARAM lParam);
  188. HRESULT _FinishNavigate();
  189. static DWORD WINAPI _AsyncNavigateThreadProc(LPVOID pvData); // do async navigation: figure out the PIDL on a separate thread.
  190. void _JustifyAddressBarText( void );
  191. HRESULT _AsyncNavigate(AsyncNav *pAsyncNav);
  192. HRESULT _CancelNavigation();
  193. // Friend Functions
  194. friend HRESULT CAddressEditBox_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi);
  195. //////////////////////////////////////////////////////
  196. // Private Member Variables
  197. //////////////////////////////////////////////////////
  198. int m_cRef; // COM Object Ref Count
  199. IUnknown * m_punkParent; // Our Parent that will receive events if something happens.
  200. DWORD m_dwFlags; // Flags that will modify the behavior of this object.
  201. HWND m_hwnd; // Address ComboBoxEx Control if we control a ComboBoxEx.
  202. HWND m_hwndEdit; // Address EditBox Control Window
  203. WNDPROC m_lpfnComboWndProc; // Former WndProc of Combo child
  204. int m_nOldSelection; // Previous Drop Down Selection.
  205. // Objects for Navigation
  206. IBandProxy * m_pbp; // The BandProxy that will take care of finding the window to Navigate.
  207. IBrowserService*m_pbs; // Only valid when we are in a Browser Windows Toolbar. (Not Toolband)
  208. DWORD m_dwcpCookie; // ConnectionPoint cookie for DWebBrowserEvents2 from the Browser Window.
  209. LPTSTR m_pszCurrentUrl; // Needed in case refresh occurs.
  210. LPTSTR m_pszPendingURL; // Pending URL. We hang on to it until navigation finished before adding to MRU.
  211. LPTSTR m_pszUserEnteredURL; // Keep the exact text the user entered just in case we need to do a search.
  212. LPTSTR m_pszHttpErrorUrl;
  213. BOOL m_fDidShellExec; // Was the last navigation handled by calleding ShellExec()? (Used when refreshing)
  214. BOOL m_fConnectedToBrowser; // Are we connected to a browser?
  215. AsyncNav * m_pAsyncNav;
  216. // AutoComplete Functionality
  217. IAutoComplete2* m_pac; // AutoComplete object
  218. IShellService * m_pssACLISF; // AutoComplete ISF List. Needed if we need to change browsers.
  219. // AddressLists
  220. ENUMLISTTYPE m_elt;
  221. ENUMLISTTYPE m_eltPrevious;
  222. IAddressList * m_palCurrent; // CurrentList.
  223. IAddressList * m_palSNS; // Shell Name Space List.
  224. IAddressList * m_palMRU; // Type-in MRU List.
  225. IMRU * m_pmru; // MRU List.
  226. CShellUrl * m_pshuUrl;
  227. // Variables for keeping dirty contens from getting clobbered
  228. static CAssociationList m_al; // associate thread id with this class
  229. WNDPROC m_lpfnComboExWndProc;// Former WndProc of ComboBoxEx
  230. WNDPROC m_lpfnEditWndProc; // Former WndProc of Edit control in ComboBox
  231. HHOOK m_hhook; // mouse message hook
  232. COMBOBOXEXITEM m_cbex; // last change received while dirty
  233. HWND m_hwndBrowser; // top-level browser window
  234. BOOL m_fAssociated; // if we are entered in m_al for this thread
  235. BOOL m_fAsyncNavInProgress; // tells if we have a pending async navigate already in progress
  236. };
  237. class CAddressEditAccessible : public CDelegateAccessibleImpl
  238. {
  239. public:
  240. CAddressEditAccessible(HWND hwndCombo, HWND hwndEdit);
  241. // *** IUnknown ***
  242. STDMETHODIMP_(ULONG) AddRef();
  243. STDMETHODIMP_(ULONG) Release();
  244. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  245. // *** IAccessible ***
  246. STDMETHODIMP get_accName(VARIANT varChild, BSTR *pszName);
  247. STDMETHODIMP get_accValue(VARIANT varChild, BSTR *pszValue);
  248. protected:
  249. virtual ~CAddressEditAccessible();
  250. private:
  251. DWORD m_dwRefCount;
  252. HWND m_hwndEdit;
  253. LPWSTR m_pwszName;
  254. };
  255. //=================================================================
  256. // Static variables
  257. //=================================================================
  258. CAssociationList CAddressEditBox::m_al;
  259. //=================================================================
  260. // Implementation of CAddressEditBox
  261. //=================================================================
  262. //===========================
  263. // *** IUnknown Interface ***
  264. HRESULT CAddressEditBox::QueryInterface(REFIID riid, void **ppvObj)
  265. {
  266. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IWinEventHandler))
  267. {
  268. *ppvObj = SAFECAST(this, IWinEventHandler*);
  269. }
  270. else if (IsEqualIID(riid, IID_IDispatch))
  271. {
  272. *ppvObj = SAFECAST(this, IDispatch*);
  273. }
  274. else if (IsEqualIID(riid, IID_IAddressBand))
  275. {
  276. *ppvObj = SAFECAST(this, IAddressBand*);
  277. }
  278. else if (IsEqualIID(riid, IID_IAddressEditBox))
  279. {
  280. *ppvObj = SAFECAST(this, IAddressEditBox*);
  281. }
  282. else if (IsEqualIID(riid, IID_IOleCommandTarget))
  283. {
  284. *ppvObj = SAFECAST(this, IOleCommandTarget*);
  285. }
  286. else if (IsEqualIID(riid, IID_IPersistStream))
  287. {
  288. *ppvObj = SAFECAST(this, IPersistStream*);
  289. }
  290. else if (IsEqualIID(riid, IID_IShellService))
  291. {
  292. *ppvObj = SAFECAST(this, IShellService*);
  293. }
  294. else
  295. {
  296. *ppvObj = NULL;
  297. return E_NOINTERFACE;
  298. }
  299. AddRef();
  300. return S_OK;
  301. }
  302. ULONG CAddressEditBox::AddRef(void)
  303. {
  304. m_cRef++;
  305. return m_cRef;
  306. }
  307. ULONG CAddressEditBox::Release(void)
  308. {
  309. ASSERT(m_cRef > 0);
  310. m_cRef--;
  311. if (m_cRef > 0)
  312. {
  313. return m_cRef;
  314. }
  315. delete this;
  316. return 0;
  317. }
  318. //=====================================
  319. // *** IOleCommandTarget Interface ***
  320. HRESULT CAddressEditBox::QueryStatus(const GUID *pguidCmdGroup,
  321. ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  322. {
  323. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  324. if (rgCmds == NULL)
  325. {
  326. return(E_INVALIDARG);
  327. }
  328. if (pguidCmdGroup==NULL)
  329. {
  330. hr = S_OK;
  331. for (UINT i=0; i<cCmds; i++)
  332. {
  333. ULONG l;
  334. rgCmds[i].cmdf = 0;
  335. switch (rgCmds[i].cmdID)
  336. {
  337. case OLECMDID_PASTE:
  338. if (m_hwndEdit && OpenClipboard(m_hwndEdit))
  339. {
  340. // IDEA: We might want to support CF_URL here (SatoNa)
  341. if (GetClipboardData(CF_TEXT))
  342. {
  343. rgCmds[i].cmdf = OLECMDF_ENABLED;
  344. }
  345. CloseClipboard();
  346. }
  347. break;
  348. case OLECMDID_COPY:
  349. case OLECMDID_CUT:
  350. if (m_hwndEdit)
  351. {
  352. l=(ULONG)SendMessage(m_hwndEdit, EM_GETSEL, 0, 0);
  353. if (LOWORD(l) != HIWORD(l))
  354. {
  355. rgCmds[i].cmdf = OLECMDF_ENABLED;
  356. }
  357. }
  358. break;
  359. case OLECMDID_SELECTALL:
  360. if (m_hwndEdit)
  361. {
  362. // Select All -- not allowed if there's no text or if everything is
  363. // selected. Latter case takes care of first one.
  364. int ichMinSel;
  365. int ichMaxSel;
  366. int cch = (int)SendMessage(m_hwndEdit, WM_GETTEXTLENGTH, 0, 0);
  367. SendMessage(m_hwndEdit, EM_GETSEL, (WPARAM)&ichMinSel, (LPARAM)&ichMaxSel);
  368. if ((ichMinSel != 0) || (ichMaxSel != cch))
  369. {
  370. rgCmds[i].cmdf = OLECMDF_ENABLED;
  371. }
  372. }
  373. }
  374. }
  375. }
  376. return(hr);
  377. }
  378. HRESULT CAddressEditBox::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
  379. VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  380. {
  381. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  382. if (pguidCmdGroup == NULL)
  383. {
  384. hr = S_OK;
  385. switch(nCmdID)
  386. {
  387. case OLECMDID_COPY:
  388. if (m_hwndEdit)
  389. SendMessage(m_hwndEdit, WM_COPY, 0, 0);
  390. break;
  391. case OLECMDID_PASTE:
  392. // IDEA: We might want to support CF_URL here (SatoNa)
  393. if (m_hwndEdit)
  394. SendMessage(m_hwndEdit, WM_PASTE, 0, 0);
  395. break;
  396. case OLECMDID_CUT:
  397. if (m_hwndEdit)
  398. SendMessage(m_hwndEdit, WM_CUT, 0, 0);
  399. break;
  400. case OLECMDID_SELECTALL:
  401. if (m_hwndEdit)
  402. Edit_SetSel(m_hwndEdit, 0, (LPARAM)-1);
  403. break;
  404. default:
  405. hr = OLECMDERR_E_UNKNOWNGROUP;
  406. break;
  407. }
  408. }
  409. else if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  410. {
  411. hr = S_OK;
  412. switch (nCmdID)
  413. {
  414. #ifdef UNIX
  415. // We do an OleCmdTarget->Exec() with this command to change the
  416. // focus to the address bar.
  417. case SBCMDID_SETADDRESSBARFOCUS:
  418. if ( m_hwndEdit )
  419. SetFocus( m_hwndEdit );
  420. break;
  421. case SBCMDID_HASADDRESSBARFOCUS:
  422. if ( GetFocus() != m_hwndEdit )
  423. return E_FAIL;
  424. break;
  425. #endif
  426. case SBCMDID_ERRORPAGE:
  427. {
  428. // We save urls to error pages so that they don't get placed
  429. // into the MRU
  430. if (pvarargIn && pvarargIn->vt == VT_BSTR)
  431. {
  432. // Save the location where the error occured
  433. Str_SetPtr(&m_pszHttpErrorUrl, pvarargIn->bstrVal);
  434. }
  435. break;
  436. }
  437. case SBCMDID_AUTOSEARCHING:
  438. {
  439. // The address did not resolve so the string is about to be sent
  440. // to the search engine or autoscanned. There is a good chance
  441. // the pending url had "http:\\" prefixed which is a bogus url.
  442. // So let's put what the user typed into the mru instead.
  443. //
  444. Str_SetPtr(&m_pszPendingURL, m_pszUserEnteredURL);
  445. break;
  446. }
  447. case SBCMDID_GETUSERADDRESSBARTEXT:
  448. UINT cb = (m_pszUserEnteredURL ? (lstrlen(m_pszUserEnteredURL) + 1) : 0);
  449. BSTR bstr = NULL;
  450. VariantInit(pvarargOut);
  451. if (cb)
  452. bstr = SysAllocStringLen(NULL, cb);
  453. if (bstr)
  454. {
  455. SHTCharToUnicode(m_pszUserEnteredURL, bstr, cb);
  456. pvarargOut->vt = VT_BSTR|VT_BYREF;
  457. pvarargOut->byref = bstr;
  458. }
  459. else
  460. {
  461. // VariantInit() might do this for us.
  462. pvarargOut->vt = VT_EMPTY;
  463. pvarargOut->byref = NULL;
  464. return E_FAIL; // Edit_GetText gave us nothing
  465. }
  466. break;
  467. }
  468. }
  469. else if (pguidCmdGroup && IsEqualGUID(CGID_AddressEditBox, *pguidCmdGroup))
  470. {
  471. switch (nCmdID)
  472. {
  473. case AECMDID_SAVE:
  474. hr = Save(0);
  475. break;
  476. default:
  477. hr = E_NOTIMPL;
  478. break;
  479. }
  480. }
  481. return(hr);
  482. }
  483. //================================
  484. // ** IWinEventHandler Interface ***
  485. /****************************************************\
  486. FUNCTION: OnWinEvent
  487. DESCRIPTION:
  488. This function will give receive events from
  489. the parent ShellToolbar.
  490. \****************************************************/
  491. HRESULT CAddressEditBox::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  492. {
  493. LRESULT lres = 0;
  494. switch (uMsg) {
  495. case WM_WININICHANGE:
  496. {
  497. HWND hwndLocal = (m_hwnd ? m_hwnd : m_hwndEdit);
  498. if (hwndLocal)
  499. SendMessage(hwndLocal, uMsg, wParam, lParam);
  500. // MRU Needs it because it May Need to purge the MRU even if it isn't the current list.
  501. if ((m_palCurrent != m_palMRU) && m_palMRU)
  502. m_palMRU->OnWinEvent(m_hwnd, uMsg, wParam, lParam, plres);
  503. _SetAutocompleteOptions();
  504. }
  505. break;
  506. case WM_COMMAND:
  507. lres = _OnCommand(wParam, lParam);
  508. break;
  509. case WM_NOTIFY:
  510. lres = _OnNotify((LPNMHDR)lParam);
  511. break;
  512. }
  513. if (plres)
  514. *plres = lres;
  515. // All Events get all events, and they need to determine
  516. // if they are active to act on most of the events.
  517. if (m_hwnd)
  518. {
  519. if (m_palCurrent)
  520. {
  521. m_palCurrent->OnWinEvent(m_hwnd, uMsg, wParam, lParam, plres);
  522. }
  523. // If we are dropping down the list, the above call could have
  524. // changed the selection, so grab it again...
  525. if ((uMsg == WM_COMMAND) && (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_DROPDOWN))
  526. {
  527. m_nOldSelection = ComboBox_GetCurSel(m_hwnd);
  528. // If nothing selected, and something matches the contents of the editbox, select that
  529. if (m_nOldSelection == -1)
  530. {
  531. TCHAR szBuffer[MAX_URL_STRING];
  532. GetWindowText(m_hwnd, szBuffer, SIZECHARS(szBuffer));
  533. m_nOldSelection = (int)SendMessage(m_hwnd, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)szBuffer);
  534. if (m_nOldSelection != CB_ERR)
  535. {
  536. ComboBox_SetCurSel(m_hwnd, m_nOldSelection);
  537. }
  538. }
  539. }
  540. }
  541. return S_OK;
  542. }
  543. /****************************************************\
  544. FUNCTION: IsWindowOwner
  545. DESCRIPTION:
  546. This function will return TRUE if the HWND
  547. passed in is a HWND owned by this band.
  548. \****************************************************/
  549. HRESULT CAddressEditBox::IsWindowOwner(HWND hwnd)
  550. {
  551. if (hwnd == m_hwnd)
  552. return S_OK;
  553. if (m_hwndEdit && (hwnd == m_hwndEdit))
  554. return S_OK;
  555. return S_FALSE;
  556. }
  557. void CAddressEditBox::_GetUrlAndCache(void)
  558. {
  559. TCHAR szTemp[MAX_URL_STRING];
  560. // This will fail when the browser first opens and the first navigation to the
  561. // default home page doesn't start downloading yet.
  562. if (SUCCEEDED(m_pshuUrl->GetUrl(szTemp, SIZECHARS(szTemp))))
  563. {
  564. SHRemoveURLTurd(szTemp);
  565. SHCleanupUrlForDisplay(szTemp);
  566. Str_SetPtr(&m_pszCurrentUrl, szTemp); // Used when refreshing
  567. }
  568. else
  569. {
  570. Str_SetPtr(&m_pszCurrentUrl, NULL);
  571. }
  572. }
  573. //================================
  574. // *** IDispatch Interface ***
  575. /****************************************************\
  576. FUNCTION: Invoke
  577. DESCRIPTION:
  578. This function will give receive events from
  579. the Browser Window if this band is connected
  580. to one. This will allow this band to remain up
  581. todate when the browser window changes URL by
  582. another means.
  583. \****************************************************/
  584. HRESULT CAddressEditBox::Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,
  585. DISPPARAMS * pdispparams, VARIANT * pvarResult,
  586. EXCEPINFO * pexcepinfo,UINT * puArgErr)
  587. {
  588. HRESULT hr = S_OK;
  589. ASSERT(pdispparams);
  590. if (!pdispparams)
  591. return E_INVALIDARG;
  592. switch(dispidMember)
  593. {
  594. case DISPID_NAVIGATECOMPLETE: // This is when we have bits back?
  595. ASSERT(0); // We didn't ask to synch these.
  596. break;
  597. // The event DISPID_NAVIGATECOMPLETE2 may be sent several times during
  598. // redirects.
  599. // The event DISPID_DOCUMENTCOMPLETE will only happen after navigation is
  600. // finished.
  601. case DISPID_DOCUMENTCOMPLETE:
  602. Str_SetPtr(&m_pszUserEnteredURL, NULL);
  603. break;
  604. case DISPID_NAVIGATECOMPLETE2:
  605. {
  606. DWORD dwCurrent;
  607. BOOL fFound = FALSE;
  608. ASSERT(m_elt != LT_NONE);
  609. IBrowserService* pbs = NULL;
  610. for (dwCurrent = 0; dwCurrent < pdispparams->cArgs; dwCurrent++)
  611. {
  612. if (pdispparams->rgvarg[dwCurrent].vt == VT_DISPATCH)
  613. {
  614. // See who's sending us this event
  615. hr = IUnknown_QueryService(pdispparams->rgvarg[dwCurrent].pdispVal, SID_SShellBrowser, IID_IBrowserService, (void**)&pbs);
  616. if (pbs)
  617. {
  618. // We don't really need this interface, just its address
  619. pbs->Release();
  620. }
  621. if (FAILED(hr) || pbs != m_pbs)
  622. {
  623. // Notification must have come from a frame, so ignore it because
  624. // it doesn't affect the URL in the address bar.
  625. return S_OK;
  626. }
  627. }
  628. else if (!fFound)
  629. {
  630. if ((pdispparams->rgvarg[dwCurrent].vt == VT_BSTR) ||
  631. ((pdispparams->rgvarg[dwCurrent].vt == (VT_VARIANT|VT_BYREF)) &&
  632. (pdispparams->rgvarg[dwCurrent].pvarVal->vt == VT_BSTR)))
  633. {
  634. fFound = TRUE;
  635. }
  636. }
  637. }
  638. ASSERT(fFound);
  639. hr = _CreateCShellUrl();
  640. if (FAILED(hr))
  641. return hr;
  642. // Yes, so let's set our current working directory to the current window.
  643. ASSERT(m_pbs);
  644. LPITEMIDLIST pidl;
  645. if (SUCCEEDED(hr = m_pbs->GetPidl(&pidl)))
  646. {
  647. DEBUG_CODE(TCHAR szDbgBuffer[MAX_PATH];)
  648. TraceMsg(TF_BAND|TF_GENERAL, "CAddressEditBox::Invoke(), Current Pidl in TravelLog. PIDL=%s;", Dbg_PidlStr(pidl, szDbgBuffer, SIZECHARS(szDbgBuffer)));
  649. ASSERT(pidl);
  650. // m_pshuUrl will free pshuCurrWorkDir, so we can't.
  651. hr = m_pshuUrl->SetPidl(pidl);
  652. ILFree(pidl);
  653. _GetUrlAndCache(); // We call this function so stack space is only used temporarily. It will set m_pszCurrentUrl.
  654. if (SUCCEEDED(hr))
  655. {
  656. LPTSTR pszTempURL = NULL;
  657. // WARNING: This code looks really strange, but it is necessary. Normally,
  658. // I would like to pass m_pszCurrentUrl as an arg to _NavigationComplete. The problem
  659. // is that the _NavigationComplete calls m_palCurrent->NavigationComplete() which will replace
  660. // the value in m_pszCurrentUrl. So I need to pass a value that will still be valid when
  661. // m_pszCurrentUrl gets reoplaced.
  662. // (That function causes the string to change values indirectly because it ends up sending
  663. // a CBEM_SETITEM message to the combobox which will update m_pszCurrentUrl.)
  664. //
  665. // We put this string on the heap because it can be very large (MAX_URL_STRING) and
  666. // this code that calls us and the code we call, use an incredible amount of stack space.
  667. // This code needs to highly optimize on how much stack space it uses or it will cause
  668. // out of memory faults when trying to grow the stack.
  669. Str_SetPtr(&pszTempURL, m_pszCurrentUrl);
  670. if (pszTempURL)
  671. {
  672. hr = _NavigationComplete(pszTempURL, TRUE, TRUE);
  673. }
  674. Str_SetPtr(&pszTempURL, NULL);
  675. }
  676. }
  677. else
  678. {
  679. Str_SetPtr(&m_pszCurrentUrl, NULL); // Init incase it's null
  680. }
  681. }
  682. break;
  683. default:
  684. hr = E_INVALIDARG;
  685. }
  686. return hr;
  687. }
  688. /****************************************************\
  689. FUNCTION: _UseNewList
  690. DESCRIPTION:
  691. This function will switch the list we use to
  692. populate the contents of the combobox.
  693. \****************************************************/
  694. HRESULT CAddressEditBox::_UseNewList(ENUMLISTTYPE eltNew)
  695. {
  696. HRESULT hr = S_OK;
  697. ASSERT(m_hwnd); // It's invalid for use to use a AddressList if we are only and EditBox.
  698. if (m_elt == eltNew)
  699. return S_OK; // We are already using this list.
  700. if (m_palCurrent)
  701. {
  702. m_palCurrent->Connect(FALSE, m_hwnd, m_pbs, m_pbp, m_pac);
  703. m_palCurrent->Release();
  704. }
  705. switch(eltNew)
  706. {
  707. #ifndef UNIX
  708. case LT_SHELLNAMESPACE:
  709. ASSERT(m_palSNS);
  710. m_palCurrent = m_palSNS;
  711. break;
  712. #endif
  713. case LT_TYPEIN_MRU:
  714. ASSERT(m_palMRU);
  715. m_palCurrent = m_palMRU;
  716. break;
  717. default:
  718. ASSERT(0); // Someone messed up.
  719. m_palCurrent = NULL;
  720. break;
  721. }
  722. if (m_palCurrent)
  723. {
  724. m_palCurrent->AddRef();
  725. m_palCurrent->Connect(TRUE, m_hwnd, m_pbs, m_pbp, m_pac);
  726. }
  727. m_elt = eltNew;
  728. return hr;
  729. }
  730. //================================
  731. // *** IAddressEditBox Interface ***
  732. /****************************************************\
  733. FUNCTION: Save
  734. DESCRIPTION:
  735. \****************************************************/
  736. HRESULT CAddressEditBox::Save(DWORD dwReserved)
  737. {
  738. HRESULT hr = S_OK;
  739. ASSERT(0 == dwReserved); // Reserved for later.
  740. if (m_palMRU)
  741. hr = m_palMRU->Save();
  742. return hr;
  743. }
  744. /****************************************************\
  745. FUNCTION: Init
  746. PARAMETERS:
  747. hwnd - Points to ComboBoxEx otherwise NULL.
  748. hwndEditBox - EditBox.
  749. dwFlags - AEB_INIT_XXXX flags (Defined in iedev\inc\shlobj.w)
  750. punkParent - Pointer to parent object that should receive events.
  751. DESCRIPTION:
  752. This function will Hook this CAddressEditBox
  753. object to the ComboBoxEx or EditBox control. If
  754. this object is being hooked up to a ComboBoxEx control,
  755. then hwnd is of the ComboBoxEx control and hwndEditBox
  756. is of that ComboBox's edit control. If this is
  757. being hooked up to only an EditBox, then hwnd is NULL
  758. and hwndEditBox points to the edit box. If punkParent
  759. is NULL, we will not be connected to a browser window
  760. at all.
  761. \****************************************************/
  762. HRESULT CAddressEditBox::Init(HWND hwnd, OPTIONAL
  763. HWND hwndEditBox,
  764. DWORD dwFlags,
  765. IUnknown * punkParent) OPTIONAL
  766. {
  767. HRESULT hr = S_OK;
  768. ASSERT(!m_hwnd);
  769. m_hwnd = hwnd;
  770. m_hwndEdit = hwndEditBox;
  771. m_dwFlags = dwFlags;
  772. IUnknown_Set(&m_punkParent, punkParent);
  773. // Get and save our top-level window
  774. m_hwndBrowser = hwnd;
  775. HWND hwndParent;
  776. while (hwndParent = GetParent(m_hwndBrowser))
  777. {
  778. m_hwndBrowser = hwndParent;
  779. }
  780. ASSERT(!(AEB_INIT_SUBCLASS &dwFlags)); // We don't support this yet.
  781. if (hwnd) // Is this a ComboBox?
  782. {
  783. // Yes,
  784. ASSERT(!m_palSNS && !m_palMRU /*&& !m_palACP*/);
  785. m_palSNS = CSNSList_Create();
  786. m_palMRU = CMRUList_Create();
  787. if (!m_palSNS || !m_palMRU /*|| !m_palACP*/)
  788. {
  789. hr = E_FAIL;
  790. }
  791. if (SUCCEEDED(hr))
  792. {
  793. HWND hwndCombo;
  794. hwndCombo = (HWND)SendMessage(m_hwnd, CBEM_GETCOMBOCONTROL, 0, 0);
  795. if (!hwndCombo)
  796. hr = E_FAIL; // This will happen if the user passed in a ComboBox instead of a ComboBoxEx for hwnd.
  797. if (hwndCombo && SetProp(hwndCombo, SZ_ADDRESSCOMBO_PROP, this))
  798. {
  799. g_hWinStationBefore = GetProcessWindowStation();
  800. // Subclass combobox for various tweaks.
  801. ASSERT(!m_lpfnComboWndProc);
  802. m_lpfnComboWndProc = (WNDPROC) SetWindowLongPtr(hwndCombo, GWLP_WNDPROC, (LONG_PTR) _ComboSubclassWndProc);
  803. TraceMsg(TF_BAND|TF_GENERAL, "CAddressEditBox::Init() wndproc=%x", m_lpfnComboWndProc);
  804. // Subclass the comboboxex too
  805. if (SetProp(hwnd, SZ_ADDRESSCOMBOEX_PROP, this))
  806. {
  807. ASSERT(!m_lpfnComboExWndProc);
  808. m_lpfnComboExWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)_ComboExSubclassWndProc);
  809. }
  810. }
  811. }
  812. }
  813. if (SUCCEEDED(hr))
  814. {
  815. //
  816. // Set g_himl*
  817. //
  818. ASSERT(!m_pbp);
  819. hr = QueryService_SID_IBandProxy(punkParent, IID_IBandProxy, &m_pbp, NULL);
  820. // We need to set the list to MRU for the first time.
  821. // We need to do this to initialize the list because
  822. // it will be used even when other lists are selected.
  823. if (m_hwnd && LT_NONE == m_elt)
  824. _UseNewList(LT_TYPEIN_MRU);
  825. }
  826. if (hwndEditBox) {
  827. SendMessage(hwndEditBox, EM_SETLIMITTEXT, INTERNET_MAX_PATH_LENGTH - 1, 0);
  828. }
  829. return hr;
  830. }
  831. /****************************************************\
  832. FUNCTION: SetOwner
  833. PARAMETERS:
  834. punkOwner - Pointer to the parent object.
  835. DESCRIPTION:
  836. This function will be called to have this
  837. object try to obtain enough information about it's
  838. parent Toolbar to create the Band window and maybe
  839. connect to a Browser Window.
  840. \****************************************************/
  841. HRESULT CAddressEditBox::SetOwner(IUnknown* punkOwner)
  842. {
  843. HRESULT hr = S_OK;
  844. if (m_pbs)
  845. _ConnectToBrwsrWnd(NULL); // On-connect from Browser Window.
  846. if (m_hwnd && !punkOwner)
  847. {
  848. if (m_palSNS)
  849. m_palSNS->Save();
  850. if (m_palMRU)
  851. m_palMRU->Save();
  852. }
  853. IUnknown_Set(&m_punkParent, punkOwner); // Needed to break ref count cycle.
  854. _ConnectToBrwsrWnd(punkOwner); // On-connect from Browser Window.
  855. return hr;
  856. }
  857. /****************************************************\
  858. FUNCTION: SetCurrentDir
  859. DESCRIPTION:
  860. Set the Current Working directory so parsing
  861. will work correctly.
  862. \****************************************************/
  863. HRESULT CAddressEditBox::SetCurrentDir(LPCOLESTR pwzDir)
  864. {
  865. HRESULT hr;
  866. SHSTR strWorkingDir;
  867. hr = strWorkingDir.SetStr(pwzDir);
  868. if (SUCCEEDED(hr))
  869. {
  870. LPITEMIDLIST pidl;
  871. hr = IECreateFromPath(strWorkingDir.GetStr(), &pidl);
  872. if (SUCCEEDED(hr))
  873. {
  874. hr = _CreateCShellUrl();
  875. ASSERT(SUCCEEDED(hr));
  876. if (SUCCEEDED(hr))
  877. hr = m_pshuUrl->SetCurrentWorkingDir(pidl);
  878. ILFree(pidl);
  879. }
  880. }
  881. return hr;
  882. }
  883. /****************************************************\
  884. FUNCTION: ParseNow
  885. PARAMETERS:
  886. dwFlags - Parse Flags
  887. DESCRIPTION:
  888. Parse the text that is currently in the EditBox.
  889. \****************************************************/
  890. HRESULT CAddressEditBox::ParseNow(DWORD dwFlags)
  891. {
  892. HRESULT hr;
  893. TCHAR szBuffer[MAX_URL_STRING];
  894. ASSERT(m_hwnd);
  895. GetWindowText(m_hwnd, szBuffer, SIZECHARS(szBuffer));
  896. hr = _CreateCShellUrl();
  897. ASSERT(SUCCEEDED(hr));
  898. if (SUCCEEDED(hr))
  899. {
  900. if (m_fConnectedToBrowser && !SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Band\\Address"), TEXT("Use Path"), FALSE, FALSE))
  901. {
  902. dwFlags |= SHURL_FLAGS_NOPATHSEARCH;
  903. }
  904. if (SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Band\\Address"), TEXT("AutoCorrect"), FALSE, /*default*/TRUE))
  905. {
  906. dwFlags |= SHURL_FLAGS_AUTOCORRECT;
  907. }
  908. hr = m_pshuUrl->ParseFromOutsideSource(szBuffer, dwFlags);
  909. }
  910. return hr;
  911. }
  912. /****************************************************\
  913. FUNCTION: Execute
  914. PARAMETERS:
  915. dwExecFlags - Execute Flags
  916. DESCRIPTION:
  917. This function will execute the last parsed string.
  918. In most cases, the caller should call ::ParseNow()
  919. first.
  920. \****************************************************/
  921. HRESULT CAddressEditBox::Execute(DWORD dwExecFlags)
  922. {
  923. HRESULT hr = E_FAIL;
  924. ASSERT(m_pshuUrl);
  925. TCHAR szShortcutFilePath[MAX_PATH];
  926. LPITEMIDLIST pidl;
  927. hr = m_pshuUrl->GetPidlNoGenerate(&pidl);
  928. if (SUCCEEDED(hr))
  929. {
  930. hr = IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szShortcutFilePath, SIZECHARS(szShortcutFilePath), NULL);
  931. ILFree(pidl);
  932. }
  933. // if this is a .url and we can navigate to it
  934. // then we need to do that now, otherwise
  935. // we'll end up with a shell exec happening
  936. // which will open the .url in whatever
  937. // browse window the system happens to like
  938. if (SUCCEEDED(hr))
  939. {
  940. ASSERT(m_punkParent != NULL);
  941. // try navigating in the current browser window
  942. // NavFrameWithFile will exit without doing
  943. // anything if we're not dealing with a .url
  944. hr = NavFrameWithFile(szShortcutFilePath, m_punkParent);
  945. }
  946. // it's not a .url or we can't nav to it for some reason
  947. // let the general handlers have a shot now
  948. if (FAILED(hr))
  949. {
  950. hr = m_pshuUrl->Execute(m_pbp, &m_fDidShellExec,dwExecFlags);
  951. }
  952. return hr;
  953. }
  954. //================================
  955. // *** IAddressBand Interface ***
  956. /****************************************************\
  957. FUNCTION: FileSysChange
  958. DESCRIPTION:
  959. This function will handle file system change
  960. notifications.
  961. \****************************************************/
  962. HRESULT CAddressEditBox::FileSysChange(DWORD dwEvent, LPCITEMIDLIST *ppidl)
  963. {
  964. // m_hwnd == NULL means we don't need to do anything
  965. // however we will probably never get that event
  966. // if that is the case.
  967. if (m_palSNS)
  968. m_palSNS->FileSysChangeAL(dwEvent, ppidl);
  969. return S_OK;
  970. }
  971. /****************************************************\
  972. FUNCTION: Refresh
  973. PARAMETERS:
  974. pvarType - NULL for a refress of everything.
  975. OLECMD_REFRESH_TOPMOST will only update the top most.
  976. DESCRIPTION:
  977. This function will force a refress of part
  978. or all of the AddressBand.
  979. \****************************************************/
  980. HRESULT CAddressEditBox::Refresh(VARIANT * pvarType)
  981. {
  982. //
  983. // Refreshing does not automatically refresh the contents of the
  984. // edit window because a DISPID_DOCUMENTCOMPLETE or DISPID_NAVIGATECOMPLETE2
  985. // is not sent. So we restore the contents ourselves.
  986. //
  987. if (m_hwndEdit && m_pszCurrentUrl && !IsErrorUrl(m_pszCurrentUrl))
  988. {
  989. TCHAR szTemp[MAX_URL_STRING];
  990. StrCpyN(szTemp, m_pszCurrentUrl, ARRAYSIZE(szTemp));
  991. SendMessage(m_hwndEdit, WM_SETTEXT, (WPARAM)0, (LPARAM)szTemp);
  992. }
  993. DWORD dwType = OLECMD_REFRESH_ENTIRELIST; // Default
  994. if (pvarType)
  995. {
  996. if (VT_I4 != pvarType->vt)
  997. return E_INVALIDARG;
  998. dwType = pvarType->lVal;
  999. }
  1000. if (m_hwnd && m_palCurrent && m_pbs)
  1001. {
  1002. if (!m_pszCurrentUrl)
  1003. {
  1004. if (!m_pshuUrl)
  1005. {
  1006. _CreateCShellUrl();
  1007. }
  1008. LPITEMIDLIST pidl;
  1009. if (SUCCEEDED(m_pbs->GetPidl(&pidl)))
  1010. {
  1011. if (SUCCEEDED(m_pshuUrl->SetPidl(pidl)) && m_pshuUrl)
  1012. {
  1013. TCHAR szDisplayName[MAX_URL_STRING];
  1014. if (SUCCEEDED(m_pshuUrl->GetUrl(szDisplayName, ARRAYSIZE(szDisplayName))))
  1015. {
  1016. Str_SetPtr(&m_pszCurrentUrl, szDisplayName);
  1017. }
  1018. }
  1019. ILFree(pidl);
  1020. }
  1021. }
  1022. if (m_pszCurrentUrl)
  1023. {
  1024. _UseNewList(PathIsURL(m_pszCurrentUrl) ? LT_TYPEIN_MRU : LT_SHELLNAMESPACE);
  1025. if (m_palCurrent)
  1026. {
  1027. m_palCurrent->Connect(TRUE, m_hwnd, m_pbs, m_pbp, m_pac);
  1028. m_palCurrent->Refresh(dwType);
  1029. }
  1030. }
  1031. }
  1032. return S_OK;
  1033. }
  1034. //================================
  1035. // *** Internal/Private Methods ***
  1036. //=================================================================
  1037. // General Band Functions
  1038. //=================================================================
  1039. /****************************************************\
  1040. Address Band Constructor
  1041. \****************************************************/
  1042. CAddressEditBox::CAddressEditBox()
  1043. {
  1044. DllAddRef();
  1045. TraceMsg(TF_SHDLIFE, "ctor CAddressEditBox %x", this);
  1046. m_cRef = 1;
  1047. // This needs to be allocated in Zero Inited Memory.
  1048. // ASSERT that all Member Variables are inited to Zero.
  1049. ASSERT(!m_punkParent);
  1050. ASSERT(!m_hwnd);
  1051. ASSERT(!m_hwndEdit);
  1052. ASSERT(!m_lpfnComboWndProc);
  1053. ASSERT(!m_pbp);
  1054. ASSERT(!m_pbs);
  1055. ASSERT(!m_dwcpCookie);
  1056. ASSERT(!m_pszCurrentUrl);
  1057. ASSERT(!m_pszPendingURL);
  1058. ASSERT(!m_pac);
  1059. ASSERT(!m_pssACLISF);
  1060. ASSERT(!m_palCurrent);
  1061. ASSERT(!m_palSNS);
  1062. ASSERT(!m_palMRU);
  1063. ASSERT(!m_pmru);
  1064. ASSERT(!m_pshuUrl);
  1065. ASSERT(!m_fDidShellExec);
  1066. ASSERT(!m_pszUserEnteredURL);
  1067. ASSERT(!m_fConnectedToBrowser);
  1068. ASSERT(!m_pAsyncNav);
  1069. ASSERT(!m_fAsyncNavInProgress);
  1070. ASSERT(AEB_INIT_DEFAULT == m_dwFlags);
  1071. m_nOldSelection = -1;
  1072. m_elt = LT_NONE;
  1073. m_cbex.mask = 0;
  1074. m_cbex.pszText = 0;
  1075. m_cbex.cchTextMax = 0;
  1076. if (!g_nAEB_AsyncNavigation)
  1077. g_nAEB_AsyncNavigation = RegisterWindowMessage(TEXT("CAEBAsyncNavigation"));
  1078. }
  1079. /****************************************************\
  1080. Address Band destructor
  1081. \****************************************************/
  1082. CAddressEditBox::~CAddressEditBox()
  1083. {
  1084. _CancelNavigation();
  1085. ATOMICRELEASE(m_punkParent);
  1086. ATOMICRELEASE(m_pac);
  1087. ATOMICRELEASE(m_pssACLISF);
  1088. ATOMICRELEASE(m_palSNS);
  1089. ATOMICRELEASE(m_palMRU);
  1090. ATOMICRELEASE(m_palCurrent);
  1091. ATOMICRELEASE(m_pbp);
  1092. ATOMICRELEASE(m_pbs);
  1093. ATOMICRELEASE(m_pmru);
  1094. if (m_pshuUrl)
  1095. {
  1096. delete m_pshuUrl;
  1097. }
  1098. Str_SetPtr(&m_pszCurrentUrl, NULL);
  1099. Str_SetPtr(&m_pszPendingURL, NULL);
  1100. Str_SetPtr(&m_pszUserEnteredURL, NULL);
  1101. Str_SetPtr(&m_pszHttpErrorUrl, NULL);
  1102. _RemoveHook();
  1103. if (m_fAssociated)
  1104. {
  1105. m_al.Delete(GetCurrentThreadId());
  1106. }
  1107. Str_SetPtr(&m_cbex.pszText, NULL);
  1108. TraceMsg(TF_SHDLIFE, "dtor CAddressEditBox %x", this);
  1109. DllRelease();
  1110. }
  1111. /****************************************************\
  1112. FUNCTION: CAddressEditBox_CreateInstance
  1113. DESCRIPTION:
  1114. This function will create an instance of the
  1115. AddressBand COM object.
  1116. \****************************************************/
  1117. HRESULT CAddressEditBox_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  1118. {
  1119. // aggregation checking is handled in class factory
  1120. *ppunk = NULL;
  1121. CAddressEditBox * p = new CAddressEditBox();
  1122. if (p)
  1123. {
  1124. *ppunk = SAFECAST(p, IAddressBand *);
  1125. return NOERROR;
  1126. }
  1127. return E_OUTOFMEMORY;
  1128. }
  1129. /****************************************************\
  1130. FUNCTION: _OnNotify
  1131. DESCRIPTION:
  1132. This function will handle WM_NOTIFY messages.
  1133. \****************************************************/
  1134. LRESULT CAddressEditBox::_OnNotify(LPNMHDR pnm)
  1135. {
  1136. // HACKHACK: combobox (comctl32\comboex.c) will pass a LPNMHDR, but it's really
  1137. // a PNMCOMBOBOXEX (which has a first element of LPNMHDR). This function
  1138. // can use this type cast iff it's guaranteed that this will only come from
  1139. // a function that behaves in this perverse way.
  1140. PNMCOMBOBOXEX pnmce = (PNMCOMBOBOXEX)pnm;
  1141. ASSERT(pnm);
  1142. switch (pnm->code)
  1143. {
  1144. case CBEN_BEGINEDIT:
  1145. _OnBeginEdit(pnm);
  1146. break;
  1147. case CBEN_ENDEDITA:
  1148. _OnEndEditA((LPNMCBEENDEDITA)pnm);
  1149. TraceMsg(TF_BAND|TF_GENERAL, "CAddressEditBox::_OnNotify(), pnm->code=CBEN_ENDEDITA");
  1150. break;
  1151. case CBEN_ENDEDITW:
  1152. _OnEndEditW((LPNMCBEENDEDITW)pnm);
  1153. TraceMsg(TF_BAND|TF_GENERAL, "CAddressEditBox::_OnNotify(), pnm->code=CBEN_ENDEDITW");
  1154. break;
  1155. default:
  1156. break;
  1157. }
  1158. return 0;
  1159. }
  1160. LRESULT CAddressEditBox::_OnBeginEdit(LPNMHDR pnm)
  1161. {
  1162. if (m_punkParent)
  1163. IUnknown_OnFocusChangeIS(m_punkParent, m_punkParent, TRUE);
  1164. return 0;
  1165. }
  1166. /****************************************************\
  1167. FUNCTION: _OnEndEditW
  1168. DESCRIPTION:
  1169. Thunk to _OnEndEditA.
  1170. \****************************************************/
  1171. LRESULT CAddressEditBox::_OnEndEditW(LPNMCBEENDEDITW pnmW)
  1172. {
  1173. NMCBEENDEDITA nmA;
  1174. nmA.hdr = pnmW->hdr;
  1175. nmA.fChanged = pnmW->fChanged;
  1176. nmA.iNewSelection = pnmW->iNewSelection;
  1177. nmA.iWhy = pnmW->iWhy;
  1178. // don't we lose unicode information on this transition?!
  1179. // We don't use pnmw->szText so don't bother converting it
  1180. // SHUnicodeToAnsi(pnmW->szText, nmA.szText, ARRAYSIZE(nmA.szText));
  1181. nmA.szText[0] = 0;
  1182. return _OnEndEditA(&nmA);
  1183. }
  1184. /****************************************************\
  1185. FUNCTION: _OnEndEditA
  1186. DESCRIPTION:
  1187. Handle the WM_NOTIFY/CBEN_ENDEDITA message.
  1188. \****************************************************/
  1189. LRESULT CAddressEditBox::_OnEndEditA(LPNMCBEENDEDITA pnmA)
  1190. {
  1191. BOOL fRestoreIcons = TRUE;
  1192. ASSERT(pnmA);
  1193. //
  1194. // Navigate only if the user pressed enter in the edit control.
  1195. //
  1196. ASSERT(m_hwnd);
  1197. switch (pnmA->iWhy)
  1198. {
  1199. case CBENF_RETURN:
  1200. {
  1201. if (g_dwProfileCAP & 0x00000002) {
  1202. StartCAP();
  1203. }
  1204. // Use szUrl and ignore pnmA->szText because it truncates to MAX_PATH (=256)
  1205. TCHAR szUrl[MAX_URL_STRING];
  1206. if (m_hwndEdit)
  1207. {
  1208. // Allow the edit text to be updated
  1209. _ClearDirtyFlag();
  1210. GetWindowText(m_hwndEdit, szUrl, SIZECHARS(szUrl));
  1211. #ifdef UNIX_FEATURE_ALIAS
  1212. // IEUNIX: Check for alises and replace the string we got
  1213. // from the address bar.
  1214. {
  1215. CHAR szTemp[MAX_URL_STRING], szUrlAlias[MAX_URL_STRING];
  1216. HDPA aliasList = GetGlobalAliasList();
  1217. if (aliasList)
  1218. {
  1219. SHUnicodeToAnsi(szUrl, szTemp, SIZECHARS(szTemp));
  1220. if ( GetURLForAliasA(aliasList, szTemp, szUrlAlias,
  1221. SIZECHARS(szUrlAlias)) )
  1222. {
  1223. SHAnsiToUnicode(szUrlAlias, szUrl, MAX_URL_STRING);
  1224. }
  1225. }
  1226. }
  1227. #endif /* UNIX_FEATURE_ALIAS */
  1228. Str_SetPtr(&m_pszUserEnteredURL, szUrl);
  1229. // If edit box is empty, don't show icon
  1230. if (*szUrl == L'\0')
  1231. {
  1232. fRestoreIcons = FALSE;
  1233. }
  1234. #ifndef NO_ETW_TRACING
  1235. // Event trace for windows enable by shlwapi.
  1236. if (g_dwStopWatchMode & SPMODE_EVENTTRACE) {
  1237. EventTraceHandler(EVENT_TRACE_TYPE_BROWSE_ADDRESS,
  1238. szUrl);
  1239. }
  1240. #endif
  1241. if (g_dwStopWatchMode & (SPMODE_BROWSER | SPMODE_JAVA))
  1242. {
  1243. DWORD dwTime = GetPerfTime();
  1244. if (g_dwStopWatchMode & SPMODE_BROWSER) // Used to get browser total download time
  1245. StopWatch_StartTimed(SWID_BROWSER_FRAME, TEXT("Browser Frame Same"), SPMODE_BROWSER | SPMODE_DEBUGOUT, dwTime);
  1246. if (g_dwStopWatchMode & SPMODE_JAVA) // Used to get java applet load time
  1247. StopWatch_StartTimed(SWID_JAVA_APP, TEXT("Java Applet Same"), SPMODE_JAVA | SPMODE_DEBUGOUT, dwTime);
  1248. }
  1249. // If the WindowText matches the last URL we navigated
  1250. // to, then we need to call Refresh() instead of _HandleUserAction().
  1251. // This is because IWebBrowser2::Navigate2() ignores any commands that
  1252. // point to the same URL that it's already navigated to.
  1253. if (m_pszCurrentUrl && m_hwnd && !m_fDidShellExec &&
  1254. m_fConnectedToBrowser && (-1 == pnmA->iNewSelection) &&
  1255. (0 == lstrcmp(m_pszCurrentUrl, szUrl)))
  1256. {
  1257. IUnknown *punk = NULL;
  1258. // Refresh Browser.
  1259. if (m_pbp)
  1260. {
  1261. m_pbp->GetBrowserWindow(&punk);
  1262. }
  1263. if (punk) {
  1264. IWebBrowser* pwb;
  1265. punk->QueryInterface(IID_IWebBrowser, (LPVOID*)&pwb);
  1266. if (pwb) {
  1267. VARIANT v = {0};
  1268. v.vt = VT_I4;
  1269. v.lVal = OLECMDIDF_REFRESH_RELOAD|OLECMDIDF_REFRESH_CLEARUSERINPUT;
  1270. Refresh(NULL);
  1271. pwb->Refresh2(&v);
  1272. pwb->Release();
  1273. }
  1274. punk->Release();
  1275. }
  1276. }
  1277. else
  1278. {
  1279. SendMessage(m_hwnd, CB_SHOWDROPDOWN, FALSE, 0);
  1280. _HandleUserAction(szUrl, pnmA->iNewSelection);
  1281. }
  1282. UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVADDRESS);
  1283. }
  1284. }
  1285. break;
  1286. case CBENF_KILLFOCUS:
  1287. fRestoreIcons = FALSE;
  1288. break;
  1289. case CBENF_ESCAPE:
  1290. // Abort and clear the dirty flag
  1291. _ClearDirtyFlag();
  1292. if (m_hwndEdit && m_pszCurrentUrl && m_cbex.mask != 0)
  1293. {
  1294. SendMessage(m_hwnd, CBEM_SETITEM, (WPARAM)0, (LPARAM)(LPVOID)&m_cbex);
  1295. }
  1296. SendMessage(m_hwnd, CB_SHOWDROPDOWN, FALSE, 0);
  1297. if (pnmA->iNewSelection != -1) {
  1298. SendMessage(m_hwnd, CB_SETCURSEL, pnmA->iNewSelection, 0);
  1299. }
  1300. fRestoreIcons = FALSE;
  1301. break;
  1302. }
  1303. if (fRestoreIcons)
  1304. {
  1305. SendMessage(m_hwnd, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOEDITIMAGE, 0);
  1306. }
  1307. return 0;
  1308. }
  1309. /****************************************************\
  1310. FUNCTION: _ConnectToBrwsrWnd
  1311. DESCRIPTION:
  1312. The IUnknown parameter needs to point to an
  1313. object that supports the IBrowserService and
  1314. IWebBrowserApp interfaces.
  1315. \****************************************************/
  1316. HRESULT CAddressEditBox::_ConnectToBrwsrWnd(IUnknown* punk)
  1317. {
  1318. HRESULT hr = S_OK;
  1319. if (m_pbs) {
  1320. _ConnectToBrwsrConnectionPoint(FALSE, m_punkParent);
  1321. ATOMICRELEASE(m_pbs);
  1322. }
  1323. if (punk)
  1324. {
  1325. IUnknown * punkHack;
  1326. // HACK: We behave differently if we are hosted outside of a browser
  1327. // than we do if we are in a browser. This call does nothing
  1328. // but identify our host.
  1329. if (SUCCEEDED(IUnknown_QueryService(punk, SID_SShellDesktop, IID_IUnknown, (void**)&punkHack)))
  1330. punkHack->Release();
  1331. else
  1332. {
  1333. // No, we are not hosted on the desktop, so we can synch to the events of the browser.
  1334. hr = IUnknown_QueryService(punk, SID_STopLevelBrowser, IID_IBrowserService, (void**)&m_pbs);
  1335. if (SUCCEEDED(hr))
  1336. {
  1337. // We only want notifications if we are the AddressBar.
  1338. _ConnectToBrwsrConnectionPoint(TRUE, punk);
  1339. }
  1340. }
  1341. }
  1342. // TODO: At some point we will need to implement IPropertyBag so
  1343. // the parent can specify if they want us to behave as though
  1344. // we are contected or not. For now, we will use the fact
  1345. // that we are either have a IBrowserService pointer or not.
  1346. m_fConnectedToBrowser = BOOLIFY(m_pbs);
  1347. if (!m_pac)
  1348. {
  1349. // We need to wait to create the AutoComplete Lists until m_fConnectedToBrowser is set.
  1350. if (m_hwndEdit)
  1351. hr = SHUseDefaultAutoComplete(m_hwndEdit, NULL, &m_pac, &m_pssACLISF, m_fConnectedToBrowser);
  1352. if (SUCCEEDED(hr))
  1353. {
  1354. _SetAutocompleteOptions();
  1355. }
  1356. }
  1357. //
  1358. // Subclass edit control of the combobox. We do this here rather than when this
  1359. // class is initialized so that we are first in the chain to receive messages.
  1360. //
  1361. if (!m_lpfnEditWndProc && m_hwndEdit && SetProp(m_hwndEdit, SZ_ADDRESSCOMBO_PROP, this))
  1362. {
  1363. m_lpfnEditWndProc = (WNDPROC)SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR) _EditSubclassWndProc);
  1364. }
  1365. // This function will be called if: 1) we are becoming connected to a
  1366. // browser, 2) switch from one browser to another, or 3) are
  1367. // becoming unconnected from a browser. In any case, we need to
  1368. // update the ISF AutoComplete List so it can retrieve
  1369. // the current location from the appropriate browser.
  1370. if (m_pssACLISF)
  1371. m_pssACLISF->SetOwner(m_pbs);
  1372. return hr;
  1373. }
  1374. /****************************************************\
  1375. FUNCTION: _ConnectToBrwsrConnectionPoint
  1376. DESCRIPTION:
  1377. Connect to Browser Window's ConnectionPoint
  1378. that will provide events to let us keep up to date.
  1379. \****************************************************/
  1380. HRESULT CAddressEditBox::_ConnectToBrwsrConnectionPoint(BOOL fConnect, IUnknown * punk)
  1381. {
  1382. HRESULT hr = S_OK;
  1383. IConnectionPointContainer *pcpContainer;
  1384. if (punk)
  1385. {
  1386. hr = IUnknown_QueryService(punk, SID_SWebBrowserApp, IID_IConnectionPointContainer, (void **)&pcpContainer);
  1387. // Let's now have the Browser Window give us notification when something happens.
  1388. if (SUCCEEDED(hr))
  1389. {
  1390. hr = ConnectToConnectionPoint(SAFECAST(this, IDispatch*), DIID_DWebBrowserEvents2, fConnect,
  1391. pcpContainer, &m_dwcpCookie, NULL);
  1392. pcpContainer->Release();
  1393. }
  1394. }
  1395. return hr;
  1396. }
  1397. /****************************************************\
  1398. FUNCTION: _OnCommand
  1399. DESCRIPTION:
  1400. Handle WM_COMMAND messages.
  1401. \****************************************************/
  1402. LRESULT CAddressEditBox::_OnCommand(WPARAM wParam, LPARAM lParam)
  1403. {
  1404. UINT uCmd = GET_WM_COMMAND_CMD(wParam, lParam);
  1405. switch (uCmd)
  1406. {
  1407. case CBN_EDITCHANGE:
  1408. {
  1409. HWND hwndFocus = GetFocus();
  1410. if ((NULL != hwndFocus) && IsChild(m_hwnd, hwndFocus))
  1411. {
  1412. DWORD dwStyle = _IsDirty() ? CBES_EX_NOEDITIMAGE : 0;
  1413. SendMessage(m_hwnd, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOEDITIMAGE, dwStyle);
  1414. }
  1415. break;
  1416. }
  1417. case CBN_CLOSEUP:
  1418. {
  1419. //
  1420. // Navigate to the selected string when the dropdown is not down.
  1421. //
  1422. int nSel = ComboBox_GetCurSel(m_hwnd);
  1423. if ((m_nOldSelection != SEL_ESCAPE_PRESSED) &&
  1424. (m_nOldSelection != nSel) && (nSel > -1))
  1425. {
  1426. _HandleUserAction(NULL, nSel);
  1427. // RedrawWindow eliminates annoying half-paint that
  1428. // occurs while navigating from one pidl to a smaller pidl.
  1429. RedrawWindow(m_hwnd, NULL, NULL, RDW_INTERNALPAINT | RDW_UPDATENOW);
  1430. }
  1431. }
  1432. if (m_pac)
  1433. m_pac->Enable(TRUE);
  1434. break;
  1435. case CBN_DROPDOWN:
  1436. if (m_pac)
  1437. m_pac->Enable(FALSE);
  1438. break;
  1439. }
  1440. return 0;
  1441. }
  1442. /*******************************************************************
  1443. FUNCTION: _CreateCShellUrl
  1444. DESCRIPTION:
  1445. Create the m_pshuUrl CShellUrl if needed.
  1446. ********************************************************************/
  1447. HRESULT CAddressEditBox::_CreateCShellUrl(void)
  1448. {
  1449. HRESULT hr = S_OK;
  1450. // Do we need to create our Shell Url?
  1451. if (!m_pshuUrl)
  1452. {
  1453. // Yes
  1454. m_pshuUrl = new CShellUrl();
  1455. if (!m_pshuUrl)
  1456. {
  1457. return E_FAIL;
  1458. }
  1459. else
  1460. {
  1461. m_pshuUrl->SetMessageBoxParent(m_hwndEdit);
  1462. // We need to set the "Shell Path" which will allow
  1463. // the user to enter Display Names of items in Shell
  1464. // Folders that are frequently used. We add "Desktop"
  1465. // and "Desktop/My Computer" to the Shell Path because
  1466. // that is what users use most often.
  1467. SetDefaultShellPath(m_pshuUrl);
  1468. }
  1469. }
  1470. return hr;
  1471. }
  1472. /*******************************************************************
  1473. FUNCTION: _HandleUserAction
  1474. PARAMETERS:
  1475. pszUrl - string of URL to navigate to.
  1476. iNewSelection - index of current selection in address bar combo box
  1477. DESCRIPTION:
  1478. Called when the user types in or selects a URL to navigate
  1479. to through the address bar.
  1480. ********************************************************************/
  1481. HRESULT CAddressEditBox::_HandleUserAction(LPCTSTR pszUrl, int iNewSelection)
  1482. {
  1483. HRESULT hr = S_OK;
  1484. TCHAR szDisplayName[MAX_URL_STRING];
  1485. HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1486. static DWORD dwParseFlags = 0xFFFFFFFF;
  1487. Str_SetPtr(&m_pszPendingURL, NULL); // Clear if one exists.
  1488. Str_SetPtr(&m_pszHttpErrorUrl, NULL);
  1489. hr = _CreateCShellUrl();
  1490. if (FAILED(hr))
  1491. return hr;
  1492. // Are we connected to a Browser Window?
  1493. if (m_pbs)
  1494. {
  1495. // Yes, so let's set our current working directory to the current window.
  1496. LPITEMIDLIST pidl;
  1497. m_pbs->GetPidl(&pidl);
  1498. DEBUG_CODE(TCHAR szDbgBuffer[MAX_PATH];)
  1499. TraceMsg(TF_BAND|TF_GENERAL, "CAddressEditBox::_HandleUserAction(), Current Pidl in TravelLog. PIDL=%s;", Dbg_PidlStr(pidl, szDbgBuffer, SIZECHARS(szDbgBuffer)));
  1500. if (pidl)
  1501. {
  1502. // m_pshuUrl will free pshuCurrWorkDir, so we can't.
  1503. hr = m_pshuUrl->SetCurrentWorkingDir(pidl);
  1504. ILFree(pidl);
  1505. }
  1506. }
  1507. if (SUCCEEDED(hr))
  1508. {
  1509. // Cancel previous pending nav if any
  1510. _CancelNavigation();
  1511. // Did the user select the item from the drop down list?
  1512. if (-1 != iNewSelection)
  1513. {
  1514. // Yes, so point our CShellUrl at the item. (Pidl or URL)
  1515. if (m_palCurrent)
  1516. m_palCurrent->SetToListIndex(iNewSelection, (LPVOID) m_pshuUrl);
  1517. // if the index indicates this was a selection from the combo box,
  1518. // remember which selection it was
  1519. SendMessage(m_hwnd, CB_SETCURSEL, (WPARAM)iNewSelection, 0L);
  1520. *szDisplayName = L'\0';
  1521. GetWindowText(m_hwnd, szDisplayName, ARRAYSIZE(szDisplayName));
  1522. Str_SetPtr(&m_pszUserEnteredURL, szDisplayName);
  1523. pszUrl = NULL;
  1524. }
  1525. else
  1526. {
  1527. // No, the user hit return with some string.
  1528. ASSERT(pszUrl); // must have valid URL
  1529. if (0xFFFFFFFF == dwParseFlags)
  1530. {
  1531. dwParseFlags = SHURL_FLAGS_NONE;
  1532. if (m_fConnectedToBrowser && !SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Band\\Address"), TEXT("Use Path"), FALSE, FALSE))
  1533. dwParseFlags = SHURL_FLAGS_NOPATHSEARCH;
  1534. if (SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Band\\Address"), TEXT("AutoCorrect"), FALSE, /*default*/TRUE))
  1535. dwParseFlags |= SHURL_FLAGS_AUTOCORRECT;
  1536. }
  1537. }
  1538. hr = E_FAIL;
  1539. if (m_hwnd && m_pshuUrl)
  1540. {
  1541. if (!(m_dwFlags & AEB_INIT_NOASYNC)) // Is async navigate enabled?
  1542. {
  1543. // Create and initialize the AsyncNav object used to communicate with the thread
  1544. m_pAsyncNav = new AsyncNav();
  1545. if (m_pAsyncNav)
  1546. {
  1547. if(m_punkParent)
  1548. {
  1549. // Get the globe spinning indicating our processing
  1550. hr = IUnknown_QueryServiceExec(m_punkParent, SID_SBrandBand, &CGID_BrandCmdGroup, CBRANDIDM_STARTGLOBEANIMATION, 0, NULL, NULL);
  1551. }
  1552. m_pAsyncNav->_dwParseFlags = dwParseFlags;
  1553. m_pAsyncNav->_hwnd = m_hwnd;
  1554. if (pszUrl)
  1555. Str_SetPtr(&(m_pAsyncNav->_pszUrl), pszUrl);
  1556. else
  1557. m_pAsyncNav->_fPidlCheckOnly = TRUE;
  1558. if (!pszUrl || (pszUrl && m_pAsyncNav->_pszUrl))
  1559. {
  1560. CShellUrl *pshu = new CShellUrl();
  1561. if (pshu)
  1562. {
  1563. hr = pshu->Clone(m_pshuUrl);
  1564. m_pAsyncNav->_pShellUrl = pshu;
  1565. // AddRef here to give it to the thread
  1566. m_pAsyncNav->AddRef();
  1567. // Create the thread that will do the PIDL creation
  1568. if (FAILED(hr) || !SHCreateThread(_AsyncNavigateThreadProc, (LPVOID)m_pAsyncNav, CTF_COINIT, NULL))
  1569. {
  1570. hr = E_FAIL;
  1571. }
  1572. else
  1573. {
  1574. hr = E_PENDING;
  1575. }
  1576. }
  1577. }
  1578. }
  1579. }
  1580. if (FAILED(hr) && hr != E_PENDING)
  1581. {
  1582. // Cancel Async navigation leftovers
  1583. _CancelNavigation();
  1584. if (pszUrl)
  1585. {
  1586. BOOL fWasCorrected = FALSE;
  1587. hr = m_pshuUrl->ParseFromOutsideSource(pszUrl, dwParseFlags, &fWasCorrected);
  1588. // If the URL was autocorrected, put the corrected url in the editbox
  1589. // so that an invalid url in not added to our MRU if navigation succeeds
  1590. if (SUCCEEDED(hr) && fWasCorrected)
  1591. {
  1592. if (SUCCEEDED(m_pshuUrl->GetUrl(szDisplayName, ARRAYSIZE(szDisplayName))))
  1593. {
  1594. SetWindowText(m_hwndEdit, szDisplayName);
  1595. }
  1596. }
  1597. }
  1598. }
  1599. }
  1600. }
  1601. if (SUCCEEDED(hr))
  1602. {
  1603. _FinishNavigate();
  1604. }
  1605. SetCursor(hCursorOld);
  1606. return hr;
  1607. }
  1608. HRESULT CAddressEditBox::_FinishNavigate()
  1609. {
  1610. HRESULT hr;
  1611. hr = Execute( (m_fConnectedToBrowser ? SHURL_EXECFLAGS_NONE : SHURL_EXECFLAGS_DONTFORCEIE));
  1612. // if we managed to navigate by one means or another, then do all the
  1613. // associated processing
  1614. if (SUCCEEDED(hr))
  1615. {
  1616. TCHAR szDisplayName[MAX_URL_STRING];
  1617. hr = m_pshuUrl->GetDisplayName(szDisplayName, SIZECHARS(szDisplayName));
  1618. ASSERT(SUCCEEDED(hr));
  1619. Str_SetPtr(&m_pszPendingURL, szDisplayName);
  1620. if (!m_fConnectedToBrowser || m_fDidShellExec)
  1621. {
  1622. // We aren't connected to a browser window
  1623. // so we need to call _NavigationComplete() our selves
  1624. // because it will not come from the Browser window
  1625. // it self.
  1626. // If m_fDidShellExec, we need to manually add this because
  1627. // we won't receive a DISPID_NAVIGATECOMPLETE event, but
  1628. // we pass NULL to indicate
  1629. hr = _NavigationComplete(szDisplayName, !m_fDidShellExec, TRUE);
  1630. }
  1631. }
  1632. return hr;
  1633. }
  1634. void CAddressEditBox::_JustifyAddressBarText( void )
  1635. {
  1636. // Either of the following appear to work:
  1637. // (a) EM_SETSEL(0,0) followed by EM_SCROLLCARET(0,0)
  1638. // SendMessage( m_hwndEdit, EM_SETSEL, 0, 0 );
  1639. // SendMessage( m_hwndEdit, EM_SCROLLCARET, 0, 0 );
  1640. // (b) WM_KEYDOWN with VK_HOME
  1641. // SendMessage( m_hwndEdit, WM_KEYDOWN, VK_HOME, 0 );
  1642. // Use the EM_SETSEL method to avoid user keyboard stroke interruption.
  1643. SendMessage( m_hwndEdit, EM_SETSEL, 0, 0 );
  1644. SendMessage( m_hwndEdit, EM_SCROLLCARET, 0, 0 );
  1645. }
  1646. HRESULT CAddressEditBox::_AsyncNavigate(AsyncNav *pAsyncNav)
  1647. {
  1648. HRESULT hr;
  1649. // we should only be called on one thread, but the interlocked can't hurt...
  1650. if (InterlockedCompareExchange((LONG*)&m_fAsyncNavInProgress, TRUE, FALSE) == FALSE)
  1651. {
  1652. // this is the first call to _AsyncNavigate
  1653. hr = pAsyncNav->_hr;
  1654. if (SUCCEEDED(hr))
  1655. {
  1656. // Get the CShellUrl back after processing
  1657. hr = m_pshuUrl->Clone(pAsyncNav->_pShellUrl);
  1658. }
  1659. // If the URL was autocorrected, put the corrected url in the editbox
  1660. // so that an invalid url in not added to our MRU if navigation succeeds
  1661. if (SUCCEEDED(hr) && pAsyncNav->_fWasCorrected)
  1662. {
  1663. TCHAR szDisplayName[MAX_URL_STRING];
  1664. if (SUCCEEDED(m_pshuUrl->GetUrl(szDisplayName, ARRAYSIZE(szDisplayName))))
  1665. {
  1666. SetWindowText(m_hwndEdit, szDisplayName);
  1667. }
  1668. }
  1669. if (SUCCEEDED(hr))
  1670. hr = _FinishNavigate();
  1671. if (FAILED(hr) && pAsyncNav->_fPidlCheckOnly)
  1672. {
  1673. // Maybe the user needs to insert the media, format, or
  1674. // reconnect to the disk before this will succeed. Check for that
  1675. // and prompt now.
  1676. // This fixes the common case where the floppy or CD isn't inserted and
  1677. // we want to display the user friendly dialog.
  1678. LPITEMIDLIST pidl;
  1679. hr = pAsyncNav->_pShellUrl->GetPidlNoGenerate(&pidl);
  1680. // We need to resolve the URL into its path so SHPathPrepareForWrite works correctly
  1681. if (SUCCEEDED(hr))
  1682. {
  1683. TCHAR szShortcutFilePath[MAX_PATH];
  1684. hr = IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szShortcutFilePath, SIZECHARS(szShortcutFilePath), NULL);
  1685. if (SUCCEEDED(hr))
  1686. {
  1687. HRESULT hrPrompt = SHPathPrepareForWrite(pAsyncNav->_hwnd, NULL, szShortcutFilePath, SHPPFW_DEFAULT);
  1688. if (SUCCEEDED(hrPrompt))
  1689. {
  1690. hr = _FinishNavigate();
  1691. }
  1692. else
  1693. {
  1694. // Propagate out the fact that the user clicked the cancel button.
  1695. hr = hrPrompt;
  1696. }
  1697. }
  1698. ILFree(pidl);
  1699. }
  1700. // Never display a err if the user cancelled the operation.
  1701. if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr))
  1702. {
  1703. TCHAR szDisplayName[MAX_URL_STRING];
  1704. if (SUCCEEDED(pAsyncNav->_pShellUrl->GetUrl(szDisplayName, ARRAYSIZE(szDisplayName))))
  1705. {
  1706. MLShellMessageBox(pAsyncNav->_hwnd, MAKEINTRESOURCE(IDS_ADDRBAND_DEVICE_NOTAVAILABLE),
  1707. MAKEINTRESOURCE(IDS_SHURL_ERR_TITLE),
  1708. (MB_OK | MB_ICONERROR), szDisplayName);
  1709. }
  1710. }
  1711. }
  1712. // Cleanup async navigation stuff
  1713. _CancelNavigation();
  1714. InterlockedExchange((LONG*)&m_fAsyncNavInProgress, FALSE);
  1715. }
  1716. else
  1717. {
  1718. // we can only do one async navigate at a time
  1719. hr = E_FAIL;
  1720. }
  1721. return hr;
  1722. }
  1723. HRESULT CAddressEditBox::_CancelNavigation()
  1724. {
  1725. if (m_pAsyncNav)
  1726. {
  1727. if(m_punkParent)
  1728. {
  1729. HRESULT hr = IUnknown_QueryServiceExec(m_punkParent, SID_SBrandBand, &CGID_BrandCmdGroup, CBRANDIDM_STOPGLOBEANIMATION, 0, NULL, NULL);
  1730. }
  1731. m_pAsyncNav->Release();
  1732. m_pAsyncNav = NULL;
  1733. }
  1734. return S_OK;
  1735. }
  1736. DWORD CAddressEditBox::_AsyncNavigateThreadProc(LPVOID pvData)
  1737. {
  1738. AsyncNav *pAsyncNav = (AsyncNav *)pvData;
  1739. if (pAsyncNav->_hwnd && g_nAEB_AsyncNavigation)
  1740. {
  1741. if(pAsyncNav->_fPidlCheckOnly)
  1742. {
  1743. LPITEMIDLIST pidl;
  1744. pAsyncNav->_hr = pAsyncNav->_pShellUrl->GetPidlNoGenerate(&pidl);
  1745. if (SUCCEEDED(pAsyncNav->_hr))
  1746. {
  1747. DWORD dwAttrib = SFGAO_VALIDATE;
  1748. pAsyncNav->_hr = IEGetNameAndFlags(pidl, 0, NULL, 0, &dwAttrib);
  1749. }
  1750. else
  1751. {
  1752. // Special case for keywords. We want to proceed if we don't have a pidl
  1753. pAsyncNav->_hr = S_OK;
  1754. }
  1755. }
  1756. else
  1757. {
  1758. pAsyncNav->_hr = pAsyncNav->_pShellUrl->ParseFromOutsideSource(pAsyncNav->_pszUrl, pAsyncNav->_dwParseFlags, &(pAsyncNav->_fWasCorrected));
  1759. }
  1760. pAsyncNav->_fReady = TRUE;
  1761. PostMessage(pAsyncNav->_hwnd, g_nAEB_AsyncNavigation, (WPARAM)pAsyncNav, NULL);
  1762. }
  1763. // We are done with this now.
  1764. // If the navigation was canceled, then the object will destruct now, and the posted
  1765. // message above will be ignored.
  1766. pAsyncNav->Release();
  1767. return 0;
  1768. }
  1769. BOOL CAddressEditBox::_IsShellUrl(void)
  1770. {
  1771. // 1. Check if we need to change the List.
  1772. BOOL fIsShellUrl = !m_pshuUrl->IsWebUrl();
  1773. if (fIsShellUrl)
  1774. {
  1775. // BUG #50703: Users want MRU when about: url is displayed.
  1776. TCHAR szUrl[MAX_URL_STRING];
  1777. if (SUCCEEDED(m_pshuUrl->GetUrl(szUrl, ARRAYSIZE(szUrl))))
  1778. {
  1779. if (URL_SCHEME_ABOUT == GetUrlScheme(szUrl))
  1780. {
  1781. fIsShellUrl = FALSE; // Make it use the MRU List.
  1782. }
  1783. }
  1784. }
  1785. return fIsShellUrl;
  1786. }
  1787. /*******************************************************************
  1788. FUNCTION: _NavigationComplete
  1789. PARAMETERS:
  1790. pszUrl - String user entered.
  1791. fChangeLists - Should we modify the Drop Down list?
  1792. fAddToMRU - Should we add it to the MRU?
  1793. DESCRIPTION:
  1794. This function is called when either: 1) a naviation completes,
  1795. or 2) the user entered text into the AddressEditBox that needs
  1796. to be handled but will not cause a NAVIGATION_COMPLETE message.
  1797. This function will change the AddressList being used and will
  1798. add the item to the Type-in MRU.
  1799. ********************************************************************/
  1800. HRESULT CAddressEditBox::_NavigationComplete(LPCTSTR pszUrl /* Optional */, BOOL fChangeLists, BOOL fAddToMRU)
  1801. {
  1802. HRESULT hr = S_OK;
  1803. // Are we controlling a ComboBoxEx?
  1804. if (m_hwnd)
  1805. {
  1806. // Yes, so do ComboBoxEx Specific things...
  1807. // If the list is dropped, undrop it so the contents of the editbox and list
  1808. // are properly updated.
  1809. if (m_hwnd && m_hwndEdit && ComboBox_GetDroppedState(m_hwnd))
  1810. {
  1811. SendMessage(m_hwndEdit, WM_KEYDOWN, VK_ESCAPE, 0);
  1812. }
  1813. if (fChangeLists)
  1814. {
  1815. BOOL fIsShellUrl = _IsShellUrl();
  1816. // 2. Do we need to change lists to MRU List?
  1817. if (!fIsShellUrl && m_elt != LT_TYPEIN_MRU)
  1818. {
  1819. // We need to start using the LT_TYPEIN_MRU list
  1820. // because that list is what is needed for Internet Urls.
  1821. _UseNewList(LT_TYPEIN_MRU);
  1822. }
  1823. // We only want to switch to using the shell name space
  1824. // if we are connected to a browser.
  1825. if (fIsShellUrl && (m_elt != LT_SHELLNAMESPACE) && m_fConnectedToBrowser)
  1826. {
  1827. // We need to start using the LT_SHELLNAMESPACE list
  1828. // because that list is what is needed for File Urls.
  1829. _UseNewList(LT_SHELLNAMESPACE);
  1830. }
  1831. ASSERT(m_palCurrent);
  1832. hr = m_palCurrent ? m_palCurrent->NavigationComplete((LPVOID) m_pshuUrl) : E_FAIL;
  1833. if ( SUCCEEDED( hr ) )
  1834. {
  1835. // Insure that after the navigation completes, the Address Bar Text is left justified.
  1836. _JustifyAddressBarText();
  1837. }
  1838. }
  1839. // Don't display the url to internal error pages. All internal error
  1840. // urls start with res:// and we don't want these in our MRU.
  1841. // We also don't want to display error pages from the server.
  1842. if ((pszUrl && (TEXT('r') == pszUrl[0]) && (TEXT('e') == pszUrl[1]) && IsErrorUrl(pszUrl)) ||
  1843. (m_pszHttpErrorUrl && StrCmp(m_pszHttpErrorUrl, pszUrl) == 0))
  1844. {
  1845. // We don't want this in our MRU!
  1846. fAddToMRU = FALSE;
  1847. }
  1848. // Do we have a Pending URL, meaning the user hand typed it in
  1849. // and the navigation finished (wasn't cancelled or failed).
  1850. //
  1851. // REARCHITECT: Currently there are a few cases when the URL (m_pszPendingURL)
  1852. // is added to the MRU when it shouldn't.
  1853. // 1. If the user enters an URL and then cancels the navigation, we
  1854. // don't clear m_pszPendingURL. If the user then causes the browser
  1855. // to navigate by some other means (HREF Click, Favorites/QLink navigation
  1856. // , or Floating AddressBand), we will receive the NAVIGATION_COMPLETE
  1857. // message and think it was for the originally cancelled URL.
  1858. if (fAddToMRU && m_pszPendingURL)
  1859. {
  1860. // Yes, so add it to the MRU.
  1861. if (SUCCEEDED(hr))
  1862. {
  1863. if (!m_pmru && m_palMRU)
  1864. hr = m_palMRU->QueryInterface(IID_IMRU, (LPVOID *)&m_pmru);
  1865. if (SUCCEEDED(hr))
  1866. {
  1867. SHCleanupUrlForDisplay(m_pszPendingURL);
  1868. hr = m_pmru->AddEntry(m_pszPendingURL); // Add to MRU
  1869. }
  1870. }
  1871. }
  1872. }
  1873. Str_SetPtr(&m_pszPendingURL, NULL);
  1874. Str_SetPtr(&m_pszHttpErrorUrl, NULL);
  1875. return hr;
  1876. }
  1877. //=================================================================
  1878. // AddressEditBox Modification Functions
  1879. //=================================================================
  1880. /****************************************************\
  1881. _ComboSubclassWndProc
  1882. Input:
  1883. Standard WndProc parameters
  1884. Return:
  1885. Standard WndProc return.
  1886. \****************************************************/
  1887. LRESULT CALLBACK CAddressEditBox::_ComboSubclassWndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  1888. {
  1889. HWND hwndBand = GetParent(hwnd);
  1890. CAddressEditBox * paeb = (CAddressEditBox*)GetProp(hwnd, SZ_ADDRESSCOMBO_PROP);
  1891. ASSERT(paeb);
  1892. g_hWinStationAfter = GetProcessWindowStation();
  1893. // In stress we see someone will stomp our property with -2. We need to find out who it is.
  1894. // Call ReinerF if this happens
  1895. AssertMsg(((void *)-2 != paeb), TEXT("Someone corrupted our window property. Call ReinerF"));
  1896. if (!paeb)
  1897. {
  1898. return DefWindowProcWrap(hwnd, uMessage, wParam, lParam);
  1899. }
  1900. switch (uMessage)
  1901. {
  1902. case WM_SETCURSOR:
  1903. {
  1904. HWND hwndCursor = (HWND)wParam;
  1905. int nHittest = LOWORD(lParam);
  1906. if (hwndCursor == paeb->m_hwndEdit && nHittest == HTCLIENT)
  1907. {
  1908. //
  1909. // If we don't have focus, we want to show an arrow because clicking will select
  1910. // the contents of the edit box. Otherwise show the I-beam. Also, if the edit box
  1911. // is empty we show the I-beam because there is nothing to select.
  1912. //
  1913. HWND hwndFocus = GetFocus();
  1914. int cch = GetWindowTextLength(paeb->m_hwndEdit);
  1915. LPCTSTR lpCursorName = (cch == 0 || hwndFocus == paeb->m_hwndEdit) ? IDC_IBEAM : IDC_ARROW;
  1916. SetCursor(LoadCursor(NULL, lpCursorName));
  1917. return TRUE;
  1918. }
  1919. break;
  1920. }
  1921. case WM_SETFOCUS:
  1922. //
  1923. // This is gross, but if the window was destroyed that had the
  1924. // focus this would fail and we would not get this to the
  1925. // combo box.
  1926. //
  1927. // This happens if you click on the combobox while
  1928. // renaming a file in the defview.
  1929. //
  1930. if (wParam && !IsWindow((HWND)wParam))
  1931. wParam = 0;
  1932. break;
  1933. case WM_DESTROY:
  1934. // Unsubclass myself.
  1935. if (!paeb->m_lpfnComboWndProc)
  1936. return 0;
  1937. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) paeb->m_lpfnComboWndProc);
  1938. RemoveProp(hwnd, SZ_ADDRESSCOMBO_PROP);
  1939. ASSERT(paeb->m_hwnd); // We don't want to be called twice
  1940. paeb->m_hwnd = NULL; // We have been destroyed.
  1941. break;
  1942. case WM_COMMAND:
  1943. if (EN_UPDATE == GET_WM_COMMAND_CMD(wParam, lParam))
  1944. {
  1945. paeb->_InstallHookIfDirty();
  1946. }
  1947. break;
  1948. case WM_KEYDOWN:
  1949. switch (wParam)
  1950. {
  1951. //
  1952. // Pressing escape results in the dropdown being hidden. If
  1953. // the mouse hot-tracks over a different selection than when the
  1954. // combo was first dropped, we get a CBN_SELCHANGE event which
  1955. // causes a false navigation. We suppress this by setting
  1956. // m_nOldSelection to a special value (-2).
  1957. //
  1958. case VK_ESCAPE:
  1959. {
  1960. paeb->m_nOldSelection = SEL_ESCAPE_PRESSED;
  1961. // Pass message on so that the content of the edit box is restored
  1962. SendMessage(paeb->m_hwndEdit, uMessage, wParam, lParam);
  1963. break;
  1964. }
  1965. }
  1966. break;
  1967. case WM_SYSKEYDOWN:
  1968. switch (wParam)
  1969. {
  1970. case VK_DOWN:
  1971. {
  1972. // Alt-down toggles the combobox dropdown. We don't
  1973. // want a navigation if this key sequence closes the dropdown.
  1974. if (HIWORD(lParam) & KF_ALTDOWN)
  1975. {
  1976. paeb->m_nOldSelection = SEL_ESCAPE_PRESSED;
  1977. }
  1978. break;
  1979. }
  1980. }
  1981. break;
  1982. case CB_SHOWDROPDOWN:
  1983. // If dropdown is hidden, suppress navigation. See comment above for VK_ESCAPE.
  1984. if (!wParam)
  1985. {
  1986. paeb->m_nOldSelection = SEL_ESCAPE_PRESSED;
  1987. }
  1988. break;
  1989. case WM_WINDOWPOSCHANGING:
  1990. {
  1991. LPWINDOWPOS pwp = (LPWINDOWPOS)lParam;
  1992. pwp->flags |= SWP_NOCOPYBITS;
  1993. }
  1994. break;
  1995. case WM_GETOBJECT:
  1996. if (lParam == OBJID_CLIENT)
  1997. {
  1998. CAddressEditAccessible *paea = new CAddressEditAccessible(hwnd, paeb->m_hwndEdit);
  1999. if (NULL != paea)
  2000. {
  2001. LRESULT lres = LresultFromObject(IID_IAccessible, wParam, SAFECAST(paea, IAccessible *));
  2002. paea->Release();
  2003. return lres;
  2004. }
  2005. }
  2006. break;
  2007. default:
  2008. // FEATURE: Do we need this?
  2009. if (!(AEB_INIT_SUBCLASS & paeb->m_dwFlags))
  2010. {
  2011. paeb->OnWinEvent(paeb->m_hwnd, uMessage, wParam, lParam, NULL);
  2012. }
  2013. break;
  2014. }
  2015. return CallWindowProc(paeb->m_lpfnComboWndProc, hwnd, uMessage, wParam, lParam);
  2016. }
  2017. void CAddressEditBox::_SetAutocompleteOptions()
  2018. {
  2019. if (m_pac)
  2020. {
  2021. // Set the autocomplete options
  2022. DWORD dwOptions = ACO_SEARCH | ACO_FILTERPREFIXES | ACO_USETAB | ACO_UPDOWNKEYDROPSLIST;
  2023. if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, /*default:*/FALSE))
  2024. {
  2025. dwOptions |= ACO_AUTOAPPEND;
  2026. }
  2027. if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, /*default:*/TRUE))
  2028. {
  2029. dwOptions |= ACO_AUTOSUGGEST;
  2030. }
  2031. m_pac->SetOptions(dwOptions);
  2032. }
  2033. }
  2034. /****************************************************\
  2035. FUNCTION: _NavigateToUrlCB
  2036. PARAMETERS:
  2037. lParam - The CAddressEditBox this pointer.
  2038. lpUrl - The URL to navigate to.
  2039. DESCRIPTION:
  2040. This function is specifically for AutoComplete
  2041. to call when it needs to navigate.
  2042. \****************************************************/
  2043. HRESULT CAddressEditBox::_NavigateToUrlCB(LPARAM lParam, LPTSTR lpUrl)
  2044. {
  2045. // NOTE: We don't need to navigate because AutoComplete will
  2046. // will send a message to the ComboBoxEx that will carry out
  2047. // the navigation.
  2048. return S_OK;
  2049. }
  2050. //=================================================================
  2051. // Functions to prevent clobbering the address contents while dirty
  2052. //=================================================================
  2053. #define TF_EDITBOX TF_BAND|TF_GENERAL
  2054. //#define TF_EDITBOX TF_ALWAYS
  2055. BOOL CAddressEditBox::_IsDirty()
  2056. {
  2057. return m_hwndEdit && SendMessage(m_hwndEdit, EM_GETMODIFY, 0, 0L);
  2058. }
  2059. void CAddressEditBox::_ClearDirtyFlag()
  2060. {
  2061. TraceMsg(TF_EDITBOX, "CAddressEditBox::_ClearDirtyFlag()");
  2062. SendMessage(m_hwndEdit, EM_SETMODIFY, FALSE, 0);
  2063. _RemoveHook();
  2064. }
  2065. void CAddressEditBox::_InstallHookIfDirty()
  2066. {
  2067. //
  2068. // We only need to install the hook if we are connected to a browser for update notifications
  2069. //
  2070. if (m_fConnectedToBrowser)
  2071. {
  2072. // Make sure we are associated with the current thread
  2073. if (!m_fAssociated)
  2074. {
  2075. //
  2076. // If a CAddressEditBox is already associated with this thread, remove that
  2077. // association and remove any pending mouse hook. This can happen if the
  2078. // open dialog comes up and the address bar is visible.
  2079. //
  2080. DWORD dwThread = GetCurrentThreadId();
  2081. CAddressEditBox* pAeb;
  2082. if (SUCCEEDED(m_al.Find(dwThread, (LPVOID*)&pAeb)))
  2083. {
  2084. pAeb->_ClearDirtyFlag();
  2085. pAeb->m_fAssociated = FALSE;
  2086. m_al.Delete(dwThread);
  2087. }
  2088. // There should not be any other CAddressEditBox associated with this thread!
  2089. ASSERT(FAILED(m_al.Find(dwThread, (LPVOID*)&pAeb)));
  2090. //
  2091. // Associate ourselves with the current thread id. We need this because
  2092. // windows hooks are global and have no data associated with them.
  2093. // On the callback, we use our thread id as the key.
  2094. //
  2095. m_al.Add(dwThread, this);
  2096. m_fAssociated = TRUE;
  2097. }
  2098. if (!m_hhook && _IsDirty())
  2099. {
  2100. // ML: HINST_THISDLL is valid in its use here
  2101. m_hhook = SetWindowsHookEx(WH_MOUSE, _MsgHook, HINST_THISDLL, GetCurrentThreadId());
  2102. TraceMsg(TF_EDITBOX, "CAddressEditBox::_InstallHookIfDirty(), Hook installed");
  2103. //
  2104. // Subclass edit control of the combobox. We do this here rather than when this
  2105. // class is initialized so that we are first in the chain to receive messages.
  2106. //
  2107. if (!m_lpfnEditWndProc && m_hwndEdit && SetProp(m_hwndEdit, SZ_ADDRESSCOMBO_PROP, this))
  2108. {
  2109. m_lpfnEditWndProc = (WNDPROC)SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR) _EditSubclassWndProc);
  2110. }
  2111. // Clear and changes that we previously cached
  2112. m_cbex.mask = 0;
  2113. }
  2114. }
  2115. }
  2116. void CAddressEditBox::_RemoveHook()
  2117. {
  2118. if (m_hhook)
  2119. {
  2120. UnhookWindowsHookEx(m_hhook);
  2121. m_hhook = FALSE;
  2122. TraceMsg(TF_EDITBOX, "CAddressEditBox::_RemoveHook(), Hook removed");
  2123. }
  2124. }
  2125. LRESULT CALLBACK CAddressEditBox::_MsgHook(int nCode, WPARAM wParam, LPARAM lParam)
  2126. {
  2127. //
  2128. // Get the CAddressEditBox associated with this thread. We need this because
  2129. // windows hooks are global and have no data associated with them.
  2130. // On the callback, we use our thread id as the key
  2131. //
  2132. CAddressEditBox* pThis;
  2133. if (SUCCEEDED(CAddressEditBox::m_al.Find(GetCurrentThreadId(), (LPVOID*)&pThis)))
  2134. {
  2135. return pThis->_MsgHook(nCode, wParam, (MOUSEHOOKSTRUCT*)lParam);
  2136. }
  2137. return 0;
  2138. }
  2139. LRESULT CAddressEditBox::_MsgHook(int nCode, WPARAM wParam, MOUSEHOOKSTRUCT *pmhs)
  2140. {
  2141. ASSERT(NULL != pmhs);
  2142. if (nCode >= 0)
  2143. {
  2144. if ((wParam == WM_LBUTTONDOWN) || (wParam == WM_RBUTTONDOWN))
  2145. {
  2146. // Ignore if the button was clicked in our combo box
  2147. RECT rc;
  2148. if (GetWindowRect(m_hwnd, &rc) && !PtInRect(&rc, pmhs->pt))
  2149. {
  2150. _ClearDirtyFlag();
  2151. _RemoveHook();
  2152. }
  2153. }
  2154. }
  2155. return CallNextHookEx(m_hhook, nCode, wParam, (LPARAM)pmhs);
  2156. }
  2157. /****************************************************\
  2158. _ComboExSubclassWndProc
  2159. Input:
  2160. Standard WndProc parameters
  2161. Return:
  2162. Standard WndProc return.
  2163. Description:
  2164. We subclass the outer combobox to prevent
  2165. the contents from getting clobbered while
  2166. and edit is in progress (ie dirty).
  2167. \****************************************************/
  2168. LRESULT CALLBACK CAddressEditBox::_ComboExSubclassWndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  2169. {
  2170. CAddressEditBox * paeb = (CAddressEditBox*)GetProp(hwnd, SZ_ADDRESSCOMBOEX_PROP);
  2171. if (!paeb)
  2172. return DefWindowProc(hwnd, uMessage, wParam, lParam);
  2173. g_hWinStationAfterEx = GetProcessWindowStation();
  2174. if (uMessage == g_nAEB_AsyncNavigation)
  2175. {
  2176. // If the navigation was not canceled before, then navigate now.
  2177. if ((AsyncNav *)wParam == paeb->m_pAsyncNav && paeb->m_pAsyncNav->_fReady)
  2178. {
  2179. paeb->_AsyncNavigate((AsyncNav *)wParam);
  2180. }
  2181. }
  2182. switch (uMessage)
  2183. {
  2184. case CBEM_SETITEM:
  2185. {
  2186. //
  2187. // If we are still dirty, don't let anyone clobber our edit control contents!
  2188. //
  2189. const COMBOBOXEXITEM* pcCBItem = (const COMBOBOXEXITEM FAR *)lParam;
  2190. if (paeb->_IsDirty() && pcCBItem->iItem == -1)
  2191. {
  2192. //
  2193. // save this info so that if the user hits esc, we restore the right thing
  2194. //
  2195. if (IsFlagSet(pcCBItem->mask, CBEIF_TEXT))
  2196. {
  2197. Str_SetPtr(&paeb->m_pszCurrentUrl, pcCBItem->pszText);
  2198. }
  2199. Str_SetPtr(&(paeb->m_cbex.pszText), NULL); // Free the previous value
  2200. paeb->m_cbex = *pcCBItem;
  2201. paeb->m_cbex.pszText = NULL;
  2202. Str_SetPtr(&(paeb->m_cbex.pszText), paeb->m_pszCurrentUrl);
  2203. paeb->m_cbex.cchTextMax = lstrlen(paeb->m_cbex.pszText);
  2204. return 0L;
  2205. }
  2206. else
  2207. {
  2208. // Make sure that the icon is visible
  2209. SendMessage(paeb->m_hwnd, CBEM_SETEXTENDEDSTYLE, CBES_EX_NOEDITIMAGE, 0);
  2210. }
  2211. }
  2212. break;
  2213. case WM_DESTROY:
  2214. // Release the lists now so that they don't try to use our
  2215. // window after we're destroyed
  2216. if (paeb->m_palCurrent)
  2217. {
  2218. paeb->m_palCurrent->Connect(FALSE, paeb->m_hwnd, NULL, NULL, NULL);
  2219. ATOMICRELEASE(paeb->m_palCurrent);
  2220. }
  2221. ATOMICRELEASE(paeb->m_palSNS);
  2222. ATOMICRELEASE(paeb->m_palMRU);
  2223. //
  2224. // Unsubclass myself.
  2225. //
  2226. RemoveProp(hwnd, SZ_ADDRESSCOMBOEX_PROP);
  2227. if (!paeb->m_lpfnComboExWndProc)
  2228. return 0;
  2229. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) paeb->m_lpfnComboExWndProc);
  2230. break;
  2231. default:
  2232. break;
  2233. }
  2234. return CallWindowProc(paeb->m_lpfnComboExWndProc, hwnd, uMessage, wParam, lParam);
  2235. }
  2236. /****************************************************\
  2237. _EnumFindWindow
  2238. Description:
  2239. Called by EnumChildWindows to see is the window
  2240. passed in lParam is a child of a given
  2241. parent.
  2242. \****************************************************/
  2243. BOOL CALLBACK CAddressEditBox::_EnumFindWindow
  2244. (
  2245. HWND hwnd, // handle to child window
  2246. LPARAM lParam // application-defined value
  2247. )
  2248. {
  2249. // Stop enumeration when match found
  2250. return (hwnd != (HWND)lParam);
  2251. }
  2252. /****************************************************\
  2253. _EditSubclassWndProc
  2254. Input:
  2255. Standard WndProc parameters
  2256. Return:
  2257. Standard WndProc return.
  2258. Description:
  2259. We subclass the edit control in the combobox
  2260. so that we can keep it from losing focus under
  2261. certain conditions.
  2262. \****************************************************/
  2263. LRESULT CALLBACK CAddressEditBox::_EditSubclassWndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  2264. {
  2265. CAddressEditBox * paeb = (CAddressEditBox*)GetProp(hwnd, SZ_ADDRESSCOMBO_PROP);
  2266. if (!paeb)
  2267. return DefWindowProc(hwnd, uMessage, wParam, lParam);
  2268. switch (uMessage)
  2269. {
  2270. case WM_SETCURSOR:
  2271. {
  2272. HWND hwndCursor = (HWND)wParam;
  2273. int nHittest = LOWORD(lParam);
  2274. if (hwndCursor == hwnd && nHittest == HTCLIENT)
  2275. {
  2276. //
  2277. // If we don't have focus, we want to show an arrow because clicking will select
  2278. // the contents of the edit box. Otherwise show the I-beam. Also, if the edit box
  2279. // is empty we show the I-beam because there is nothing to select.
  2280. //
  2281. int cch = GetWindowTextLength(paeb->m_hwndEdit);
  2282. LPCTSTR lpCursorName = (cch == 0 || GetFocus() == hwnd) ? IDC_IBEAM : IDC_ARROW;
  2283. SetCursor(LoadCursor(NULL, lpCursorName));
  2284. return TRUE;
  2285. }
  2286. break;
  2287. }
  2288. case WM_KILLFOCUS:
  2289. {
  2290. //
  2291. // If we lose focus with the mouse hook installed, the user probably did
  2292. // not initiate the change so we try to grab it back. The hook is removed
  2293. // when the user clicks outside the edit box or presses a key to finish the edit
  2294. // (tab, enter, or esc)
  2295. //
  2296. HWND hwndGetFocus = (HWND)wParam;
  2297. if ((paeb->m_hhook) && hwndGetFocus && (hwnd != hwndGetFocus))
  2298. {
  2299. //
  2300. // Make sure that this is not the drop-down portion of the combo.
  2301. // Also, if we are in a dialog (open dialog) then we don't see the
  2302. // tab key. So if focus is going to a sibling we'll let it through.
  2303. //
  2304. HWND hwndGetFocusParent = GetParent(hwndGetFocus);
  2305. HWND hwndSiblingParent = paeb->m_hwnd ? GetParent(paeb->m_hwnd) : GetParent(hwnd);
  2306. if ((paeb->m_hwnd != hwndGetFocusParent) && (hwndGetFocusParent != hwndSiblingParent) &&
  2307. EnumChildWindows(hwndSiblingParent, _EnumFindWindow, (LPARAM)hwndGetFocus))
  2308. {
  2309. // Get the top-level window of who's getting focus
  2310. HWND hwndFrame = hwndGetFocus;
  2311. HWND hwndParent;
  2312. while (hwndParent = GetParent(hwndFrame))
  2313. hwndFrame = hwndParent;
  2314. // If focus is going somewhere else in our browser window, grab focus back
  2315. if (hwndFrame == paeb->m_hwndBrowser)
  2316. {
  2317. DWORD dwStart, dwEnd;
  2318. SendMessage(paeb->m_hwndEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
  2319. SetFocus(paeb->m_hwndEdit);
  2320. SendMessage(paeb->m_hwndEdit, EM_SETSEL, dwStart, dwEnd);
  2321. TraceMsg(TF_BAND|TF_GENERAL, "CAddressEditBox::_EditSubclassWndProc, Restoring focus");
  2322. return 0L;
  2323. }
  2324. }
  2325. }
  2326. //
  2327. // Losing focus so allow others to change our contents
  2328. //
  2329. paeb->_ClearDirtyFlag();
  2330. }
  2331. break;
  2332. case WM_KEYDOWN:
  2333. {
  2334. // If we are tabbing away, clear our dirty flag
  2335. switch (wParam)
  2336. {
  2337. case VK_TAB:
  2338. paeb->_ClearDirtyFlag();
  2339. break;
  2340. case VK_ESCAPE:
  2341. {
  2342. if (paeb->m_hwnd && ComboBox_GetDroppedState(paeb->m_hwnd))
  2343. {
  2344. SendMessage(paeb->m_hwnd, CB_SHOWDROPDOWN, FALSE, 0);
  2345. }
  2346. else
  2347. {
  2348. IUnknown *punk = NULL;
  2349. if (paeb->m_pbp)
  2350. {
  2351. paeb->m_pbp->GetBrowserWindow(&punk);
  2352. }
  2353. if (punk)
  2354. {
  2355. IWebBrowser* pwb;
  2356. punk->QueryInterface(IID_IWebBrowser, (LPVOID*)&pwb);
  2357. if (pwb)
  2358. {
  2359. pwb->Stop();
  2360. pwb->Release();
  2361. }
  2362. punk->Release();
  2363. }
  2364. // Cancel pending navigation, if any
  2365. paeb->_CancelNavigation();
  2366. }
  2367. LRESULT lResult = CallWindowProc(paeb->m_lpfnEditWndProc, hwnd, uMessage, wParam, lParam);
  2368. // This bit of magic that restores the icon in the combobox. Otherwise when we
  2369. // dismiss the dropwown with escape we get the icon last selected in the dropdown.
  2370. HWND hwndCombo = (HWND)SendMessage(paeb->m_hwnd, CBEM_GETCOMBOCONTROL, 0, 0);
  2371. SendMessage(hwndCombo, CB_SETCURSEL, -1, 0);
  2372. return lResult;
  2373. }
  2374. }
  2375. break;
  2376. }
  2377. case WM_DESTROY:
  2378. // Unsubclass myself.
  2379. RemoveProp(hwnd, SZ_ADDRESSCOMBO_PROP);
  2380. if (!paeb->m_lpfnEditWndProc)
  2381. return 0;
  2382. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) paeb->m_lpfnEditWndProc);
  2383. ASSERT(paeb->m_hwndEdit);
  2384. paeb->m_hwndEdit = NULL;
  2385. break;
  2386. default:
  2387. break;
  2388. }
  2389. return CallWindowProc(paeb->m_lpfnEditWndProc, hwnd, uMessage, wParam, lParam);
  2390. }
  2391. BOOL GetLabelStringW(HWND hwnd, LPWSTR pwszBuf, DWORD cchBuf)
  2392. {
  2393. HWND hwndLabel;
  2394. LONG lStyle;
  2395. LRESULT lResult;
  2396. BOOL result = FALSE;
  2397. ASSERT(pwszBuf && cchBuf);
  2398. *pwszBuf = 0;
  2399. if (IsWindow(hwnd))
  2400. {
  2401. hwndLabel = hwnd;
  2402. while (hwndLabel = GetWindow(hwndLabel, GW_HWNDPREV))
  2403. {
  2404. lStyle = GetWindowLong(hwndLabel, GWL_STYLE);
  2405. //
  2406. // Skip if invisible
  2407. //
  2408. if (!(lStyle & WS_VISIBLE))
  2409. continue;
  2410. //
  2411. // Is this a static dude?
  2412. //
  2413. lResult = SendMessage(hwndLabel, WM_GETDLGCODE, 0, 0);
  2414. if (lResult & DLGC_STATIC)
  2415. {
  2416. //
  2417. // Great, we've found our label.
  2418. //
  2419. result = GetWindowTextWrapW(hwndLabel, pwszBuf, cchBuf);
  2420. }
  2421. //
  2422. // Is this a tabstop or group? If so, bail out now.
  2423. //
  2424. if (lStyle & (WS_GROUP | WS_TABSTOP))
  2425. break;
  2426. }
  2427. }
  2428. return result;
  2429. }
  2430. CAddressEditAccessible::CAddressEditAccessible(HWND hwndCombo, HWND hwndEdit)
  2431. {
  2432. m_dwRefCount = 1;
  2433. m_hwndEdit = hwndEdit;
  2434. WCHAR wszTitle[MAX_PATH];
  2435. if (!GetLabelStringW(GetParent(hwndCombo), wszTitle, ARRAYSIZE(wszTitle)))
  2436. {
  2437. MLLoadStringW(IDS_BAND_ADDRESS, wszTitle, ARRAYSIZE(wszTitle));
  2438. }
  2439. Str_SetPtr(&m_pwszName, wszTitle);
  2440. CreateStdAccessibleObject(hwndCombo, OBJID_CLIENT, IID_IAccessible, (void **)&m_pDelegateAccObj);
  2441. }
  2442. CAddressEditAccessible::~CAddressEditAccessible()
  2443. {
  2444. Str_SetPtr(&m_pwszName, NULL);
  2445. }
  2446. // *** IUnknown ***
  2447. STDMETHODIMP_(ULONG) CAddressEditAccessible::AddRef()
  2448. {
  2449. InterlockedIncrement((LPLONG)&m_dwRefCount);
  2450. return m_dwRefCount;
  2451. }
  2452. STDMETHODIMP_(ULONG) CAddressEditAccessible::Release()
  2453. {
  2454. ASSERT(m_dwRefCount > 0);
  2455. if (InterlockedDecrement((LPLONG)&m_dwRefCount))
  2456. {
  2457. return m_dwRefCount;
  2458. }
  2459. delete this;
  2460. return 0;
  2461. }
  2462. STDMETHODIMP CAddressEditAccessible::QueryInterface(REFIID riid, LPVOID * ppvObj)
  2463. {
  2464. return _DefQueryInterface(riid, ppvObj);
  2465. }
  2466. // *** IAccessible ***
  2467. STDMETHODIMP CAddressEditAccessible::get_accName(VARIANT varChild, BSTR *pszName)
  2468. {
  2469. *pszName = (m_pwszName != NULL) ? SysAllocString(m_pwszName) : NULL;
  2470. return (*pszName != NULL) ? S_OK : S_FALSE;
  2471. }
  2472. STDMETHODIMP CAddressEditAccessible::get_accValue(VARIANT varChild, BSTR *pszValue)
  2473. {
  2474. WCHAR wszValue[MAX_URL_STRING];
  2475. if (Edit_GetText(m_hwndEdit, wszValue, ARRAYSIZE(wszValue)))
  2476. {
  2477. *pszValue = SysAllocString(wszValue);
  2478. }
  2479. else
  2480. {
  2481. *pszValue = NULL;
  2482. }
  2483. return (*pszValue != NULL) ? S_OK : S_FALSE;
  2484. }