aeditbox.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 82k
Category:

Windows Kernel

Development Platform:

Visual C++

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