#include "priv.h" #include "sccls.h" #include #include "itbdrop.h" #include #include "autocomp.h" #include "itbar.h" #include "address.h" #include #include "basebar.h" #include "shbrowse.h" #include "brand.h" #include "resource.h" #include "theater.h" #include "browmenu.h" #include "util.h" #include "droptgt.h" #include "legacy.h" #include "apithk.h" #include "shbrows2.h" #include "stdenum.h" #include "iehelpid.h" #include #include "mediautil.h" #define WANT_CBANDSITE_CLASS #include "bandsite.h" #include "schedule.h" #include "uemapp.h" #include "mluisupp.h" #ifdef UNIX extern "C" const GUID CLSID_MsgBand; #endif // Offset of the comctl32 default bitmaps #define OFFSET_HIST (MAX_TB_BUTTONS - 1 + 0) // 15 #define OFFSET_STD (MAX_TB_BUTTONS - 1 + 6) // 21 #define OFFSET_VIEW (MAX_TB_BUTTONS - 1 + 21) // 36 // This is the offset in the toolbar for the Shell glyphs and the Shell toolbar labels #define SHELLTOOLBAR_OFFSET (MAX_TB_BUTTONS - 1 + 1) // 16 #define FONTGLYPH_OFFSET (MAX_TB_BUTTONS - 1 + 38) // 53 #define BRIEFCASEGLYPH_OFFSET (MAX_TB_BUTTONS - 1 + 34) // 49 #define RNAUIGLYPH_OFFSET (MAX_TB_BUTTONS - 1 + 36) // 51 #define WEBCHECKGLYPH_OFFSET (MAX_TB_BUTTONS - 1 + 42) // 57 #define EDITGLYPH_OFFSET (9) #define IDT_UPDATETOOLBAR 0x1 #define TIMEOUT_UPDATETOOLBAR 400 const GUID CLSID_Separator = { 0x67077B90L, 0x4F9D, 0x11D0, 0xB8, 0x84, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04 }; extern HRESULT VariantClearLazy(VARIANTARG *pvarg); // How many CT_TABLE structures to allocated at a time. #define TBBMPLIST_CHUNK 5 #define MAX_EXTERNAL_BAND_NAME_LEN 64 #define MAX_TB_COMPRESSED_WIDTH 42 // 16 is added to the the MAX_TB defines. This is added through the strings // in the RC file. This is done so that the localization folks can increase // or decrease the width of the toolbar buttons #define MAX_TB_WIDTH_LORES 38 #define MAX_TB_WIDTH_HIRES 60 // Dimensions of Coolbar Glyphs .. #define TB_SMBMP_CX 16 #define TB_SMBMP_CY 16 #define TB_BMP_CX 20 #define TB_BMP_CY 20 #define TB_BMP_CX_ALPHABITMAP 24 #define TB_BMP_CY_ALPHABITMAP 24 int g_iToolBarLargeIconWidth = TB_BMP_CX; int g_iToolBarLargeIconHeight = TB_BMP_CY; #define CX_SEPARATOR 6 // we override toolbar control's default separator width of 8 #define DM_TBSITE 0 #define DM_TBCMD 0 #define DM_TBREF TF_SHDREF #define DM_LAYOUT 0 #define DM_ITBAR 0 #define TF_TBCUST 0x01000000 #if CBIDX_LAST != 5 #error Expected CBIDX_LAST to have value of 5 #endif #if (FCIDM_EXTERNALBANDS_LAST - FCIDM_EXTERNALBANDS_FIRST + 1) < MAXEXTERNALBANDS #error Insufficient range for FCIDM_EXTERNALBANDS_FIRST to FCIDM_EXTERNALBANDS_LAST #endif __inline UINT EXTERNALBAND_VBF_BIT(UINT uiBandExt) { ASSERT(uiBandExt < MAXEXTERNALBANDS); // Formula: take 1, shift left by uiBandExt + 16 // => a bit in range (0x80000000, 0x00010000) UINT uBit = 1 << (uiBandExt + 16); ASSERT(uBit & VBF_EXTERNALBANDS); return uBit; } __inline BOOL IS_EXTERNALBAND(int idBand) { return (InRange(idBand, CBIDX_EXTERNALFIRST, CBIDX_EXTERNALLAST)); } __inline int MAP_TO_EXTERNAL(int idBand) { ASSERT(IS_EXTERNALBAND(idBand)); // CBIDX_LAST is one-based, mapping is zero-based return (idBand - (1 + CBIDX_LAST)); } // maximum number of menu items in the context menus for back and forward. #define MAX_NAV_MENUITEMS 9 #define DEFAULT_SEARCH_GUID SRCID_SFileSearch //SRCID_SWebSearch #define SZ_PROP_CUSTDLG TEXT("Itbar custom dialog hwnd") #define REG_KEY_BANDSTATE TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar") // MHTML Editing #define SZ_IE_DEFAULT_MHTML_EDITOR "Default MHTML Editor" #define REGSTR_PATH_DEFAULT_MHTML_EDITOR TSZIEPATH TEXT("\\") TEXT(SZ_IE_DEFAULT_MHTML_EDITOR) #define REGSTR_KEY_DEFAULT_MHTML_EDITOR TEXT(SZ_IE_DEFAULT_MHTML_EDITOR) DWORD DoNetConnect(HWND hwnd); DWORD DoNetDisconnect(HWND hwnd); void _LoadToolbarGlyphs(HWND hwnd, IMLCACHE *pimlCache, int cx, int idBmp, int iBitmapBaseIndex, BOOL bUseClassicGlyphs, HINSTANCE hInst); BOOL _UseSmallIcons(); typedef struct tagTBBMP_LIST { HINSTANCE hInst; UINT_PTR uiResID; UINT uiOffset; BITBOOL fNormal:1; BITBOOL fHot:1; BITBOOL fDisabled:1; UINT uiCount; } TBBMP_LIST; typedef struct tagCMDMAP { GUID guidButtonGroup; UINT nCmdID; LPARAM lParam; // app's data } CMDMAP; typedef struct tagCMDMAPCUSTOMIZE { TBBUTTON btn; CMDMAP cm; } CMDMAPCUSTOMIZE; typedef struct { // the IOleCommandTarget info: GUID guid; UINT nCmdID; UINT fButtonState; } BUTTONSAVEINFO; #define TBSI_VERSION 7 typedef struct { int cVersion; } TOOLBARSAVEINFO; typedef struct { HDSA hdsa; BITBOOL fAdjust:1; BITBOOL fDirty:1; } CUSTOMIZEINFO, *LPCUSTOMIZEINFO; //Current latest version. #define CBS_VERSION 17 // NOTE: Be very careful changing COOLBARSAVE because _LoadUpgradeSettings makes // assumptions about the layout of the structure. To avoid breaking that // upgrade code, be sure you: // // - don't change the order of existing members // - always add new members to the end of the structure. // - update _LoadUpgradeSettings if appropriate // typedef struct tagCOOLBARSAVE { UINT cbVer; UINT uiMaxTBWidth; UINT uiMaxQLWidth; #ifdef UNIX BITBOOL fUnUsed : 28; // unused #endif BITBOOL fVertical : 1; // The bar is oriented vertically BITBOOL fNoText :1; // "NoText" BITBOOL fList : 1; // toolbar is TBSTYLE_LIST (text on right) + TBSTYLE_EX_MIXEDBUTTONS BITBOOL fAutoHide : 1; // Auto hide toolbar in theater mode BITBOOL fStatusBar : 1; // Status bar in theater mode BITBOOL fSaveInShellIntegrationMode : 1; // Did we save in shell integration mode? UINT uiVisible; // "Visible bands" UINT cyRebar; BANDSAVE bs[CBANDSMAX]; CLSID aclsidExternalBands[ MAXEXTERNALBANDS ]; // Check classid CLSID clsidVerticalBar; //clsid of bar persisted within vertical band CLSID clsidHorizontalBar; } COOLBARSAVE, *LPCOOLBARSAVE; //Flags for dwFlags passed to UpdateToolbarDisplay() #define UTD_TEXTLABEL 0x00000001 #define UTD_VISIBLE 0x00000002 static const TCHAR c_szRegKeyCoolbar[] = TSZIEPATH TEXT("\\Toolbar"); static const TCHAR c_szValueTheater[] = TEXT("Theater"); typedef struct tagFOLDERSEARCHITEM { UINT idCmd; GUID guidSearch; int iIcon; WCHAR wszUrl[MAX_URL_STRING]; WCHAR wszName[80]; // friendly name }FOLDERSEARCHITEM, *LPFOLDERSEARCHITEM; BOOL _GetSearchHKEY(LPGUID lpguidSearch, HKEY *phkey); #define REG_SZ_STATIC TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FindExtensions\\Static") #define REG_SZ_SEARCH_GUID TEXT("SearchGUID") #define REG_SZ_SEARCH_URL TEXT("SearchGUID\\Url") #define VIEW_OFFSET (SHELLGLYPHS_OFFSET + HIST_MAX + STD_MAX) #define VIEW_ALLFOLDERS (VIEW_NETCONNECT + 14) static const TBBUTTON c_tbExplorer[] = { // override default toolbar width for separators; iBitmap member of // TBBUTTON struct is a union of bitmap index & separator width { 0, TBIDM_BACK , 0, BTNS_DROPDOWN | BTNS_SHOWTEXT, {0,0}, 0, 0 }, { 1, TBIDM_FORWARD, 0, BTNS_DROPDOWN, {0,0}, 0, 1 }, { 2, TBIDM_STOPDOWNLOAD, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 2 }, { 3, TBIDM_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 3 }, { 4, TBIDM_HOME, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 4 }, { VIEW_PARENTFOLDER + VIEW_OFFSET, TBIDM_PREVIOUSFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, VIEW_PARENTFOLDER + VIEW_OFFSET }, { VIEW_NETCONNECT + VIEW_OFFSET, TBIDM_CONNECT, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, VIEW_NETCONNECT + VIEW_OFFSET }, { VIEW_NETDISCONNECT + VIEW_OFFSET, TBIDM_DISCONNECT, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, VIEW_NETDISCONNECT + VIEW_OFFSET }, { CX_SEPARATOR, 0, TBSTATE_ENABLED, BTNS_SEP, {0,0}, 0, -1 }, { 5, TBIDM_SEARCH, TBSTATE_ENABLED, BTNS_SHOWTEXT, {0,0}, 0, 5 }, { VIEW_ALLFOLDERS + VIEW_OFFSET, TBIDM_ALLFOLDERS, TBSTATE_ENABLED, BTNS_SHOWTEXT, {0,0}, 0, VIEW_ALLFOLDERS + VIEW_OFFSET }, { 6, TBIDM_FAVORITES, TBSTATE_ENABLED, BTNS_SHOWTEXT, {0,0}, 0, 6 }, // IF YOU CHANGE THE ORDERING OF THIS, please change AddMediaBarButton to reflect this ordering. { 11, TBIDM_MEDIABAR, TBSTATE_ENABLED, BTNS_SHOWTEXT, {0,0}, 0, 11 }, { 12, TBIDM_HISTORY, TBSTATE_ENABLED, 0/*BTNS_SHOWTEXT*/, {0,0}, 0, 12}, { CX_SEPARATOR, 0, TBSTATE_ENABLED, BTNS_SEP, {0,0}, 0, -1 }, #ifndef DISABLE_FULLSCREEN // IE UNIX : No theater mode for beta1 { 14, TBIDM_THEATER, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 14 }, #endif }; // these IDs are the array indices into c_tbExplorer above // keep in sync, be aware there are ASSERTs to enforce them to be in sync #define TBXID_BACK 0 #define TBXID_FORWARD 1 #define TBXID_STOPDOWNLOAD 2 #define TBXID_REFRESH 3 #define TBXID_HOME 4 #define TBXID_PREVIOUSFOLDER 5 #define TBXID_CONNECT 6 #define TBXID_DISCONNECT 7 #define TBXID_SEPARATOR1 8 #define TBXID_SEARCH 9 #define TBXID_ALLFOLDERS 10 #define TBXID_FAVORITES 11 #define TBXID_MEDIABAR 12 #define TBXID_HISTORY 13 #define TBXID_SEPARATOR2 14 #define TBXID_THEATER 15 static const BROWSER_RESTRICTIONS c_rest[] = { REST_BTN_BACK, REST_BTN_FORWARD, REST_BTN_STOPDOWNLOAD, REST_BTN_REFRESH, REST_BTN_HOME, REST_BROWSER_NONE, // no policy for up REST_BROWSER_NONE, // no policy for map drive REST_BROWSER_NONE, // no policy for disconnect drive REST_BROWSER_NONE, // separator REST_BTN_SEARCH, REST_BTN_ALLFOLDERS, REST_BTN_FAVORITES, REST_BTN_MEDIABAR, REST_BTN_HISTORY, REST_BROWSER_NONE, // separator #ifndef DISABLE_FULLSCREEN REST_BTN_THEATER, #endif }; // init flags to avoid multiple inits of toolbar and buttons #define TBBIF_REG_PATH TEXT("Software\\Microsoft\\Internet Explorer") #define TBBIF_REG_KEY TEXT("AddButtons") // defined flags as bitfield #define TBBIF_NONE 0 #define TBBIF_XBAR 0x1 // reserved/used to distinguish pre IE6/RC1 where PersonalBar/xBar was configured #define TBBIF_MEDIA 0x2 #define SUPERCLASS CBaseBar class CInternetToolbar : public CBaseBar, public IDockingWindow, public IObjectWithSite, // *not* CObjectWithSite (want _ptbSite) public IExplorerToolbar, public DWebBrowserEvents, public IPersistStreamInit, public IShellChangeNotify, public ISearchItems { public: // *** IUnknown *** virtual STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj); virtual STDMETHODIMP_(ULONG) AddRef(void) { return SUPERCLASS::AddRef(); }; virtual STDMETHODIMP_(ULONG) Release(void){ return SUPERCLASS::Release(); }; // *** IOleWindow methods *** virtual STDMETHODIMP GetWindow(HWND * lphwnd) { return SUPERCLASS::GetWindow(lphwnd);}; virtual STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) {return SUPERCLASS::ContextSensitiveHelp(fEnterMode);}; // *** IDockingWindow methods *** virtual STDMETHODIMP ShowDW(BOOL fShow); virtual STDMETHODIMP CloseDW(DWORD dwReserved); virtual STDMETHODIMP ResizeBorderDW(LPCRECT prcBorder, IUnknown* punkToolbarSite, BOOL fReserved); // *** IObjectWithSite methods *** virtual STDMETHODIMP SetSite(IUnknown* punkSite); // is E_NOTIMPL ok? virtual STDMETHODIMP GetSite(REFIID riid, void** ppvSite) { ASSERT(0); return E_NOTIMPL; }; // *** IInputObjectSite methods *** virtual STDMETHODIMP OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus); // *** IInputObject methods *** virtual STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg); // *** IServiceProvider methods *** virtual STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void** ppvObj); // *** IExplorerToolbar method *** virtual STDMETHODIMP SetCommandTarget(IUnknown* punkCmdTarget, const GUID* pguidButtonGroup, DWORD dwFlags); virtual STDMETHODIMP AddStdBrowserButtons(void); virtual STDMETHODIMP AddButtons(const GUID* pguidButtonGroup, UINT nButtons, const TBBUTTON * lpButtons); virtual STDMETHODIMP AddString(const GUID * pguidButtonGroup, HINSTANCE hInst, UINT_PTR uiResID, LONG_PTR *pOffset); virtual STDMETHODIMP GetButton(const GUID* pguidButtonGroup, UINT uiCommand, LPTBBUTTON lpButton); virtual STDMETHODIMP GetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT * pfState); virtual STDMETHODIMP SetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT fState); virtual STDMETHODIMP AddBitmap(const GUID * pguidButtonGroup, UINT uiBMPType, UINT uiCount, TBADDBITMAP * ptb, LRESULT * pOffset, COLORREF rgbMask); virtual STDMETHODIMP GetBitmapSize(UINT * uiID); virtual STDMETHODIMP SendToolbarMsg(const GUID * pguidButtonGroup, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT * plRes); virtual STDMETHODIMP SetImageList( const GUID* pguidCmdGroup, HIMAGELIST himlNormal, HIMAGELIST himlHot, HIMAGELIST himlDisabled); virtual STDMETHODIMP ModifyButton( const GUID * pguidButtonGroup, UINT uiCommand, LPTBBUTTON lpButton); // IOleCommandTarget virtual STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext); virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut); // IPersistStreamInit STDMETHOD(GetClassID)(GUID *pguid); STDMETHOD(Load)(IStream *pStm); STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty); STDMETHOD(InitNew)(void); STDMETHOD(IsDirty)(void); STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize); /* IDispatch methods */ virtual STDMETHODIMP GetTypeInfoCount(UINT *pctinfo); virtual STDMETHODIMP GetTypeInfo(UINT itinfo,LCID lcid,ITypeInfo **pptinfo); virtual STDMETHODIMP GetIDsOfNames(REFIID riid,OLECHAR **rgszNames,UINT cNames, LCID lcid, DISPID * rgdispid); virtual STDMETHODIMP Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,UINT * puArgErr); // IShellChangeNotify virtual STDMETHODIMP OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); // CBaseBar overrides virtual LRESULT v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // *** ISearchItems methods *** virtual STDMETHODIMP GetDefaultSearchUrl(LPWSTR pwzUrl, UINT cch); CInternetToolbar(); protected: virtual ~CInternetToolbar(); static LRESULT CALLBACK SizableWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void _OnCommand(WPARAM wParam, LPARAM lParam); BOOL _SendToToolband(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres); LRESULT _OnNotify(LPNMHDR pnmh); void _OnTooltipNeeded(LPTOOLTIPTEXT pnmTT); BOOL _UpEnabled(); void _UpdateCommonButton(int iCmd, UINT nCmdID); void _UpdateToolbar(BOOL fForce); void _UpdateToolbarNow(); void _UpdateGroup(const GUID *pguidCmdGroup, int cnt, OLECMD rgcmds[], const GUID* pguidButton, const int buttonsInternal[]); void _CSHSetStatusBar(BOOL fOn); void _StartDownload(); void _StopDownload(BOOL fClosing); BOOL _CompressBands(BOOL fCompress, UINT uRowsNew, BOOL fForceUpdate); void _TrackSliding(int x, int y); void _Unadvise(void); LRESULT _OnBeginDrag(NMREBAR* pnm); void _InsertURL(LPTSTR pszURL); void _ShowContextMenu(HWND hwnd, LPARAM lParam, LPRECT prcExclude); BOOL _ShowBackForwardMenu(BOOL fForward, POINT pt, LPRECT prcExclude); // search helper methods BOOL _GetFolderSearchData(); void _SetSearchStuff(); BOOL _GetSearchUrl(LPWSTR pwszUrl, DWORD cch); HRESULT _GetFolderSearches(IFolderSearches **ppfs); void _ReloadButtons(); void _UpdateToolsStyle(BOOL fList); void _InitBitmapDSA(); void _ReloadBitmapDSA(); void _InitForScreenSize(); void _InitToolbar(); BOOL _FoldersButtonAvailable(); void _AdminMarkDefaultButtons(PTBBUTTON ptbb, UINT cButtons); void _MarkDefaultButtons(PTBBUTTON ptbb, UINT cButtons); void _AddCommonButtons(); HRESULT _CreateBands(); BOOL _ShowBands(UINT fVisible); HRESULT _ShowTools(PBANDSAVE pbs); HRESULT _ShowAddressBand(PBANDSAVE pbs); HRESULT _ShowExternalBand(PBANDSAVE pbs, int idBand ); HRESULT _ShowLinks(PBANDSAVE pbs); HRESULT _ShowBrand(PBANDSAVE pbs); HRESULT _ShowMenu(PBANDSAVE pbs); void _ShowBandCommon(PBANDSAVE pbs, CBandItemData *pbid, BOOL fShow); void _EnsureAllBandsShown(); HRESULT _GetMinRowHeight(); HBITMAP _LoadBackBitmap(); void _SetBackground(); void _CommonHandleFileSysChange(LONG lEvent, LPITEMIDLIST* ppidl); int _ConvertHwndToID(HWND hwnd); HRESULT _GetPersistedBand(const CLSID clsid, REFIID riid, void ** ppiface); // Multiple command target LRESULT _AddBitmapFromForeignModule(UINT uiGetMSG, UINT uiSetMSG, UINT uiCount, HINSTANCE hinst, UINT_PTR nID, COLORREF rgbMask); HRESULT _LoadDefaultSettings(void); HRESULT _LoadUpgradeSettings(ULONG cbRead); HRESULT _LoadDefaultWidths(void); void _TryLoadIE3Settings(); HRESULT _UpdateToolbarDisplay(DWORD dwFlags, UINT uVisibleBands, BOOL fNoText, BOOL fPersist); void _UpdateBrandSize(); void _ShowVisible(DWORD dwVisible, BOOL fPersist); void _BuildSaveStruct(COOLBARSAVE* pcs); void _RestoreSaveStruct(COOLBARSAVE* pcs); void _GetVisibleBrowserBar(UINT idBar, CLSID *pclsidOut); VOID _UpdateLocking(); CBandItemData *_AddNewBand(IDeskBand* pdb, DWORD dwID); void _TheaterModeLayout(BOOL fEnter); HBITMAP _bmpBack; // this is the state we think the itbar is in static BMPCACHE s_bmpBackShell; // this is the state of the shell bmp cache static BMPCACHE s_bmpBackInternet; // this is the state of the internet bmp cache static IMLCACHE s_imlTBGlyphs; HWND _hwndMenu; HWND _hwndAddressBand; IDockingWindowSite* _ptbsite; IOleCommandTarget* _ptbsitect; IBrowserService* _pbs; IBrowserService2* _pbs2; IServiceProvider* _psp; IBandProxy * _pbp; BITBOOL _fCreatedBandProxy:1; BITBOOL _fBackEnabled:1; BITBOOL _fForwardEnabled:1; BITBOOL _fEditEnabled:1; BITBOOL _fShow:1; BITBOOL _fAnimating:1; BITBOOL _fCompressed:1; BITBOOL _fUserNavigated :1; BITBOOL _fAutoCompInitialized :1; BITBOOL _fDirty:1; BITBOOL _fUsingDefaultBands:1; BITBOOL _fTransitionToHTML:1; BITBOOL _fInitialPidlIsWeb:1; BITBOOL _fTheater: 1; // are we in theater mode? claim no border space BITBOOL _fAutoHide :1; BITBOOL _fRebarDragging :1; BITBOOL _fShellView:1; // are we in shell view or web view? BITBOOL _fNoShowMenu:1; // can show menu band? BITBOOL _fUpdateToolbarTimer:1; BITBOOL _fNeedUpdateToolbar:1; BITBOOL _fNavigateComplete:1; BITBOOL _fLoading:1; // are we still loading the bar? BITBOOL _fDestroyed:1; // Did we destroy our member varibles and are shutting down? If so, don't use the varibles. (Stress bug w/messages coming in) BITBOOL _fLockedToolbar:1; UINT _nVisibleBands; // bitmask of which bands are visible: VBF_* IWebBrowser2* _pdie; DWORD _dwcpCookie; // DIID_DWebBrowserEvents2 int _xCapture; int _yCapture; // for multiple command target support HDSA _hdsaTBBMPs; UINT _uiMaxTBWidth; UINT _uiTBTextRows; UINT _uiTBDefaultTextRows; // search stuff HDPA _hdpaFSI; // folder search items GUID _guidCurrentSearch; GUID _guidDefaultSearch; COOLBARSAVE _cs; //Coolbar layout info from registry! BOOL _fDontSave; // force ourselves not to persist out the state. struct EXTERNALBANDINFO { CLSID clsid; // CLSID of the band LPWSTR pwszName; // Band name LPWSTR pwszHelp; // Band help text }; EXTERNALBANDINFO _rgebi[ MAXEXTERNALBANDS ]; void _LoadExternalBandInfo(); TBBUTTON _tbExplorer[ARRAYSIZE(c_tbExplorer)]; int _iButtons; // Variables for customizing the edit button glyph HIMAGELIST _himlEdit; // Monochrome Image list for the edit button HIMAGELIST _himlEditHot; // Hot image list for edit button int _iEditIcon; // index of current edit icon int _cxEditGlyph; // cx of glyph size int _cyEditGlyph; // cx of glyph size // Functions for managing a custom edit glyph void _InitEditButtonStyle(); void _SetEditGlyph(int iIcon); void _RefreshEditGlyph(); void _UpdateEditButton(); static HIMAGELIST _CreateGrayScaleImagelist(HBITMAP hbmpImage, HBITMAP hbmpMask); static BSTR _GetEditProgID(IHTMLDocument2* pHTMLDocument); // // We can have multiple edit verbs associated with a document. The following class // maintains a list of verbs. // #define FCIDM_EDITFIRST 2000 #define FCIDM_EDITLAST 2100 #define SZ_EDITVERB_PROP TEXT("CEditVerb_This") #define IL_EDITBUTTON 2 // Index of image list used for the edit button #define IL_SEARCHBUTTON 3 // || search button // MSAA Menu Info declarations. // These will eventually be incorporated into oleacc.h - but for the // moment, we declare them privately... #define MSAA_MENU_SIG 0xAA0DF00DL class CEditVerb { public: CEditVerb(); ~CEditVerb(); // Functions for managing the verbs BOOL Add(LPTSTR pszProgID); UINT GetSize() { return _nElements; } void RemoveAll(); // Functions to access the default edit verb int GetIcon() { return (_nElements && _pVerb[_nDefault].fShowIcon) ? _GetVerb(_nDefault).iIcon : -1; } BOOL GetToolTip(LPTSTR pszToolTip, UINT cchMax, BOOL fStripAmpersands = TRUE); BOOL GetMenuText(LPTSTR pszText, UINT cchMax) { return GetToolTip(pszText, cchMax, FALSE); } void Edit(LPCTSTR pszUrl) { _Edit(pszUrl, _nDefault); } // Pop-up menu BOOL ShowEditMenu(POINT pt, HWND hwnd, LPTSTR pszUrl); // Get default editor from the registry void InitDefaultEditor(HKEY hkey = NULL); protected: struct MSAAMenuInfo { DWORD m_MSAASig; // Must be MSAA_MENU_SIG DWORD m_CharLen; // Length in characters of text, excluding terminating NUL LPWSTR m_pWStr; // Menu text, in UNICODE, with terminating UNICODE-NUL. }; struct EDITVERB { MSAAMenuInfo m_MSAA; // MSAA info - must be first element. HKEY hkeyProgID; // Key the we shellexec BITBOOL fUseOpenVerb:1; // use open verb instead of edit BITBOOL fInit:1; // true if the data below has beed initialized BITBOOL fShowIcon:1; // true if icon should show up on button int iIcon; // cached icon index UINT idCmd; // menu id LPTSTR pszDesc; // executable name or document name LPTSTR pszMenuText; // Menu text LPTSTR pszExe; // Path of the exe used to edit }; EDITVERB* _Add(HKEY hkeyProgID, BOOL fPermitOpenVerb, BOOL fCheckForOfficeApp, BOOL fShowIcon); EDITVERB& _GetVerb(UINT nIndex); void _FetchInfo(UINT nIndex); void _Edit(LPCTSTR pszUrl, UINT nIndex); LPCTSTR _GetDescription(EDITVERB& rVerb); void _SetMSAAMenuInfo(EDITVERB& rVerb); void _ClearMSAAMenuInfo(EDITVERB& rVerb); void _FormatMenuText(UINT nIndex); BOOL _IsUnique(EDITVERB& rNewVerb); BOOL _IsHtmlStub(LPCWSTR pszPath); LPCTSTR _GetExePath(EDITVERB& rVerb); LPCTSTR _GetDefaultEditor(); void _InitDefaultMHTMLEditor(); static LRESULT CALLBACK _WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Member data UINT _nElements; // number of edit verbs UINT _nDefault; // Default edit verb EDITVERB* _pVerb; // array of edit verbs WNDPROC _lpfnOldWndProc; // former wndProc LPWSTR _pszDefaultEditor; // Friendly name of default HTML editor BOOL _fInitEditor; // if we checked for a default editor }; CEditVerb _aEditVerb; // internal bandsite class class CBrowserToolsBand; class CITBandSite : public CBandSite { CITBandSite(); virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut); virtual STDMETHODIMP AddBand(IUnknown *punk); virtual STDMETHODIMP HasFocusIO(); protected: virtual void v_SetTabstop(LPREBARBANDINFO prbbi); BOOL _SetMinDimensions(); friend class CInternetToolbar; friend class CBrowserToolsBand; virtual HRESULT _OnContextMenu(WPARAM wParm, LPARAM lParam); virtual HRESULT _Initialize(HWND hwndParent); }; CITBandSite _bs; #define TOOLSBANDCLASS CInternetToolbar::CBrowserToolsBand class CBrowserToolsBand : public CToolbarBand { CMDMAP* _GetCmdMapByIndex(int nIndex) { return _GetCmdMap(nIndex, TRUE);}; CMDMAP* _GetCmdMapByID(int id) { return _GetCmdMap(id, FALSE);}; LRESULT _ToolsCustNotify (LPNMHDR pnmh); // Handle TBCustomization Notify BOOL _SaveRestoreToolbar(BOOL fSave); void _FreeCustomizeInfo(); void _FreeCmdMap(CMDMAP*); BOOL _RemoveAllButtons(); int _CommandFromIndex(UINT uIndex); HRESULT _ConvertCmd(const GUID* pguidButtonGroup, UINT id, GUID* pguidOut, UINT * pid); void _OnDeletingButton(TBNOTIFY* ptbn); LONG_PTR _AddString(LPWSTR pwstr); void _PreProcessButtonString(TBBUTTON *ptbn, DWORD dwFlags); void _PreProcessExternalTBButton(TBBUTTON *ptbn); UINT _ProcessExternalButtons(PTBBUTTON ptbb, UINT cButtons); void _GetButtons(IOleCommandTarget* pct, const GUID* pguid, HDSA hdsa); void _RecalcButtonWidths(); void _AddMediaBarButton(); void _UpdateTextSettings(INT_PTR ids); static BOOL_PTR CALLBACK _BtnAttrDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static void _PopulateComboBox(HWND hwnd, const int iResource[], UINT cResources); static void _SetComboSelection(HWND hwnd, int iCurOption); void _SetDialogSelections(HWND hDlg, BOOL fSmallIcons); static void _PopulateDialog(HWND hDlg); void _OnBeginCustomize(LPNMTBCUSTOMIZEDLG pnm); BOOL _BuildButtonDSA(); CMDMAPCUSTOMIZE* _GetCmdMapCustomize(GUID* guid, UINT nCmdID); virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut); virtual STDMETHODIMP GetClassID(CLSID *pClassID) {return E_NOTIMPL;}; virtual STDMETHODIMP Load(IStream *pStm) {return E_NOTIMPL;}; virtual STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty) {return E_NOTIMPL;}; // *** IUnknown *** virtual STDMETHODIMP_(ULONG) AddRef(void) { return CToolBand::AddRef(); }; virtual STDMETHODIMP_(ULONG) Release(void){ return CToolBand::Release(); }; virtual STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj); // *** IDeskBand methods *** virtual STDMETHODIMP GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi); // *** IWinEventHandler methods *** virtual STDMETHODIMP OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres); // *** IDockingWindow methods *** virtual STDMETHODIMP CloseDW(DWORD dwReserved) { return S_OK;}; // *** IInputObject methods *** virtual STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg); protected: IOleCommandTarget* _CommandTargetFromCmdMap(CMDMAP* pcm); LRESULT _OnToolbarDropDown(TBNOTIFY *ptbn); virtual LRESULT _OnNotify(LPNMHDR pnmh); LRESULT _OnContextMenu(LPARAM lParam, WPARAM wParam); CMDMAP* _GetCmdMap(int i, BOOL fByIndex); void _OnEndCustomize(); LRESULT _TryShowBackForwardMenu(DWORD dwItemSpec, LPPOINT ppt, LPRECT prcExclude); CBrowserToolsBand(); void _FreeBtnsAdded(); friend class CInternetToolbar; friend class CITBandSite; GUID _guidCurrentButtonGroup; IOleCommandTarget* _pctCurrentButtonGroup; LPTBBUTTON _pbtnsAdded; int _cBtnsAdded; DWORD _nNextCommandID; CUSTOMIZEINFO *_pcinfo; BITBOOL _fCustomize :1; BITBOOL _fNeedFreeCmdMapsAdded :1; }; CBrowserToolsBand _btb; friend class CBrowserToolsBand; friend class CITBandSite; friend void CInternetToolbar_CleanUp(); friend void CInternetToolbar_Preload(); friend void ITBar_LoadToolbarGlyphs(HWND hwnd); }; // // Gets the stream corresponding to the type of the given pidl // If the stream already doesn't exist, then it returns NULL. HRESULT _GetStreamName(DWORD dwITBS, LPTSTR pszName, DWORD cchSize) { HRESULT hr = S_OK; ASSERT(pszName); switch (dwITBS) { case ITBS_WEB: StrCpyN(pszName, TEXT("WebBrowser"), cchSize); break; case ITBS_SHELL: StrCpyN(pszName, TEXT("ShellBrowser"), cchSize); break; case ITBS_EXPLORER: StrCpyN(pszName, TEXT("Explorer"), cchSize); break; default: hr = E_FAIL; break; } if (FAILED(hr)) pszName[0] = '\0'; return hr; } // // Gets the stream corresponding to the type of the given pidl // If the stream already doesn't exist, then it returns NULL. IStream *GetRegStream(BOOL fInternet, LPCTSTR pszValue, DWORD grfMode) { IStream *pstm = NULL; HKEY hkToolbar; // read/write since grfMode could be anything if (RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegKeyCoolbar, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkToolbar, NULL) == ERROR_SUCCESS) { TCHAR szStreamName[MAX_PATH]; if (SUCCEEDED(_GetStreamName(fInternet, szStreamName, ARRAYSIZE(szStreamName)))) pstm = OpenRegStream(hkToolbar, szStreamName, pszValue, grfMode); RegCloseKey(hkToolbar); } return(pstm); } // // Gets the stream corresponding to the type of the given pidl // If the stream already doesn't exist, then it returns NULL. IStream *GetITBarStream(BOOL fInternet, DWORD grfMode) { return GetRegStream(fInternet, TEXT("ITBarLayout"), grfMode); } IMLCACHE CInternetToolbar::s_imlTBGlyphs = {NULL}; BMPCACHE CInternetToolbar::s_bmpBackShell = {NULL}; BMPCACHE CInternetToolbar::s_bmpBackInternet = {NULL}; BOOL g_fSmallIcons = FALSE; void IMLCACHE_CleanUp(IMLCACHE * pimlCache, DWORD dwFlags) { for (int i = 0; i < CIMLISTS; i++) { if (pimlCache->arhimlPendingDelete[i]) ImageList_Destroy(pimlCache->arhimlPendingDelete[i]); if ((dwFlags & IML_DESTROY) && pimlCache->arhiml[i]) ImageList_Destroy(pimlCache->arhiml[i]); } } // DO NOT change the numbering of the following bitmap specs. // If you want to add new sizes, add them _after_ ITB_1616_HOT_HICOLOR #define ITB_2020_NORMAL 0 #define ITB_2020_HOT 1 #define ITB_1616_NORMAL 2 #define ITB_1616_HOT 3 #define ITB_2020_NORMAL_HICOLOR 4 #define ITB_2020_HOT_HICOLOR 5 #define ITB_1616_NORMAL_HICOLOR 6 #define ITB_1616_HOT_HICOLOR 7 void ITBar_LoadToolbarGlyphs(HWND hwnd) { int cx, idBmpType; int iBitmapBaseIndex; BOOL bUseClassicGlyphs = SHUseClassicToolbarGlyphs(); HINSTANCE hInst; g_fSmallIcons = _UseSmallIcons(); if (bUseClassicGlyphs) { g_iToolBarLargeIconWidth = TB_BMP_CX; g_iToolBarLargeIconHeight = TB_BMP_CY; iBitmapBaseIndex = IDB_SHSTD; hInst = HINST_THISDLL; } else { g_iToolBarLargeIconWidth = TB_BMP_CX_ALPHABITMAP; g_iToolBarLargeIconHeight = TB_BMP_CY_ALPHABITMAP; iBitmapBaseIndex = IDB_TB_SH_BASE; hInst = GetModuleHandle(TEXT("shell32.dll")); } if (g_fSmallIcons) { cx = TB_SMBMP_CX; idBmpType = ITB_1616_NORMAL; } else { cx = g_iToolBarLargeIconWidth; idBmpType = ITB_2020_NORMAL; } if (SHGetCurColorRes() > 8) idBmpType += DELTA_HICOLOR; _LoadToolbarGlyphs(hwnd, &CInternetToolbar::s_imlTBGlyphs, cx, idBmpType, iBitmapBaseIndex, bUseClassicGlyphs, hInst); } void CInternetToolbar_Preload() { ENTERCRITICAL; ITBar_LoadToolbarGlyphs(NULL); Brand_InitBrandContexts(); LEAVECRITICAL; } void CInternetToolbar_CleanUp() { TraceMsg(DM_ITBAR, "CInternetToolbar_CleanUp: Destroying shared GDI objects"); if (CInternetToolbar::s_bmpBackInternet.hbmp) DeleteObject(CInternetToolbar::s_bmpBackInternet.hbmp); if (CInternetToolbar::s_bmpBackShell.hbmp) DeleteObject(CInternetToolbar::s_bmpBackShell.hbmp); IMLCACHE_CleanUp(&CInternetToolbar::s_imlTBGlyphs, IML_DESTROY); } STDAPI CInternetToolbar_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi) { // aggregation checking is handled in class factory CInternetToolbar *pitbar = new CInternetToolbar(); if (pitbar) { *ppunk = SAFECAST(pitbar, IDockingWindow *); return S_OK; } return E_OUTOFMEMORY; } LRESULT CInternetToolbar::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if ( uMsg == WM_SYSCOLORCHANGE ) { // refresh the back drop incase the colours have changed _SetBackground(); } return SUPERCLASS::v_WndProc( hwnd, uMsg, wParam, lParam ); } void CInternetToolbar::_LoadExternalBandInfo() { #ifdef DEBUG int i; // Should have been zero-initialized for (i = 0; i < ARRAYSIZE(_rgebi); i++) { ASSERT(IsEqualGUID(_rgebi[i].clsid, GUID_NULL)); ASSERT(_rgebi[i].pwszName == NULL); ASSERT(_rgebi[i].pwszHelp == NULL); } #endif if ((!SHRegGetBoolUSValue(TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\Main"), TEXT("Enable Browser Extensions"), FALSE, TRUE)) || (GetSystemMetrics(SM_CLEANBOOT)!=0)) { return; } HKEY hkey; DWORD dwClsidIndex = 0; if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_KEY_BANDSTATE, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { TCHAR tszReg[MAX_PATH]; StrCpyN(tszReg, TEXT("CLSID\\"), ARRAYSIZE(tszReg)); const int cchClsidPrefix = 6; // 6 = strlen("CLSID\\") LPTSTR ptszClsid = tszReg + cchClsidPrefix; DWORD cchClsid; for (DWORD dwIndex = 0; cchClsid = ARRAYSIZE(tszReg) - cchClsidPrefix, dwClsidIndex < ARRAYSIZE(_rgebi) && RegEnumValue( hkey, dwIndex, ptszClsid, &cchClsid, NULL, NULL, NULL, NULL ) == ERROR_SUCCESS; dwIndex++) { CLSID clsid; // We want to ignore the radio toolband {8E718888-423F-11D2-876E-00A0C9082467} // without affecting its existing registration. Makes uninstall easier. if (GUIDFromString( ptszClsid, &clsid ) && StrCmpI(ptszClsid, TEXT("{8E718888-423F-11D2-876E-00A0C9082467}"))) { HKEY hkeyClsid; if (RegOpenKeyEx(HKEY_CLASSES_ROOT, tszReg, 0, KEY_READ, &hkeyClsid) == ERROR_SUCCESS) { // Don't save the CLSID until we're sure it worked _rgebi[dwClsidIndex].clsid = clsid; WCHAR wszBuf[MAX_PATH]; // Get the name; use SHLoadRegUIString so the app can localize SHLoadRegUIStringW( hkeyClsid, L"", wszBuf, ARRAYSIZE(wszBuf) ); Str_SetPtrW( &_rgebi[dwClsidIndex].pwszName, wszBuf); // Get the help; use SHLoadRegUIString so the app can localize SHLoadRegUIStringW( hkeyClsid, L"HelpText", wszBuf, ARRAYSIZE(wszBuf) ); Str_SetPtrW( &_rgebi[dwClsidIndex].pwszHelp, wszBuf); RegCloseKey(hkeyClsid); dwClsidIndex++; } } } RegCloseKey( hkey ); } } CInternetToolbar::CInternetToolbar() : CBaseBar(), _yCapture(-1), _iButtons(-1) , _iEditIcon(-1), _cxEditGlyph(-1), _cyEditGlyph(-1) { DllAddRef(); if (GetSystemMetrics(SM_CXSCREEN) < 650) _uiMaxTBWidth = MAX_TB_WIDTH_LORES; else _uiMaxTBWidth = MAX_TB_WIDTH_HIRES; ASSERT(_fLoading == FALSE); ASSERT(_hwnd == NULL); ASSERT(_btb._guidCurrentButtonGroup == CLSID_NULL); _btb._nNextCommandID = 1000; DWORD dwResult = FALSE, dwType, dwcbData = sizeof(dwResult), dwDefault = TRUE; SHRegGetUSValue(c_szRegKeyCoolbar, TEXT("Locked"), &dwType, &dwResult, &dwcbData, FALSE, &dwDefault, sizeof(dwDefault)); SHSetValue(HKEY_CURRENT_USER, c_szRegKeyCoolbar, TEXT("Locked"), REG_DWORD, &dwResult, sizeof(dwResult)); _fLockedToolbar = dwResult; _LoadExternalBandInfo(); } void CInternetToolbar::_Unadvise(void) { if(_dwcpCookie) { ConnectToConnectionPoint(NULL, DIID_DWebBrowserEvents2, FALSE, _pdie, &_dwcpCookie, NULL); } } int CALLBACK DeleteDPAPtrCB(void *pItem, void *pData) { if ( pItem ) { ASSERT( ::LocalSize(pItem) == sizeof(FOLDERSEARCHITEM) ); LocalFree(pItem); pItem = NULL; } return TRUE; } CInternetToolbar::~CInternetToolbar() { ATOMICRELEASE(_pdie); if(_pbp && _fCreatedBandProxy) { _pbp->SetSite(NULL); } if (IsWindow(_hwnd)) { DestroyWindow(_hwnd); } ATOMICRELEASE(_pbp); ASSERT(!_ptbsite && !_ptbsitect && !_psp && !_pbs && !_pbs2); SetSite(NULL); if ( _hdpaFSI ) { DPA_DestroyCallback(_hdpaFSI, DeleteDPAPtrCB, NULL); _hdpaFSI = NULL; } for (int i = 0; i < ARRAYSIZE(_rgebi); i++) { Str_SetPtrW( &_rgebi[i].pwszName, NULL); Str_SetPtrW( &_rgebi[i].pwszHelp, NULL); } TraceMsg(TF_SHDLIFE, "dtor CInternetToolbar %x", this); DllRelease(); } #define IID_DWebBrowserEvents DIID_DWebBrowserEvents HRESULT CInternetToolbar::QueryInterface(REFIID riid, void ** ppvObj) { static const QITAB qit[] = { // perf: last tuned 980728 QITABENTMULTI(CInternetToolbar, IDispatch, DWebBrowserEvents), // IID_IDispatch QITABENT(CInternetToolbar, IExplorerToolbar), // IID_IDispatch QITABENT(CInternetToolbar, IObjectWithSite), // IID_IObjectWithSite QITABENT(CInternetToolbar, IPersistStreamInit), // IID_IPersistStreamInit QITABENT(CInternetToolbar, IDockingWindow), // IID_IDockingWindow QITABENT(CInternetToolbar, DWebBrowserEvents), // IID_DWebBrowserEvents QITABENT(CInternetToolbar, IShellChangeNotify), // rare IID_IShellChangeNotify QITABENT(CInternetToolbar, ISearchItems), // rare IID_ISearchItems { 0 }, }; HRESULT hres = QISearch(this, qit, riid, ppvObj); if (FAILED(hres)) hres = SUPERCLASS::QueryInterface(riid, ppvObj); return hres; } /* IDispatch methods */ HRESULT CInternetToolbar::GetTypeInfoCount(UINT *pctinfo) { return(E_NOTIMPL); } HRESULT CInternetToolbar::GetTypeInfo(UINT itinfo,LCID lcid,ITypeInfo **pptinfo) { return(E_NOTIMPL); } HRESULT CInternetToolbar::GetIDsOfNames(REFIID riid,OLECHAR **rgszNames,UINT cNames, LCID lcid, DISPID * rgdispid) { return(E_NOTIMPL); } #if 0 // NOTE - StevePro changed it so this code isnt called // this is a goodness, because it calls SHVerbExists() which // is a TCHAR API, that is actually compiled as an ANSI API // and since we are UNICODE it just always fails. // leaving this in so that we know about the issue of // frontpad.exe possibly needing to be disabled. BOOL _ShowEditForExtension(LPCTSTR pszExtension) { TCHAR szBuf[MAX_PATH]; if (SHVerbExists(pszExtension, TEXT("edit"), szBuf)) { // don't show it if it's just our own if (StrStrI(szBuf, TEXT("frontpad.exe"))) { return FALSE; } return TRUE; } return FALSE; } #endif //+------------------------------------------------------------------------- // This function scans the html document for META tags that indicate the // program that was used to create the HTML page. Examples are: // // // // // If a match is found, the content of the first match is returned. This // progid is used to edit the document. //-------------------------------------------------------------------------- BSTR CInternetToolbar::_GetEditProgID(IHTMLDocument2* pHTMLDocument) { BSTR bstrProgID = NULL; // // First get all document elements. Note that this is very fast in // ie5 because the collection directly accesses the internal tree. // IHTMLElementCollection * pAllCollection; if (SUCCEEDED(pHTMLDocument->get_all(&pAllCollection))) { IHTMLMetaElement* pMetaElement; IHTMLBodyElement* pBodyElement; IHTMLFrameSetElement* pFrameSetElement; IDispatch* pDispItem; // // Now we scan the document for meta tags. Since these must reside in // in the head, and since Trident always creates a body tag, we can // stop looking when we hit the body. // // Note, the alternative of using pAllCollection->tags to return the // collection of meta tags is likely more expensive because it will // walk the whole tree (unless Trident optimizes this). // long lItemCnt = 0; VARIANT vEmpty; V_VT(&vEmpty) = VT_EMPTY; VARIANT vIndex; V_VT(&vIndex) = VT_I4; pAllCollection->get_length(&lItemCnt); for (long lItem = 0; lItem < lItemCnt; lItem++) { V_I4(&vIndex) = lItem; if (S_OK == pAllCollection->item(vIndex, vEmpty, &pDispItem)) { // // First see if it's a meta tag // if (SUCCEEDED(pDispItem->QueryInterface(IID_PPV_ARG(IHTMLMetaElement, &pMetaElement)))) { BSTR bstrName = NULL; // // We have a META element, check its NAME and CONTENT // if ( SUCCEEDED(pMetaElement->get_name(&bstrName)) && (bstrName != NULL) && (StrCmpIW(bstrName, OLESTR("ProgId")) == 0) && SUCCEEDED(pMetaElement->get_content(&bstrProgID)) && (bstrProgID != NULL) ) { // We got the ProgID, so terminate the search; lItem = lItemCnt; } if (bstrName != NULL) SysFreeString(bstrName); pMetaElement->Release(); } // // Next check for the body tag // else if (SUCCEEDED(pDispItem->QueryInterface(IID_PPV_ARG(IHTMLBodyElement, &pBodyElement)))) { // Found the body tag, so terminate the search lItem = lItemCnt; pBodyElement->Release(); } // // Finally, check for a frameset tag // else if (SUCCEEDED(pDispItem->QueryInterface(IID_PPV_ARG(IHTMLFrameSetElement, &pFrameSetElement)))) { // Found a frameset tag, so terminate the search lItem = lItemCnt; pFrameSetElement->Release(); } pDispItem->Release(); } } // Make sure that these don't have to be cleared (should not have been modified) ASSERT(vEmpty.vt == VT_EMPTY); ASSERT(vIndex.vt == VT_I4); pAllCollection->Release(); } return bstrProgID; } //+------------------------------------------------------------------------- // Returns grey-scale image from the icon passed in. //-------------------------------------------------------------------------- HIMAGELIST CInternetToolbar::_CreateGrayScaleImagelist(HBITMAP hbmpImage, HBITMAP hbmpMask) { // Determine the button dimensions int cx = g_fSmallIcons ? TB_SMBMP_CX : g_iToolBarLargeIconWidth; int cy = g_fSmallIcons ? TB_SMBMP_CY : g_iToolBarLargeIconHeight; // Start with a 24 bit color image list HIMAGELIST himlEdit = ImageList_Create(cx, cy, ILC_COLOR24 | ILC_MASK, 1, 1); if (NULL == himlEdit) { return NULL; } ImageList_Add(himlEdit, hbmpImage, hbmpMask); // Get the dib section from the image list IMAGEINFO ii; if (ImageList_GetImageInfo(himlEdit, 0, &ii)) { DIBSECTION ds = {0}; if (GetObject(ii.hbmImage, sizeof(ds), &ds)) { // // Map each pixel to a monochrome equivalent. // BYTE* pBits = (BYTE*)ds.dsBm.bmBits; BYTE* pScan = pBits; int xWid = ds.dsBm.bmWidth; int yHei = ds.dsBm.bmHeight; long cbScan = ((xWid * 24 + 31) & ~31) / 8; for (int y=0; y < yHei; ++y) { for (int x=0; x < xWid; ++x) { // // Map to equivalent gray color by setting r,g,b to the same value. // Using the average of r,g,b can be too dark, and using the max // of r,g,b can be too bright. So, as a simple algorithm we use // the average of the two schemes. This is cheaper than using true // intensity matching. // BYTE nMax = max(max(pScan[0], pScan[1]), pScan[2]); BYTE nAve = ((UINT)pScan[0] + pScan[1] + pScan[2])/3; pScan[0] = pScan[1] = pScan[2] = ((UINT)nMax + nAve)/2; // Increment to next pixel pScan += 3; } // Increment to the next scan line pBits += cbScan; pScan = pBits; } } } return himlEdit; } //+------------------------------------------------------------------------- // Returns image and mask bitmaps for the desired image list item //-------------------------------------------------------------------------- BOOL MyImageList_GetBitmaps ( HIMAGELIST himl, // image list to use int iImage, // image to copy int x, // x-offset to draw in bitmap int y, // x-offset to draw in bitmap int cx, // width of bitmap int cy, // height of bitmap HBITMAP* phbmpImage, // returned color bitmap HBITMAP* phbmpMask // returned mask bitmap ) { ASSERT(phbmpImage); ASSERT(phbmpMask); BOOL fRet = FALSE; HDC hdc = GetDC(NULL); if (hdc) { HDC hdcDst = CreateCompatibleDC(hdc); if (hdcDst) { HBITMAP hbmpImage = CreateCompatibleBitmap(hdc, cx, cy); if (hbmpImage) { HBITMAP hbmpMask = CreateBitmap(cx, cy, 1, 1, NULL); if (hbmpMask) { // Draw mask bitmap HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDst, hbmpMask); PatBlt(hdcDst, 0, 0, cx, cy, WHITENESS); ImageList_Draw(himl, iImage, hdcDst, x, y, ILD_MASK); // Draw image bitmap SelectObject(hdcDst, hbmpImage); ImageList_Draw(himl, iImage, hdcDst, x, y, ILD_NORMAL); SelectObject(hdcDst, hbmpOld); *phbmpImage = hbmpImage; *phbmpMask = hbmpMask; fRet = TRUE; } else { DeleteObject(hbmpImage); } } DeleteDC(hdcDst); } ReleaseDC(NULL, hdc); } return fRet; } extern HBITMAP CreateMirroredBitmap( HBITMAP hbmOrig); //+------------------------------------------------------------------------- // Creates a special image list for the edit button and configures the edit // button to use it. If the hIcon is -1, the edit button is reset to use // it's default glyph. //-------------------------------------------------------------------------- void CInternetToolbar::_SetEditGlyph ( int iIcon // new edit button glyph, index into shell image cache ) { // If no toolbar, we just need to see if we need to free the old image lists. if (_btb._hwnd == NULL) { if (iIcon == -1) { if (_himlEdit) { ImageList_Destroy(_himlEdit); _himlEdit = NULL; } if (_himlEditHot) { ImageList_Destroy(_himlEditHot); _himlEditHot = NULL; } } else { // Can't set the glyph if no toolbar! ASSERT(FALSE); } return; } // Determine the button dimensions int cx = g_fSmallIcons ? TB_SMBMP_CX : g_iToolBarLargeIconWidth; int cy = g_fSmallIcons ? TB_SMBMP_CY : g_iToolBarLargeIconHeight; UINT uiCmd = -1; // Dochost merges under one of two clsids, so have to check both if (FAILED(_btb._ConvertCmd(&CLSID_InternetButtons, DVIDM_EDITPAGE, NULL, &uiCmd)) && FAILED(_btb._ConvertCmd(&CLSID_MSOButtons, DVIDM_EDITPAGE, NULL, &uiCmd))) { // The edit button is not on toolbar, so free the edit glyphs iIcon = -1; } // If the current icon is already set, we are done if ((_iEditIcon == iIcon) && (_cxEditGlyph == cx) && (_cyEditGlyph == cy)) { if (_himlEdit) { // Set up the new image lists SendMessage(_btb._hwnd, TB_SETIMAGELIST, IL_EDITBUTTON, (LPARAM)_himlEdit); if (_himlEditHot) { SendMessage(_btb._hwnd, TB_SETHOTIMAGELIST, IL_EDITBUTTON, (LPARAM)_himlEditHot); } // Redirect the edit button to the new image list TBBUTTONINFO tbi = {0}; tbi.cbSize = sizeof(tbi); tbi.dwMask = TBIF_IMAGE; tbi.iImage = MAKELONG(0, IL_EDITBUTTON); SendMessage(_btb._hwnd, TB_SETBUTTONINFO, uiCmd, (LPARAM)&tbi); } return; } _iEditIcon = iIcon; _cxEditGlyph = cx; _cyEditGlyph = cy; if (-1 == iIcon) { if (_himlEdit) { if (uiCmd != -1) { // Reset to the original edit glyph TBBUTTONINFO tbi = {0}; tbi.cbSize = sizeof(tbi); tbi.dwMask = TBIF_IMAGE; tbi.iImage = EDITGLYPH_OFFSET; SendMessage(_btb._hwnd, TB_SETBUTTONINFO, uiCmd, (LPARAM)&tbi); } // Destroy the custom edit glyphs. Note that we have to reset the primary image list // or the image sizes are messed up. SendMessage(_btb._hwnd, TB_SETIMAGELIST, IL_EDITBUTTON, (LPARAM)NULL); ImageList_Destroy(_himlEdit); _himlEdit = NULL; } if (_himlEditHot) { SendMessage(_btb._hwnd, TB_SETHOTIMAGELIST, IL_EDITBUTTON, (LPARAM)NULL); ImageList_Destroy(_himlEditHot); _himlEditHot = NULL; } } else { // Get the image bitmaps HBITMAP hbmpImage = NULL; HBITMAP hbmpMask = NULL; BOOL bMirrored = IS_WINDOW_RTL_MIRRORED(_btb._hwnd); HIMAGELIST himlSmall; int cxSmall; int cySmall; if (Shell_GetImageLists(NULL, &himlSmall) && ImageList_GetIconSize(himlSmall, &cxSmall, &cySmall) && MyImageList_GetBitmaps(himlSmall, iIcon, (cx - cxSmall)/2, (cy - cySmall)/2, cx, cy, &hbmpImage, &hbmpMask)) { if (bMirrored) { HBITMAP hbmpTemp; hbmpTemp = CreateMirroredBitmap(hbmpImage); if (hbmpTemp) { DeleteObject(hbmpImage); hbmpImage = hbmpTemp; } hbmpTemp = CreateMirroredBitmap(hbmpMask); if (hbmpTemp) { DeleteObject(hbmpMask); hbmpMask = hbmpTemp; } } // Create a monochrome glyph for the edit button HIMAGELIST himlEdit = _CreateGrayScaleImagelist(hbmpImage, hbmpMask); SendMessage(_btb._hwnd, TB_SETIMAGELIST, IL_EDITBUTTON, (LPARAM)himlEdit); if (_himlEdit) { ImageList_Destroy(_himlEdit); } _himlEdit = himlEdit; // Create a hot glyph for the edit button HIMAGELIST himlEditHot = ImageList_Create(cx, cy, ILC_COLORDDB | ILC_MASK, 1, 1); int nIndex = ImageList_Add(himlEditHot, hbmpImage, hbmpMask); SendMessage(_btb._hwnd, TB_SETHOTIMAGELIST, IL_EDITBUTTON, (LPARAM)himlEditHot); if (_himlEditHot) { ImageList_Destroy(_himlEditHot); } _himlEditHot = himlEditHot; // Redirect the edit button to the new image list if (_himlEdit) { TBBUTTONINFO tbi = {0}; tbi.cbSize = sizeof(tbi); tbi.dwMask = TBIF_IMAGE; tbi.iImage = MAKELONG(nIndex, IL_EDITBUTTON); SendMessage(_btb._hwnd, TB_SETBUTTONINFO, uiCmd, (LPARAM)&tbi); } DeleteObject(hbmpImage); DeleteObject(hbmpMask); } else { // Couldn't create images so use the default edit glyph _SetEditGlyph(-1); } } } //+------------------------------------------------------------------------- // Initializes the edit button to display a drop-down menu if there are // multiple verbs. Also optionally displays a custion glyph. //-------------------------------------------------------------------------- void CInternetToolbar::_InitEditButtonStyle() { // If we have or want a custon edit glyph, load it _SetEditGlyph(_aEditVerb.GetIcon()); UINT uiCmd; // Dochost merges under one of two clsids, so have to check both if (SUCCEEDED(_btb._ConvertCmd(&CLSID_InternetButtons, DVIDM_EDITPAGE, NULL, &uiCmd)) || SUCCEEDED(_btb._ConvertCmd(&CLSID_MSOButtons, DVIDM_EDITPAGE, NULL, &uiCmd))) { ASSERT(uiCmd != -1); // If multiple verbs, make the button a split button TBBUTTONINFO tbi = {0}; tbi.cbSize = sizeof(tbi); tbi.dwMask = TBIF_STYLE | TBIF_STATE; tbi.fsState = 0; if (_aEditVerb.GetSize() > 1) { tbi.fsStyle |= BTNS_DROPDOWN; } if (_aEditVerb.GetSize() > 0) { tbi.fsState = TBSTATE_ENABLED; } SendMessage(_btb._hwnd, TB_SETBUTTONINFO, uiCmd, (LPARAM)&tbi); } } //+------------------------------------------------------------------------- // If the edit button is displaying a custon glyph, this function reloads // the glyph. //-------------------------------------------------------------------------- void CInternetToolbar::_RefreshEditGlyph() { // If we have a custon edit glyph, reload it if (_himlEdit) { // Refresh the edit glyph _iEditIcon = -1; _InitEditButtonStyle(); } } //+------------------------------------------------------------------------- // Updates the edit button based on the document type currently loaded //-------------------------------------------------------------------------- void CInternetToolbar::_UpdateEditButton() { _aEditVerb.RemoveAll(); _fEditEnabled = FALSE; BOOL fNoEditSpecified = FALSE; // // First add editors associated with the url // BSTR bstrUrl = NULL; _pdie->get_LocationURL(&bstrUrl); if (bstrUrl) { LPTSTR pszExt; // // Find the cache file associated with the url. The file extension for this entry // is based off of the mime type. (Note that get_mimeType on the document // returns a frindly name that is hard to translate back to an actual mimetype. // So we use the file extension instead.) // WCHAR szCacheFileName[MAX_PATH]; *szCacheFileName = 0; if (FAILED(URLToCacheFile(bstrUrl, szCacheFileName, ARRAYSIZE(szCacheFileName)))) { // If we can't get a file associated with the url, probably want to disable the edit button // because most apps need a file to edit. SysFreeString(bstrUrl); return; } pszExt = PathFindExtension(szCacheFileName); // bug 79055 - The cache has a bug where some html entries are not // given a file extension. Too risky to fix for 5.x, so we'll just // assume .htm for http if no extension is present. if (L'\0' == *pszExt && GetUrlScheme(bstrUrl) == URL_SCHEME_HTTP) { StrCpyN(szCacheFileName, L".htm", ARRAYSIZE(szCacheFileName)); pszExt = szCacheFileName; } if (*pszExt) { _aEditVerb.Add(pszExt); // If ".html", use the ".htm" editors too if (StrCmpI(pszExt, L".html") == 0 ) { // This is an html document, so add the .htm editors if (!_aEditVerb.Add(TEXT(".htm")) && StrCmpI(pszExt, L".html") != 0) { _aEditVerb.Add(TEXT(".html")); } } } SysFreeString(bstrUrl); } // // See if the feature to search the doc for the progid is enabled // static int fCheckDocForProgID = -1; if (fCheckDocForProgID == -1) { fCheckDocForProgID = SHRegGetBoolUSValue(REGSTR_PATH_MAIN, TEXT("CheckDocumentForProgID"), FALSE, TRUE) ? 1 : 0; } // Check for a meta tag that specifies a progid for editing this document if (fCheckDocForProgID) { // // Next see if this is an html document with a progid // IWebBrowser2* pWB2 = NULL; IDispatch * pDispatch = NULL; IHTMLDocument2 * pHTMLDocument = NULL; // Get the html document currently loaded if (_psp && SUCCEEDED(_psp->QueryService(SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &pWB2))) && SUCCEEDED(pWB2->get_Document(&pDispatch)) && SUCCEEDED(pDispatch->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &pHTMLDocument)))) { // // Check the current document for a META tag specifying the program to use to // edit this file. // BSTR bstrProgID = _GetEditProgID(pHTMLDocument); if (bstrProgID) { if (lstrcmpi(bstrProgID, TEXT("NoEdit")) == 0) { fNoEditSpecified = TRUE; } else { // this edit verb progid comes directly from the html document so its not trusted. // however, the CEditVerb will validate that the progid in the registry has the "edit" // or "open" verb associated with it and thats all it will do, so its not like a blind // shellexecute or running a dispatch object or anything. // there are also no objects installed by default that will format a users hard drive // upon cocreate or anything. _aEditVerb.Add(bstrProgID); SysFreeString(bstrProgID); } } } SAFERELEASE(pWB2); SAFERELEASE(pDispatch); SAFERELEASE(pHTMLDocument); } if (!fNoEditSpecified) { _fEditEnabled = (_aEditVerb.GetSize() > 0); } // Update edit glyph, drop-down style, & enabled state _InitEditButtonStyle(); } HRESULT CInternetToolbar::Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,UINT * puArgErr) { if(!pdispparams) return E_INVALIDARG; switch(dispidMember) { case DISPID_NAVIGATECOMPLETE2: { // // Notify the brand and theater mode objects about whether we're in shell or // web mode. Wait til now to do it (rather than doing it in SetCommandTarget) // because they might want to ask the browser about the new pidl, which isn't // yet filled in at SetCommandTarget time. // DWORD nCmdexecopt = _fShellView ? CITE_SHELL : CITE_INTERNET; CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_BRAND); if (pbid) { IUnknown_Exec(pbid->pdb, &CGID_PrivCITCommands, CITIDM_ONINTERNET, nCmdexecopt, NULL, NULL); pbid->Release(); } if (_fTheater) { IUnknown_Exec(_ptbsite, &CGID_Theater, THID_ONINTERNET, nCmdexecopt, NULL, NULL); } // If notification is not from a frame, set the _fNavigateComplete flag for (DWORD i = 0; i < pdispparams->cArgs; i++) { if (pdispparams->rgvarg[i].vt == VT_DISPATCH) { // See who's sending us this event IBrowserService* pbs = NULL; HRESULT hr = IUnknown_QueryService(pdispparams->rgvarg[i].pdispVal, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &pbs)); if (pbs) { // We don't really need this interface, just its address pbs->Release(); } if (SUCCEEDED(hr) && pbs == _pbs) { // Notification did not come from a frame, _fNavigateComplete = TRUE; } } } } break; case DISPID_BEFORENAVIGATE: { BOOL fWeb = FALSE; ASSERT((pdispparams->rgvarg[5].vt == VT_BSTR) && (pdispparams->rgvarg[5].bstrVal != NULL)); PARSEDURL pu = { 0 }; pu.cbSize = sizeof(pu); ParseURL(pdispparams->rgvarg[5].bstrVal, &pu); if ((URL_SCHEME_UNKNOWN != pu.nScheme) && (URL_SCHEME_FILE != pu.nScheme)) fWeb = TRUE; UINT uiState = 0; GetState(&CLSID_CommonButtons, TBIDM_STOPDOWNLOAD, &uiState); if ((uiState & TBSTATE_HIDDEN) && fWeb) { _fTransitionToHTML = TRUE; uiState &= ~TBSTATE_HIDDEN; SetState(&CLSID_CommonButtons, TBIDM_STOPDOWNLOAD, uiState); } // Default to the edit button hidden _fEditEnabled = FALSE; } break; case DISPID_DOWNLOADBEGIN:// This is when we just started to navigate? No bits? _StartDownload(); break; case DISPID_DOWNLOADCOMPLETE: // we be done _fTransitionToHTML = FALSE; _StopDownload(FALSE); break; case DISPID_DOCUMENTCOMPLETE: // This is where we have all the bits { // // Sometimes we get a premature document complete (for framesets). We can catch this // by checking to see if we have received a DISPID_NAVIGATECOMPLETE2 event // for the top window. We have to update the edit button here instead of in // navigate complete because otherwise the document is not in the interactive // state and our metatag search sees the previous document. // // REARCHITECT: Is it possible that this event came from a frame and the document is not // interactive yet? Trident posts an interactive event right before calling us so // we're probably ok. We don't want to wait for the document complete for the top window // in framesets because it can take too long. Really need to sink DISPID_READYSTATECHANGE // and wait for the document to go interactive. // if (_fNavigateComplete) { _fNavigateComplete = FALSE; _UpdateEditButton(); } break; } case DISPID_COMMANDSTATECHANGE: BOOL fEnable; if(!pdispparams || (pdispparams->cArgs != 2) || (pdispparams->rgvarg[0].vt != VT_BOOL) || (pdispparams->rgvarg[1].vt != VT_I4)) return E_INVALIDARG; fEnable = (BOOL) pdispparams->rgvarg[0].boolVal; UINT uiCmd; switch (pdispparams->rgvarg[1].lVal) { case CSC_UPDATECOMMANDS: // corresponds to OLECMDID_UPDATECOMMANDS from Exec() _UpdateToolbar(FALSE); break; case CSC_NAVIGATEBACK: _fBackEnabled = fEnable; _btb._ConvertCmd(&CLSID_CommonButtons, TBIDM_BACK, NULL, &uiCmd); SendMessage(_btb._hwnd, TB_ENABLEBUTTON, uiCmd, MAKELONG(fEnable, 0)); break; case CSC_NAVIGATEFORWARD: _fForwardEnabled = fEnable; _btb._ConvertCmd(&CLSID_CommonButtons, TBIDM_FORWARD, NULL, &uiCmd); SendMessage(_btb._hwnd, TB_ENABLEBUTTON, uiCmd, MAKELONG(fEnable, 0)); break; default: return(E_INVALIDARG); } // FEATURE need to handle the case of navigation failure and // do some cleanup } return S_OK; } // *** IInputObjectSite methods *** HRESULT CInternetToolbar::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus) { return IUnknown_OnFocusChangeIS(_ptbsite, SAFECAST(this, IInputObject*), fSetFocus); } //*** CInternetToolbar::IInputObject::* { HRESULT CInternetToolbar::TranslateAcceleratorIO(LPMSG lpMsg) { if (_fShow) { if (lpMsg->message == WM_KEYDOWN) { switch (lpMsg->wParam) { case VK_F4: Laddrband: if (_nVisibleBands & VBF_ADDRESS) { CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_ADDRESS); if (pbid) { HRESULT hrT = IUnknown_TranslateAcceleratorIO(pbid->pdb, lpMsg); ASSERT(hrT == S_OK); pbid->Release(); } } return S_OK; // (even if we just eat it) } } else if(lpMsg->message == WM_SYSCHAR) { static CHAR szAccel[2] = "\0"; CHAR szChar [2] = "\0"; if ('\0' == szAccel[0]) MLLoadStringA(IDS_ADDRBAND_ACCELLERATOR, szAccel, ARRAYSIZE(szAccel)); szChar[0] = (CHAR)lpMsg->wParam; if (lstrcmpiA(szChar,szAccel) == 0) { goto Laddrband; } } return _bs.TranslateAcceleratorIO(lpMsg); } return S_FALSE; } // } HRESULT CInternetToolbar::SetSite(IUnknown* punkSite) { ATOMICRELEASE(_ptbsite); ATOMICRELEASE(_ptbsitect); ATOMICRELEASE(_pbs); ATOMICRELEASE(_pbs2); ATOMICRELEASE(_psp); _Unadvise(); ATOMICRELEASE(_pdie); ASSERT(_ptbsite==NULL); ASSERT(_ptbsitect==NULL); ASSERT(_pbs==NULL); ASSERT(_pbs2==NULL); ASSERT(_pdie==NULL); if (_pbp && _fCreatedBandProxy) _pbp->SetSite(punkSite); if (punkSite) { punkSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &_ptbsite)); punkSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_ptbsitect)); punkSite->QueryInterface(IID_PPV_ARG(IBrowserService2, &_pbs2)); punkSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &_psp)); if (_psp) { _psp->QueryService(SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &_pdie)); _psp->QueryService(SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &_pbs)); ASSERT(_pdie); } else { ASSERT(0); } } else { SetClient(NULL); } return S_OK; } //*** // void CInternetToolbar::_UpdateGroup(const GUID *pguidCmdGroup, int cnt, OLECMD rgcmds[], const GUID* pguidButton, const int buttonsInternal[]) { if (!IsEqualGUID(*pguidButton, CLSID_CommonButtons) && !IsEqualGUID(*pguidButton, _btb._guidCurrentButtonGroup)) return; // we don't have any buttons at this time, so no use checking if (_ptbsitect) { _ptbsitect->QueryStatus(pguidCmdGroup, cnt, rgcmds, NULL); // make sure stop is enabled while we are animating if (_fAnimating && pguidCmdGroup == NULL && rgcmds[0].cmdID == OLECMDID_STOP) { rgcmds[0].cmdf = OLECMDF_ENABLED; } } for (int i = 0; i < cnt; i++) { // do nothing if command is not available or not in our table if (rgcmds[i].cmdf & OLECMDF_SUPPORTED) { UINT idBut; if (SUCCEEDED(_btb._ConvertCmd(pguidButton, buttonsInternal[i], NULL, (UINT*)&idBut))) { SendMessage(_btb._hwnd, TB_ENABLEBUTTON, idBut, (rgcmds[i].cmdf & OLECMDF_ENABLED) ? TRUE : FALSE); SendMessage(_btb._hwnd, TB_CHECKBUTTON, idBut, (rgcmds[i].cmdf & OLECMDF_LATCHED) ? TRUE : FALSE); } } } return; } void CInternetToolbar::_UpdateToolbar(BOOL fForce) { if (fForce || SHIsChildOrSelf(GetForegroundWindow(), _hwnd) == S_OK) { if (!_fUpdateToolbarTimer) { SetTimer(_hwnd, IDT_UPDATETOOLBAR, TIMEOUT_UPDATETOOLBAR, NULL); _fUpdateToolbarTimer = TRUE; _UpdateToolbarNow(); } else { _fNeedUpdateToolbar = TRUE; } } } BOOL CInternetToolbar::_UpEnabled() { OLECMD rgcmd = { FCIDM_PREVIOUSFOLDER, 0 }; _ptbsitect->QueryStatus(&CGID_ShellBrowser, 1, &rgcmd, NULL); return (rgcmd.cmdf & OLECMDF_ENABLED); } void CInternetToolbar::_UpdateCommonButton(int iCmd, UINT nCmdID) { switch (nCmdID) { case TBIDM_THEATER: SendMessage(_btb._hwnd, TB_CHECKBUTTON, iCmd, _fTheater); break; case TBIDM_PREVIOUSFOLDER: case TBIDM_BACK: case TBIDM_FORWARD: { BOOL fEnabled; switch (nCmdID) { case TBIDM_PREVIOUSFOLDER: fEnabled = _UpEnabled(); break; case TBIDM_BACK: fEnabled = _fBackEnabled; break; case TBIDM_FORWARD: fEnabled = _fForwardEnabled; break; } SendMessage(_btb._hwnd, TB_ENABLEBUTTON, iCmd, MAKELONG(fEnabled, 0)); } break; } } void CInternetToolbar::_UpdateToolbarNow() { _fNeedUpdateToolbar = FALSE; { // MUST not be static (due to ConvertCmd overwrite) OLECMD rgcmds[] = { { OLECMDID_STOP, 0 }, // NOTE: must be first { OLECMDID_REFRESH, 0 }, }; static const int buttonsInternal[] = { // MUST be in same order as above array TBIDM_STOPDOWNLOAD, TBIDM_REFRESH, }; _UpdateGroup(NULL, ARRAYSIZE(buttonsInternal), rgcmds, &CLSID_CommonButtons, buttonsInternal); } { OLECMD rgcmds[] = { { SBCMDID_SEARCHBAR, 0 }, { SBCMDID_FAVORITESBAR, 0 }, { SBCMDID_HISTORYBAR, 0 }, { SBCMDID_EXPLORERBAR, 0 }, { SBCMDID_MEDIABAR, 0 }, }; static const int buttonsInternal[] = { // MUST be in same order as above array TBIDM_SEARCH, TBIDM_FAVORITES, TBIDM_HISTORY, TBIDM_ALLFOLDERS, TBIDM_MEDIABAR, }; _UpdateGroup(&CGID_Explorer, ARRAYSIZE(buttonsInternal), rgcmds, &CLSID_CommonButtons, buttonsInternal); } int nButtons = (int) SendMessage(_btb._hwnd, TB_BUTTONCOUNT, 0, 0L); for (int nIndex = 0; nIndex < nButtons; nIndex++) { CMDMAP* pcm = _btb._GetCmdMapByIndex(nIndex); if (pcm) { int iCmd = _btb._CommandFromIndex(nIndex); if (IsEqualGUID(pcm->guidButtonGroup, CLSID_CommonButtons)) { _UpdateCommonButton(iCmd, pcm->nCmdID); } else { // NOTE (andrewgu): ie5.5 b#106047 - the two conditions below used to be ASSERTs, // the second one was faulting under stress. if either one of these checks fails, // the button is stale. if (IsEqualGUID(pcm->guidButtonGroup, _btb._guidCurrentButtonGroup) && NULL != _btb._pctCurrentButtonGroup) { OLECMD ocButton; ocButton.cmdID = pcm->nCmdID; ocButton.cmdf = 0; if (SUCCEEDED(_btb._pctCurrentButtonGroup->QueryStatus(&pcm->guidButtonGroup, 1, &ocButton, NULL))) { SendMessage(_btb._hwnd, TB_ENABLEBUTTON, iCmd, (ocButton.cmdf & OLECMDF_ENABLED) ? TRUE : FALSE); SendMessage(_btb._hwnd, TB_CHECKBUTTON, iCmd, (ocButton.cmdf & OLECMDF_LATCHED) ? TRUE : FALSE); } } } } } if (_btb._hwnd) { _btb._BandInfoChanged(); } } void CInternetToolbar::_StartDownload() { UINT uiCmd; if (SUCCEEDED(_btb._ConvertCmd(&CLSID_CommonButtons, TBIDM_STOPDOWNLOAD, NULL, &uiCmd))) { SendMessage(_btb._hwnd, TB_ENABLEBUTTON, uiCmd, MAKELONG(TRUE, 0)); _fAnimating = TRUE; } } // // Parameters: // fClosing -- TRUE only if we are calling this from CloseDW member. // In that case, we can skip all UI-update code. // void CInternetToolbar::_StopDownload(BOOL fClosing) { _fAnimating = FALSE; } HRESULT CInternetToolbar::CloseDW(DWORD dwReserved) { _fDestroyed = TRUE; // Stop using the member variables, they are invalid. _StopDownload(TRUE); ASSERT(!_btb._pcinfo); ATOMICRELEASE(_btb._pctCurrentButtonGroup); _btb._FreeBtnsAdded(); if (_btb._hwnd) { _btb._RemoveAllButtons(); SendMessage(_btb._hwnd, TB_SETIMAGELIST, 0, NULL); SendMessage(_btb._hwnd, TB_SETHOTIMAGELIST, 0, NULL); DSA_Destroy(_hdsaTBBMPs); _hdsaTBBMPs = NULL; // So we don't try to re-destroy in _InitBitmapDSA() } _SetEditGlyph(-1); _bs._Close(); SUPERCLASS::CloseDW(dwReserved); _btb._hwnd = NULL; // We advise during ShowDW, so unadvise here. Also, we hit a stress // case where it seems that an event came in after closedw but before // one of the other _Unadvise calls. This event percolated down to // a reference to _hdsaCT which we freed above, causing a GPF. // _Unadvise(); return S_OK; } void CInternetToolbar::CITBandSite::v_SetTabstop(LPREBARBANDINFO prbbi) { // Don't set tabstops for all bands in the browser case. A band // can still make itself a tabstop by setting WS_TABSTOP. return; } BOOL CInternetToolbar::CITBandSite::_SetMinDimensions() { INT_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0); int icBands = (int) SendMessage( _hwnd, RB_GETBANDCOUNT, 0, 0 ); for (int i = 0; i < icBands; i++) { REBARBANDINFO rbbi; rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_ID | RBBIM_CHILDSIZE; if (SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { rbbi.cxMinChild = 0; rbbi.cyMinChild = 0; CBandItemData *pbid = _GetBandItemDataStructByID(rbbi.wID); if (pbid) { if (IS_VALID_HANDLE(pbid->hwnd, WND)) { rbbi.cxMinChild = pbid->ptMinSize.x; rbbi.cyMinChild = pbid->ptMinSize.y; } pbid->Release(); } SendMessage(_hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi); } } SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0); return TRUE; } BOOL HimlCacheDirty(IMLCACHE* pimlCache, BOOL fSmallIcons) { if (fSmallIcons != pimlCache->fSmallIcons) return TRUE; COLORREF cr3D = GetSysColor(COLOR_3DFACE); if (cr3D != pimlCache->cr3D) return TRUE; if (SHUseClassicToolbarGlyphs() != pimlCache->fUseClassicGlyphs) return TRUE; for (int i = 0; i < CIMLISTS; i++) if (!pimlCache->arhiml[i]) return TRUE; return FALSE; } #define SZ_REGKEY_SMALLICONS REGSTR_PATH_EXPLORER TEXT("\\SmallIcons") #define SZ_REGVALUE_SMALLICONS TEXT("SmallIcons") BOOL _DefaultToSmallIcons() { // We default to small icons if: // // This is NT 5, or the policy says to use small icons, or this is any // of the Whistler servers (server, adv server, dtc) return ((GetUIVersion() == 5) || SHRestricted2(REST_SMALLICONS, NULL, 0) || (IsOS(OS_WHISTLERORGREATER) && IsOS(OS_ANYSERVER))); } BOOL _UseSmallIcons() { BOOL fDefaultToSmall = _DefaultToSmallIcons(); return SHRegGetBoolUSValue(SZ_REGKEY_SMALLICONS, SZ_REGVALUE_SMALLICONS, FALSE, fDefaultToSmall); } BOOL _UseMapNetDrvBtns() { #define SZ_REGKEY_ADVFOLDER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced") #define SZ_REGVALUE_MAPNETDRV TEXT("MapNetDrvBtn") DWORD dwData = 0; if (GetUIVersion() >= 4) { DWORD cbData = sizeof(dwData); DWORD dwDefault = 0; DWORD cbDefault = sizeof(dwDefault); SHRegGetUSValue(SZ_REGKEY_ADVFOLDER, SZ_REGVALUE_MAPNETDRV, NULL, &dwData, &cbData, FALSE, &dwDefault, cbDefault); } return dwData; } HIMAGELIST _LoadThemedToolbarGlyphs(int idBmpType, int iTemperature, int cx, COLORREF crMask, UINT uFlags, BOOL bUseClassicGlyphs, HINSTANCE hInst); void _LoadToolbarGlyphs(HWND hwnd, IMLCACHE *pimlCache, int cx, int idBmpType, int iBitmapBaseIndex, BOOL bUseClassicGlyphs, HINSTANCE hInst) { // set uMsg and uFlags for first iteration of loop (default state) UINT uMsg = TB_SETIMAGELIST; UINT uFlags = LR_CREATEDIBSECTION; int i; HBITMAP hBMP; BOOL fSmallIcons = g_fSmallIcons; if (HimlCacheDirty(pimlCache, fSmallIcons)) { COLORREF cr3D = GetSysColor(COLOR_3DFACE); COLORREF crMask = RGB( 255, 0, 255 ); #ifdef UNIX if (SHGetCurColorRes() < 2 ) { crMask = CLR_NONE; } #endif ENTERCRITICAL; if (!HimlCacheDirty(pimlCache, fSmallIcons) ) goto DontReload; for (i = 0; i < CIMLISTS; i++) { if ((!pimlCache->arhiml[i]) || (cr3D != pimlCache->cr3D) || (fSmallIcons != pimlCache->fSmallIcons) || (bUseClassicGlyphs != pimlCache->fUseClassicGlyphs)) { TraceMsg(DM_ITBAR, "_LoadToolbarGlyphs: Loading New Images"); if (pimlCache->arhimlPendingDelete[i]) ImageList_Destroy(pimlCache->arhimlPendingDelete[i]); pimlCache->arhimlPendingDelete[i] = pimlCache->arhiml[i]; pimlCache->arhiml[i] = _LoadThemedToolbarGlyphs(idBmpType, i, cx, crMask, uFlags, bUseClassicGlyphs, hInst); if (pimlCache->arhiml[i]) { // add shell glyphs int idShellBmp = iBitmapBaseIndex + idBmpType; hBMP = (HBITMAP) LoadImage (hInst, MAKEINTRESOURCE(idShellBmp + i), IMAGE_BITMAP, 0, 0, uFlags); ImageList_AddMasked(pimlCache->arhiml[i], (HBITMAP)hBMP, crMask); DeleteObject(hBMP); } } } pimlCache->cr3D = cr3D; pimlCache->fSmallIcons = fSmallIcons; pimlCache->fUseClassicGlyphs = bUseClassicGlyphs; DontReload: LEAVECRITICAL; } if (hwnd) { ASSERT(IS_VALID_HANDLE(hwnd, WND)); for (i = 0; i < CIMLISTS; i++) { SendMessage(hwnd, uMsg, 0, (LPARAM) pimlCache->arhiml[i]); // set uMsg and uFlags for last iteration of loop (hot state) uMsg = TB_SETHOTIMAGELIST; uFlags = 0; } } } #ifdef THEME_BUTTONS BOOL _GetThemeSetting(HKEY hkey, PDWORD pdwSetting) { ASSERT(pdwSetting); BOOL fRet = FALSE; DWORD dwType, dwcbData = sizeof(*pdwSetting); *pdwSetting = 0; if (ERROR_SUCCESS==SHGetValue(hkey, c_szRegKeyCoolbar, TEXT("UseTheme"), &dwType, pdwSetting, &dwcbData)) { // We going to assume that the data type and size is correct. This way, we can break // into an error state. fRet = TRUE; // Acceptable values: // 0: use IE6 icons // 1: use IE5.5 icons // 2: use themed icons // other values are reserved. if (*pdwSetting > 2) { *pdwSetting = 0; } } return fRet; } HIMAGELIST _LoadThemedToolbarGlyphs(int idBmpType, int iTemperature, int cx, COLORREF crMask, UINT uFlags, BOOL bUseClassicGlyphs, HINSTANCE hInst) { HIMAGELIST himl = NULL; // Restriction goes here. HKEY hkey = HKEY_CURRENT_USER; DWORD dwSetting = 0; if (!_GetThemeSetting(hkey, &dwSetting)) { hkey = HKEY_LOCAL_MACHINE; _GetThemeSetting(hkey, &dwSetting); } DWORD dwType, dwcbData; if (dwSetting==2) { TCHAR szPath[MAX_PATH]; TCHAR szItem[] = TEXT("ITBx"); szItem[3] = TEXT('0') + idBmpType + iTemperature; dwcbData = sizeof(szPath); if ((ERROR_SUCCESS==SHGetValue(hkey, c_szRegKeyCoolbar, szItem, &dwType, szPath, &dwcbData)) && (dwType==REG_SZ)) { int nBmpIndex = PathParseIconLocation(szPath); WCHAR szExpPath[MAX_PATH]; SHExpandEnvironmentStrings(szPath, szExpPath, ARRAYSIZE(szExpPath)); // If no resource id, assume it's a bmp file if (nBmpIndex==0) { himl = CreateImageList(NULL, szExpPath, cx, 0, crMask, IMAGE_BITMAP, uFlags | LR_LOADFROMFILE, !bUseClassicGlyphs); } // Otherwise, see if it's a resouce if (!himl) { HINSTANCE hInst = LoadLibraryEx(szExpPath, NULL, LOAD_LIBRARY_AS_DATAFILE); if (hInst) { himl = CreateImageList(hInst, MAKEINTRESOURCE(nBmpIndex), cx, 0, crMask, IMAGE_BITMAP, uFlags, !bUseClassicGlyphs); FreeLibrary(hInst); } } if (himl) { // You just can't trust anyone these days. If the graphics aren't the expected // size, or there aren't the expected number, we're going to use the defaults // ISSUE: 16 is a magic number. Do we have a constant anywhere? I can't find it. int ecx, ecy; if (!(ImageList_GetIconSize(himl, &ecx, &ecy) && (ecx==ecy) && (ecy==cx) && (ImageList_GetImageCount(himl)==16))) { ImageList_Destroy(himl); himl = NULL; } } } } if (!himl) { // dwSetting must be 1 to get IE6 icons. If dwSetting isn't set to 1, then default // either to the new Whistler icons or the default IE icons (as appropriate) int iResource; if (dwSetting == 1) { iResource = IDB_IE6_TOOLBAR; } else { if (bUseClassicGlyphs) { iResource = IDB_IETOOLBAR; } else { iResource = IDB_TB_IE_BASE; } } iResource += (idBmpType + iTemperature); himl = CreateImageList(hInst, MAKEINTRESOURCE(iResource), cx, 0, crMask, IMAGE_BITMAP, uFlags, !bUseClassicGlyphs); } return himl; } #else HIMAGELIST _LoadThemedToolbarGlyphs(int idBmpType, int iTemperature, int cx, COLORREF crMask, UINT uFlags, BOOL bUseClassicGlyphs, HINSTANCE hInst) { HIMAGELIST himl = NULL; int iResource; if (bUseClassicGlyphs) { iResource = IDB_IETOOLBAR; } else { iResource = IDB_TB_IE_BASE; } iResource += (idBmpType + iTemperature); himl = CreateImageList(hInst, MAKEINTRESOURCE(iResource), cx, 0, crMask, IMAGE_BITMAP, uFlags, !bUseClassicGlyphs); return himl; } #endif void CInternetToolbar::_InitBitmapDSA() { DSA_Destroy(_hdsaTBBMPs); _hdsaTBBMPs = DSA_Create(sizeof(TBBMP_LIST), TBBMPLIST_CHUNK); if (_hdsaTBBMPs) { TBBMP_LIST tbl = { HINST_COMMCTRL, 0, 0, TRUE, TRUE, FALSE }; tbl.uiResID = IDB_STD_SMALL_COLOR; tbl.uiOffset = OFFSET_STD; DSA_AppendItem(_hdsaTBBMPs, &tbl); tbl.uiResID = IDB_STD_LARGE_COLOR; DSA_AppendItem(_hdsaTBBMPs, &tbl); tbl.uiResID = IDB_VIEW_SMALL_COLOR; tbl.uiOffset = OFFSET_VIEW; DSA_AppendItem(_hdsaTBBMPs, &tbl); tbl.uiResID = IDB_VIEW_LARGE_COLOR; DSA_AppendItem(_hdsaTBBMPs, &tbl); tbl.uiResID = IDB_HIST_SMALL_COLOR; tbl.uiOffset = OFFSET_HIST; DSA_AppendItem(_hdsaTBBMPs, &tbl); tbl.uiResID = IDB_HIST_LARGE_COLOR; DSA_AppendItem(_hdsaTBBMPs, &tbl); } } void CInternetToolbar::_ReloadBitmapDSA() { if (_hdsaTBBMPs) { TBBMP_LIST * pTBBs = NULL; int nCount = DSA_GetItemCount(_hdsaTBBMPs); // We want to skip the first 6 entries in the DSA, which are added by InitBitmapDSA for (int nIndex = 6; nIndex < nCount; nIndex++) { pTBBs = (TBBMP_LIST*)DSA_GetItemPtr(_hdsaTBBMPs, nIndex); if (pTBBs) { HIMAGELIST himl = NULL; if (pTBBs->fNormal) { himl = (HIMAGELIST)SendMessage(_btb._hwnd, TB_GETIMAGELIST, 0, 0L); if (himl && (pTBBs->uiOffset==ImageList_GetImageCount(himl))) { LRESULT lOffset = _AddBitmapFromForeignModule(TB_GETIMAGELIST, TB_SETIMAGELIST, pTBBs->uiCount, pTBBs->hInst, pTBBs->uiResID, RGB(192,192,192)); ASSERT(pTBBs->uiOffset==lOffset); } } if (pTBBs->fHot) { himl = (HIMAGELIST)SendMessage(_btb._hwnd, TB_GETHOTIMAGELIST, 0, 0L); if (himl && (pTBBs->uiOffset==ImageList_GetImageCount(himl))) { LRESULT lOffset = _AddBitmapFromForeignModule(TB_GETHOTIMAGELIST, TB_SETHOTIMAGELIST, pTBBs->uiCount, pTBBs->hInst, pTBBs->uiResID, RGB(192,192,192)); ASSERT(pTBBs->uiOffset==lOffset); } } if (pTBBs->fDisabled) { himl = (HIMAGELIST)SendMessage(_btb._hwnd, TB_GETDISABLEDIMAGELIST, 0, 0L); if (himl && (pTBBs->uiOffset==ImageList_GetImageCount(himl))) { LRESULT lOffset = _AddBitmapFromForeignModule(TB_GETDISABLEDIMAGELIST, TB_SETDISABLEDIMAGELIST, pTBBs->uiCount, pTBBs->hInst, pTBBs->uiResID, RGB(192,192,192)); ASSERT(pTBBs->uiOffset==lOffset); } } } } } } void CInternetToolbar::_InitForScreenSize() { TCHAR szScratch[16]; if (GetSystemMetrics(SM_CXSCREEN) < 650) { MLLoadString(IDS_TB_WIDTH_EXTRA_LORES, szScratch, ARRAYSIZE(szScratch)); _uiMaxTBWidth = MAX_TB_WIDTH_LORES; } else { MLLoadString(IDS_TB_WIDTH_EXTRA_HIRES, szScratch, ARRAYSIZE(szScratch)); _uiMaxTBWidth = MAX_TB_WIDTH_HIRES; } _uiMaxTBWidth += StrToInt(szScratch) * WIDTH_FACTOR; } // removes all buttons marked hidden. returns the number // of buttons left int RemoveHiddenButtons(TBBUTTON* ptbn, int iCount) { int i; int iTotal = 0; TBBUTTON* ptbn1 = ptbn; for (i = 0; i < iCount; i++, ptbn1++) { if (!(ptbn1->fsState & TBSTATE_HIDDEN)) { if (ptbn1 != ptbn) { *ptbn = *ptbn1; } ptbn++; iTotal++; } } return iTotal; } #ifdef DEBUG void _AssertRestrictionOrderIsCorrect() { COMPILETIME_ASSERT(ARRAYSIZE(c_tbExplorer) == ARRAYSIZE(c_rest)); for (UINT i = 0; i < ARRAYSIZE(c_tbExplorer); i++) { // If any of these rip, it means that c_rest and c_tbExplorer have // gotten out of sync. Need to fix up c_rest to match c_tbExplorer. switch (c_tbExplorer[i].idCommand) { case TBIDM_BACK: ASSERT(c_rest[i] == REST_BTN_BACK); break; case TBIDM_FORWARD: ASSERT(c_rest[i] == REST_BTN_FORWARD); break; case TBIDM_STOPDOWNLOAD: ASSERT(c_rest[i] == REST_BTN_STOPDOWNLOAD); break; case TBIDM_REFRESH: ASSERT(c_rest[i] == REST_BTN_REFRESH); break; case TBIDM_HOME: ASSERT(c_rest[i] == REST_BTN_HOME); break; case TBIDM_SEARCH: ASSERT(c_rest[i] == REST_BTN_SEARCH); break; case TBIDM_HISTORY: ASSERT(c_rest[i] == REST_BTN_HISTORY); break; case TBIDM_FAVORITES: ASSERT(c_rest[i] == REST_BTN_FAVORITES); break; case TBIDM_ALLFOLDERS: ASSERT(c_rest[i] == REST_BTN_ALLFOLDERS); break; case TBIDM_THEATER: ASSERT(c_rest[i] == REST_BTN_THEATER); break; case TBIDM_MEDIABAR: ASSERT(c_rest[i] == REST_BTN_MEDIABAR); break; default: ASSERT(c_rest[i] == REST_BROWSER_NONE); break; } } } #endif __inline BOOL CInternetToolbar::_FoldersButtonAvailable() { return (GetUIVersion() >= 4); } void CInternetToolbar::_AdminMarkDefaultButtons(PTBBUTTON ptbb, UINT cButtons) { // We only have policies for web buttons. ASSERT(!_fShellView); // Caller should have checked this. ASSERT(SHRestricted2(REST_SPECIFYDEFAULTBUTTONS, NULL, 0)); // SHRestricted2 returns 0 if it can't find the policy. Assert that // this lines up with RESTOPT_BTN_STATE_DEFAULT. COMPILETIME_ASSERT(RESTOPT_BTN_STATE_DEFAULT == 0); for (UINT i = 0; i < cButtons; i++) { if (c_rest[i] != 0) { DWORD dwRest = SHRestricted2(c_rest[i], NULL, 0); ptbb[i].fsState = SHBtnStateFromRestriction(dwRest, ptbb[i].fsState); } } // Folders button is not available on non-integrated platforms, so // set state to hidden even if policy specifies that it should be shown. ASSERT(c_tbExplorer[TBXID_ALLFOLDERS].idCommand == TBIDM_ALLFOLDERS); if (!_FoldersButtonAvailable()) ptbb[TBXID_ALLFOLDERS].fsState |= TBSTATE_HIDDEN; } void CInternetToolbar::_MarkDefaultButtons(PTBBUTTON ptbb, UINT cButtons) { if (SHRestricted(REST_NONLEGACYSHELLMODE)) { ASSERT(ptbb[TBXID_BACK].idCommand == TBIDM_BACK); ptbb[TBXID_BACK].fsState |= TBSTATE_HIDDEN; ASSERT(ptbb[TBXID_FORWARD].idCommand == TBIDM_FORWARD); ptbb[TBXID_FORWARD].fsState |= TBSTATE_HIDDEN; } if (_fShellView) { ASSERT(c_tbExplorer[TBXID_STOPDOWNLOAD].idCommand == TBIDM_STOPDOWNLOAD); ptbb[TBXID_STOPDOWNLOAD].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_REFRESH].idCommand == TBIDM_REFRESH); ptbb[TBXID_REFRESH].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_HOME].idCommand == TBIDM_HOME); ptbb[TBXID_HOME].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_SEARCH].idCommand == TBIDM_SEARCH); ASSERT(c_tbExplorer[TBXID_HISTORY].idCommand == TBIDM_HISTORY); ASSERT(c_tbExplorer[TBXID_SEPARATOR2].idCommand == 0); // (a separator) if (GetUIVersion() < 5) { ptbb[TBXID_SEARCH].fsState |= TBSTATE_HIDDEN; ptbb[TBXID_HISTORY].fsState |= TBSTATE_HIDDEN; ptbb[TBXID_SEPARATOR2].fsState |= TBSTATE_HIDDEN; } else { if (GetUIVersion() > 5) { ptbb[TBXID_HISTORY].fsState |= TBSTATE_HIDDEN; } if (SHRestricted(REST_NOSHELLSEARCHBUTTON)) { ptbb[TBXID_SEARCH].fsState |= TBSTATE_HIDDEN; } ASSERT(c_tbExplorer[TBXID_CONNECT].idCommand == TBIDM_CONNECT); ASSERT(c_tbExplorer[TBXID_DISCONNECT].idCommand == TBIDM_DISCONNECT); if (SHRestricted(REST_NONETCONNECTDISCONNECT)) { ptbb[TBXID_CONNECT].fsState |= TBSTATE_HIDDEN; ptbb[TBXID_DISCONNECT].fsState |= TBSTATE_HIDDEN; } } ASSERT(c_tbExplorer[TBXID_FAVORITES].idCommand == TBIDM_FAVORITES); ptbb[TBXID_FAVORITES].fsState |= TBSTATE_HIDDEN; } ASSERT(c_tbExplorer[TBXID_PREVIOUSFOLDER].idCommand == TBIDM_PREVIOUSFOLDER); if (!_fShellView) ptbb[TBXID_PREVIOUSFOLDER].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_CONNECT].idCommand == TBIDM_CONNECT); ASSERT(c_tbExplorer[TBXID_DISCONNECT].idCommand == TBIDM_DISCONNECT); if (!_fShellView || !_UseMapNetDrvBtns()) { ptbb[TBXID_CONNECT].fsState |= TBSTATE_HIDDEN; ptbb[TBXID_DISCONNECT].fsState |= TBSTATE_HIDDEN; } // If this TBIDM_ALLFOLDERS assertion rips, remember to fix up _AdminMarkDefaultButtons too. ASSERT(c_tbExplorer[TBXID_ALLFOLDERS].idCommand == TBIDM_ALLFOLDERS); if (!_fShellView || GetUIVersion() < 5) ptbb[TBXID_ALLFOLDERS].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_THEATER].idCommand == TBIDM_THEATER); ptbb[TBXID_THEATER].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_MEDIABAR].idCommand == TBIDM_MEDIABAR); if (_fShellView || SHRestricted2W(REST_No_LaunchMediaBar, NULL, 0) || !CMediaBarUtil::IsWMP7OrGreaterCapable()) { ptbb[TBXID_MEDIABAR].fsState |= TBSTATE_HIDDEN; } ASSERT(c_tbExplorer[TBXID_PREVIOUSFOLDER].idCommand == TBIDM_PREVIOUSFOLDER); if (!_fShellView) { ptbb[TBXID_PREVIOUSFOLDER].fsState |= TBSTATE_HIDDEN; } } void CInternetToolbar::_AddCommonButtons() { TBBUTTON tbExplorer[ARRAYSIZE(c_tbExplorer)]; memcpy(tbExplorer, c_tbExplorer, sizeof(TBBUTTON) * ARRAYSIZE(c_tbExplorer)); if (IS_BIDI_LOCALIZED_SYSTEM()) { if (!SHUseClassicToolbarGlyphs()) { tbExplorer[0].iBitmap = 1; tbExplorer[1].iBitmap = 0; } } _MarkDefaultButtons(tbExplorer, ARRAYSIZE(c_tbExplorer)); #ifdef DEBUG _AssertRestrictionOrderIsCorrect(); #endif if (!_fShellView && SHRestricted2(REST_SPECIFYDEFAULTBUTTONS, NULL, 0)) _AdminMarkDefaultButtons(tbExplorer, ARRAYSIZE(c_tbExplorer)); int iButtons = RemoveHiddenButtons(tbExplorer, ARRAYSIZE(tbExplorer)); for (int i = 0; i < iButtons; i++) { if (!(tbExplorer[i].fsStyle & BTNS_SEP)) { CMDMAP* pcm = (CMDMAP*)LocalAlloc(LPTR, sizeof(CMDMAP)); if (pcm) { pcm->guidButtonGroup = CLSID_CommonButtons; pcm->nCmdID = tbExplorer[i].idCommand; tbExplorer[i].idCommand = _btb._nNextCommandID++; tbExplorer[i].dwData = (LPARAM)pcm; } } } SendMessage(_btb._hwnd, TB_ADDBUTTONS, iButtons, (LPARAM) tbExplorer); _btb._RecalcButtonWidths(); } #define IS_LIST_STYLE(hwnd) (BOOLIFY(GetWindowLong(hwnd, GWL_STYLE) & TBSTYLE_LIST)) void CInternetToolbar::_UpdateToolsStyle(BOOL fList) { if (BOOLIFY(fList) != IS_LIST_STYLE(_btb._hwnd)) { _fDirty = TRUE; // toggle TBSTYLE_LIST SHSetWindowBits(_btb._hwnd, GWL_STYLE, TBSTYLE_LIST, fList ? TBSTYLE_LIST : 0); // toggle TBSTYLE_EX_MIXEDBUTTONS SendMessage(_btb._hwnd, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_MIXEDBUTTONS, fList ? TBSTYLE_EX_MIXEDBUTTONS : 0); } } void CInternetToolbar::_InitToolbar() { int nRows = _fCompressed ? 0 : _uiTBTextRows; DWORD dwStyle = TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS; if (IsOS(OS_WHISTLERORGREATER)) dwStyle |= TBSTYLE_EX_DOUBLEBUFFER; // this tells the toolbar what version we are SendMessage(_btb._hwnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); SendMessage(_btb._hwnd, TB_SETEXTENDEDSTYLE, dwStyle, dwStyle); SendMessage(_btb._hwnd, TB_SETMAXTEXTROWS, nRows, 0L); SendMessage(_btb._hwnd, TB_SETDROPDOWNGAP, GetSystemMetrics(SM_CXEDGE) / 2, 0); SendMessage(_btb._hwnd, CCM_SETVERSION, COMCTL32_VERSION, 0); _UpdateToolsStyle(_cs.fList); _fDirty = FALSE; // _UpdateToolsStyle unfortunately sets this early on; but we can assume we're not dirty now. ITBar_LoadToolbarGlyphs(_btb._hwnd); _InitBitmapDSA(); _InitForScreenSize(); SendMessage(_btb._hwnd, TB_ADDSTRING, (WPARAM)MLGetHinst(), IDS_IE_TB_LABELS); _AddCommonButtons(); INT_PTR nRet = SendMessage(_btb._hwnd, TB_ADDSTRING, (WPARAM)MLGetHinst(), IDS_SHELL_TB_LABELS); #ifdef DEBUG if (nRet != SHELLTOOLBAR_OFFSET) TraceMsg(TF_ERROR, "CInternetToolbar::_InitToolbar -- nRet != SHELLTOOLBAR_OFFSET"); #endif } HRESULT CInternetToolbar::_ShowTools(PBANDSAVE pbs) { HRESULT hr = S_OK; CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_TOOLS); if (!pbid) { ASSERT(!_btb._hwnd); _btb._hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL, WS_CHILD | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE, 0, 0, 0, 0, _bs._hwnd, (HMENU) FCIDM_TOOLBAR, HINST_THISDLL, NULL); if (_btb._hwnd) { _InitToolbar(); pbid = _AddNewBand((IDeskBand*)&_btb, CBIDX_TOOLS); } if (!pbid) return E_OUTOFMEMORY; } else { pbs = NULL; } _ShowBandCommon(pbs, pbid, _nVisibleBands & VBF_TOOLS); pbid->Release(); return hr; } void CInternetToolbar::_ShowBandCommon(PBANDSAVE pbs, CBandItemData *pbid, BOOL fShow) { REBARBANDINFO rbbi; pbid->fShow = BOOLIFY(fShow); if (pbid->pdb) { pbid->pdb->ShowDW(pbid->fShow); } INT_PTR i = BandIDtoIndex(_bs._hwnd, pbid->dwBandID); if (pbs) { rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_SIZE | RBBIM_STYLE; // we just want to change the RBBS_BREAK bit // assert that our caller doesn't expect to set any other bits // ASSERT(!(pbs->fStyle & ~RBBS_BREAK)); <--- I hit this assert all the time // get old style SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi); rbbi.fStyle = (rbbi.fStyle & ~RBBS_BREAK) | (pbs->fStyle & RBBS_BREAK); rbbi.cx = pbs->cx; SendMessage(_bs._hwnd, RB_SETBANDINFO, i, (LPARAM)&rbbi); } if ( pbid->dwModeFlags & DBIMF_BREAK ) { rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_STYLE; if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { // in theater mode we don't allow bands to have breaks if ((rbbi.fStyle & RBBS_BREAK ) && _fTheater) { rbbi.fStyle &= ~RBBS_BREAK; SendMessage(_bs._hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi); } } } SendMessage(_bs._hwnd, RB_SHOWBAND, i, pbid->fShow); } HRESULT CInternetToolbar::_GetPersistedBand(const CLSID clsid, REFIID riid, void ** ppiface) { HRESULT hr = E_FAIL; TCHAR szStreamName[MAX_PATH]; if (SUCCEEDED(_GetStreamName(_fInitialPidlIsWeb, szStreamName, ARRAYSIZE(szStreamName)))) { static BOOL fBrowserOnly = (WhichPlatform() != PLATFORM_INTEGRATED); TCHAR szKey[MAX_PATH]; TCHAR szGUID[MAX_PATH]; wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("Software\\Microsoft\\Internet Explorer\\Toolbar\\%s"), szStreamName); SHStringFromGUID(clsid, szGUID, ARRAYSIZE(szGUID)); if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, szKey, szGUID, NULL, NULL, NULL)) { // Was the stream saved by an Integrated shell and we are in browser only mode? if ((_cs.fSaveInShellIntegrationMode) && fBrowserOnly) { // Yes, so we need to ignore the stream. } else { IStream * pstm = GetRegStream(_fInitialPidlIsWeb, szGUID, STGM_READ); if (pstm) { hr = _bs.LoadFromStreamBS(pstm, riid, ppiface); pstm->Release(); } } } } if (FAILED(hr)) { hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppiface); if (SUCCEEDED(hr)) { IPersistStreamInit * ppsi; ((IUnknown *) *ppiface)->QueryInterface(IID_PPV_ARG(IPersistStreamInit, &ppsi)); if (ppsi) { ppsi->InitNew(); ppsi->Release(); } } } return hr; } HRESULT CInternetToolbar::_ShowExternalBand( PBANDSAVE pbs, int idBand ) { HRESULT hr; if (IS_EXTERNALBAND(idBand)) { int idBandExt = MAP_TO_EXTERNAL(idBand); if (!IsEqualCLSID(_rgebi[idBandExt].clsid, GUID_NULL)) { CBandItemData *pbid = _bs._GetBandItemDataStructByID( idBand ); BOOL fIsVisible = _nVisibleBands & EXTERNALBAND_VBF_BIT(idBandExt); if (!pbid && fIsVisible) { IDeskBand *pitbBand; hr = _GetPersistedBand(_rgebi[idBandExt].clsid, IID_PPV_ARG(IDeskBand, &pitbBand)); if (SUCCEEDED(hr)) { pbid = _AddNewBand( pitbBand, idBand ); pitbBand->Release(); } if (!pbid) return E_OUTOFMEMORY; } else { pbs = NULL; if (!pbid) return S_OK; } _ShowBandCommon(pbs, pbid, fIsVisible); pbid->Release(); } } return S_OK; } HRESULT CInternetToolbar::_ShowAddressBand(PBANDSAVE pbs) { HRESULT hr = S_OK; CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_ADDRESS); if (!pbid) { if (_nVisibleBands & VBF_ADDRESS) { IDeskBand *pitbAddressBand; hr = _GetPersistedBand(CLSID_AddressBand, IID_PPV_ARG(IDeskBand, &pitbAddressBand)); if (SUCCEEDED(hr)) { pbid = _AddNewBand(pitbAddressBand, CBIDX_ADDRESS); if (pbid) { _hwndAddressBand = pbid->hwnd; if (!pbs) { for (int i = 0; i < CBANDSMAX; i++) { if (_cs.bs[i].wID == CBIDX_ADDRESS) { pbs = _cs.bs + i; break; } } } } pitbAddressBand->Release(); } } else { return S_OK; } if (!pbid) return E_OUTOFMEMORY; } else pbs = NULL; _ShowBandCommon(pbs, pbid, _nVisibleBands & VBF_ADDRESS); pbid->Release(); return S_OK; } CBandItemData * CInternetToolbar::_AddNewBand(IDeskBand* pdb, DWORD dwID) { if (SUCCEEDED(_bs._AddBandByID(pdb, dwID))) { return _bs._GetBandItemDataStructByID(dwID); } return NULL; } HRESULT CInternetToolbar::_ShowLinks(PBANDSAVE pbs) { HRESULT hr = S_OK; CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_LINKS); if (!pbid) { IDeskBand* pdbLinks = NULL; // Check if custom link band GUID is present in the registry, // and if so, do a full CoCreateInstance using this GUID. // Otherwise, just do the normal internal call to the link's band factory. if (_nVisibleBands & VBF_LINKS) { if (!_fInitialPidlIsWeb || FAILED(CreateFromRegKey(c_szRegKeyCoolbar, TEXT("QuickLinksCLSID"), IID_PPV_ARG(IDeskBand, &pdbLinks)))) { hr = _GetPersistedBand(CLSID_QuickLinks, IID_PPV_ARG(IDeskBand, &pdbLinks)); IUnknown_Exec(pdbLinks, &CLSID_QuickLinks, QLCMD_SINGLELINE, 1, NULL, NULL); } } else { return S_OK; } if (pdbLinks) { // mark it so ISFBand knows it's qlinks (for UAssist) VARIANTARG v; #ifdef DEBUG { // n.b. we overwrite old persisted guys (which should be -1) IUnknown_Exec(pdbLinks, &CGID_ISFBand, ISFBID_PRIVATEID, 0, NULL, &v); ASSERT(v.lVal == -1 || v.lVal == CSIDL_FAVORITES); } #endif v.vt = VT_I4; v.lVal = CSIDL_FAVORITES; // close enough for our purposes... IUnknown_Exec(pdbLinks, &CGID_ISFBand, ISFBID_PRIVATEID, 0, &v, NULL); pbid = _AddNewBand(pdbLinks, CBIDX_LINKS); if (pbid && !pbs) { for (int i = 0; i < CBANDSMAX; i++) { if (_cs.bs[i].wID == CBIDX_LINKS) { pbs = _cs.bs + i; break; } } } pdbLinks->Release(); } if (!pbid) return E_OUTOFMEMORY; } else pbs = NULL; _ShowBandCommon(pbs, pbid, _nVisibleBands & VBF_LINKS); pbid->Release(); return hr; } HRESULT CInternetToolbar::_ShowMenu(PBANDSAVE pbs) { CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_MENU); if (!pbid) { CFavoritesCallback* pfcb = new CFavoritesCallback(); if (pfcb) { IShellMenu* psm; if (SUCCEEDED(CoCreateInstance(CLSID_MenuBand, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellMenu, &psm)))) { VARIANTARG var; if (SUCCEEDED(IUnknown_Exec(_pbs2, &CGID_Explorer, SBCMDID_GETCURRENTMENU, 0, NULL, &var)) && var.vt == VT_INT_PTR && var.byref) { IDeskBand* pdbMenu; if (SUCCEEDED(psm->Initialize(pfcb, -1, ANCESTORDEFAULT, SMINIT_HORIZONTAL | SMINIT_TOPLEVEL)) && SUCCEEDED(psm->SetMenu((HMENU)var.byref, GetParent(_hwnd), SMSET_DONTOWN)) && SUCCEEDED(psm->QueryInterface(IID_PPV_ARG(IDeskBand, &pdbMenu)))) { pbid = _AddNewBand(pdbMenu, CBIDX_MENU); if (pbid) { // Tell the menuband we're not a real bar/bandsite/band IUnknown_Exec(pbid->pdb, &CGID_MenuBand, MBANDCID_NOTAREALSITE, TRUE, NULL, NULL); _bs.SetBandState(CBIDX_MENU, BSSF_NOTITLE, BSSF_NOTITLE); _hwndMenu = pbid->hwnd; } pdbMenu->Release(); } } psm->Release(); } pfcb->Release(); } if (!pbid) return E_OUTOFMEMORY; } else pbs = NULL; _ShowBandCommon(pbs, pbid, _nVisibleBands & VBF_MENU); pbid->Release(); return S_OK; } HBITMAP CInternetToolbar::_LoadBackBitmap() { if (SHIsLowMemoryMachine(ILMM_IE4)) return NULL; if (_fInitialPidlIsWeb) { static LPTSTR s_pszBitmapInternet = NULL; return LoadToolbarBackBmp(&s_pszBitmapInternet, &s_bmpBackInternet, _fInitialPidlIsWeb); } else { static LPTSTR s_pszBitmapShell = NULL; return LoadToolbarBackBmp(&s_pszBitmapShell, &s_bmpBackShell, _fInitialPidlIsWeb); } } void CInternetToolbar::_SetBackground() { REBARBANDINFO rbbi; HBITMAP hbmp; // Theater mode doesn't allow bitmap customization, so don't bother loading one from the cache if (_fTheater) hbmp = NULL; else hbmp = _LoadBackBitmap(); // don't bother updating the bkcolor if we know we'll just set it to CLR_NONE below (otherwise rebar invalidates) if (!hbmp) SendMessage(_bs._hwnd, RB_SETBKCOLOR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); // If we think we have a bitmap, or the cache thinks we have a bitmap, we have some work to do if (_bmpBack || hbmp) { BOOL fRemove = (NULL!=_bmpBack && NULL==hbmp); if (hbmp) SendMessage(_bs._hwnd, RB_SETBKCOLOR, 0, (LPARAM)CLR_NONE); _bmpBack = hbmp; rbbi.cbSize = sizeof(REBARBANDINFO); INT_PTR fRedraw = SendMessage(_bs._hwnd, WM_SETREDRAW, FALSE, 0); INT icBands = (INT) SendMessage( _bs._hwnd, RB_GETBANDCOUNT, 0, 0 ); for (int i = 0; i < icBands; i++) { rbbi.fMask = RBBIM_ID | RBBIM_CHILD | RBBIM_BACKGROUND; if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { if (rbbi.wID != CBIDX_BRAND && rbbi.hbmBack != hbmp) { rbbi.fMask = RBBIM_BACKGROUND; rbbi.hbmBack = hbmp; SendMessage(_bs._hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi); InvalidateRect(rbbi.hwndChild, NULL, TRUE); } } } SendMessage(_bs._hwnd, WM_SETREDRAW, fRedraw, 0); // When removing the background bitmap, we need to invalidate *outside* // of the WM_SETREDRAW so we actually erase the background properly // if (fRemove) InvalidateRect(_bs._hwnd, NULL, TRUE); } } HRESULT CInternetToolbar::_ShowBrand(PBANDSAVE pbs) { HRESULT hr = S_OK; BOOL fCreated = FALSE; CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_BRAND); if (!pbid) { IDeskBand *pdbBrandBand; hr = CBrandBand_CreateInstance(NULL, (IUnknown **)&pdbBrandBand, NULL); if (SUCCEEDED(hr)) { pbid = _AddNewBand(pdbBrandBand, CBIDX_BRAND); fCreated = TRUE; pdbBrandBand->Release(); } else return hr; } if (!pbid) return E_OUTOFMEMORY; pbid->pdb->ShowDW(TRUE); pbid->Release(); INT_PTR i = BandIDtoIndex(_bs._hwnd, CBIDX_BRAND); if (fCreated) { REBARBANDINFO rbbi; // add these to ::IDeskBand::GetBandInfo() rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_STYLE; rbbi.fStyle = RBBS_FIXEDSIZE | RBBS_VARIABLEHEIGHT; if (pbs) { rbbi.fMask |= RBBIM_SIZE; rbbi.fStyle |= pbs->fStyle; rbbi.cx = pbs->cx; } SendMessage(_bs._hwnd, RB_SETBANDINFO, i, (LPARAM)&rbbi); // this can cause the band to move because a fixed size band // is forced in a particular location. // so we need to re-fetch the index i = BandIDtoIndex(_bs._hwnd, CBIDX_BRAND); } SendMessage(_bs._hwnd, RB_SHOWBAND, i, _nVisibleBands & VBF_BRAND); return S_OK; } void CInternetToolbar::_EnsureAllBandsShown() { if (_hwnd) { INT_PTR fRedraw = SendMessage(_bs._hwnd, WM_SETREDRAW, FALSE, 0); _ShowMenu(NULL); _ShowTools(NULL); _ShowAddressBand(NULL); _ShowLinks(NULL); _ShowBrand(NULL); for (int i = CBIDX_EXTERNALFIRST; i <= CBIDX_EXTERNALLAST; i++) { _ShowExternalBand( NULL, i ); } _SetBackground(); _bs._SetMinDimensions(); _UpdateLocking(); SendMessage(_bs._hwnd, WM_SETREDRAW, fRedraw, 0); } } BOOL CInternetToolbar::_ShowBands(UINT fVisible) { fVisible &= VBF_VALID; if (fVisible == _nVisibleBands) return(TRUE); _nVisibleBands = fVisible; _EnsureAllBandsShown(); ShowDW(_fShow); return(TRUE); } HRESULT CInternetToolbar::_CreateBands() { HRESULT hr = S_OK; if (!_hwnd && _ptbsite) { HWND hwndParent; hr = _ptbsite->GetWindow(&hwndParent); if (SUCCEEDED(hr)) { TCHAR szScratch[16]; int i; // Check if coolbar layout had already been loaded from the registry if(_cs.cbVer != CBS_VERSION) { TraceMsg(DM_ITBAR, "CInternetToolbar::_CreateBands failed. Bad Version"); ASSERT(0); return(S_FALSE); } _nVisibleBands = _cs.uiVisible; _InitComCtl32(); // don't check result, if this fails our CreateWindows will fail MLLoadString(IDS_WEB_TB_TEXTROWS, szScratch, ARRAYSIZE(szScratch)); _uiTBTextRows = _uiTBDefaultTextRows = StrToInt(szScratch); _fCompressed = (_cs.fNoText != FALSE); _hwnd = SHCreateWorkerWindow(SizableWndProc, hwndParent, 0, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, (HMENU)FCIDM_REBAR, this); if (!IS_VALID_HANDLE(_hwnd, WND)) { _fDontSave = TRUE; TraceMsg(TF_ERROR, "CInternetToolbar::_CreateBands() - _hwnd failed"); return E_OUTOFMEMORY; } // delay until now // this sets up the parent child chain so that these children can // queryservice through us hr = SetClient(SAFECAST(&_bs, IInputObjectSite*)); if (SUCCEEDED(hr)) { INT_PTR fRedraw = SendMessage(_bs._hwnd, WM_SETREDRAW, FALSE, 0); for (i = 0; i < CBANDSMAX; i++) { hr = S_OK; switch (_cs.bs[i].wID) { case CBIDX_TOOLS: if(!SHRestricted2W(REST_NoToolBar, NULL, 0)) { hr = _ShowTools(_cs.bs + i); } else { _nVisibleBands &= ~VBF_TOOLS; } break; case CBIDX_ADDRESS: if(!SHRestricted2W(REST_NoAddressBar, NULL, 0)) { hr = _ShowAddressBand(_cs.bs + i); } else { _nVisibleBands &= ~VBF_ADDRESS; } break; case CBIDX_LINKS: if(!SHRestricted2W(REST_NoLinksBar, NULL, 0)) { hr = _ShowLinks(_cs.bs + i); } else { _nVisibleBands &= ~VBF_LINKS; } break; case CBIDX_BRAND: hr = _ShowBrand(_cs.bs + i); break; case CBIDX_MENU: hr = _ShowMenu(_cs.bs + i); break; // If there is no id associated, there's nothing more to restore. case 0: { // Out of bands; stop loop. i = CBANDSMAX; break; } default: if (IS_EXTERNALBAND(_cs.bs[i].wID)) { for (DWORD j = 0; j < MAXEXTERNALBANDS; j++) { if (_cs.aclsidExternalBands[MAP_TO_EXTERNAL(_cs.bs[i].wID)] == _rgebi[j].clsid) { CLSID clsidTemp = _rgebi[j].clsid; _rgebi[j].clsid = _rgebi[MAP_TO_EXTERNAL(_cs.bs[i].wID)].clsid; _rgebi[MAP_TO_EXTERNAL(_cs.bs[i].wID)].clsid = clsidTemp; hr = _ShowExternalBand(_cs.bs + i, _cs.bs[i].wID); break; } } } break; } if (hr != S_OK) { TraceMsg(TF_ERROR, "CInternetToolbar::_CreateBands -- band ID %x creation failed", _cs.bs[i].wID); // if band creation failed, we still go ahead and open the browser and do our normal stuff -- // including persisting the band state. // unfortunately for the user who opens too many windows, they hit GDI limits and we can't // create the bands and we fail, and then persist out that state. so all future windows // are broken without the file menu etc. and the user cant get out. _fDontSave = TRUE; } } _SetBackground(); _bs._SetMinDimensions(); _UpdateLocking(); SendMessage(_bs._hwnd, WM_SETREDRAW, fRedraw, 0); } } } return hr; } HRESULT CInternetToolbar::ShowDW(BOOL fShow) { if ((g_dwProfileCAP & 0x00000008) && s_imlTBGlyphs.arhiml[0]) { StartCAP(); } HRESULT hres = _CreateBands(); if (FAILED(hres)) return hres; if (!_nVisibleBands && fShow) return(FALSE); _fShow = fShow; _bs.UIActivateDBC(fShow ? DBC_SHOW : DBC_HIDE); ResizeBorderDW(NULL, NULL, FALSE); ShowWindow(_hwnd, fShow ? SW_SHOW : SW_HIDE); BOOL fConnect = (fShow && _dwcpCookie == 0); if (fConnect || (!fShow && _dwcpCookie != 0)) { ConnectToConnectionPoint(SAFECAST(this, IDockingWindow*), DIID_DWebBrowserEvents2, fConnect, _pdie, &_dwcpCookie, NULL); } return hres; } int ITBar_TrackPopupMenuEx(HMENU hmenu, UINT uFlags, int x, int y, HWND hwnd, LPRECT prcExclude) { TPMPARAMS tpm; if (prcExclude) { tpm.cbSize = sizeof(TPMPARAMS); CopyRect(&tpm.rcExclude, prcExclude); } return TrackPopupMenuEx(hmenu, uFlags, x, y, hwnd, prcExclude ? &tpm : NULL); } /******************************************************************* NAME: CInternetToolbar::_ShowBackForwardMenu SYNOPSIS: NOTES: ********************************************************************/ BOOL CInternetToolbar::_ShowBackForwardMenu(BOOL fForward, POINT pt, LPRECT prcExclude) { BOOL fRet = FALSE; HMENU hmenuBF = CreatePopupMenu(); if (hmenuBF) { ASSERT(_pbs2); ITravelLog *ptl; _pbs2->GetTravelLog(&ptl); if (NULL != ptl) { HRESULT hr; hr = ptl->InsertMenuEntries(_pbs2, hmenuBF, 0, 1, MAX_NAV_MENUITEMS, fForward ? TLMENUF_FORE : TLMENUF_BACK); if (S_OK == hr) { OLECMD cmd; cmd.cmdID = SBCMDID_HISTORYBAR; cmd.cmdf = 0; ASSERT(NULL != _ptbsitect); _ptbsitect->QueryStatus(&CGID_Explorer, 1, &cmd, NULL); if (((cmd.cmdf & OLECMDF_ENABLED) && !(cmd.cmdf & OLECMDF_LATCHED)) && (1 /* MAX_NAV_MENUITEMS */ < ptl->CountEntries(_pbs2))) { static TCHAR s_szMenuText[MAX_PATH]; static int s_iMenuIcon = -1; if (TEXT('\0') == s_szMenuText[0]) { MLLoadString(IDS_MI_BACK_HISTORY, s_szMenuText, ARRAYSIZE(s_szMenuText)); ASSERT(TEXT('\0') != s_szMenuText[0]); } if (-1 == s_iMenuIcon) { IShellFolder *psfParent; LPITEMIDLIST pidlHistory; LPCITEMIDLIST pidlItem; psfParent = NULL; pidlHistory = NULL; pidlItem = NULL; SHGetSpecialFolderLocation(NULL, CSIDL_HISTORY, &pidlHistory); if (NULL != pidlHistory) { SHBindToIDListParent(pidlHistory, IID_PPV_ARG(IShellFolder, &psfParent), &pidlItem); if (NULL != psfParent) { ASSERT(NULL != pidlItem); hr = SHMapPIDLToSystemImageListIndex(psfParent, pidlItem, &s_iMenuIcon); if (FAILED(hr)) s_iMenuIcon = -1; psfParent->Release(); } ILFree(pidlHistory); } } ULONG_PTR rgpData[2]; rgpData[0] = (ULONG_PTR)s_szMenuText; rgpData[1] = s_iMenuIcon; AppendMenu(hmenuBF, MF_SEPARATOR, -1, NULL); AppendMenu(hmenuBF, MF_OWNERDRAW, FCIDM_VBBHISTORYBAND, (PCTSTR)rgpData); } // If any menu items were added, show the menu and navigate to it #ifndef MAINWIN int nIndex; if (nIndex = ITBar_TrackPopupMenuEx (hmenuBF, TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, _hwnd, prcExclude)) #else // Because mainwin doesn't support win95 look and feel we are // having a problem to keep the popup from dismissing when we // pass NULL as noDismissal area. RECT rect; GetWindowRect( _hwnd, &rect ); if (nIndex = (int)TrackPopupMenu (hmenuBF, TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, _hwnd, &rect)) #endif { if (FCIDM_VBBHISTORYBAND != nIndex) { ptl->Travel(_pbs2, (fForward ? nIndex : -nIndex)); } else { VARIANTARG varOn; varOn.vt = VT_I4; varOn.lVal = 1; _ptbsitect->Exec(&CGID_Explorer, SBCMDID_HISTORYBAR, OLECMDEXECOPT_DONTPROMPTUSER, &varOn, NULL); } } } ptl->Release(); } DestroyMenu (hmenuBF); } return fRet; } // get per folder search items and default search BOOL CInternetToolbar::_GetFolderSearchData() { int iInserted=0; if (_pbs2) { LPCBASEBROWSERDATA pbbd; if (SUCCEEDED(_pbs2->GetBaseBrowserData(&pbbd)) && (pbbd->_psfPending || pbbd->_psf)) { IShellFolder2 * psf2; IShellFolder* psf = pbbd->_psfPending ? pbbd->_psfPending : pbbd->_psf; if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2)))) { LPENUMEXTRASEARCH penum; GUID guid; if (SUCCEEDED(psf2->GetDefaultSearchGUID(&guid))) _guidDefaultSearch = guid; // get per folder search items if (_hdpaFSI && SUCCEEDED(psf2->EnumSearches(&penum))) { EXTRASEARCH xs; while(penum->Next(1, &xs, NULL) == S_OK) { LPFOLDERSEARCHITEM pfsi = (LPFOLDERSEARCHITEM)LocalAlloc(LPTR, sizeof(FOLDERSEARCHITEM)); if (pfsi) { pfsi->idCmd = -1; pfsi->guidSearch = xs.guidSearch; StrCpyNW(pfsi->wszUrl, xs.wszUrl, ARRAYSIZE(pfsi->wszUrl)); StrCpyNW(pfsi->wszName, xs.wszFriendlyName, ARRAYSIZE(pfsi->wszName)); if (DPA_InsertPtr(_hdpaFSI, iInserted, pfsi) != -1) iInserted++; else LocalFree(pfsi); } } penum->Release(); } psf2->Release(); } } } return (iInserted > 0); } void RestrictItbarViewMenu(HMENU hmenu, IUnknown *punkBar ) { BOOL fIsRestricted = SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0); if (fIsRestricted) { _EnableMenuItem(hmenu, FCIDM_VIEWLINKS, FALSE); _EnableMenuItem(hmenu, FCIDM_VIEWMENU, FALSE); _EnableMenuItem(hmenu, FCIDM_VIEWADDRESS, FALSE); _EnableMenuItem(hmenu, FCIDM_VIEWTOOLS, FALSE); } for (int i = 0; i < MAXEXTERNALBANDS; i++) { OLECMD cmd = { CITIDM_VIEWEXTERNALBAND_FIRST + i, 0 }; OLECMDTEXTV cmdtv; OLECMDTEXT *pcmdText = &cmdtv; pcmdText->cmdtextf = OLECMDTEXTF_NAME; pcmdText->cwActual = 0; pcmdText->cwBuf = MAX_EXTERNAL_BAND_NAME_LEN; IUnknown_QueryStatus( punkBar, &CGID_PrivCITCommands, 1, &cmd, pcmdText ); if (cmd.cmdf & OLECMDF_SUPPORTED) { DWORD dwMenuCommand = FCIDM_EXTERNALBANDS_FIRST + i; InsertMenu( hmenu, FCIDM_VIEWCONTEXTMENUSEP, MF_BYCOMMAND, dwMenuCommand, pcmdText->rgwz ); if (cmd.cmdf & OLECMDF_ENABLED) { _CheckMenuItem( hmenu, dwMenuCommand, TRUE ); } if (fIsRestricted) { _EnableMenuItem( hmenu, dwMenuCommand, FALSE ); } } } } void CInternetToolbar::_ShowContextMenu(HWND hwnd, LPARAM lParam, LPRECT prcExclude) { // Bail if this context menu doesn't correspond to a band (fixes NT5 #181899) POINT pt; int iIndex = _bs._ContextMenuHittest(lParam, &pt); int idBandActive = _bs._IndexToBandID(iIndex); if (!InRange(idBandActive, CBIDX_FIRST, CBANDSMAX)) return; // Bail if we can't find the resource HMENU hmenuITB = LoadMenuPopup(MENU_ITOOLBAR); if (!hmenuITB) return; UEMFireEvent(&UEMIID_SHELL, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_UICONTEXT, idBandActive == -1 ? UIBL_CTXTITBBKGND : UIBL_CTXTITBITEM); // Set the initial state of the menu _CheckMenuItem (hmenuITB, FCIDM_VIEWTOOLS, _nVisibleBands & VBF_TOOLS); _CheckMenuItem (hmenuITB, FCIDM_VIEWADDRESS, _nVisibleBands & VBF_ADDRESS); _CheckMenuItem (hmenuITB, FCIDM_VIEWLINKS, _nVisibleBands & VBF_LINKS); int cItemsBelowSep = 4; // only in theater mode can we autohide if (!_fTheater) { DeleteMenu(hmenuITB, FCIDM_VIEWAUTOHIDE, MF_BYCOMMAND); cItemsBelowSep--; if (_nVisibleBands & VBF_MENU || _fNoShowMenu) DeleteMenu(hmenuITB, FCIDM_VIEWMENU, MF_BYCOMMAND); } else { if (_fNoShowMenu) DeleteMenu(hmenuITB, FCIDM_VIEWMENU, MF_BYCOMMAND); DeleteMenu(hmenuITB, FCIDM_VIEWTOOLS, MF_BYCOMMAND); _CheckMenuItem (hmenuITB, FCIDM_VIEWAUTOHIDE, _fAutoHide); _CheckMenuItem (hmenuITB, FCIDM_VIEWMENU, _nVisibleBands & VBF_MENU); } if (_fTheater || SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0)) { // No lock in theater mode or Windows Explorer DeleteMenu(hmenuITB, FCIDM_VIEWLOCKTOOLBAR, MF_BYCOMMAND); } else { _CheckMenuItem(hmenuITB, FCIDM_VIEWLOCKTOOLBAR, _fLockedToolbar); } // if it was done via the keyboard, but focus wasn't on the tools band, // then don't have customize menu option // or if click didn't happen on the band if (!(_btb._fCustomize && idBandActive == CBIDX_TOOLS)) { DeleteMenu(hmenuITB, FCIDM_VIEWTOOLBARCUSTOMIZE, MF_BYCOMMAND); cItemsBelowSep--; } BOOL fGoButtonAvailable = WasOpenedAsBrowser(static_cast(this)) || (GetUIVersion() >= 5); // Only show the go button item when you click on the address bar if (idBandActive != CBIDX_ADDRESS || !fGoButtonAvailable) { DeleteMenu(hmenuITB, FCIDM_VIEWGOBUTTON, MF_BYCOMMAND); cItemsBelowSep--; } else { BOOL fShowGoButton = SHRegGetBoolUSValue(REGSTR_PATH_MAIN, TEXT("ShowGoButton"), FALSE, /*default*/TRUE); _CheckMenuItem(hmenuITB, FCIDM_VIEWGOBUTTON, fShowGoButton); } if (_fTheater || _btb._fCustomize || SHRestricted2(REST_LOCKICONSIZE, NULL, 0)) { DeleteMenu(hmenuITB, FCIDM_VIEWTEXTLABELS, MF_BYCOMMAND); cItemsBelowSep--; } else { // If customize is unavailable, then there's no way for the user to // turn list style on/off. In this case we want toggling text labels // to work the way it did in IE4 -- that is, switch between "text on // all buttons" and "text on no buttons". So, if we're in "selective // text on right" mode, we say that labels are turned off. If the user // picks this menu option, we'll go into "text on all buttons" mode. BOOL fChecked = !_fCompressed && !IS_LIST_STYLE(_btb._hwnd); _CheckMenuItem(hmenuITB, FCIDM_VIEWTEXTLABELS, fChecked); } if (!cItemsBelowSep) DeleteMenu(hmenuITB, FCIDM_VIEWCONTEXTMENUSEP, MF_BYCOMMAND); RestrictItbarViewMenu(hmenuITB, SAFECAST( this, IOleCommandTarget* ) ); ITBar_TrackPopupMenuEx(hmenuITB, TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pt.x, pt.y, _hwnd, prcExclude); // HACK: since the ITBar isn't a real bar/bandsite, we have to // do this so any menuband that might be up can take back the // mouse capture. CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_MENU); if (pbid) { IUnknown_Exec(pbid->pdb, &CGID_MenuBand, MBANDCID_RECAPTURE, 0, NULL, NULL); pbid->Release(); } DestroyMenu (hmenuITB); } BOOL _IsDocHostGUID(const GUID* pguid) { // Dochost merges under one of two clsids, so have to check both BOOL fRet = IsEqualGUID(*pguid, CLSID_InternetButtons) || IsEqualGUID(*pguid, CLSID_MSOButtons); return fRet; } void _PruneAmpersands(LPTSTR psz) { // // Collapse double ampersands in the string to single // ampersands, and rip out single ampersands. e.g., // // "AT&T" -> "ATT" // "AT&&T" -> "AT&T" // // We need to do this to hack around the ToolTips control's // annoying prefix behavior. When TTS_NOPREFIX is set // (which is true of itbar's), TT leaves prefix characters // alone completely. However when it is not set, besides just // letting DrawText do it's prefix thing on the string, TT also // pre-processes the string using an analogous version of the // below function, collapsing double ampersands to single // ampersands and ripping out single ampersands. This is so // that that if you use menu text (e.g. "&File") as a tooltip, // you won't get an underline. Unfortunately, the side effect // is that you're in trouble if you really wanted an ampersand in // the title (e.g. "AT&&T"), since the preprocessing turns "AT&&T" // into "AT&T", which DrawText then renders with an underline. // // Thus we have to leave TTS_NOPREFIX set and mimic the DrawText // preprocessing ourselves. // if (psz) { LPTSTR pszOut = psz; BOOL fLastAmpSkipped = FALSE; while (*psz) { if (*psz == TEXT('&')) { if (fLastAmpSkipped) { fLastAmpSkipped = FALSE; *pszOut++ = *psz; } else { fLastAmpSkipped = TRUE; } } else { *pszOut++ = *psz; } psz++; } *pszOut = TEXT('\0'); } } void CInternetToolbar::_OnTooltipNeeded(LPTOOLTIPTEXT pnmTT) { UINT uiCmd; GUID guid; ASSERT(pnmTT->hdr.hwndFrom == (HWND)SendMessage(_btb._hwnd, TB_GETTOOLTIPS, 0, 0)); pnmTT->szText[0] = TEXT('\0'); // Make sure tooltips don't filter out ampersands LONG lStyle = GetWindowLong(pnmTT->hdr.hwndFrom, GWL_STYLE); if (!IsFlagSet(lStyle, TTS_NOPREFIX)) { SetWindowLong(pnmTT->hdr.hwndFrom, GWL_STYLE, lStyle | TTS_NOPREFIX); } if (SUCCEEDED(_btb._ConvertCmd(NULL, (UINT)pnmTT->hdr.idFrom, &guid, &uiCmd))) { if (IsEqualGUID(guid, CLSID_CommonButtons)) { switch (uiCmd) { case TBIDM_FORWARD: case TBIDM_BACK: if (_ptbsite) { IBrowserService *pbsvc; if (SUCCEEDED(_ptbsite->QueryInterface(IID_PPV_ARG(IBrowserService, &pbsvc)))) { // FEATURE raymondc - make ITravelLog UNICODE someday ITravelLog *ptl; pbsvc->GetTravelLog( &ptl ); if (ptl) { WCHAR szTemp[ARRAYSIZE(pnmTT->szText)]; if (uiCmd == TBIDM_BACK) ptl->GetToolTipText(pbsvc, TLOG_BACK, 0, szTemp, ARRAYSIZE(szTemp)); else if (uiCmd == TBIDM_FORWARD) ptl->GetToolTipText(pbsvc, TLOG_FORE, 0, szTemp, ARRAYSIZE(szTemp)); SHUnicodeToTChar(szTemp, pnmTT->szText, ARRAYSIZE(pnmTT->szText)); ptl->Release(); } pbsvc->Release(); } } } } // Dochost merges under one of two clsids, so have to check both else if (_IsDocHostGUID(&guid)) { if (uiCmd == DVIDM_EDITPAGE) { _aEditVerb.GetToolTip(pnmTT->szText, ARRAYSIZE(pnmTT->szText)); } else { // If the button text is hidden or truncated, we use that text for the tooltip. TBBUTTONINFO tbbi = {0}; tbbi.cbSize = sizeof(TBBUTTONINFO); tbbi.dwMask = TBIF_STYLE | TBIF_STATE; SendMessage(_btb._hwnd, TB_GETBUTTONINFO, pnmTT->hdr.idFrom, (LPARAM)&tbbi); if (_fCompressed || IS_LIST_STYLE(_btb._hwnd) && !(tbbi.fsStyle & BTNS_SHOWTEXT) || (tbbi.fsState & TBSTATE_ELLIPSES)) { // // Get the button text and fix up the ampersands so that the // tooltip will look right // UINT cch = (UINT)SendMessage(_btb._hwnd, TB_GETBUTTONTEXT, pnmTT->hdr.idFrom, NULL); if (cch != 0 && cch < ARRAYSIZE(pnmTT->szText)) { if (SendMessage(_btb._hwnd, TB_GETBUTTONTEXT, pnmTT->hdr.idFrom, (LPARAM)&pnmTT->szText)) { _PruneAmpersands(pnmTT->szText); } } } } } } } LRESULT CInternetToolbar::_OnBeginDrag(NMREBAR *pnm) { if (SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0) || _fLockedToolbar) { return 1; } if (_fTheater) { // if we're in theater mode, we do our own drag handling where we force // all the mouse moves into the middle of the band, thereby disallowing // the user to make a multi line rebar SetCapture(_hwnd); SendMessage(_bs._hwnd, RB_BEGINDRAG, pnm->uBand, (LPARAM)-2); _fRebarDragging = TRUE; return 1; } return SHRestricted2(REST_NoToolbarOptions, NULL, 0); } LRESULT CInternetToolbar::_OnNotify(LPNMHDR pnmh) { LRESULT lres = 0; if (!_pdie) return 0; if (pnmh->code == TTN_NEEDTEXT && pnmh->hwndFrom == (HWND)SendMessage(_btb._hwnd, TB_GETTOOLTIPS, 0, 0)) { _OnTooltipNeeded((LPTOOLTIPTEXT)pnmh); return 0; } if(_SendToToolband(pnmh->hwndFrom, WM_NOTIFY,0, (LPARAM)pnmh, &lres)) return lres; switch (pnmh->idFrom) { case FCIDM_REBAR: switch (pnmh->code) { case RBN_BEGINDRAG: return _OnBeginDrag((NMREBAR*)pnmh); case RBN_HEIGHTCHANGE: ResizeBorderDW(NULL, NULL, FALSE); break; case RBN_CHILDSIZE: { // make the brand always take the full height NMREBARCHILDSIZE *pnm = (NMREBARCHILDSIZE*)pnmh; if (pnm->wID == CBIDX_BRAND) { pnm->rcChild.top = pnm->rcBand.top; pnm->rcChild.bottom = pnm->rcBand.bottom; } break; } case RBN_LAYOUTCHANGED: //Because the layout has changed, remember to save later! _fDirty = TRUE; _UpdateBrandSize(); if (_ptbsitect) _ptbsitect->Exec(&CGID_ShellBrowser, FCIDM_PERSISTTOOLBAR, 0, NULL, NULL); break; case RBN_GETOBJECT: { NMOBJECTNOTIFY *pnmon = (NMOBJECTNOTIFY *)pnmh; if (IsEqualIID(*pnmon->piid, IID_IDropTarget)) { HWND hwnd; switch (pnmon->iItem) { case CBIDX_MENU: case CBIDX_LINKS: { CBandItemData *pbid = _bs._GetBandItemDataStructByID(pnmon->iItem); if (pbid) { if (pbid->pdb) { pnmon->hResult = pbid->pdb->QueryInterface(IID_IDropTarget, (void**)&pnmon->pObject); } pbid->Release(); } break; } case CBIDX_TOOLS: hwnd = _btb._hwnd; pnmon->hResult = (HRESULT)SendMessage(hwnd, TB_GETOBJECT, (WPARAM)&IID_IDropTarget, (LPARAM)&pnmon->pObject); break; case CBIDX_ADDRESS: if (_ptbsite) { pnmon->hResult = _ptbsite->QueryInterface(IID_IDropTarget, (void**)&pnmon->pObject); } break; } } ASSERT((SUCCEEDED(pnmon->hResult) && pnmon->pObject) ? (IS_VALID_CODE_PTR(pnmon->pObject, IUnknown)) : (pnmon->pObject == NULL)); return TRUE; } case RBN_CHEVRONPUSHED: { LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnmh; if (pnmch->wID == CBIDX_TOOLS) { int idMenu = MENU_TBMENU; // this must be the tools band (not enumerated in bandsite) MapWindowPoints(pnmh->hwndFrom, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2); if (!_btb._fCustomize) idMenu = 0; ToolbarMenu_Popup(_hwnd, &pnmch->rc, NULL, _btb._hwnd, idMenu, (DWORD)pnmch->lParamNM); return TRUE; } _bs._OnNotify(pnmh); break; } default: return _bs._OnNotify(pnmh); } // switch (pnmh->code) break; } // switch (pnmh->idFrom) return 0; } void CInternetToolbar::_CommonHandleFileSysChange(LONG lEvent, LPITEMIDLIST* ppidl) { // stuff that needs to be done tree or no tree switch (lEvent) { // README: // If you need to add events here, then you must change SHELLBROWSER_FSNOTIFY_FLAGS in // shbrowse.cpp in order to get the notifications case SHCNE_DRIVEREMOVED: case SHCNE_MEDIAREMOVED: case SHCNE_MEDIAINSERTED: case SHCNE_DRIVEADD: case SHCNE_UPDATEIMAGE: case SHCNE_UPDATEITEM: // Forward this command to CAddressBand::FileSysChange() // by using IToolbandHelper::OnWinEvent(). { CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_ADDRESS); if (pbid) { // REVIEW: why don't we use IShellChangeNotify here? // IUnknown_FileSysChange(pbid->pdb, (DWORD)lEvent, (LPCITEMIDLIST*)ppidl); pbid->Release(); } } break; } } HRESULT CInternetToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { LPITEMIDLIST ppidl[2] = {(LPITEMIDLIST)pidl1, (LPITEMIDLIST)pidl2}; _CommonHandleFileSysChange(lEvent, ppidl); return S_OK; } void CInternetToolbar::_OnCommand(WPARAM wParam, LPARAM lParam) { if (!_pdie) return; HWND hwndControl = GET_WM_COMMAND_HWND(wParam, lParam); UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam); // If this is a command from the toolbar, and it is not one of the StdBrowseButtons // call Exec() on the appropriate CmdTarget if (hwndControl == _btb._hwnd) { UINT uiInternalCmdID = idCmd; // Convert to the real thing and get the guid CMDMAP* pcm = _btb._GetCmdMapByID(idCmd); IOleCommandTarget* pct = _btb._CommandTargetFromCmdMap(pcm); if (pct) { VARIANTARG var; var.vt = VT_I4; var.lVal = uiInternalCmdID; if (SHIsSameObject(_btb._pctCurrentButtonGroup, pct)) { // give the browser a chance to pick this off in case // focus doesn't belong to the view currently if (SUCCEEDED(_ptbsitect->Exec(&IID_IExplorerToolbar, pcm->nCmdID, 0, NULL, &var))) return; } UEMFireEvent(&UEMIID_BROWSER, UEME_UITOOLBAR, UEMF_XEVENT, UIG_COMMON, (LPARAM)pcm->nCmdID); pct->Exec(&pcm->guidButtonGroup, (DWORD)pcm->nCmdID, 0, NULL, &var); } return; } if (_SendToToolband(hwndControl, WM_COMMAND, wParam, lParam, NULL)) return; // this switch block actually executes switch(idCmd) { case FCIDM_VIEWTOOLBARCUSTOMIZE: ASSERT(!SHRestricted2(REST_NOTOOLBARCUSTOMIZE, NULL, 0)); SendMessage (_btb._hwnd, TB_CUSTOMIZE, 0, 0L); break; case FCIDM_DRIVELIST: _SendToToolband(_hwndAddressBand, WM_COMMAND, wParam, lParam, NULL); break; case FCIDM_VIEWADDRESS: case FCIDM_VIEWTOOLS: case FCIDM_VIEWMENU: case FCIDM_VIEWLINKS: if (!SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0) && !SHRestricted2(REST_NoToolbarOptions, NULL, 0)) { DWORD dw = _nVisibleBands; switch (idCmd) { case FCIDM_VIEWTOOLS: dw ^= VBF_TOOLS; break; case FCIDM_VIEWMENU: dw ^= VBF_MENU; break; case FCIDM_VIEWADDRESS: dw ^= VBF_ADDRESS; break; case FCIDM_VIEWLINKS: dw ^= VBF_LINKS; break; } if ( !( dw & ~VBF_BRAND)) { _pdie->put_ToolBar( FALSE ); } _ShowVisible(dw, TRUE); } return; case FCIDM_VIEWAUTOHIDE: { ASSERT(_fTheater); _fAutoHide = !_fAutoHide; VARIANTARG v = {0}; v.vt = VT_I4; v.lVal = _fAutoHide; IUnknown_Exec(_ptbsite, &CGID_Theater, THID_SETTOOLBARAUTOHIDE, 0, &v, NULL); ResizeBorderDW(NULL, NULL, FALSE); break; } case FCIDM_VIEWLOCKTOOLBAR: { _fLockedToolbar = !_fLockedToolbar; DWORD dwResult = _fLockedToolbar; SHSetValue(HKEY_CURRENT_USER, c_szRegKeyCoolbar, TEXT("Locked"), REG_DWORD, &dwResult, sizeof(dwResult)); _UpdateLocking(); break; } case FCIDM_VIEWTEXTLABELS: if(!SHRestricted2(REST_NoToolbarOptions, NULL, 0)) { if (!_btb._fCustomize && IS_LIST_STYLE(_btb._hwnd)) { // If customize is unavailable, then there's no way for the user to // turn list style on/off. In this case we want toggling text labels // to work the way it did in IE4 -- that is, switch between "text on // all buttons" and "text on no buttons". So, if we're in "selective // text on right" mode, we say that labels are turned off. If the user // picks this menu option, we'll go into "text on all buttons" mode. _UpdateToolsStyle(FALSE); // Make ourselves believe that text labels are turned off (so // that _UpdateToolbarDisplay will turn them on) _fCompressed = TRUE; } _UpdateToolbarDisplay(UTD_TEXTLABEL, 0, !_fCompressed, TRUE); } return; case FCIDM_VIEWGOBUTTON: _SendToToolband(_hwndAddressBand, WM_COMMAND, wParam, lParam, NULL); break; default: if (InRange( idCmd, FCIDM_EXTERNALBANDS_FIRST, FCIDM_EXTERNALBANDS_LAST )) { if (!SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0)) { DWORD dw = _nVisibleBands; dw ^= EXTERNALBAND_VBF_BIT(idCmd - FCIDM_EXTERNALBANDS_FIRST); if ( !( dw & ~VBF_BRAND)) { _pdie->put_ToolBar( FALSE ); } _ShowVisible(dw, TRUE); } return; } break; } } BOOL CInternetToolbar::_CompressBands(BOOL fCompress, UINT uRowsNew, BOOL fForceUpdate) { UINT_PTR uRowsOld = SendMessage(_btb._hwnd, TB_GETTEXTROWS, 0, 0L); if (fCompress) uRowsNew = 0; if (!fForceUpdate && (uRowsOld == uRowsNew)) { // same as what we've already got, blow it off return FALSE; } _fCompressed = fCompress; // Change the size of the Brand window and add ot remove the text SendMessage(_btb._hwnd, TB_SETMAXTEXTROWS, uRowsNew, 0L); UINT uWidthNew = _fCompressed ? MAX_TB_COMPRESSED_WIDTH : _uiMaxTBWidth; SendMessage(_btb._hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM) MAKELONG(0, uWidthNew)); _btb._BandInfoChanged(); _UpdateBrandSize(); _bs._SetMinDimensions(); return TRUE; } #define ABS(x) (((x) < 0) ? -(x) : (x)) void CInternetToolbar::_TrackSliding(int x, int y) { INT_PTR cBands = SendMessage(_bs._hwnd, RB_GETBANDCOUNT, 0, 0L); INT_PTR cRows = SendMessage(_bs._hwnd, RB_GETROWCOUNT, 0, 0L); INT_PTR cyHalfRow = SendMessage(_bs._hwnd, RB_GETROWHEIGHT, cBands-1, 0L) / 2; RECT rc; int cyBefore; int c; BOOL_PTR fChanged = FALSE; // do this instead of GetClientRect so that we include borders GetWindowRect(_bs._hwnd, &rc); MapWindowPoints(HWND_DESKTOP, _bs._hwnd, (LPPOINT)&rc, 2); cyBefore = rc.bottom - rc.top; c = y - _yCapture; rc.bottom = y; // was there enough change? if (ABS(c) <= cyHalfRow) return; if ((cRows == 1) || _fCompressed) { if (c < -cyHalfRow) fChanged = _CompressBands(TRUE, 0, FALSE); else fChanged = _CompressBands(FALSE, _uiTBTextRows, FALSE); } if (!fChanged) { // if the compressing bands didn't change anything, try to fit it to size fChanged = SendMessage(_bs._hwnd, RB_SIZETORECT, 0, (LPARAM)&rc); } // TODO: There is a drawing glitch when you resize from 3 bars (No Text) to 3 bars // with text. The _yCapture gets set to a value greater than y. So on the // next MOUSEMOVE it figures that the user moved up and switches from 3 bars with text // to 2 bars with text. if (fChanged) { _UpdateBrandSize(); GetWindowRect(_bs._hwnd, &rc); _yCapture += (rc.bottom - rc.top) - cyBefore; _fDirty = TRUE; //Since the band layout changed, set the dirty bit ON. if (_ptbsitect) _ptbsitect->Exec(&CGID_ShellBrowser, FCIDM_PERSISTTOOLBAR, 0, NULL, NULL); } } void CInternetToolbar::_ShowVisible(DWORD dwVisibleBands, BOOL fPersist) { // PERF (scotth): is this even necessary now that we have a // menu band always showing? BOOL fShowInitial = (! (_nVisibleBands & ~VBF_BRAND)); _UpdateToolbarDisplay(UTD_VISIBLE, dwVisibleBands, _fCompressed, fPersist); if (fShowInitial) _pdie->put_ToolBar(TRUE); } HRESULT CInternetToolbar::_UpdateToolbarDisplay(DWORD dwFlags, UINT uVisibleBands, BOOL fNoText, BOOL fPersist) { _fDirty = TRUE; //Since we are making changes, set the dirty bit! //Update the back bitmap _SetBackground(); //Show the bands. if(dwFlags & UTD_VISIBLE) _ShowBands(uVisibleBands); //Show/Hide the text. if(dwFlags & UTD_TEXTLABEL) _CompressBands(fNoText, _uiTBTextRows, TRUE); _fDirty = TRUE; //Since we are making changes, set the dirty bit! if (!_fTheater && fPersist && _ptbsitect) _ptbsitect->Exec(&CGID_ShellBrowser, FCIDM_PERSISTTOOLBAR, 0, NULL, NULL); return S_OK; } void CInternetToolbar::_UpdateBrandSize() { CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_BRAND); if (pbid) { if (((_nVisibleBands & (VBF_TOOLS | VBF_BRAND)) == (VBF_TOOLS | VBF_BRAND))) { BOOL fMinAlways = _fCompressed; if (!fMinAlways) { INT_PTR iTools = BandIDtoIndex(_bs._hwnd, CBIDX_TOOLS); INT_PTR iBrand = BandIDtoIndex(_bs._hwnd, CBIDX_BRAND); if (iBrand < iTools && !_fTheater) fMinAlways = TRUE; } VARIANTARG v = {0}; v.vt = VT_I4; v.lVal = fMinAlways; IUnknown_Exec(pbid->pdb, &CGID_PrivCITCommands, CITIDM_BRANDSIZE, 0, &v, NULL); } pbid->Release(); } } LRESULT CALLBACK CInternetToolbar::SizableWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CInternetToolbar* pitbar = (CInternetToolbar*)GetWindowPtr0(hwnd); // GetWindowLong(hwnd, 0) switch(uMsg) { case WM_SETCURSOR: { if (pitbar->_fLockedToolbar) { SetCursor(LoadCursor(NULL, IDC_ARROW)); return TRUE; } if ((HWND)wParam == hwnd && LOWORD(lParam) == HTCLIENT && !SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0)) { SetCursor(LoadCursor(NULL, IDC_SIZENS)); return TRUE; } goto DoDefault; } case WM_SYSCOLORCHANGE: // // BUG : 535039 - WM_SYSCOLORCHANGE messages dont have a valid wParam and lParam included // SHExplorerIniChange expects these to be NULLed out. If an app doesnt NULL these out, we crash in // SHExplorerIniChange. Greater safety here. // wParam = 0; lParam = 0; // // Fall through.. // case WM_WININICHANGE: if (FALSE == pitbar->_fDestroyed) { DWORD dwSection = SHIsExplorerIniChange(wParam, lParam); BOOL fRebuild = (uMsg == WM_SYSCOLORCHANGE) || (dwSection == EICH_KWINEXPLSMICO) || (wParam == SPI_SETNONCLIENTMETRICS); if (fRebuild) { pitbar->_InitForScreenSize(); ITBar_LoadToolbarGlyphs(pitbar->_btb._hwnd); pitbar->_ReloadBitmapDSA(); pitbar->_SetSearchStuff(); pitbar->_ReloadButtons(); if (uMsg == WM_SYSCOLORCHANGE) { pitbar->_RefreshEditGlyph(); } } if (dwSection == EICH_KINET) { pitbar->_aEditVerb.InitDefaultEditor(); pitbar->_UpdateEditButton(); } SendMessage(pitbar->_bs._hwnd, uMsg, wParam, lParam); pitbar->_SendToToolband(HWND_BROADCAST, uMsg, wParam, lParam, NULL); if (fRebuild) { pitbar->_SetBackground(); InvalidateRect(pitbar->_bs._hwnd, NULL, TRUE); pitbar->_bs._SetMinDimensions(); } } break; case WM_LBUTTONDOWN: // RelayToToolTips(prb->hwndToolTips, hwnd, wMsg, wParam, lParam); // Don't allow toolbar resizing in theater mode if (!pitbar->_fTheater && !SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0) && (!pitbar->_fLockedToolbar)) { pitbar->_xCapture = GET_X_LPARAM(lParam); pitbar->_yCapture = GET_Y_LPARAM(lParam); SetCapture(hwnd); } break; case WM_MOUSEMOVE: // RelayToToolTips(prb->hwndToolTips, hwnd, wMsg, wParam, lParam); if (pitbar->_yCapture != -1) { if (hwnd != GetCapture()) pitbar->_yCapture = -1; else pitbar->_TrackSliding(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } else if (pitbar->_fRebarDragging) { RECT rc; POINT pt; GetClientRect(pitbar->_bs._hwnd, &rc); GetCursorPos(&pt); MapWindowPoints(HWND_DESKTOP, pitbar->_bs._hwnd, &pt, 1); rc.bottom /= 2; if (pt.y > rc.bottom) pt.y = rc.bottom; SendMessage(pitbar->_bs._hwnd, RB_DRAGMOVE, 0, MAKELPARAM(pt.x, pt.y)); } break; case WM_LBUTTONUP: case WM_RBUTTONUP: // RelayToToolTips(prb->hwndToolTips, hwnd, wMsg, wParam, lParam); pitbar->_yCapture = -1; if (pitbar->_fRebarDragging) { pitbar->_fRebarDragging = FALSE; SendMessage(pitbar->_bs._hwnd, RB_ENDDRAG, 0, 0); } if (GetCapture() == hwnd) ReleaseCapture(); break; case WM_CONTEXTMENU: pitbar->_bs.OnWinEvent(pitbar->_hwnd, uMsg, wParam, lParam, NULL); break; case WM_VKEYTOITEM: case WM_CHARTOITEM: // We must swallow these messages to avoid infinit SendMessage break; case WM_NOTIFY: // We must swallow these messages to avoid infinit SendMessage return pitbar->_OnNotify((LPNMHDR)lParam); case WM_NOTIFYFORMAT: if (NF_QUERY == lParam) return (DLL_IS_UNICODE ? NFR_UNICODE : NFR_ANSI); break; case WM_COMMAND: pitbar->_OnCommand(wParam, lParam); break; case WM_ERASEBKGND: { HDC hdc = (HDC)wParam; RECT rc; GetClientRect(hwnd, &rc); SHFillRectClr(hdc, &rc, (pitbar->_fTheater) ? RGB(0,0,0) : GetSysColor(COLOR_3DFACE)); break; } case WM_PALETTECHANGED: // // PERF: we could optimize this by realizing and checking the // return value // // for now we will just invalidate ourselves and all children... // RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); break; case WM_MEASUREITEM: { PMEASUREITEMSTRUCT pmis; ASSERT(NULL != lParam); pmis = (PMEASUREITEMSTRUCT)lParam; switch (pmis->itemID) { case FCIDM_VBBHISTORYBAND: ASSERT(0 == wParam); { PULONG_PTR pData = (PULONG_PTR)pmis->itemData; ASSERT(NULL != pData); MeasureMenuItem(pmis, (PCTSTR)pData[0]); } break; default: goto DoDefault; } break; } case WM_DRAWITEM: { PDRAWITEMSTRUCT pdis; ASSERT(NULL != lParam); pdis = (PDRAWITEMSTRUCT)lParam; switch (pdis->itemID) { case FCIDM_VBBHISTORYBAND: ASSERT(0 == wParam); { PULONG_PTR pData = (PULONG_PTR)pdis->itemData; ASSERT(NULL != pData); DrawMenuItem(pdis, (PCTSTR)pData[0], (UINT) pData[1]); } break; default: goto DoDefault; } break; } case WM_MENUCHAR: if (MF_POPUP == HIWORD(wParam)) { MENUITEMINFO mii = { 0 }; mii.cbSize = sizeof(mii); mii.fMask = MIIM_DATA | MIIM_TYPE; GetMenuItemInfo((HMENU)lParam, FCIDM_VBBHISTORYBAND, FALSE, &mii); if (TEXT('h') == LOWORD(wParam) || TEXT('H') == LOWORD(wParam)) { return MAKELRESULT(FCIDM_VBBHISTORYBAND, MNC_EXECUTE); } } break; case WM_TIMER: switch (wParam) { case IDT_UPDATETOOLBAR: pitbar->_fUpdateToolbarTimer = FALSE; KillTimer(hwnd, wParam); if (pitbar->_fNeedUpdateToolbar) pitbar->_UpdateToolbarNow(); break; } break; case WM_DESTROY: pitbar->_Unadvise(); // remove ref-loop with _pdie TraceMsg(DM_TBREF, "CInternetToolbar::SizableWndProc() - Called RemoveProp. Called Release new _cRef=%d", pitbar->_cRef); goto DoDefault; DoDefault: default: return(DefWindowProcWrap(hwnd, uMsg, wParam, lParam)); } return 0L; } HRESULT CInternetToolbar::ResizeBorderDW(LPCRECT prcBorder, IUnknown* punkToolbarSite, BOOL fReserved) { TraceMsg(DM_LAYOUT, "CITB::ResizeBorderDW called (_fShow==%d)", _fShow); HRESULT hres = S_OK; ASSERT(_ptbsite); if (_ptbsite) { RECT rcRequest = { 0, 0, 0, 0 }; if (_fShow) { RECT rcRebar, rcBorder; int cx,cy; GetWindowRect(_bs._hwnd, &rcRebar); cx = rcRebar.right - rcRebar.left; cy = rcRebar.bottom - rcRebar.top; int iExtra = 3; if (_fTheater) { // 1 for the 1 pixel border on the bottom iExtra = 1; } else if (_fLockedToolbar) { iExtra = 0; } TraceMsg(DM_LAYOUT, "CITB::ResizeBorderDW cy = %d", cy); if (!prcBorder) { _ptbsite->GetBorderDW(SAFECAST(this, IDockingWindow*), &rcBorder); prcBorder = &rcBorder; } cx = prcBorder->right - prcBorder->left; SetWindowPos(_bs._hwnd, NULL, 0, 0, cx, cy, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); GetWindowRect(_bs._hwnd, &rcRebar); rcRequest.top = rcRebar.bottom - rcRebar.top + iExtra; SetWindowPos(_hwnd, NULL, prcBorder->left, prcBorder->top, rcRebar.right - rcRebar.left, rcRequest.top, SWP_NOZORDER | SWP_NOACTIVATE); } if (_fTheater && _fAutoHide) { // if we're in theater mode, then we should request no space rcRequest.left = rcRequest.top = 0; } TraceMsg(DM_LAYOUT, "CITB::ResizeBorderDW calling RequstBS with %d,%d,%d,%d", rcRequest.left, rcRequest.top, rcRequest.right, rcRequest.bottom); _ptbsite->RequestBorderSpaceDW(SAFECAST(this, IDockingWindow*), &rcRequest); TraceMsg(DM_LAYOUT, "CITB::ResizeBorderDW calling SetBS with %d,%d,%d,%d", rcRequest.left, rcRequest.top, rcRequest.right, rcRequest.bottom); _ptbsite->SetBorderSpaceDW(SAFECAST(this, IDockingWindow*), &rcRequest); } return hres; } HRESULT CInternetToolbar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) { HRESULT hr = OLECMDERR_E_UNKNOWNGROUP; CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_ADDRESS); if (pbid) { if (pbid->pdb) { IOleCommandTarget *poct; if (SUCCEEDED(pbid->pdb->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poct)))) { hr = poct->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext); poct->Release(); } } pbid->Release(); } if (pguidCmdGroup && IsEqualGUID(CGID_PrivCITCommands, *pguidCmdGroup)) { hr = S_OK; for (ULONG i = 0 ; i < cCmds; i++) { rgCmds[i].cmdf = 0; switch (rgCmds[i].cmdID) { case CITIDM_VIEWTOOLS: if (_nVisibleBands & VBF_TOOLS) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_VIEWMENU: if (_nVisibleBands & VBF_MENU) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_VIEWTOOLBARCUSTOMIZE: if (_btb._fCustomize) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_VIEWAUTOHIDE: if (_fAutoHide) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_VIEWLOCKTOOLBAR: if (_fLockedToolbar) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_VIEWADDRESS: if (_nVisibleBands & VBF_ADDRESS) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_VIEWLINKS: if (_nVisibleBands & VBF_LINKS) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_TEXTLABELS: if (!_fCompressed) rgCmds[i].cmdf = OLECMDF_ENABLED; break; case CITIDM_EDITPAGE: if (_fEditEnabled) rgCmds[i].cmdf = OLECMDF_ENABLED; // The tooltip text is also used for the menu if (pcmdtext) { TCHAR szBuf[MAX_PATH]; if ((pcmdtext->cmdtextf == OLECMDTEXTF_NAME) && _aEditVerb.GetMenuText(szBuf, ARRAYSIZE(szBuf))) { SHTCharToUnicode(szBuf, pcmdtext->rgwz, pcmdtext->cwBuf); pcmdtext->cwActual = lstrlenW(pcmdtext->rgwz) + 1; } else { pcmdtext->cwActual = 0; } } break; default: if (InRange( rgCmds[i].cmdID, CITIDM_VIEWEXTERNALBAND_FIRST, CITIDM_VIEWEXTERNALBAND_LAST)) { int iBand = rgCmds[i].cmdID - CITIDM_VIEWEXTERNALBAND_FIRST; if (!IsEqualCLSID( _rgebi[iBand].clsid, GUID_NULL )) { rgCmds[i].cmdf |= OLECMDF_SUPPORTED; if (_nVisibleBands & EXTERNALBAND_VBF_BIT( iBand )) { rgCmds[i].cmdf |= OLECMDF_ENABLED; } if (pcmdtext) { pcmdtext->rgwz[0] = TEXT('\0'); switch (pcmdtext->cmdtextf) { case OLECMDTEXTF_NAME: if (_rgebi[iBand].pwszName) Str_GetPtrW(_rgebi[iBand].pwszName, pcmdtext->rgwz, pcmdtext->cwBuf ); break; case OLECMDTEXTF_STATUS: if (_rgebi[iBand].pwszHelp) Str_GetPtrW(_rgebi[iBand].pwszHelp, pcmdtext->rgwz, pcmdtext->cwBuf ); break; default: break; } pcmdtext->cwActual = lstrlen( pcmdtext->rgwz ); } } } break; } } } return hr; } void CInternetToolbar::_RestoreSaveStruct(COOLBARSAVE* pcs) { REBARBANDINFO rbbi; rbbi.cbSize = sizeof(REBARBANDINFO); int i; _fAutoHide = pcs->fAutoHide; _ShowVisible(pcs->uiVisible, FALSE); BOOL fAllowRetry = TRUE; BOOL fNeedRetry = FALSE; INT_PTR fRedraw = SendMessage(_bs._hwnd, WM_SETREDRAW, FALSE, 0); Retry: for (i = 0; i < CBANDSMAX; i++) { INT_PTR iIndex = SendMessage(_bs._hwnd, RB_IDTOINDEX, pcs->bs[i].wID, 0); if (iIndex != -1) { SendMessage(_bs._hwnd, RB_MOVEBAND, iIndex, i); rbbi.fMask = RBBIM_STYLE; if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { rbbi.fMask = RBBIM_SIZE | RBBIM_STYLE; rbbi.cx = pcs->bs[i].cx; rbbi.fStyle = pcs->bs[i].fStyle; SendMessage(_bs._hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi); } // the SetBandInfo could have potentially caused items to shift around // verify that this didn't happen. iIndex = SendMessage(_bs._hwnd, RB_IDTOINDEX, pcs->bs[i].wID, 0); if (iIndex != i) { fNeedRetry = TRUE; } } } if (fAllowRetry && fNeedRetry) { fAllowRetry = FALSE; goto Retry; } _CSHSetStatusBar(pcs->fStatusBar); _UpdateToolsStyle(pcs->fList); RECT rc; GetWindowRect(_bs._hwnd, &rc); SetWindowPos(_bs._hwnd, NULL, 0,0, RECTWIDTH(rc), pcs->cyRebar, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); SendMessage(_bs._hwnd, WM_SETREDRAW, fRedraw, 0); } void CInternetToolbar::_CSHSetStatusBar(BOOL fOn) { VARIANTARG v = { 0 }; v.vt = VT_I4; v.lVal = fOn; IUnknown_Exec(_ptbsite, &CGID_ShellBrowser, FCIDM_SETSTATUSBAR, 0, &v, NULL); } void CInternetToolbar::_TheaterModeLayout(BOOL fEnter) { static const struct { int id; int cx; } c_layout[] = { { CBIDX_TOOLS, 400 }, { CBIDX_MENU, 200 }, { CBIDX_ADDRESS, 300 }, { CBIDX_LINKS, 40 } }; REBARBANDINFO rbbi; rbbi.cbSize = sizeof(REBARBANDINFO); BOOL_PTR fRedraw = SendMessage(_bs._hwnd, WM_SETREDRAW, FALSE, 0); SHSetWindowBits(_bs._hwnd, GWL_STYLE, RBS_AUTOSIZE, 0); if (fEnter) { _BuildSaveStruct(&_cs); // turn off text labels COOLBARSAVE cs; DWORD dwType, cbSize = sizeof(COOLBARSAVE); if (SHRegGetUSValue(c_szRegKeyCoolbar, c_szValueTheater, &dwType, (void*)&cs, &cbSize, FALSE, NULL, 0) == ERROR_SUCCESS && cs.cbVer == CBS_VERSION) { _RestoreSaveStruct(&cs); _UpdateToolbarDisplay(UTD_TEXTLABEL, 0, TRUE, TRUE); } else { _UpdateToolbarDisplay(UTD_TEXTLABEL, 0, TRUE, TRUE); _ShowVisible(VBF_TOOLS | VBF_BRAND, FALSE); // only show tools band by default RECT rc = { 0, 0, GetSystemMetrics(SM_CXSCREEN), 20 }; // something arbitrarily small vertically SendMessage(_bs._hwnd, RB_SIZETORECT, 0, (LPARAM)&rc); int cBands = (int) SendMessage(_bs._hwnd, RB_GETBANDCOUNT, 0, 0L); int i; // strip off all blanks rbbi.fMask = RBBIM_STYLE; for (i = 0; i < cBands; i++) { if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { rbbi.fStyle &= ~RBBS_BREAK; SendMessage(_bs._hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi); } } // then move into the proper order and size for (i = 0; i < ARRAYSIZE(c_layout); i++) { INT_PTR iIndex = SendMessage(_bs._hwnd, RB_IDTOINDEX, c_layout[i].id, 0); if (iIndex != -1) { SendMessage(_bs._hwnd, RB_MOVEBAND, iIndex, i); rbbi.fMask = RBBIM_SIZE; rbbi.cx = c_layout[i].cx; SendMessage(_bs._hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi); } } _CSHSetStatusBar(FALSE); // default value in theater mode } SHSetWindowBits(_bs._hwnd, GWL_STYLE, RBS_BANDBORDERS | WS_BORDER, RBS_BANDBORDERS); } else { COOLBARSAVE cs; _BuildSaveStruct(&cs); SHRegSetUSValue(c_szRegKeyCoolbar, c_szValueTheater, REG_BINARY, (void*)&cs, sizeof(COOLBARSAVE), SHREGSET_HKCU | SHREGSET_FORCE_HKCU); _RestoreSaveStruct(&_cs); _UpdateToolbarDisplay(UTD_TEXTLABEL, 0, _cs.fNoText, FALSE); SHSetWindowBits(_bs._hwnd, GWL_STYLE, RBS_BANDBORDERS | WS_BORDER, RBS_BANDBORDERS | WS_BORDER); } _SetBackground(); SHSetWindowBits(_bs._hwnd, GWL_STYLE, RBS_AUTOSIZE, RBS_AUTOSIZE); SendMessage(_bs._hwnd, WM_SETREDRAW, fRedraw, 0); SetWindowPos(_bs._hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); } HRESULT CInternetToolbar::_GetMinRowHeight() { UINT iHeight = 0; int icBands = (int) SendMessage( _bs._hwnd, RB_GETBANDCOUNT, 0, 0 ); for (int i = 0; i < icBands; i++) { REBARBANDINFO rbbi; rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_STYLE; if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi)) { // go until the end of the row if (rbbi.fStyle & RBBS_BREAK) break; if (!(rbbi.fStyle & RBBS_HIDDEN)) { if (rbbi.cyMinChild > iHeight) iHeight = rbbi.cyMinChild; } } } return ResultFromShort(iHeight); } BOOL IsBarRefreshable(IDeskBar* pdb) { ASSERT(pdb); BOOL fIsRefreshable = TRUE; VARIANT varClsid = {0}; if (SUCCEEDED(IUnknown_Exec(pdb, &CGID_DeskBarClient, DBCID_CLSIDOFBAR, 1, NULL, &varClsid)) && (varClsid.vt == VT_BSTR)) { CLSID clsidBar; //if the bar is hidden, it returns GUID_NULL, so don't refresh it if ( GUIDFromString(varClsid.bstrVal, &clsidBar) && (IsEqualGUID(clsidBar, GUID_NULL)) ) { fIsRefreshable = FALSE; } else { //APPHACK for office discussions band (and possibly others) //CLSID\GUID\Instance WCHAR wszKey[6+40+1+9]; DWORD dwValue, dwType=REG_DWORD, dwcbData = 4; wnsprintf(wszKey, ARRAYSIZE(wszKey), L"CLSID\\%s\\Instance", varClsid.bstrVal); if ( (SHGetValue(HKEY_CLASSES_ROOT, wszKey, L"DontRefresh", &dwType, &dwValue, &dwcbData) == ERROR_SUCCESS) && (dwValue != 0) ) { fIsRefreshable = FALSE; } } VariantClear(&varClsid); } return fIsRefreshable; } HRESULT CInternetToolbar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { HRESULT hr = OLECMDERR_E_UNKNOWNGROUP; // assume failure if (!pguidCmdGroup) { goto Lother; } else if (IsEqualGUID(CLSID_CommonButtons, *pguidCmdGroup)) { if (pvarargOut) { ASSERT(pvarargOut && pvarargOut->vt == VT_I4); UINT uiInternalCmdID = pvarargOut->lVal; if (nCmdID == TBIDM_SEARCH && uiInternalCmdID == -1) _btb._ConvertCmd(pguidCmdGroup, nCmdID, NULL, &uiInternalCmdID); switch (nCmdID) { case TBIDM_BACK: case TBIDM_FORWARD: case TBIDM_STOPDOWNLOAD: case TBIDM_REFRESH: case TBIDM_HOME: case TBIDM_SEARCH: case TBIDM_FAVORITES: case TBIDM_HISTORY: case TBIDM_ALLFOLDERS: case TBIDM_MEDIABAR: if (!SendMessage(_btb._hwnd, TB_ISBUTTONENABLED, uiInternalCmdID, 0)) return S_OK; break; } if (nCmdexecopt == OLECMDEXECOPT_PROMPTUSER) { // the user hit the drop down if (_ptbsitect && pvarargIn && pvarargIn->vt == VT_INT_PTR) { // v.vt = VT_I4; POINT pt; RECT* prc = (RECT*)pvarargIn->byref; pt.x = prc->left; pt.y = prc->bottom; switch (nCmdID) { case TBIDM_BACK: _ShowBackForwardMenu(FALSE, pt, prc); break; case TBIDM_FORWARD: _ShowBackForwardMenu(TRUE, pt, prc); break; } // VariantClearLazy(&v); } return S_OK; } switch(nCmdID) { case TBIDM_PREVIOUSFOLDER: _ptbsitect->Exec(&CGID_ShellBrowser, FCIDM_PREVIOUSFOLDER, 0, NULL, NULL); break; case TBIDM_CONNECT: DoNetConnect(_hwnd); break; case TBIDM_DISCONNECT: DoNetDisconnect(_hwnd); break; case TBIDM_BACK: _pdie->GoBack(); break; case TBIDM_FORWARD: _pdie->GoForward(); break; case TBIDM_HOME: _pdie->GoHome(); break; case TBIDM_SEARCH: if (_ptbsitect) { VARIANTARG vaOut = {0}; VARIANTARG* pvaOut = NULL; LPITEMIDLIST pidl = NULL; // i'm leaving this not #ifdefed out because it is used by explorer bar // persistance (reljai) //_SetSearchStuff initializes _guidDefaultSearch, which may or may not have // been called yet if (IsEqualGUID(_guidDefaultSearch, GUID_NULL)) _SetSearchStuff(); // see if what the state of search pane is, so we can toggle it... OLECMD rgcmds[] = {{ SBCMDID_SEARCHBAR, 0 },}; if (_ptbsitect) _ptbsitect->QueryStatus(&CGID_Explorer, ARRAYSIZE(rgcmds), rgcmds, NULL); // not pressed, then show the pane if (!(rgcmds[0].cmdf & OLECMDF_LATCHED)) { WCHAR wszUrl[MAX_URL_STRING]; if (_GetSearchUrl(wszUrl, ARRAYSIZE(wszUrl))) { CLSID clsid; if (GUIDFromString(wszUrl, &clsid)) { IContextMenu* pcm; if (SUCCEEDED(SHCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IContextMenu, &pcm)))) { CMINVOKECOMMANDINFO ici = {0}; CHAR szGuid[GUIDSTR_MAX]; BOOL bSetSite = TRUE; ici.cbSize = sizeof(ici); ici.hwnd = _hwnd; ici.lpVerb = (LPSTR)MAKEINTRESOURCE(0); ici.nShow = SW_NORMAL; SHStringFromGUIDA(_guidDefaultSearch, szGuid, ARRAYSIZE(szGuid)); ici.lpParameters = szGuid; // in case of rooted browser we need to open the search in the new window // 'coz otherwise the pane opens in the same window and user starts search // and browseobject (or someone) detects the rooted case and launches new // browser for our search results view (which is blank because it cannot do // search by itself and also there is not search pane) (reljai) if (_pbs2) { LPITEMIDLIST pidl; if (SUCCEEDED(_pbs2->GetPidl(&pidl))) { bSetSite = !ILIsRooted(pidl); ILFree(pidl); } } // if there is no site, InvokeCommand bellow will launch new browser w/ the // search pane open if (bSetSite) IUnknown_SetSite(pcm, _psp); hr = pcm->InvokeCommand(&ici); if (bSetSite) IUnknown_SetSite(pcm, NULL); pcm->Release(); } break; } //_guidCurrentSearch = _guidDefaultSearch;//done on set state IECreateFromPathW(wszUrl, &pidl); // convert pidl into VARIANT // way to pass the pidl, so... InitVariantFromIDList(&vaOut, pidl); pvaOut = &vaOut; } } hr = _ptbsitect->Exec(&CGID_Explorer, SBCMDID_SEARCHBAR, OLECMDEXECOPT_DONTPROMPTUSER, NULL, pvaOut); // vaIn:NULL means toggle ASSERT(SUCCEEDED(hr)); if (pvaOut) VariantClear(pvaOut); ILFree(pidl); } else { TraceMsg(DM_ERROR, "CITBar::Exec: no IOleCommandTarget!"); } break; case TBIDM_FAVORITES: case TBIDM_HISTORY: case TBIDM_ALLFOLDERS: case TBIDM_MEDIABAR: if (_ptbsitect) { static const int tbtab[] = { TBIDM_FAVORITES , TBIDM_HISTORY , TBIDM_ALLFOLDERS , TBIDM_MEDIABAR , }; static const int cttab[] = { SBCMDID_FAVORITESBAR, SBCMDID_HISTORYBAR, SBCMDID_EXPLORERBAR, SBCMDID_MEDIABAR, }; HRESULT hres; int idCT; idCT = SHSearchMapInt(tbtab, cttab, ARRAYSIZE(tbtab), nCmdID); hres = _ptbsitect->Exec(&CGID_Explorer, idCT, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); // vaIn:NULL means toggle ASSERT(SUCCEEDED(hres)); } else { TraceMsg(DM_ERROR, "CITBar::Exec: no IOleCommandTarget!"); } break; case TBIDM_THEATER: { VARIANT_BOOL b; if (SUCCEEDED(_pdie->get_TheaterMode(&b))) _pdie->put_TheaterMode( b == VARIANT_TRUE ? VARIANT_FALSE : VARIANT_TRUE); break; } case TBIDM_STOPDOWNLOAD: if (_fTransitionToHTML) { UINT uiState; _fTransitionToHTML = FALSE; if (SUCCEEDED(GetState(&CLSID_CommonButtons, TBIDM_STOPDOWNLOAD, &uiState))) { uiState |= TBSTATE_HIDDEN; SetState(&CLSID_CommonButtons, TBIDM_STOPDOWNLOAD, uiState); } SendMessage(_hwndAddressBand, CB_SETEDITSEL, NULL, (LPARAM)MAKELONG(-1,0)); } _pdie->Stop(); break; case TBIDM_REFRESH: { VARIANT v = {0}; v.vt = VT_I4; v.lVal = (GetAsyncKeyState(VK_CONTROL) < 0) ? OLECMDIDF_REFRESH_COMPLETELY|OLECMDIDF_REFRESH_PROMPTIFOFFLINE : OLECMDIDF_REFRESH_NO_CACHE|OLECMDIDF_REFRESH_PROMPTIFOFFLINE; _pdie->Refresh2(&v); if (_hwndAddressBand) { CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_ADDRESS); if (pbid) { if (pbid->pdb) { IAddressBand *pab = NULL; if (SUCCEEDED(pbid->pdb->QueryInterface(IID_PPV_ARG(IAddressBand, &pab)))) { VARIANTARG varType = {0}; varType.vt = VT_I4; varType.lVal = OLECMD_REFRESH_TOPMOST; pab->Refresh(&varType); pab->Release(); } } pbid->Release(); } } // pass this to vert and horz bars IDockingWindowFrame *psb; if (_psp && SUCCEEDED(_psp->QueryService(SID_STopLevelBrowser, IID_PPV_ARG(IDockingWindowFrame, &psb)))) { IDeskBar* pdb; if (SUCCEEDED(psb->FindToolbar(INFOBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdb))) && pdb && IsBarRefreshable(pdb)) { IUnknown_Exec(pdb, NULL, OLECMDID_REFRESH, OLECMDIDF_REFRESH_NORMAL|OLECMDIDF_REFRESH_PROMPTIFOFFLINE, NULL, NULL); pdb->Release(); } if (SUCCEEDED(psb->FindToolbar(COMMBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdb))) && pdb && IsBarRefreshable(pdb)) { IUnknown_Exec(pdb, NULL, OLECMDID_REFRESH, OLECMDIDF_REFRESH_NORMAL|OLECMDIDF_REFRESH_PROMPTIFOFFLINE, NULL, NULL); pdb->Release(); } psb->Release(); } } break; } } } else if (IsEqualGUID(IID_IExplorerToolbar, *pguidCmdGroup)) { switch (nCmdID) { case ETCMDID_GETBUTTONS: { if (_iButtons == -1) { // haven't initialized yet _iButtons = ARRAYSIZE(c_tbExplorer); memcpy(_tbExplorer, c_tbExplorer, sizeof(TBBUTTON) * ARRAYSIZE(c_tbExplorer)); if (IS_BIDI_LOCALIZED_SYSTEM()) { if (!SHUseClassicToolbarGlyphs()) { _tbExplorer[0].iBitmap = 1; _tbExplorer[1].iBitmap = 0; } } if (GetUIVersion() < 5) { // we don't want up button and network drive buttons available // on < nt5 shell (by trident pm design) // no customization in shell view on < nt5 ASSERT(!_fShellView); ASSERT(c_tbExplorer[TBXID_PREVIOUSFOLDER].idCommand == TBIDM_PREVIOUSFOLDER); _tbExplorer[TBXID_PREVIOUSFOLDER].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_CONNECT].idCommand == TBIDM_CONNECT); _tbExplorer[TBXID_CONNECT].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_DISCONNECT].idCommand == TBIDM_DISCONNECT); _tbExplorer[TBXID_DISCONNECT].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_ALLFOLDERS].idCommand == TBIDM_ALLFOLDERS); if (!_FoldersButtonAvailable()) _tbExplorer[TBXID_ALLFOLDERS].fsState |= TBSTATE_HIDDEN; } else { ASSERT(c_tbExplorer[TBXID_SEARCH].idCommand == TBIDM_SEARCH); if (_fShellView && SHRestricted(REST_NOSHELLSEARCHBUTTON)) _tbExplorer[TBXID_SEARCH].fsState |= TBSTATE_HIDDEN; ASSERT(c_tbExplorer[TBXID_CONNECT].idCommand == TBIDM_CONNECT); ASSERT(c_tbExplorer[TBXID_DISCONNECT].idCommand == TBIDM_DISCONNECT); if (SHRestricted(REST_NONETCONNECTDISCONNECT)) { _tbExplorer[TBXID_CONNECT].fsState |= TBSTATE_HIDDEN; _tbExplorer[TBXID_DISCONNECT].fsState |= TBSTATE_HIDDEN; } } ASSERT(_tbExplorer[TBXID_MEDIABAR].idCommand == TBIDM_MEDIABAR); if (_fShellView || SHRestricted2W(REST_No_LaunchMediaBar, NULL, 0) || !CMediaBarUtil::IsWMP7OrGreaterCapable()) { _tbExplorer[TBXID_MEDIABAR].fsState |= TBSTATE_HIDDEN; } ASSERT(_tbExplorer[TBXID_PREVIOUSFOLDER].idCommand == TBIDM_PREVIOUSFOLDER); if (!_fShellView) { _tbExplorer[TBXID_PREVIOUSFOLDER].fsState |= TBSTATE_HIDDEN; } _iButtons = RemoveHiddenButtons(_tbExplorer, ARRAYSIZE(_tbExplorer)); } pvarargOut->vt = VT_BYREF; pvarargOut->byref = (void*)_tbExplorer; *pvarargIn->plVal = _iButtons; } return S_OK; } } else if (IsEqualGUID(CGID_PrivCITCommands, *pguidCmdGroup)) { DWORD dw; hr = S_OK; switch (nCmdID) { case CITIDM_GETFOLDERSEARCHES: { hr = E_INVALIDARG; if (pvarargOut) { IFolderSearches *pfs; hr = _GetFolderSearches(&pfs); if (SUCCEEDED(hr)) { VariantClear(pvarargOut); pvarargOut->vt = VT_UNKNOWN; pvarargOut->punkVal = pfs; } } } break; case CITIDM_SET_DIRTYBIT: _fDirty = BOOLIFY(nCmdexecopt); break; case CITIDM_GETMINROWHEIGHT: hr = _GetMinRowHeight(); break; case CITIDM_VIEWTOOLBARCUSTOMIZE: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWTOOLBARCUSTOMIZE, _hwnd, 0)); break; case CITIDM_TEXTLABELS: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWTEXTLABELS, _hwnd, 0)); break; case CITIDM_EDITPAGE: // FEATURE: temp code -- edit code moving to dochost.cpp _btb.Exec(&CLSID_InternetButtons, DVIDM_EDITPAGE, 0, NULL, NULL); break; case CITIDM_ONINTERNET: switch (nCmdexecopt) { case CITE_INTERNET: _fInitialPidlIsWeb = TRUE; _fShellView = !_fInitialPidlIsWeb; break; case CITE_SHELL: _fInitialPidlIsWeb = FALSE; _fShellView = !_fInitialPidlIsWeb; break; case CITE_QUERY: return ResultFromScode(_fShellView ? CITE_SHELL : CITE_INTERNET); break; } return ResultFromScode(_fInitialPidlIsWeb ? CITE_INTERNET : CITE_SHELL); case CITIDM_VIEWTOOLS: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWTOOLS, _hwnd, 0)); break; case CITIDM_VIEWAUTOHIDE: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWAUTOHIDE, _hwnd, 0)); break; case CITIDM_VIEWLOCKTOOLBAR: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWLOCKTOOLBAR, _hwnd, 0)); break; case CITIDM_VIEWADDRESS: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWADDRESS, _hwnd, 0)); break; case CITIDM_VIEWLINKS: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWLINKS, _hwnd, 0)); break; case CITIDM_VIEWMENU: _OnCommand(GET_WM_COMMAND_MPS(FCIDM_VIEWMENU, _hwnd, 0)); break; case CITIDM_SHOWTOOLS: dw = VBF_TOOLS; goto ShowABand; case CITIDM_SHOWADDRESS: dw = VBF_ADDRESS; goto ShowABand; case CITIDM_SHOWLINKS: dw = VBF_LINKS; goto ShowABand; #ifdef UNIX case CITIDM_SHOWBRAND: dw = VBF_BRAND; goto ShowABand; #endif case CITIDM_SHOWMENU: dw = VBF_MENU; ShowABand: if (nCmdexecopt) dw |= _nVisibleBands; // Set else dw = (_nVisibleBands & ~dw); // Clear _ShowVisible(dw, TRUE); _fUsingDefaultBands = FALSE; break; case CITIDM_DISABLESHOWMENU: _fNoShowMenu = BOOLIFY(nCmdexecopt); break; case CITIDM_STATUSCHANGED: _fDirty = TRUE; if (_ptbsitect) _ptbsitect->Exec(&CGID_ShellBrowser, FCIDM_PERSISTTOOLBAR, 0, NULL, NULL); break; case CITIDM_THEATER: if (_fShow) { // IF YOU SEE HTIS ASSERT, TRY TO REMEMBER WHAT YOU DID AND CALL CHEE ASSERT(_fTheater || _nVisibleBands & VBF_MENU); switch (nCmdexecopt) { case THF_ON: _fTheater = TRUE; ResizeBorderDW(NULL, NULL, FALSE); _TheaterModeLayout(TRUE); // theater has its own brand, so needs to know whether we're in shell or web view so it can show the right brand IUnknown_Exec(_ptbsite, &CGID_Theater, THID_ONINTERNET, _fShellView ? CITE_SHELL : CITE_INTERNET, NULL, NULL); // pass back _fAutoHide pvarargOut->vt = VT_I4; pvarargOut->lVal = _fAutoHide; goto notify_bands; case THF_OFF: _fTheater = FALSE; ResizeBorderDW(NULL, NULL, FALSE); _TheaterModeLayout(FALSE); // position everything properly (needed after reparenting) SendMessage(_hwnd, RB_PRIV_RESIZE, 0, 0); goto notify_bands; notify_bands: { int icBands = (int) SendMessage( _bs._hwnd, RB_GETBANDCOUNT, 0, 0 ); for (int i = 0; i < icBands; i++) { REBARBANDINFO rbbi; rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_ID; if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { CBandItemData *pbid = _bs._GetBandItemDataStructByID(rbbi.wID); if (pbid) { IUnknown_Exec(pbid->pdb, pguidCmdGroup, CITIDM_THEATER, nCmdexecopt, NULL, NULL); pbid->Release(); } } } } break; case THF_UNHIDE: // position everything properly (needed after reparenting) SendMessage(_hwnd, RB_PRIV_RESIZE, 0, 0); break; } // IF YOU SEE HTIS ASSERT, TRY TO REMEMBER WHAT YOU DID AND CALL CHEE ASSERT(_fTheater || _nVisibleBands & VBF_MENU); } break; case CITIDM_VIEWEXTERNALBAND_BYCLASSID: if ((pvarargIn->vt == VT_BSTR) && pvarargIn->bstrVal) { CLSID clsid; if (GUIDFromString( pvarargIn->bstrVal, &clsid )) { hr = E_FAIL; for (DWORD i = 0; i < MAXEXTERNALBANDS; i++) { if (clsid == _rgebi[i].clsid) { DWORD dw = _nVisibleBands; DWORD dwBit = EXTERNALBAND_VBF_BIT( i ); dw = (nCmdexecopt) ? dw | dwBit : dw & ~dwBit; if ( !( dw & ~VBF_BRAND)) { _pdie->put_ToolBar( FALSE ); } _ShowVisible(dw, TRUE); _fUsingDefaultBands = FALSE; hr = S_OK; break; } } } } break; default: if (InRange( nCmdID, CITIDM_VIEWEXTERNALBAND_FIRST, CITIDM_VIEWEXTERNALBAND_LAST )) { _OnCommand(GET_WM_COMMAND_MPS( nCmdID - CITIDM_VIEWEXTERNALBAND_FIRST + FCIDM_EXTERNALBANDS_FIRST, _hwnd, 0)); break; } ASSERT(0); break; } } else { Lother: CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_ADDRESS); if (pbid) { hr = IUnknown_Exec(pbid->pdb, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); pbid->Release(); } } return hr; } BOOL _GetSearchHKEY(REFGUID guidSearch, HKEY *phkey) { HKEY hkey; BOOL bRet = FALSE; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_SZ_STATIC, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { TCHAR szExt[MAX_PATH];//extension key name DWORD cchExt = ARRAYSIZE(szExt); int iExt; BOOL bNoUrl = FALSE; // true iff guidSearch is found and there is no Url subkey for (iExt=0; !bRet && RegEnumKeyEx(hkey, iExt, szExt, &cchExt, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; cchExt = ARRAYSIZE(szExt), iExt++) { HKEY hkeyExt; // static extension key if (RegOpenKeyEx(hkey, szExt, 0, KEY_READ, &hkeyExt) == ERROR_SUCCESS) { int i; TCHAR szSubKey[32]; HKEY hkeySub; for (i = 0; !bRet && (wnsprintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%d"), i), RegOpenKeyEx(hkeyExt, szSubKey, 0, KEY_READ, &hkeySub) == ERROR_SUCCESS); i++) { TCHAR szSearchGuid[GUIDSTR_MAX]; DWORD cb; DWORD dwType; cb = sizeof(szSearchGuid); if (SHGetValue(hkeySub, REG_SZ_SEARCH_GUID, NULL, &dwType, (BYTE*)szSearchGuid, &cb) == ERROR_SUCCESS) { GUID guid; if (GUIDFromString(szSearchGuid, &guid) && IsEqualGUID(guid, guidSearch)) { HKEY hkeyTmp; if (RegOpenKeyEx(hkeySub, REG_SZ_SEARCH_URL, 0, KEY_READ, &hkeyTmp) == ERROR_SUCCESS) RegCloseKey(hkeyTmp); else bNoUrl = TRUE; bRet = TRUE; } } if (!bRet || bNoUrl) RegCloseKey(hkeySub); else *phkey = hkeySub; } if (!bNoUrl) RegCloseKey(hkeyExt); else { ASSERT(bRet); *phkey = hkeyExt; } } } RegCloseKey(hkey); } return bRet; } HRESULT CInternetToolbar::GetDefaultSearchUrl(LPWSTR pwszUrl, UINT cch) { HRESULT hr = E_FAIL; if (GetDefaultInternetSearchUrlW(pwszUrl, cch, TRUE)) hr = S_OK; return hr; } void WINAPI CopyEnumElement(void *pDest, const void *pSource, DWORD dwSize) { if (!pDest) return; memcpy(pDest, pSource, dwSize); } class CFolderSearches : public IFolderSearches { public: // *** IUnknown *** STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // *** IFolderSearches *** STDMETHODIMP EnumSearches(IEnumUrlSearch **ppenum); STDMETHODIMP DefaultSearch(GUID *pguid); CFolderSearches(GUID *pguid, int iCount, URLSEARCH *pUrlSearch); ~CFolderSearches(); private: LONG _cRef; int _iCount; GUID _guidDefault; URLSEARCH *_pUrlSearch; }; CFolderSearches::CFolderSearches(GUID *pguid, int iCount, URLSEARCH *pUrlSearch) { _cRef = 1; _iCount = iCount; _guidDefault = *pguid; _pUrlSearch = pUrlSearch; } CFolderSearches::~CFolderSearches() { if (_pUrlSearch) LocalFree(_pUrlSearch); } HRESULT CFolderSearches::QueryInterface(REFIID riid, void **ppvObj) { static const QITAB qit[] = { QITABENT(CFolderSearches, IFolderSearches), { 0 }, }; return QISearch(this, qit, riid, ppvObj); } ULONG CFolderSearches::AddRef() { return ++_cRef; } ULONG CFolderSearches::Release() { if (--_cRef > 0) return _cRef; delete this; return 0; } HRESULT CFolderSearches::EnumSearches(IEnumUrlSearch **ppenum) { HRESULT hres = E_OUTOFMEMORY; *ppenum = (IEnumUrlSearch *)new CStandardEnum(IID_IEnumUrlSearch, FALSE, _iCount, sizeof(URLSEARCH), _pUrlSearch, CopyEnumElement); if (*ppenum) { _pUrlSearch = NULL; _iCount = 0; hres = S_OK; } return hres; } HRESULT CFolderSearches::DefaultSearch(GUID *pguid) { *pguid = _guidDefault; return S_OK; } HRESULT CInternetToolbar::_GetFolderSearches(IFolderSearches **ppfs) { HRESULT hres = E_FAIL; *ppfs = NULL; if (_hdpaFSI) { LPURLSEARCH pUrlSearch = NULL; int iCount = 0; int cFSIs = DPA_GetPtrCount(_hdpaFSI); hres = E_OUTOFMEMORY; if (cFSIs > 0 && ((pUrlSearch = (LPURLSEARCH)LocalAlloc(LPTR, sizeof(URLSEARCH)*cFSIs)) != NULL)) { LPFOLDERSEARCHITEM pfsi; int i; // insert per folder items for (i = 0; i < cFSIs && (pfsi = (LPFOLDERSEARCHITEM)DPA_GetPtr(_hdpaFSI, i)) != NULL; i++) { CLSID clsid; // check if Url is actually a GUID. if yes we cannot enumerate it because // we need Title/Url pair. if (!GUIDFromStringW(pfsi->wszUrl, &clsid)) { lstrcpynW(pUrlSearch[iCount].wszName, pfsi->wszName, ARRAYSIZE(pUrlSearch[iCount].wszName)); lstrcpynW(pUrlSearch[iCount].wszUrl, pfsi->wszUrl, ARRAYSIZE(pUrlSearch[iCount].wszUrl)); iCount++; } } } *ppfs = new CFolderSearches(&_guidDefaultSearch, iCount, pUrlSearch); if (*ppfs) hres = S_OK; else LocalFree(pUrlSearch); } return hres; } BOOL CInternetToolbar::_GetSearchUrl(LPWSTR pwszUrl, DWORD cch) { BOOL bRet = FALSE; HKEY hkey; if (pwszUrl) { pwszUrl[0] = L'\0'; // if we are looking for web search url bypass the registry lookup and the // per folder items and go straight to GetDefaultSearchUrl which call // GetSearchAssistantUrlW if (!IsEqualGUID(_guidDefaultSearch, SRCID_SWebSearch)) { // _GetSearchHKEY looks in the registry where shell search items are registered // if we have old shell32 then we don't display shell search items so we should // not look in the registry if (GetUIVersion() >= 5 && _GetSearchHKEY(_guidDefaultSearch, &hkey)) { DWORD cb = cch*sizeof(TCHAR); TCHAR szGuid[GUIDSTR_MAX]; DWORD cbGuid = sizeof(szGuid); // is there a url key if (SHGetValueW(hkey, REG_SZ_SEARCH_URL, NULL, NULL, pwszUrl, &cb) == ERROR_SUCCESS) bRet = TRUE; // no? try the default value, maybe it's the clsid else if (SHGetValueW(hkey, NULL, NULL, NULL, szGuid, &cbGuid) == ERROR_SUCCESS) { GUID guid; // is it a valid guid string if (GUIDFromString(szGuid, &guid)) { StrCpyNW(pwszUrl, szGuid, cch); bRet = TRUE; } } RegCloseKey(hkey); } // maybe it's one of the per-folder items... else if (_hdpaFSI) //FSI = folder search items { int i; LPFOLDERSEARCHITEM pfsi; for (i=0; (pfsi = (LPFOLDERSEARCHITEM)DPA_GetPtr(_hdpaFSI, i)) != NULL; i++) { if (IsEqualGUID(_guidDefaultSearch, pfsi->guidSearch)) { StrCpyNW(pwszUrl, pfsi->wszUrl, cch); bRet = TRUE; break; } } } } if (!bRet) bRet = SUCCEEDED(GetDefaultSearchUrl(pwszUrl, cch)); } return bRet; } void CInternetToolbar::_SetSearchStuff() { UINT uiState; BOOL bChecked = FALSE; if (SUCCEEDED(GetState(&CLSID_CommonButtons, TBIDM_SEARCH, &uiState))) bChecked = uiState & TBSTATE_CHECKED; if (!_hdpaFSI) { _hdpaFSI = DPA_Create(2); } else { DPA_EnumCallback(_hdpaFSI, DeleteDPAPtrCB, NULL); // delete all ptrs DPA_DeleteAllPtrs(_hdpaFSI); // now tell hdpa to forget about them } // this is bogus -- _fShellView is always FALSE when using automation if (_fShellView) _guidDefaultSearch = SRCID_SFileSearch; else _guidDefaultSearch = SRCID_SWebSearch; // get per folder search items and the default search (if any) // and insert them to _himlSrc _GetFolderSearchData(); if (!bChecked) { _guidCurrentSearch = _guidDefaultSearch; } } // // CInternetToolbar::SetCommandTarget() // // This function sets the current command target and button group. A client calls this // before merging in buttons with the AddButtons method. // // There are a couple of tricky things about this function. // // NTRAID#NTBUG9-196149-2000/12/11-AIDANL Hide Address Bar by default in explorer for Per/Pro // We no longer allow dwFlags to set links, address, tools, brand, relying on // CInternetToolbar::_LoadDefaultSettings() for those settings. // // One is that the client can pass some flags (dwFlags param) specifying the bands it wants // showing by default (menu, links, address, tools, brand, external). But we don't let them change // the state of the menu band. And, if another client has already set the default bands, we // don't let them change the state of any of the bands. // // The other is that we do some stuff to figure out if the caller is just another instantiation of the same // client. If we think this is a new client (new guidButtonGroup), we flush the toolbar and return S_OK. // But if we think this is the same client reincarnated (same guidButtonGroup and non-NULL command target), // we return S_FALSE without flushing the toolbar. This is done for performance. A new dochost is instantiated // on each navigation, but its toolbar buttons never change, so don't bother remerging its toolbar buttons. // HRESULT CInternetToolbar::SetCommandTarget(IUnknown* punkCmdTarget, const GUID* pguidButtonGroup, DWORD dwFlags) { if (!pguidButtonGroup || !punkCmdTarget || IsEqualGUID(CLSID_CommonButtons, *pguidButtonGroup)) return E_INVALIDARG; // RAID 196149 - disallow changes to links, address, tools, brand, instead use _cs.uiVisible for these settings dwFlags = dwFlags & ~(VBF_LINKS| VBF_ADDRESS | VBF_TOOLS | VBF_BRAND); dwFlags |= (_cs.uiVisible & (VBF_LINKS| VBF_ADDRESS | VBF_TOOLS | VBF_BRAND)); // this should not change the menu bit or external bands. dwFlags |= (_nVisibleBands & (VBF_MENU | VBF_EXTERNALBANDS)); _btb._fCustomize = !((dwFlags & VBF_NOCUSTOMIZE) || SHRestricted2(REST_NOTOOLBARCUSTOMIZE, NULL, 0)); // if the new button group is the internet button group, then we're // in internet mode; else we're in shell mode _fShellView = !(_IsDocHostGUID(pguidButtonGroup)); _SetSearchStuff(); HRESULT hr = S_FALSE; BOOL fNewButtonGroup = !IsEqualGUID(*pguidButtonGroup, _btb._guidCurrentButtonGroup); BOOL fNewCommandTarget = !SHIsSameObject(_btb._pctCurrentButtonGroup, punkCmdTarget); // when changing button groups we need to invalidate our cache of buttons for customization // why? well, with browse in separate process not turned on, navigating from shell to web // reuses the toolbar and some buttons may be disabled for shell but not for browser and vice versa. if (fNewButtonGroup) _iButtons = -1; if (fNewButtonGroup || fNewCommandTarget) { if (_btb._pctCurrentButtonGroup) _btb._pctCurrentButtonGroup->Exec(&IID_IExplorerToolbar, ETCMDID_NEWCOMMANDTARGET, 0, NULL, NULL); _btb._guidCurrentButtonGroup = *pguidButtonGroup; ATOMICRELEASE(_btb._pctCurrentButtonGroup); punkCmdTarget->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_btb._pctCurrentButtonGroup)); // A new view can tell us how many rows of text it NEEDs. // if it doesn't specify, we give it the default. (stored in _uiDefaultTBTextRows) if (dwFlags & VBF_ONELINETEXT ) _uiTBTextRows = 1; else if (dwFlags & VBF_TWOLINESTEXT) _uiTBTextRows = 2; else _uiTBTextRows = _uiTBDefaultTextRows; _CompressBands(_fCompressed, _uiTBTextRows, FALSE); if (fNewButtonGroup) { // new button group; flush toolbar _btb._RemoveAllButtons(); hr = S_OK; } if (_fUsingDefaultBands && !_fTheater) _fUsingDefaultBands = FALSE; else dwFlags = _nVisibleBands; if (dwFlags) _ShowBands(dwFlags); } return hr; } HRESULT CInternetToolbar::AddStdBrowserButtons() { // // code to add browser buttons has moved to CDocObjectHost::_AddButtons // ASSERT(0); return E_NOTIMPL; } void CInternetToolbar::_ReloadButtons() { if (!IsEqualGUID(_btb._guidCurrentButtonGroup, CLSID_CommonButtons) && _btb._pctCurrentButtonGroup) { HRESULT hres = _btb._pctCurrentButtonGroup->Exec(&IID_IExplorerToolbar, ETCMDID_RELOADBUTTONS, 0, NULL, NULL); if (FAILED(hres)) AddButtons(&_btb._guidCurrentButtonGroup, _btb._cBtnsAdded, _btb._pbtnsAdded); _InitEditButtonStyle(); _UpdateToolbar(TRUE); } } // The cmdTarget should have already added the Imagelists and the strings. HRESULT CInternetToolbar::AddButtons(const GUID* pguidButtonGroup, UINT nNewButtons, const TBBUTTON * lpButtons) { if (!pguidButtonGroup || !IsEqualGUID(*pguidButtonGroup, _btb._guidCurrentButtonGroup)) return E_INVALIDARG; if (!IsWindow(_btb._hwnd)) return E_FAIL; LPTBBUTTON lpTBCopy = (LPTBBUTTON)LocalAlloc(LPTR, nNewButtons * sizeof(TBBUTTON)); if (!lpTBCopy) return E_OUTOFMEMORY; _CreateBands(); _btb._RemoveAllButtons(); memcpy(lpTBCopy, lpButtons, sizeof(TBBUTTON) * nNewButtons); nNewButtons = _btb._ProcessExternalButtons(lpTBCopy, nNewButtons); // Free the old button array _btb._FreeBtnsAdded(); _btb._pbtnsAdded = lpTBCopy; _btb._cBtnsAdded = nNewButtons; if (_btb._fCustomize && _btb._SaveRestoreToolbar(FALSE)) { // Customization mechanism filled the toolbar for us // // The customization mechanism allocated its own set of // cmdmaps for the buttons, which means that we need to // free those hanging off _pbtnsAdded when _pbtnsAdded is // freed. // _btb._fNeedFreeCmdMapsAdded = TRUE; _btb._RecalcButtonWidths(); // // If we had a custom edit glyph, reload it so that we // don't momentarily flash the default glyph during // navigation. We'll update it again when we get a // DISPID_DOCUMENTCOMPLETE event. // _RefreshEditGlyph(); if (!_fShellView) { _btb._AddMediaBarButton(); } } else { // No customization found for this button group // // We're adding the button array to toolbar directly, // and the cmdmaps get freed on TBN_DELETINGBUTTON, so // we shouldn't also try to free them when _pbtnsAdded // is freed. // _btb._fNeedFreeCmdMapsAdded = FALSE; _AddCommonButtons(); SendMessage(_btb._hwnd, TB_ADDBUTTONS, nNewButtons, (LPARAM)lpTBCopy); } _bs._SetMinDimensions(); return S_OK; } HRESULT CInternetToolbar::AddString(const GUID * pguidButtonGroup, HINSTANCE hInst, UINT_PTR uiResID, LONG_PTR *pOffset) { TraceMsg(DM_ITBAR, "CITBar::AddString called"); *pOffset = -1; if (!IsWindow(_btb._hwnd)) { TraceMsg(DM_ERROR, "CITBar::AddString failed"); return E_FAIL; } *pOffset= SendMessage(_btb._hwnd, TB_ADDSTRING, (WPARAM)hInst, (LPARAM)uiResID); if (*pOffset != -1) return S_OK; TraceMsg(DM_ERROR, "CITBar::AddString failed"); return E_FAIL; } HRESULT CInternetToolbar::GetButton(const GUID* pguidButtonGroup, UINT uiCommand, LPTBBUTTON lpButton) { UINT_PTR uiIndex = 0; TraceMsg(DM_ITBAR, "CITBar::GetButton called"); if (!pguidButtonGroup || !IsWindow(_btb._hwnd)) return E_FAIL; if (SUCCEEDED(_btb._ConvertCmd(pguidButtonGroup, uiCommand, NULL, &uiCommand))) { uiIndex = SendMessage(_btb._hwnd, TB_COMMANDTOINDEX, uiCommand, 0L); if (SendMessage(_btb._hwnd, TB_GETBUTTON, uiIndex, (LPARAM)lpButton)) { GUID guid; _btb._ConvertCmd(NULL, lpButton->idCommand, &guid, (UINT*)&lpButton->idCommand); return S_OK; } } return E_FAIL; } HRESULT CInternetToolbar::GetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT * pfState) { TraceMsg(DM_ITBAR, "CITBar::GetState called"); if (!pguidButtonGroup || !IsWindow(_btb._hwnd)) return E_FAIL; if (SUCCEEDED(_btb._ConvertCmd(pguidButtonGroup, uiCommand, NULL, &uiCommand))) { *pfState = (UINT)SendMessage(_btb._hwnd, TB_GETSTATE, uiCommand, 0L); return S_OK; } return E_FAIL; } HRESULT CInternetToolbar::SetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT fState) { BOOL bIsSearchBtn; if (!pguidButtonGroup || !IsWindow(_btb._hwnd)) return E_FAIL; TraceMsg(DM_ITBAR, "CITBar::SetState called"); bIsSearchBtn = uiCommand == TBIDM_SEARCH; if (SUCCEEDED(_btb._ConvertCmd(pguidButtonGroup, uiCommand, NULL, &uiCommand))) { UINT_PTR uiState; uiState = SendMessage(_btb._hwnd, TB_GETSTATE, uiCommand, NULL); uiState ^= fState; if (uiState) { // search button is being unchecked, change the icon to the default search's if (bIsSearchBtn && !(fState & TBSTATE_CHECKED) && !IsEqualGUID(_guidCurrentSearch, _guidDefaultSearch)) { _guidCurrentSearch = _guidDefaultSearch; } if (SendMessage(_btb._hwnd, TB_SETSTATE, uiCommand, (LPARAM)fState)) { if (uiState & TBSTATE_HIDDEN) _bs._SetMinDimensions(); } } return S_OK; } return E_FAIL; } // // A bitmap can be added in two ways: // 1. Send a bitmap in the hBMPNew field. The uiBMPType parameter needs to be a BITMAP_BMP* // The uiCount and the ptb parameters are ignored // The offset is placed in puiOffset // // 2. A TBADDBITMAP struct can be sent. The uiCount should have the count // uiBMPType parameter needs to be a BITMAP_TBA* value // The offset is placed in puiOffset HRESULT CInternetToolbar::AddBitmap(const GUID * pguidButtonGroup, UINT uiBMPType, UINT uiCount, TBADDBITMAP * ptb, LRESULT * pOffset, COLORREF rgbMask) { UINT uiGetMSG, uiSetMSG; TBBMP_LIST tbl = {NULL}; TraceMsg(DM_ITBAR, "CITBar::AddBitmap called"); *pOffset = -1; _CreateBands(); if ((!pguidButtonGroup) || (!IsWindow(_btb._hwnd)) || !_hdsaTBBMPs) { TraceMsg(DM_ERROR, "CITBar::AddBitmap failed - NULL pguidButtonGroup or invalid _hwnd"); return E_FAIL; } // See if we already have the bitmap loaded. TBBMP_LIST * pTBBs = NULL; int nCount = DSA_GetItemCount(_hdsaTBBMPs); for (int nIndex = 0; nIndex < nCount; nIndex++) { pTBBs = (TBBMP_LIST*)DSA_GetItemPtr(_hdsaTBBMPs, nIndex); if ((pTBBs) && (pTBBs->hInst == ptb->hInst) && (pTBBs->uiResID == ptb->nID)) break; pTBBs = NULL; } // If it was in the commctrl, then we should already have an entry in the DSA if ((ptb->hInst == HINST_COMMCTRL) && (!pTBBs)) { TraceMsg(DM_ERROR, "CITBar::AddBitmap failed - bogus ResID for HINST_COMMCTL"); return E_FAIL; } // If the icons being added are from fontsext.dll or from dialup networking // or the briefcase, then we have it. So just send return the offset if (ptb->hInst != HINST_COMMCTRL) { TCHAR szDLLFileName[MAX_PATH], *pszFN; ZeroMemory(szDLLFileName, sizeof(szDLLFileName)); if (GetModuleFileName(ptb->hInst, szDLLFileName, ARRAYSIZE(szDLLFileName))) { pszFN = PathFindFileName(szDLLFileName); if(!lstrcmpi(pszFN, TEXT("fontext.dll"))) *pOffset = FONTGLYPH_OFFSET; else if (!lstrcmpi(pszFN, TEXT("shell32.dll"))) { // 140 and 141 are the glyphs that Shell32.dll uses: // IDB_BRF_TB_SMALL 140 // IDB_BRF_TB_LARGE 141 if ((ptb->nID == 140) || (ptb->nID == 141)) *pOffset = BRIEFCASEGLYPH_OFFSET; } else if (!lstrcmpi(pszFN, TEXT("rnaui.dll"))) *pOffset = RNAUIGLYPH_OFFSET; else if (!lstrcmpi(pszFN, TEXT("webcheck.dll"))) *pOffset = WEBCHECKGLYPH_OFFSET; if (*pOffset != -1) return S_OK; } } // So the bitmaps is not from commctrl. And we have never seen this before. // Add an entry into the DSA and then add the bitmap to the himage list. if (!pTBBs) { tbl.hInst = ptb->hInst; tbl.uiResID = ptb->nID; nIndex = DSA_AppendItem(_hdsaTBBMPs, &tbl); if (nIndex < 0) { TraceMsg(DM_ERROR, "CITBar::AddBitmap failed - nIndex < 0!"); return E_FAIL; } pTBBs = (TBBMP_LIST*)DSA_GetItemPtr(_hdsaTBBMPs, nIndex); if (!pTBBs) { TraceMsg(DM_ERROR, "CITBar::AddBitmap failed - pTBBS is NULL!"); return E_FAIL; } } switch(uiBMPType) { case BITMAP_NORMAL: if ((pTBBs) && (pTBBs->fNormal)) { *pOffset = pTBBs->uiOffset; return S_OK; } else if (pTBBs) pTBBs->fNormal = TRUE; uiGetMSG = TB_GETIMAGELIST; uiSetMSG = TB_SETIMAGELIST; break; case BITMAP_HOT: if ((pTBBs) && (pTBBs->fHot)) { *pOffset = pTBBs->uiOffset; return S_OK; } else if (pTBBs) pTBBs->fHot = TRUE; uiGetMSG = TB_GETHOTIMAGELIST; uiSetMSG = TB_SETHOTIMAGELIST; break; case BITMAP_DISABLED: if ((pTBBs) && (pTBBs->fDisabled)) { *pOffset = pTBBs->uiOffset; return S_OK; } else if (pTBBs) pTBBs->fDisabled = TRUE; uiGetMSG = TB_GETDISABLEDIMAGELIST; uiSetMSG = TB_SETDISABLEDIMAGELIST; break; default: ASSERT(FALSE); return E_FAIL; } pTBBs->uiCount = uiCount; *pOffset = _AddBitmapFromForeignModule(uiGetMSG, uiSetMSG, uiCount, ptb->hInst, ptb->nID, rgbMask); if (pTBBs) pTBBs->uiOffset = (UINT)*pOffset; return S_OK; } // the CmdTarget needs to call this to see what size of bmps we are using. HRESULT CInternetToolbar::GetBitmapSize(UINT * uiSize) { TraceMsg(DM_ITBAR, "CITBar::GetBitmapSize called"); *uiSize = g_fSmallIcons ? MAKELONG(TB_SMBMP_CX, TB_SMBMP_CY) : MAKELONG(g_iToolBarLargeIconWidth,g_iToolBarLargeIconHeight); return S_OK; } HRESULT CInternetToolbar::SetImageList( const GUID* pguidCmdGroup, HIMAGELIST himlNormal, HIMAGELIST himlHot, HIMAGELIST himlDisabled) { if (IsEqualGUID(*pguidCmdGroup, _btb._guidCurrentButtonGroup)) { SendMessage(_btb._hwnd, TB_SETIMAGELIST, 1, (LPARAM)himlNormal); SendMessage(_btb._hwnd, TB_SETHOTIMAGELIST, 1, (LPARAM)himlHot); SendMessage(_btb._hwnd, TB_SETDISABLEDIMAGELIST, 1, (LPARAM)himlDisabled); } return S_OK; } HRESULT CInternetToolbar::ModifyButton( const GUID * pguidButtonGroup, UINT uiCommand, LPTBBUTTON lpButton) { UINT uiIndex = 0; TraceMsg(DM_ITBAR, "CITBar::ModifyButton called"); if (!pguidButtonGroup || !IsWindow(_btb._hwnd)) return E_FAIL; if (SUCCEEDED(_btb._ConvertCmd(pguidButtonGroup, uiCommand, NULL, &uiCommand))) { TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_STATE | TBIF_IMAGE; tbbi.fsState = lpButton->fsState; tbbi.iImage = lpButton->iBitmap; if (SendMessage(_btb._hwnd, TB_SETBUTTONINFO, uiCommand, (LPARAM)&tbbi)) { return S_OK; } } return E_FAIL; } HRESULT CInternetToolbar::SendToolbarMsg(const GUID* pguidButtonGroup, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT * plRes) { LRESULT lRes; if (!IsWindow(_btb._hwnd)) { TraceMsg(DM_ERROR, "CITBar::SendToolbarMsg Message failed"); return E_FAIL; } if ( // this api is only here for back compat, and these messages didn't // exist when the old clients were written uMsg == TB_GETBUTTONINFOA || uMsg == TB_GETBUTTONINFOW || uMsg == TB_SETBUTTONINFOA || uMsg == TB_SETBUTTONINFOW || // unsupported right now uMsg == TB_ADDBUTTONSA || uMsg == TB_ADDBUTTONSW ) { ASSERT(0); return E_FAIL; } if ((uMsg == TB_ENABLEBUTTON) || (uMsg == TB_HIDEBUTTON) || (uMsg == TB_CHECKBUTTON) || (uMsg == TB_PRESSBUTTON) || (uMsg == TB_MARKBUTTON)) { unsigned int uiTemp; if (SUCCEEDED(_btb._ConvertCmd(pguidButtonGroup, (UINT)wParam, NULL, &uiTemp))) wParam = uiTemp; } if (uMsg == TB_INSERTBUTTON && lParam) { TBBUTTON btn = (*(TBBUTTON*)lParam); _btb._PreProcessExternalTBButton(&btn); lRes = SendMessage(_btb._hwnd, uMsg, wParam, (LPARAM)&btn); } else { lRes = SendMessage(_btb._hwnd, uMsg, wParam, lParam); if (uMsg == TB_GETBUTTON) { TBBUTTON* pbtn = (TBBUTTON*)lParam; if (pbtn && pbtn->dwData) { CMDMAP* pcm = (CMDMAP*)pbtn->dwData; pbtn->idCommand = pcm->nCmdID; pbtn->dwData = pcm->lParam; } } } if (plRes) *plRes = lRes; return S_OK; } TOOLSBANDCLASS::CBrowserToolsBand() : CToolbarBand() { _fCanFocus = TRUE; } #define DEFAULT_LIST_VALUE() (GetUIVersion() >= 5) void TOOLSBANDCLASS::_FreeBtnsAdded() { if (_pbtnsAdded) { if (_fNeedFreeCmdMapsAdded) { for (int i = 0; i < _cBtnsAdded; i++) { CMDMAP* pcm = (CMDMAP*)_pbtnsAdded[i].dwData; _FreeCmdMap(pcm); } } LocalFree(_pbtnsAdded); _pbtnsAdded = NULL; _cBtnsAdded = 0; } } LRESULT TOOLSBANDCLASS::_ToolsCustNotify (LPNMHDR pnmh) { LPTBNOTIFY ptbn = (LPTBNOTIFY) pnmh; switch (pnmh->code) { case TBN_SAVE: { NMTBSAVE *pnmtbs = (NMTBSAVE*)pnmh; if (pnmtbs->iItem == -1) { // before the save int nButtons = (int) SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0L); int uSize = pnmtbs->cbData + sizeof(BUTTONSAVEINFO) * nButtons + // stuff for each button sizeof(TOOLBARSAVEINFO); // stuff for the toolbar pnmtbs->pData = (LPDWORD)LocalAlloc(LPTR, uSize); pnmtbs->pCurrent = pnmtbs->pData; pnmtbs->cbData = uSize; if (pnmtbs->pData) { TOOLBARSAVEINFO *ptbsi = (TOOLBARSAVEINFO*)pnmtbs->pData; ptbsi->cVersion = TBSI_VERSION; pnmtbs->pCurrent = (LPDWORD)(ptbsi+1); } } else { CMDMAP *pcm = (CMDMAP*)pnmtbs->tbButton.dwData; BUTTONSAVEINFO* pbsi = (BUTTONSAVEINFO*)pnmtbs->pCurrent; pnmtbs->pCurrent = (LPDWORD)(pbsi+1); if (pcm) { pbsi->guid = pcm->guidButtonGroup; pbsi->nCmdID = pcm->nCmdID; pbsi->fButtonState = pnmtbs->tbButton.fsState; #ifdef DEBUG TCHAR szGuid[80]; SHStringFromGUID(pcm->guidButtonGroup, szGuid, ARRAYSIZE(szGuid)); TraceMsg(TF_TBCUST, "Saving: %s - %d (%x)", szGuid, pbsi->nCmdID, pbsi->nCmdID); #endif } else { ASSERT(pnmtbs->tbButton.fsStyle & BTNS_SEP); if (pnmtbs->tbButton.idCommand) { TraceMsg(TF_TBCUST, "Saving: a separator w/ id %d (%x)", pnmtbs->tbButton.idCommand, pnmtbs->tbButton.idCommand); pbsi->guid = CLSID_Separator; pbsi->nCmdID = pnmtbs->tbButton.idCommand; } else { TraceMsg(TF_TBCUST, "Saving: a separator"); } } } break; } case TBN_RESTORE: { NMTBRESTORE* pnmtbr = (NMTBRESTORE*)pnmh; if (pnmtbr->iItem == -1) { // before the restore. // take the data, verify the version, // fill in the button count, bytes per record // initialize the pCurrent to the end of the tb header // TOOLBARSAVEINFO* ptbsi = (TOOLBARSAVEINFO*)pnmtbr->pCurrent; if (ptbsi->cVersion != TBSI_VERSION) { TraceMsg( TF_WARNING, "TOOLSBANDCLASS::_ToolsCustNotify() - Wrong Toolbar Save Info Version (0x%x vs. 0x%x)!", ptbsi->cVersion, TBSI_VERSION ); return 1; // abort } // we're actually going to do a restore. initialize our database: _BuildButtonDSA(); pnmtbr->pCurrent = (LPDWORD)(ptbsi+1); pnmtbr->cbBytesPerRecord += sizeof(BUTTONSAVEINFO); pnmtbr->cButtons = (pnmtbr->cbData - sizeof(TOOLBARSAVEINFO)) / pnmtbr->cbBytesPerRecord; // make sure we did the math right and there are no remainders ASSERT(((pnmtbr->cbData - sizeof(TOOLBARSAVEINFO)) % pnmtbr->cbBytesPerRecord) == 0); //this is going to clobber all of the buttons in the current toolbar. // since toolbar control just writes over the dwords, we need to go free them now. int nButtons = (int) SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0L); for (int nTemp = 0; nTemp < nButtons; nTemp++) { CMDMAP *pcm = _GetCmdMapByIndex(nTemp); _FreeCmdMap(pcm); TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.lParam = (LPARAM)NULL; tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX; SendMessage(_hwnd, TB_SETBUTTONINFO, nTemp, (LPARAM)&tbbi); } } else { BUTTONSAVEINFO* pbsi = (BUTTONSAVEINFO*)pnmtbr->pCurrent; pnmtbr->pCurrent = (LPDWORD)(pbsi+1); pnmtbr->tbButton.dwData = 0; pnmtbr->tbButton.iString = -1; if (IsEqualGUID(CLSID_Separator, pbsi->guid)) { // restore a separator with a command id pnmtbr->tbButton.fsStyle = BTNS_SEP; TraceMsg(TF_TBCUST, "Restoring: a separator w/ id %d (%x)", pnmtbr->tbButton.idCommand, pnmtbr->tbButton.idCommand); } else if (!(pnmtbr->tbButton.fsStyle & BTNS_SEP)) { // Make sure that the button exists for this site CMDMAPCUSTOMIZE* pcmc = _GetCmdMapCustomize(&pbsi->guid, pbsi->nCmdID); if ((pcmc == NULL) || (SHRestricted(REST_NONLEGACYSHELLMODE) && ((pbsi->nCmdID == TBIDM_BACK) || (pbsi->nCmdID == TBIDM_FORWARD)))) { // Ignore this button return 1; } CMDMAP* pcm = (CMDMAP*)LocalAlloc(LPTR, sizeof(CMDMAP)); if (pcm) { pcm->guidButtonGroup = pbsi->guid; pcm->nCmdID = pbsi->nCmdID; #ifdef DEBUG TCHAR szGuid[80]; SHStringFromGUID(pcm->guidButtonGroup, szGuid, ARRAYSIZE(szGuid)); TraceMsg(TF_TBCUST, "Restoring: %s - %d (%x)", szGuid, pbsi->nCmdID, pbsi->nCmdID); #endif // fill in the rest of the info pnmtbr->tbButton = pcmc->btn; pnmtbr->tbButton.fsState = pbsi->fButtonState; pnmtbr->tbButton.dwData = (DWORD_PTR) pcm; } } else { TraceMsg(TF_TBCUST, "Restoring: a separator"); } } } break; case TBN_ENDADJUST: _OnEndCustomize(); break; case TBN_TOOLBARCHANGE: _pcinfo->fDirty = TRUE; break; case TBN_INITCUSTOMIZE: _OnBeginCustomize((NMTBCUSTOMIZEDLG*)pnmh); return TBNRF_HIDEHELP; case TBN_RESET: _pcinfo->fDirty = FALSE; if (_pctCurrentButtonGroup) { NMTBCUSTOMIZEDLG *pnm = (NMTBCUSTOMIZEDLG*)pnmh; CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); TCHAR szGuid[GUIDSTR_MAX]; SHStringFromGUID(_guidCurrentButtonGroup, szGuid, ARRAYSIZE(szGuid)); SHDeleteValue(HKEY_CURRENT_USER, REGSTR_PATH_TOOLBAR, szGuid); // Default text labels setting should be as follows: // // If fullscreen mode, any platform -- "No text labels" // Else if NT5 -- "Selective text on right" // Else -- "Show text labels" // int idsDefault; if (pitbar->_fTheater) idsDefault = IDS_NOTEXTLABELS; else if (DEFAULT_LIST_VALUE()) idsDefault = IDS_PARTIALTEXT; else idsDefault = IDS_TEXTLABELS; _UpdateTextSettings(idsDefault); HWND hwnd = (HWND) GetProp(pnm->hDlg, SZ_PROP_CUSTDLG); if (hwnd) { // update our dialog's control selection states _SetDialogSelections(hwnd, _DefaultToSmallIcons()); } _RemoveAllButtons(); _OnEndCustomize(); if (_pbtnsAdded) { pitbar->AddButtons(&_guidCurrentButtonGroup, _cBtnsAdded, _pbtnsAdded); // Restore the edit button pitbar->_InitEditButtonStyle(); pitbar->_UpdateToolbar(TRUE); } else { return TBNRF_ENDCUSTOMIZE; } } break; case TBN_QUERYINSERT: return TRUE; case TBN_QUERYDELETE: return (SendMessage(_hwnd, TB_ISBUTTONHIDDEN, (WPARAM) ptbn->tbButton.idCommand, (LPARAM) 0)) ? FALSE : TRUE; case TBN_GETBUTTONINFO: if (ptbn->iItem < DSA_GetItemCount(_pcinfo->hdsa)) { CMDMAPCUSTOMIZE *pcmc; pcmc = (CMDMAPCUSTOMIZE*)DSA_GetItemPtr(_pcinfo->hdsa, ptbn->iItem); ptbn->tbButton = pcmc->btn; ptbn->tbButton.fsState &= ~TBSTATE_HIDDEN; return TRUE; } return FALSE; case TBN_BEGINADJUST: if (!_pcinfo || !_pcinfo->fAdjust) return 1; break; } return FALSE; } BOOL TOOLSBANDCLASS::_SaveRestoreToolbar(BOOL fSave) { TBSAVEPARAMS tbsp; TCHAR szGuid[GUIDSTR_MAX]; SHStringFromGUID(_guidCurrentButtonGroup, szGuid, ARRAYSIZE(szGuid)); tbsp.hkr = HKEY_CURRENT_USER; tbsp.pszSubKey = REGSTR_PATH_TOOLBAR; tbsp.pszValueName = szGuid; BOOL fRet = BOOLFROMPTR(SendMessage(_hwnd, TB_SAVERESTORE, (WPARAM) fSave, (LPARAM) &tbsp)); _FreeCustomizeInfo(); return fRet; } void TOOLSBANDCLASS::_AddMediaBarButton() { // Wrap this with a reg key to make sure it happens only once // then check to make sure it's not already in the thing if (_hwnd && !SHRestricted2W(REST_No_LaunchMediaBar, NULL, 0) && !SHRestricted2(REST_BTN_MEDIABAR, NULL, 0) && CMediaBarUtil::IsWMP7OrGreaterCapable()) { DWORD dwType, dwSize; DWORD dwValue = TBBIF_NONE; dwSize = sizeof(dwValue); if ( (ERROR_SUCCESS==SHGetValue(HKEY_CURRENT_USER, TBBIF_REG_PATH, TBBIF_REG_KEY, &dwType, &dwValue, &dwSize)) && (dwType==REG_DWORD) && ((dwValue & TBBIF_MEDIA) != 0)) { return; } dwValue |= TBBIF_MEDIA; SHSetValue(HKEY_CURRENT_USER, TBBIF_REG_PATH, TBBIF_REG_KEY, REG_DWORD, &dwValue, sizeof(dwValue)); TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_STATE | TBIF_BYINDEX | TBIF_LPARAM; int iFavs = -1, iHist = -1, iLastTool = -1; int iMedia = -1; // lookup MediaBar in current toolbar // this could be a previous PersonalBar since the MediaBar reuses the cmdID BOOL fFound = FALSE; int cntButtons = (int)SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0); for (int j = 0; j < cntButtons; j++) { if (SendMessage(_hwnd, TB_GETBUTTONINFO, j, (LPARAM)&tbbi)!=-1) { CMDMAP* pcm = (CMDMAP*)tbbi.lParam; if (pcm) { // already present ? if (pcm->nCmdID == TBIDM_MEDIABAR) { fFound = TRUE; // no need to add, only care about updating position in toolbar iMedia = j; } // will try placing after Favorites.... else if (pcm->nCmdID == TBIDM_FAVORITES) { iFavs = j; iLastTool = j; } // ... and/or before History else if (pcm->nCmdID == TBIDM_HISTORY) { iHist = j; iLastTool = j; } // ... but at least after last found button in second group else if ( (pcm->nCmdID == TBIDM_SEARCH) || (pcm->nCmdID == TBIDM_ALLFOLDERS)) { iLastTool = j; } } } } // force-expose MediaBar button at least once if (!fFound) { TBBUTTON tbXBar; memcpy((VOID*)&tbXBar, (VOID*)&c_tbExplorer[TBXID_MEDIABAR], sizeof(TBBUTTON)); CMDMAP* pcm = (CMDMAP*)LocalAlloc(LPTR, sizeof(CMDMAP)); if (pcm) { pcm->guidButtonGroup = CLSID_CommonButtons; pcm->nCmdID = c_tbExplorer[TBXID_MEDIABAR].idCommand; tbXBar.idCommand = _nNextCommandID++; tbXBar.dwData = (LPARAM)pcm; SendMessage(_hwnd, TB_ADDBUTTONS, 1, (LPARAM)&tbXBar); } } if (iMedia < 0) { cntButtons = (int)SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0); for (j = cntButtons - 1; j >= 0; j--) { if (SendMessage(_hwnd, TB_GETBUTTONINFO, j, (LPARAM)&tbbi)!=-1) { CMDMAP* pcm = (CMDMAP*)tbbi.lParam; if (pcm) { // already present ? if (pcm->nCmdID == TBIDM_MEDIABAR) { iMedia = j; break; } } } } } // update position of MediaBar button // do we know a preferred position where the MediaBar button should move to? if ((iMedia >= 0) && ((iFavs >= 0) || (iHist >= 0) || (iLastTool >= 0))) { int iNewPos = -1; if (iFavs >= 0) { iNewPos = iFavs; } else if (iHist >= 0) { iNewPos = max(iHist - 1, 0); } else if (iLastTool >= 0) { iNewPos = iLastTool; } if (iNewPos >= 0) { if (iNewPos < iMedia) SendMessage(_hwnd, TB_MOVEBUTTON, iMedia, iNewPos + 1); else SendMessage(_hwnd, TB_MOVEBUTTON, iMedia, iNewPos); _SaveRestoreToolbar(TRUE); _RecalcButtonWidths(); } } } } int TOOLSBANDCLASS::_CommandFromIndex(UINT uIndex) { TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_COMMAND | TBIF_BYINDEX; SendMessage(_hwnd, TB_GETBUTTONINFO, uIndex, (LPARAM)&tbbi); return tbbi.idCommand; } // _btb._ConvertCmd() // This is used to covert a external Command ID to an internal ID or vice versa // If we are converting to an external ID then // call with pguidButtonGroup == NULL (to external: pguidButtonGroup == NULL) // otherwise call with the external button group GUID (to internal: pguidOut == NULL) HRESULT TOOLSBANDCLASS::_ConvertCmd(const GUID* pguidButtonGroup, UINT id, GUID* pguidOut, UINT * pid) { HRESULT hres = E_FAIL; BOOL fToInternal = (bool) (pguidButtonGroup); ASSERT((pguidButtonGroup == NULL) ^ (pguidOut == NULL)); // First look for the command if (fToInternal) { if (_hwnd) { int nCount = (int) SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0); for (int i = 0; i < nCount; i++) { CMDMAP *pcm = _GetCmdMapByIndex(i); if (pcm) { // loop through the command mapping structures until we // find this guid and id if (IsEqualGUID(pcm->guidButtonGroup, *pguidButtonGroup) && id == pcm->nCmdID) { *pid = _CommandFromIndex(i); hres = S_OK; break; } } } } } else { // going from toolbar id to commandtarget info CMDMAP *pcm = _GetCmdMapByID(id); if (pcm) { *pguidOut = pcm->guidButtonGroup; *pid = pcm->nCmdID; hres = S_OK; } } return hres; } LRESULT CInternetToolbar::_AddBitmapFromForeignModule(UINT uiGetMSG, UINT uiSetMSG, UINT uiCount, HINSTANCE hinst, UINT_PTR nID, COLORREF rgbMask) { HBITMAP hBMPRaw = NULL, hBMPFixedUp = NULL; HBITMAP * phBmp = &hBMPFixedUp; BITMAP bmp; HIMAGELIST himlTemp; LRESULT lRes = 1L; BOOL fOk = TRUE; HDC dc = NULL, dcMemSrc = NULL, dcMemDest = NULL; HBITMAP hbmpOldDest = NULL, hbmpOldSrc = NULL; int cxOrg = 0; int xDest = 0, yDest = 0; RECT rect = {0,0,0,0}; HBRUSH hbr = NULL; // What if hinst == NULL? That means that nID is really an HBITMAP ASSERT( hinst != NULL ); if (!(hBMPRaw = LoadBitmap(hinst, MAKEINTRESOURCE(nID)))) return 0L; fOk = (BOOL)(GetObject(hBMPRaw, sizeof(BITMAP), &bmp) != 0); // Check is the size is OK if (fOk && (bmp.bmWidth != (LONG)(g_iToolBarLargeIconWidth * uiCount)) || (bmp.bmHeight != (LONG)g_iToolBarLargeIconHeight) ) { int cxBmp; int cyBmp; if (g_fSmallIcons) { cxBmp = TB_SMBMP_CX; cyBmp = TB_SMBMP_CY; } else { cxBmp = g_iToolBarLargeIconWidth; cyBmp = g_iToolBarLargeIconHeight; } // If the height is 15, the we assume that this is one of the old bitmaps therefore // the width is 16. We cannot rely on the (bmp.bmWidth / uiCount) because some apps // like SecureFile give us a bitmap 192 wide and say that there are 10 glyphs in it. if (bmp.bmHeight == 15) cxOrg = 16; else cxOrg = bmp.bmWidth / (uiCount ? uiCount : 1); if (rgbMask) fOk = (BOOL)((hbr = CreateSolidBrush(rgbMask))!= NULL); if (fOk) fOk = (BOOL)((dc = GetDC(_btb._hwnd)) != NULL); if (fOk) fOk = (BOOL)((hBMPFixedUp = CreateCompatibleBitmap(dc, (cxBmp * uiCount), cyBmp)) != NULL); if (fOk) fOk = (BOOL)((dcMemSrc = CreateCompatibleDC(dc)) != NULL); if (fOk) fOk = (BOOL)((dcMemDest = CreateCompatibleDC(dc)) != NULL); if (!fOk) goto Error; hbmpOldSrc = (HBITMAP)SelectObject(dcMemSrc, hBMPRaw); hbmpOldDest = (HBITMAP)SelectObject(dcMemDest, hBMPFixedUp); rect.right = (cxBmp * uiCount); rect.bottom = cyBmp; if (rgbMask) FillRect(dcMemDest, &rect, hbr); for (UINT n = 0; n < uiCount; n++) { int cxCopy; int cyCopy; xDest = (n * cxBmp); if (cxOrg < cxBmp) { // if the bitmap is too small, we need to center it. // the amount we copy is the full bitmap cxCopy = cxOrg; xDest += ((cxBmp - cxOrg) / 2); } else { // if the bitmap is big enough, we align it to top left and // we strecth(shrink) it down to fit cxCopy = cxBmp; } if (bmp.bmHeight < cyBmp) { cyCopy = bmp.bmHeight; yDest = ((cyBmp - bmp.bmHeight) / 2); } else { cyCopy = cyBmp; yDest = 0; } StretchBlt(dcMemDest, xDest, yDest, cxOrg, bmp.bmHeight, dcMemSrc, (cxOrg * n), 0, cxCopy, cyCopy, SRCCOPY); } SelectObject(dcMemDest, hbmpOldDest); SelectObject(dcMemSrc, hbmpOldSrc); } else phBmp = &hBMPRaw; if (!(himlTemp = (HIMAGELIST)SendMessage(_btb._hwnd, uiGetMSG, 0, 0L))) { TraceMsg(DM_ERROR, "CITBar::_AddBitmapFromForeignModule Failed - uiGetMSG SendMessage Failure"); fOk = FALSE; goto Error; } if (rgbMask) lRes = ImageList_AddMasked(himlTemp, (HBITMAP)*phBmp, rgbMask); else lRes = ImageList_Add(himlTemp, (HBITMAP)*phBmp, NULL); if (lRes == -1) { TraceMsg(DM_ERROR, "CITBar::_AddBitmapFromForeignModule Failed - lRes == -1"); fOk = FALSE; goto Error; } if (!SendMessage(_btb._hwnd, uiSetMSG, 0, (LPARAM)himlTemp)) { TraceMsg(DM_ERROR, "CITBar::_AddBitmapFromForeignModule Failed - uiSetMSG SendMessage Failed"); fOk = FALSE; goto Error; } Error: if (hBMPFixedUp) DeleteObject(hBMPFixedUp); if (hBMPRaw) DeleteObject(hBMPRaw); if (dc) ReleaseDC(_btb._hwnd, dc); if (dcMemSrc) DeleteDC(dcMemSrc); if (dcMemDest) DeleteDC(dcMemDest); if (hbr) DeleteObject(hbr); if (!fOk) lRes = 0L; return lRes; } #define VERY_HIGH_NUMBER 4000 HRESULT CInternetToolbar::_LoadDefaultSettings() { ZeroMemory(&_cs, sizeof(_cs)); _cs.cbVer = CBS_VERSION; _cs.bs[0].wID = CBIDX_MENU; _cs.bs[0].cx = VERY_HIGH_NUMBER; _cs.bs[1].wID = CBIDX_BRAND; _cs.bs[2].wID = CBIDX_TOOLS; _cs.bs[2].cx = VERY_HIGH_NUMBER; _cs.bs[2].fStyle = RBBS_BREAK; _cs.bs[3].wID = CBIDX_ADDRESS; _cs.bs[3].cx = VERY_HIGH_NUMBER; _cs.bs[3].fStyle = RBBS_BREAK; _cs.bs[4].wID = CBIDX_LINKS; if (!_fInitialPidlIsWeb) { // we're in shell view, or we're rooted. for perf, don't bother creating the links band. if (IsOS(OS_WHISTLERORGREATER) && (IsOS(OS_PERSONAL))) { _cs.uiVisible = (VBF_MENU | VBF_TOOLS | VBF_BRAND); } else { _cs.uiVisible = (VBF_MENU | VBF_TOOLS | VBF_ADDRESS | VBF_BRAND); } } else { // web page _cs.uiVisible = (VBF_MENU | VBF_TOOLS | VBF_ADDRESS | VBF_LINKS | VBF_BRAND); } _cs.clsidVerticalBar = GUID_NULL; _cs.clsidHorizontalBar = GUID_NULL; _cs.fNoText = FALSE; _cs.fList = DEFAULT_LIST_VALUE(); _fUsingDefaultBands = TRUE; return(NOERROR); } typedef struct tagCOOLBARSAVEv12 // IE4 { UINT cbVer; UINT uiMaxTBWidth; UINT uiMaxQLWidth; #ifdef UNIX BITBOOL fUnUsed : 28; // unused #endif BOOL fVertical : 1; // The bar is oriented vertically BOOL fNoText :1; // "NoText" BOOL fAutoHide : 1; // Auto hide toolbar in theater mode BOOL fStatusBar : 1; // Status bar in theater mode BOOL fSaveInShellIntegrationMode : 1; // Did we save in shell UINT uiVisible; // "Visible bands" UINT cyRebar; BANDSAVE bs[5]; } COOLBARSAVEv12; typedef struct tagCOOLBARSAVEv15 // IE5 Beta2 { UINT cbVer; UINT uiMaxTBWidth; UINT uiMaxQLWidth; #ifdef UNIX BITBOOL fUnUsed : 28; // unused #endif BITBOOL fVertical : 1; // The bar is oriented vertically BITBOOL fNoText :1; // "NoText" BITBOOL fList : 1; // toolbar is TBSTYLE_LIST (text on right) + TBSTYLE_EX_MIXEDBUTTONS BITBOOL fAutoHide : 1; // Auto hide toolbar in theater mode BITBOOL fStatusBar : 1; // Status bar in theater mode BITBOOL fSaveInShellIntegrationMode : 1; // Did we save in shell integration mode? UINT uiVisible; // "Visible bands" UINT cyRebar; BANDSAVE bs[5]; CLSID clsidVerticalBar; //clsid of bar persisted within vertical band CLSID clsidHorizontalBar; } COOLBARSAVEv15; #define CB_V12 (sizeof(COOLBARSAVEv12)) #define CB_V13 (sizeof(COOLBARSAVEv15)) #define CB_V14 CB_V13 // 14: added fList:1 (in middle!) #define CB_V15 CB_V14 // 15: new rbbi.fStyle semantics #define CB_V17 (sizeof(COOLBARSAVE)) HRESULT CInternetToolbar::_LoadUpgradeSettings(ULONG cbRead) { // If we shipped with the CBS_VERSION you're incrementing, you need // to add upgrade code here for that version, then update this assertion. COMPILETIME_ASSERT(CBS_VERSION == 17); // Double-check our size calculations. #ifndef UNIX COMPILETIME_ASSERT(CB_V12 == (6 * sizeof(UINT) + CBIDX_LAST * sizeof(BANDSAVE))); #endif COMPILETIME_ASSERT(CB_V12 == (CB_V15 - sizeof(CLSID) * 2)); COMPILETIME_ASSERT(CB_V13 == (CB_V12 + 2 * sizeof(CLSID))); COMPILETIME_ASSERT(CB_V14 == (CB_V13 + 0)); COMPILETIME_ASSERT(CB_V15 == (CB_V14 + 0)); COMPILETIME_ASSERT(CB_V17 == (CB_V15 + (MAXEXTERNALBANDS * sizeof(BANDSAVE)) + (MAXEXTERNALBANDS * sizeof(CLSID)))); // If the stream was shorter than the version data field, there's nothing we can do. if (cbRead < sizeof(_cs.cbVer)) { return E_FAIL; } // Check to see if the version is one we know about and that the stream // size is the same as that version's structure size. if (!((_cs.cbVer == 12 && cbRead == CB_V12) || // IE4 (_cs.cbVer == 13 && cbRead == CB_V13) || // ? (_cs.cbVer == 14 && cbRead == CB_V14) || // ? (_cs.cbVer == 15 && cbRead == CB_V15))) // IE5 Beta2 { return E_FAIL; } TraceMsg(DM_WARNING, "citb._lus: try upgrade %d->%d", _cs.cbVer, CBS_VERSION); // Make a scratch copy of _cs so we don't worry about overwriting // parts of _cs we need to read later. COOLBARSAVE cs = _cs; if (_cs.cbVer == 12) { // clsidVerticalBar/clsidHorizontalBar weren't a part // of the structure until v13 cs.clsidVerticalBar = GUID_NULL; cs.clsidHorizontalBar = GUID_NULL; } else { ASSERT(_cs.cbVer < 16); // Band array (bs) grew in v16 to include external bands, so // clsidVerticalBar/clsidHorizontalBar were at a different offset. COOLBARSAVEv15 *pv15 = (COOLBARSAVEv15 *) &_cs; cs.clsidVerticalBar = pv15->clsidVerticalBar; cs.clsidHorizontalBar = pv15->clsidHorizontalBar; cs.bs[CBIDX_LAST].wID = 0xFFFFFFFF; } if (InRange(_cs.cbVer, 12, 13)) { // fList was inserted into the middle of the bitbool list in v14. // Copy the displaced bitbools and initialize fList. COOLBARSAVEv12 *pv12 = (COOLBARSAVEv12 *) &_cs; cs.fAutoHide = pv12->fAutoHide; cs.fStatusBar = pv12->fStatusBar; cs.fSaveInShellIntegrationMode = pv12->fSaveInShellIntegrationMode; cs.fList = DEFAULT_LIST_VALUE(); } // Force FALSE as no longer support vertical itbar mode. cs.fVertical = FALSE; // Strip off any invalid visible band bits cs.uiVisible &= VBF_VALID; // Set current version and copy scratch cs back to _cs cs.cbVer = CBS_VERSION; _cs = cs; return S_OK; } HRESULT CInternetToolbar::_LoadDefaultWidths() { // If there was no max width set for the QL bar or the Toolbar, then // before we use the default, check it the localization people wanted to // increase the width. The RC file string range from '0' to '9' TCHAR szScratch[16]; UINT uiExtraWidth = 0; if (GetSystemMetrics(SM_CXSCREEN) < 650) { MLLoadString(IDS_TB_WIDTH_EXTRA_LORES, szScratch, ARRAYSIZE(szScratch)); _uiMaxTBWidth = MAX_TB_WIDTH_LORES; } else { MLLoadString(IDS_TB_WIDTH_EXTRA_HIRES, szScratch, ARRAYSIZE(szScratch)); _uiMaxTBWidth = MAX_TB_WIDTH_HIRES; } _uiMaxTBWidth += StrToInt(szScratch) * WIDTH_FACTOR; return(NOERROR); } BOOL IsClsidInHKCR(REFGUID pclsid) { HKEY hkeyResult; if (SHRegGetCLSIDKeyW(pclsid, NULL, FALSE, FALSE, &hkeyResult) == ERROR_SUCCESS) { RegCloseKey(hkeyResult); return TRUE; } return FALSE; } typedef struct tagCOOLBARSAVEv2 // IE3 { UINT cbVer; UINT uiMaxTBWidth; UINT uiMaxQLWidth; BOOL fVertical; // The bar is oriented vertically BANDSAVE bs[4]; } COOLBARSAVEv2; #define VBF_VALIDv2 (VBF_TOOLS | VBF_ADDRESS | VBF_LINKS) void CInternetToolbar::_TryLoadIE3Settings() { HKEY hKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegKeyCoolbar, 0, KEY_QUERY_VALUE, &hKey)) { COOLBARSAVEv2 cbv2; DWORD dwcbData = sizeof(cbv2); if (SHQueryValueEx(hKey, TEXT("Layout"), NULL, NULL, (LPBYTE)&cbv2, &dwcbData) == ERROR_SUCCESS) { _cs.uiMaxTBWidth = cbv2.uiMaxTBWidth; _cs.uiMaxQLWidth = cbv2.uiMaxQLWidth; // FEATURE: todo -- read in bs field too; need to do some conversions as // CBIDX_ numbers were zero-based and there was no menuband in IE3. } BOOL fNoText; dwcbData = sizeof(fNoText); if (SHQueryValueEx(hKey, TEXT("NoText"), NULL, NULL, (LPBYTE)&fNoText, &dwcbData) == ERROR_SUCCESS) { // Set the no-text flag. _cs.fNoText = BOOLIFY(fNoText); } UINT uiVisible; dwcbData = sizeof(uiVisible); if (SHQueryValueEx(hKey, TEXT("VisibleBands"), NULL, NULL, (LPBYTE)&uiVisible, &dwcbData) == ERROR_SUCCESS) { // Set the visible bands, changing only the ones that IE3 knew about. _cs.uiVisible = (_cs.uiVisible &~ VBF_VALIDv2) | (uiVisible & VBF_VALIDv2); } RegCloseKey(hKey); } } VOID CInternetToolbar::_UpdateLocking() { // if we have no gripper then turn them off BANDSITEINFO bsinfo; bsinfo.dwMask = BSIM_STYLE; bsinfo.dwStyle = BSIS_LEFTALIGN | (_fLockedToolbar ? BSIS_NOGRIPPER : 0); _bs.SetBandSiteInfo(&bsinfo); _bs._UpdateAllBands(FALSE, TRUE); ResizeBorderDW(NULL, NULL, FALSE); } HRESULT CInternetToolbar::Load(IStream *pstm) { ULONG ulRead; //Read from the given stream and initialize the Toolbar data! _fLoading = TRUE; HRESULT hr = pstm->Read(&_cs, sizeof(COOLBARSAVE), &ulRead); if (SUCCEEDED(hr)) { if (ulRead != sizeof(COOLBARSAVE) || _cs.cbVer != CBS_VERSION) { hr = _LoadUpgradeSettings(ulRead); } } if (FAILED(hr)) { _LoadDefaultSettings(); } ASSERT(_cs.uiVisible & VBF_MENU); // make sure that the settings include a menu _cs.uiVisible |= VBF_MENU; _LoadDefaultWidths(); hr = _CreateBands(); _UpdateLocking(); //if in web view, show the last visible browser bars too if (!_fShellView) { VARIANT varOut = {0}; varOut.vt = VT_I4; if (!IsEqualGUID(_cs.clsidVerticalBar, GUID_NULL) && IsClsidInHKCR(_cs.clsidVerticalBar)) { BOOL fSearch = IsEqualGUID(_cs.clsidVerticalBar, CLSID_SearchBand) || IsEqualGUID(_cs.clsidVerticalBar, CLSID_FileSearchBand); WCHAR wsz[GUIDSTR_MAX]; SHStringFromGUID((const CLSID)_cs.clsidVerticalBar, wsz, ARRAYSIZE(wsz)); #ifdef UNIX // IEUNIX: Donot persist/load MsgBand if (!IsEqualGUID(_cs.clsidVerticalBar, CLSID_MsgBand)) #endif { if (!fSearch) { VARIANT varClsid; varClsid.vt = VT_BSTR; varClsid.bstrVal = wsz; IUnknown_Exec(_pbs2, &CGID_ShellDocView, SHDVID_SHOWBROWSERBAR, 1, &varClsid, &varOut); } else { // if it's the search band, must be shown in this way to get correct search VARIANTARG var; var.vt = VT_I4; var.lVal = -1; Exec(&CLSID_CommonButtons, TBIDM_SEARCH, 0, NULL, &var); } } } if (!IsEqualGUID(_cs.clsidHorizontalBar, GUID_NULL) && IsClsidInHKCR(_cs.clsidHorizontalBar)) { WCHAR wsz[GUIDSTR_MAX]; SHStringFromGUID((const CLSID)_cs.clsidHorizontalBar, wsz, ARRAYSIZE(wsz)); VARIANT varClsid; varClsid.vt = VT_BSTR; varClsid.bstrVal = wsz; IUnknown_Exec(_pbs2, &CGID_ShellDocView, SHDVID_SHOWBROWSERBAR, 1, &varClsid, &varOut); } } _fLoading = FALSE; return hr; } //see APPHACK note below const GUID CLSID_AlexaVert = { 0xBA0B386CL, 0x7143, 0x11d1, 0xba, 0x8c, 0x00, 0x60, 0x08, 0x27, 0x87, 0x8d }; const GUID CLSID_AlexaHorz = { 0xBA0B386EL, 0x7143, 0x11d1, 0xba, 0x8c, 0x00, 0x60, 0x08, 0x27, 0x87, 0x8d }; void CInternetToolbar::_GetVisibleBrowserBar(UINT idBar, CLSID *pclsidOut) { *pclsidOut = GUID_NULL; ASSERT(idBar == IDBAR_VERTICAL || idBar == IDBAR_HORIZONTAL); IDockingWindowFrame *psb; if (_psp && SUCCEEDED(_psp->QueryService(SID_STopLevelBrowser, IID_PPV_ARG(IDockingWindowFrame, &psb)))) { IDeskBar* pdb; if ( (IDBAR_VERTICAL == idBar && (SUCCEEDED(psb->FindToolbar(INFOBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdb))) && pdb)) || (IDBAR_HORIZONTAL == idBar && (SUCCEEDED(psb->FindToolbar(COMMBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdb))) && pdb)) ) { VARIANT varClsid = {0}; if (SUCCEEDED(IUnknown_Exec(pdb, &CGID_DeskBarClient, DBCID_CLSIDOFBAR, 1, NULL, &varClsid))) { if (varClsid.vt == VT_BSTR) { GUIDFromString(varClsid.bstrVal, pclsidOut); VariantClear(&varClsid); } //APPHACK // Alexa 3.0 has some code so that their explorer bar persists that works in ie4. however, when ie5 // persists them, they don't handle the case where the main page has not finished loading yet, which // causes them to fault on launch of the browser. see IE5 55895. if ( (IDBAR_VERTICAL == idBar && (IsEqualGUID(*pclsidOut, CLSID_AlexaVert))) || (IDBAR_HORIZONTAL == idBar && (IsEqualGUID(*pclsidOut, CLSID_AlexaHorz))) ) { *pclsidOut = GUID_NULL; } //END APPHACK } pdb->Release(); } psb->Release(); } } void CInternetToolbar::_BuildSaveStruct(COOLBARSAVE* pcs) { REBARBANDINFO rbbi; RECT rc; static BOOL fBrowserOnly = (WhichPlatform() != PLATFORM_INTEGRATED); //Save into the given stream! ZeroMemory(pcs, sizeof(*pcs)); pcs->cbVer = CBS_VERSION; // Browser Only can't load Shell Integrated streams because of the Favorites // shell extension created pidls unreadable by browser only which doesn't have the Favorites ShellExt pcs->fSaveInShellIntegrationMode = !fBrowserOnly; GetWindowRect(_bs._hwnd, &rc); pcs->cyRebar = RECTHEIGHT(rc); //Save the new fields. pcs->fAutoHide = _fAutoHide; pcs->fNoText = _fCompressed; pcs->fList = IS_LIST_STYLE(_btb._hwnd); pcs->uiVisible = _nVisibleBands; //only persist the visible bars for web view if (!_fShellView) { _GetVisibleBrowserBar(IDBAR_VERTICAL, &pcs->clsidVerticalBar); _GetVisibleBrowserBar(IDBAR_HORIZONTAL, &pcs->clsidHorizontalBar); } //else pcs->clsid*Bar nulled out by memset above LRESULT lStyle = GetWindowLong(_bs._hwnd, GWL_STYLE); pcs->fVertical = BOOLIFY(lStyle & CCS_VERT); pcs->uiMaxTBWidth = _uiMaxTBWidth; rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_STYLE | RBBIM_SIZE | RBBIM_ID; int icBands = (int) SendMessage(_bs._hwnd, RB_GETBANDCOUNT, 0, 0); for (int i = 0; i < icBands; i++) { pcs->bs[i].wID = 0xFFFFFFFF; if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { if (rbbi.wID < CBANDSMAX) { // desk band objects have the choice of not saving there visibility // state CBandItemData *pbid = _bs._GetBandItem(i); if (pbid) { UINT uiMask = rbbi.wID <= CBIDX_LAST ? ( 1 << (rbbi.wID - 1) ) : EXTERNALBAND_VBF_BIT(rbbi.wID - CBIDX_LAST-1); if (pbid->pdb && (pcs->uiVisible & uiMask)) { OLECMD cmd; cmd.cmdID = CITIDM_DISABLEVISIBILITYSAVE; cmd.cmdf = 0; IUnknown_QueryStatus(pbid->pdb, &CGID_PrivCITCommands, 1, &cmd, NULL); if (cmd.cmdf & OLECMDF_ENABLED) { pcs->uiVisible &= ~uiMask; rbbi.fStyle |= RBBS_HIDDEN; } } pbid->Release(); } pcs->bs[i].fStyle = rbbi.fStyle; pcs->bs[i].cx = rbbi.cx; pcs->bs[i].wID = rbbi.wID; if (IS_EXTERNALBAND(rbbi.wID)) { pcs->aclsidExternalBands[MAP_TO_EXTERNAL(rbbi.wID)] = _rgebi[MAP_TO_EXTERNAL(rbbi.wID)].clsid; } } } } // Query CShellBrowser for status bar state VARIANTARG v = { 0 }; v.vt = VT_I4; IUnknown_Exec(_ptbsite, &CGID_ShellBrowser, FCIDM_GETSTATUSBAR, 0, NULL, &v); pcs->fStatusBar = v.lVal; } typedef struct tagCLSID_BANDTYPE { const CLSID * pclsid; DWORD dwBandID; } CLSID_BANDTYPE; CLSID_BANDTYPE c_CLSIDsToSave[] = { {&CLSID_AddressBand, CBIDX_ADDRESS}, {&CLSID_QuickLinks, CBIDX_LINKS}, }; HRESULT CInternetToolbar::Save(IStream *pstm, BOOL fClearDirty) { COOLBARSAVE cs; HRESULT hr = S_FALSE; // avoid the hit of saving when we are still loading. State will not have // changed, at least not enough to justify saving, until after we are loaded. if (_fLoading) return S_OK; // Check the dirty bit to see if we need to save. if (!_fDirty) return S_OK; // if we failed during creation, our current state isnt good enough to persist. if (_fDontSave) return S_OK; ASSERT(!_fTheater); _BuildSaveStruct(&cs); if(SUCCEEDED(hr = pstm->Write(&cs, sizeof(COOLBARSAVE), NULL)) && fClearDirty) _fDirty = FALSE; REBARBANDINFO rbbi; rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_ID; int icBands = (int) SendMessage( _bs._hwnd, RB_GETBANDCOUNT, 0, 0 ); for (int i = 0; i < icBands; i++) { if (SendMessage(_bs._hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi)) { if ((rbbi.wID == CBIDX_ADDRESS) || (rbbi.wID == CBIDX_LINKS) || IS_EXTERNALBAND(rbbi.wID)) { CBandItemData *pbid = _bs._GetBandItem( i ); if (pbid) { if (pbid->pdb) { IPersistStream *pStream; if (SUCCEEDED(pbid->pdb->QueryInterface(IID_PPV_ARG(IPersistStream, &pStream)))) { CLSID clsid; if (SUCCEEDED(pStream->GetClassID(&clsid))) { TCHAR szGUID[MAX_PATH]; SHStringFromGUID( clsid, szGUID, ARRAYSIZE(szGUID) ); IStream *pstm = GetRegStream( _fInitialPidlIsWeb, szGUID, STGM_WRITE | STGM_CREATE ); if (pstm) { HRESULT hrInternal = _bs.SaveToStreamBS(pbid->pdb, pstm); // Only return Success values if (SUCCEEDED(hrInternal)) hr = S_OK; pstm->Release(); } } pStream->Release(); } } pbid->Release(); } } } } return(hr); } HRESULT CInternetToolbar::InitNew(void) { // This shouldn't get called if Load has already been called, so assert // that _cs is uninitialized. ASSERT(_cs.cbVer == 0); _LoadDefaultSettings(); // Look for any IE3 settings and override defaults with those. (IE3 // wrote structures directly to registry, rather than via IPersistStream). _TryLoadIE3Settings(); _LoadDefaultWidths(); return S_OK; } BOOL CInternetToolbar::_SendToToolband(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres) { return _bs._SendToToolband(hwnd, uMsg, wParam, lParam, plres); } HRESULT CInternetToolbar::IsDirty(void) { if (_fDirty && !_fLoading) return S_OK; else return S_FALSE; } HRESULT CInternetToolbar::QueryService(REFGUID guidService, REFIID riid, void **ppvObj) { *ppvObj = NULL; HRESULT hr = E_NOTIMPL; if (IsEqualIID(guidService, SID_IBandProxy)) { hr = QueryService_SID_IBandProxy(SAFECAST(_ptbsitect, IUnknown *), riid, &_pbp, ppvObj); if (!_pbp) { // We need to create it ourselves since our parent couldn't help ASSERT(FALSE == _fCreatedBandProxy); hr = CreateIBandProxyAndSetSite(SAFECAST(_ptbsitect, IUnknown *), riid, &_pbp, ppvObj); if (_pbp) { ASSERT(S_OK == hr); _fCreatedBandProxy = TRUE; } } } else if (IsEqualGUID(guidService, IID_IBandSite)) { hr = _bs.QueryInterface(riid, ppvObj); } else if (IsEqualGUID(guidService, IID_IAddressBand)) { hr = E_FAIL; CBandItemData *pbid = _bs._GetBandItemDataStructByID(CBIDX_ADDRESS); if (pbid) { if (pbid->pdb) { hr = pbid->pdb->QueryInterface(riid, ppvObj); } pbid->Release(); } } else if (_psp) { hr = _psp->QueryService(guidService, riid, ppvObj); } else { hr = SUPERCLASS::QueryService(guidService, riid, ppvObj); } return hr; } // // FEATURE: Do we really need to implement the following two functions? // Currently nobody uses them. // HRESULT CInternetToolbar::GetClassID(GUID *pguid) { *pguid = CLSID_InternetToolbar; return(S_OK); } HRESULT CInternetToolbar::GetSizeMax(ULARGE_INTEGER *ulMaxSize) { ulMaxSize->LowPart = sizeof(COOLBARSAVE); ulMaxSize->HighPart = 0; return(S_OK); } CInternetToolbar::CITBandSite::CITBandSite() : CBandSite(NULL) { // HACKHACK: set the initial band ID to something bigger // than the number of toolbars that is in this // object. Currently those toolbars are not // individual bands, but we want CBandSite to // at least be aware of them. // _dwBandIDNext = CBANDSMAX; } HRESULT CInternetToolbar::CITBandSite::_OnContextMenu(WPARAM wParam, LPARAM lParam) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _bs, this); pitbar->_ShowContextMenu((HWND)wParam, lParam, NULL); return S_OK; } HRESULT CInternetToolbar::CITBandSite::_Initialize(HWND hwndParent) { _hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_REGISTERDROP | RBS_DBLCLKTOGGLE | WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | // WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN, 0, 0, 100, 36, hwndParent, (HMENU) FCIDM_REBAR, HINST_THISDLL, NULL); if (_hwnd) { Comctl32_SetWindowTheme(_hwnd, TEXT("ExplorerToolbar")); SendMessage(_hwnd, RB_SETTEXTCOLOR, 0, CLR_DEFAULT); SendMessage(_hwnd, RB_SETBKCOLOR, 0, CLR_DEFAULT); SendMessage(_hwnd, CCM_SETVERSION, COMCTL32_VERSION, 0); } return CBandSite::_Initialize(hwndParent); } HRESULT CInternetToolbar::CITBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { if (!pguidCmdGroup) { /*NOTHING*/ } else if (IsEqualGUID(CGID_PrivCITCommands, *pguidCmdGroup)) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _bs, this); return pitbar->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } else if (IsEqualGUID(CGID_Theater, *pguidCmdGroup)) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _bs, this); return IUnknown_Exec(pitbar->_ptbsite, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } return CBandSite::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } HRESULT CInternetToolbar::CITBandSite::AddBand(IUnknown *punk) { HRESULT hres = CBandSite::AddBand(punk); if (SUCCEEDED(hres)) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _bs, this); pitbar->_SetBackground(); } return hres; } HRESULT CInternetToolbar::CITBandSite::HasFocusIO() { HRESULT hres = CBandSite::HasFocusIO(); if (hres == S_FALSE) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _bs, this); if (pitbar->_btb._hwnd == GetFocus()) hres = S_OK; } return hres; } // This will remove all the buttons except the first 2 BOOL TOOLSBANDCLASS::_RemoveAllButtons() { INT_PTR nCount = SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0L); if (!nCount) return FALSE; while (nCount-- > 0) { SendMessage(_hwnd, TB_DELETEBUTTON, nCount, 0L); } return S_OK; } HRESULT TOOLSBANDCLASS::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); if (!pguidCmdGroup) { /*NOTHING*/ #ifdef DEBUG } else if (IsEqualGUID(*pguidCmdGroup, IID_IExplorerToolbar)) { switch(nCmdID) { case ETCMDID_GETBUTTONS: // if this rips call tjgreen ASSERT(0); return E_FAIL; } #endif } else if (_IsDocHostGUID(pguidCmdGroup)) { UEMFireEvent(&UEMIID_BROWSER, UEME_UITOOLBAR, UEMF_XEVENT, UIG_INET, nCmdID); if (nCmdexecopt == OLECMDEXECOPT_PROMPTUSER) { // the user hit the drop down if (pitbar->_ptbsitect && pvarargIn && pvarargIn->vt == VT_INT_PTR) { // v.vt = VT_I4; POINT pt; RECT* prc = (RECT*)pvarargIn->byref; pt.x = prc->left; pt.y = prc->bottom; switch (nCmdID) { case DVIDM_EDITPAGE: { // Show the edit pop-up BSTR bstrURL; pitbar->_pdie->get_LocationURL(&bstrURL); if (bstrURL) { pitbar->_aEditVerb.ShowEditMenu(pt, pitbar->_hwnd, bstrURL); SysFreeString(bstrURL); } break; } default: // if this rips find tjgreen ASSERT(0); break; } } return S_OK; } switch(nCmdID) { case DVIDM_EDITPAGE: { BSTR bstrURL; ULONG fMask = 0; TCHAR szCacheFileName[MAX_PATH + MAX_URL_STRING + 2]; memset(szCacheFileName, 0, sizeof(szCacheFileName)); pitbar->_pdie->get_LocationURL(&bstrURL); if (NULL == bstrURL) break; // Use the default edit verb pitbar->_aEditVerb.Edit(bstrURL); } break; default: // if this rips call tjgreen ASSERT(0); break; } } return S_OK; } // *** IInputObject methods *** HRESULT TOOLSBANDCLASS::TranslateAcceleratorIO(LPMSG lpMsg) { if (SendMessage(_hwnd, TB_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg)) return S_OK; return CToolBand::TranslateAcceleratorIO(lpMsg); } // *** IUnknown methods *** HRESULT TOOLSBANDCLASS::QueryInterface(REFIID riid, void ** ppvObj) { static const QITAB qit[] = { QITABENT(TOOLSBANDCLASS, IWinEventHandler), { 0 }, }; HRESULT hres = QISearch(this, qit, riid, ppvObj); if (FAILED(hres)) hres = CToolBand::QueryInterface(riid, ppvObj); return hres; } // *** IDeskBand methods *** HRESULT TOOLSBANDCLASS::GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi) { _dwBandID = dwBandID; // set dwModeFlags pdbi->dwModeFlags = DBIMF_FIXEDBMP | DBIMF_USECHEVRON; // set ptMinSize { if (SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0)) { // make our min size just big enough to show the first button RECT rc; SendMessage(_hwnd, TB_GETITEMRECT, 0, (LPARAM)&rc); pdbi->ptMinSize.x = RECTWIDTH(rc); pdbi->ptMinSize.y = RECTHEIGHT(rc); } else { // we don't have any buttons; so use standard button size LONG lButtonSize = (long) SendMessage(_hwnd, TB_GETBUTTONSIZE, 0, 0); pdbi->ptMinSize.x = LOWORD(lButtonSize); pdbi->ptMinSize.y = HIWORD(lButtonSize); } CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); if (pitbar->_fTheater && (pdbi->ptMinSize.y < (THEATER_CYTOOLBAR - 1))) pdbi->ptMinSize.y = (THEATER_CYTOOLBAR - 1); } // set ptActual { SIZE size; size.cy = pdbi->ptMinSize.y; SendMessage(_hwnd, TB_GETIDEALSIZE, FALSE, (LPARAM)&size); pdbi->ptActual.x = size.cx; pdbi->ptActual.y = size.cy; } // no title pdbi->dwMask &= ~DBIM_TITLE; return S_OK; } IOleCommandTarget* TOOLSBANDCLASS::_CommandTargetFromCmdMap(CMDMAP* pcm) { IOleCommandTarget* pct = NULL; if (pcm) { if (IsEqualGUID(pcm->guidButtonGroup, CLSID_CommonButtons)) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); pct = SAFECAST(pitbar, IOleCommandTarget*); } else { // If either of these rip, the button is stale ASSERT(IsEqualGUID(pcm->guidButtonGroup, _guidCurrentButtonGroup)); ASSERT(_pctCurrentButtonGroup); pct = _pctCurrentButtonGroup; } } return pct; } BOOL ShiftRectToEdgeOfMonitor(RECT *prc) { BOOL bRet = FALSE; POINT pt = {prc->left, prc->top}; HMONITOR hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); if (hmon) { MONITORINFO mi = {sizeof(MONITORINFO)}; if (GetMonitorInfo(hmon, &mi)) { // get the different between the monitor's left edge and the rect's left edge int iShift = mi.rcMonitor.left - prc->left; if (iShift > 0) { prc->left += iShift; prc->right += iShift; bRet = TRUE; } } } return bRet; } LRESULT TOOLSBANDCLASS::_OnToolbarDropDown(TBNOTIFY *ptbn) { if (ptbn->hdr.hwndFrom == _hwnd) { CMDMAP* pcm = _GetCmdMapByID(ptbn->iItem); IOleCommandTarget* pct = _CommandTargetFromCmdMap(pcm); if (pct) { VARIANTARG var; var.vt = VT_I4; var.lVal = ptbn->iItem; // REARCHITECT: use VARIANT[TO/FROM]BUFFER here to fix win64 problem VARIANT v = {VT_INT_PTR}; v.byref = &ptbn->rcButton; MapWindowRect(_hwnd, HWND_DESKTOP, &ptbn->rcButton); // // If this window is mirrored, then let's take the // other coordinate [samera] // if (IS_WINDOW_RTL_MIRRORED(_hwnd)) { int iTmp = ptbn->rcButton.right; ptbn->rcButton.right = ptbn->rcButton.left; ptbn->rcButton.left = iTmp; } // TrackMenuPopup is lame when confronted with negative co-ordinates... lets clip to the edge of the screen. ShiftRectToEdgeOfMonitor(&ptbn->rcButton); // FEATURE: temp code -- edit code moving to dochost.cpp if (_IsDocHostGUID(&pcm->guidButtonGroup) && pcm->nCmdID == DVIDM_EDITPAGE) Exec(&pcm->guidButtonGroup, (DWORD)pcm->nCmdID, OLECMDEXECOPT_PROMPTUSER, &v, &var); else pct->Exec(&pcm->guidButtonGroup, (DWORD)pcm->nCmdID, OLECMDEXECOPT_PROMPTUSER, &v, &var); } } return TBDDRET_DEFAULT; } LRESULT TOOLSBANDCLASS::_TryShowBackForwardMenu(DWORD dwItemSpec, LPPOINT ppt, LPRECT prcExclude) { LRESULT lres = 0; GUID guid; UINT id; if (SUCCEEDED(_ConvertCmd(NULL, dwItemSpec, &guid, &id))) { // If the user right clicked on the the back or forward button, show the context menu // On all other buttons show the regular shortcut menu if (IsEqualGUID(guid, CLSID_CommonButtons)) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); if (id == TBIDM_BACK) { pitbar->_ShowBackForwardMenu(FALSE, *ppt, prcExclude); lres = 1; } else if (id == TBIDM_FORWARD) { pitbar->_ShowBackForwardMenu(TRUE, *ppt, prcExclude); lres = 1; } } } return lres; } LRESULT TOOLSBANDCLASS::_OnNotify(LPNMHDR pnmh) { LRESULT lres = 0; ASSERT(pnmh->idFrom == FCIDM_TOOLBAR); switch (pnmh->code) { case NM_RCLICK: { NMCLICK * pnm = (LPNMCLICK)pnmh; if (!pnm) break; // Convert to Screen coordinates MapWindowPoints(pnmh->hwndFrom, HWND_DESKTOP, &pnm->pt, 1); if (pnmh->hwndFrom == _hwnd) lres = _TryShowBackForwardMenu((DWORD)pnm->dwItemSpec, &pnm->pt, NULL); } break; case TBN_DROPDOWN: lres = _OnToolbarDropDown((TBNOTIFY *)pnmh); break; case TBN_DELETINGBUTTON: _OnDeletingButton((TBNOTIFY*)pnmh); break; case TBN_SAVE: case TBN_RESET: case TBN_INITCUSTOMIZE: case TBN_RESTORE: case TBN_BEGINADJUST: case TBN_GETBUTTONINFO: case TBN_ENDADJUST: case TBN_QUERYDELETE: case TBN_QUERYINSERT: case TBN_TOOLBARCHANGE: if (pnmh->hwndFrom == _hwnd) lres = _ToolsCustNotify (pnmh); break; case TBN_GETOBJECT: { NMOBJECTNOTIFY *pnmon = (NMOBJECTNOTIFY *)pnmh; if (IsEqualIID(*pnmon->piid, IID_IDropTarget)) { if (pnmh->hwndFrom == _hwnd) { UINT uiCmd; GUID guid; _ConvertCmd(NULL, pnmon->iItem, &guid, &uiCmd); if (IsEqualGUID(guid, CLSID_CommonButtons) && (uiCmd == TBIDM_HOME || uiCmd == TBIDM_FAVORITES)) { CITBarDropTarget *pdtgt = new CITBarDropTarget(_hwnd, uiCmd); if (pdtgt) { pnmon->pObject = SAFECAST(pdtgt, IDropTarget*); pnmon->hResult = NOERROR; } } else // pass back CDropDummy to handle basics. { CDropDummy *pdtgt = new CDropDummy(_hwnd); if (pdtgt) { pnmon->pObject = SAFECAST(pdtgt, IDropTarget*); pnmon->hResult = NOERROR; } } } lres = TRUE; } } break; default: lres = CToolbarBand::_OnNotify(pnmh); break; } return lres; } LRESULT TOOLSBANDCLASS::_OnContextMenu(LPARAM lParam, WPARAM wParam) { LRESULT lres = 0; if (IS_WM_CONTEXTMENU_KEYBOARD(lParam)) { // keyboard context menu. figure out where to pop up menu and // which context menu to use, and tell itbar to pop it up. RECT rc; BOOL fBackForward = FALSE; // figure out coordinates to use INT_PTR iBtn = SendMessage(_hwnd, TB_GETHOTITEM, 0, 0); if (iBtn != -1) { // use lower left corner of current hot button SendMessage(_hwnd, TB_GETITEMRECT, iBtn, (LPARAM)&rc); } else { // no hot button; use top left corner of tools window SetRect(&rc, 0, 0, 0, 0); } MapWindowPoints(_hwnd, HWND_DESKTOP, (LPPOINT)&rc, 2); if (iBtn != -1) { // get hot button's command TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(TBBUTTONINFO); tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; SendMessage(_hwnd, TB_GETBUTTONINFO, iBtn, (LPARAM)&tbbi); POINT pt = {rc.left, rc.bottom}; // try popping up the back/forward context menu if (_TryShowBackForwardMenu(tbbi.idCommand, &pt, &rc)) fBackForward = TRUE; } if (!fBackForward) { // pop up the standard context menu CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); pitbar->_ShowContextMenu((HWND)wParam, MAKELONG(rc.left, rc.bottom), (iBtn == -1 ? NULL : &rc)); } lres = 1; } return lres; } void TOOLSBANDCLASS::_RecalcButtonWidths() { // We need the toolbars buttons to use ONLY exactly as much space as is needed. // By setting the size a a really small number like 10, and then setting it to // the real number we can accomplish this. // If we don't use do this, then when we add new buttons after doing this // RemoveAllButtons(), the new buttons will be at least as wide as the widest // button that existed on the last set of buttons (the ones we are just removing) CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); SendMessage(_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM)MAKELONG(0, 10)); SendMessage(_hwnd, TB_SETBUTTONWIDTH, 0, (LPARAM)(pitbar->_fCompressed ? MAKELONG(0, MAX_TB_COMPRESSED_WIDTH) : MAKELONG(0, pitbar->_uiMaxTBWidth))); } // *** IWinEventHandler methods *** HRESULT TOOLSBANDCLASS::OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres) { HRESULT hres = S_OK; switch (dwMsg) { case WM_CONTEXTMENU: *plres = _OnContextMenu(lParam, wParam); break; case WM_NOTIFY: *plres = _OnNotify((LPNMHDR)lParam); break; case WM_WININICHANGE: *plres = SendMessage(_hwnd, dwMsg, wParam, lParam); if (wParam == SPI_SETNONCLIENTMETRICS) { _RecalcButtonWidths(); _BandInfoChanged(); } break; default: hres = CToolbarBand::OnWinEvent(hwnd, dwMsg, wParam, lParam, plres); break; } return hres; } CMDMAP* TOOLSBANDCLASS::_GetCmdMap(int i, BOOL fByIndex) { TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_LPARAM; tbbi.lParam = 0; if (fByIndex) tbbi.dwMask |= TBIF_BYINDEX; SendMessage(_hwnd, TB_GETBUTTONINFO, i, (LPARAM)&tbbi); return (CMDMAP*)(void*)tbbi.lParam; } void TOOLSBANDCLASS::_FreeCmdMap(CMDMAP* pcm) { if (pcm) LocalFree(pcm); } void TOOLSBANDCLASS::_OnDeletingButton(TBNOTIFY* ptbn) { CMDMAP *pcm = (CMDMAP*)(void*)ptbn->tbButton.dwData; _FreeCmdMap(pcm); } LONG_PTR TOOLSBANDCLASS::_AddString(LPWSTR pwstr) { LONG_PTR lOffset; CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); pitbar->AddString(&_guidCurrentButtonGroup, 0, (UINT_PTR)pwstr, &lOffset); return lOffset; } #define PPBS_LOOKINTOOLBAR 0x00000001 #define PPBS_EXTERNALBUTTON 0x00000002 void TOOLSBANDCLASS::_PreProcessButtonString(TBBUTTON *ptbn, DWORD dwFlags) { // Caller should have checked this. ASSERT(!(ptbn->fsStyle & BTNS_SEP)); // If we don't have a command target, we shouldn't have any external buttons. ASSERT(_pctCurrentButtonGroup || !(dwFlags & PPBS_EXTERNALBUTTON)); if (ptbn->iString < 0 && ptbn->iBitmap <= MAX_SHELLGLYPHINDEX) { // total hack // we're hard coding the strings in to match // the bitmap. so if anyone uses the shell bitmaps, // they're going to get our text labels // also hacking in that the bitmap array and string array are // matched // who designed reviewed this??? ptbn->iString = ptbn->iBitmap; } else if (!ptbn->iString && (dwFlags & PPBS_EXTERNALBUTTON)) { // Some Extensions are giving us bogus string ids (Font ext sends 0) ptbn->iString = -1; } else if (ptbn->iString != -1 && !IS_INTRESOURCE(ptbn->iString)) { // It's a string pointer. The customization mechanism requires that all buttons // use strings from the tb string pool. So add the string to the pool and set // iString to the pool index. ptbn->iString = _AddString((LPWSTR)ptbn->iString); } if (ptbn->iString == -1 && IsFlagSet(dwFlags, PPBS_LOOKINTOOLBAR | PPBS_EXTERNALBUTTON)) { // If we're building the customization dsa rather than adding new buttons to the // toolbar, we may already have this button in the toolbar. If so, use that string. UINT idCommand; if (SUCCEEDED(_ConvertCmd(&_guidCurrentButtonGroup, ptbn->idCommand, NULL, &idCommand))) { TBBUTTON tbb; if (SendMessage(_hwnd, TB_GETBUTTON, idCommand, (LPARAM)&tbb)) ptbn->iString = tbb.iString; } } if (ptbn->iString == -1 && (dwFlags & PPBS_EXTERNALBUTTON)) { // Still don't have a string for this puppy. Last resort is to ask via QueryStatus. OLECMDTEXTV cmdtv; OLECMDTEXT *pcmdText = &cmdtv; pcmdText->cwBuf = MAX_TOOLTIP_STRING; pcmdText->cmdtextf = OLECMDTEXTF_NAME; pcmdText->cwActual = 0; OLECMD rgcmd = {ptbn->idCommand, 0}; HRESULT hr = _pctCurrentButtonGroup->QueryStatus(&_guidCurrentButtonGroup, 1, &rgcmd, pcmdText); if (SUCCEEDED(hr) && (pcmdText->cwActual)) ptbn->iString = _AddString(pcmdText->rgwz); } // If it's an internal button, we'd better have found a string for it. ASSERT(ptbn->iString != -1 || (dwFlags & PPBS_EXTERNALBUTTON)); } void TOOLSBANDCLASS::_PreProcessExternalTBButton(TBBUTTON *ptbn) { if (!(ptbn->fsStyle & BTNS_SEP)) { CMDMAP* pcm = (CMDMAP*)LocalAlloc(LPTR, sizeof(CMDMAP)); if (pcm) { pcm->guidButtonGroup = _guidCurrentButtonGroup; pcm->nCmdID = ptbn->idCommand; _PreProcessButtonString(ptbn, PPBS_EXTERNALBUTTON); _nNextCommandID++; pcm->lParam = ptbn->dwData; } ptbn->dwData = (LPARAM)pcm; } else { ptbn->dwData = 0; // override default toolbar width for separators; iBitmap member of // TBBUTTON struct is a union of bitmap index & separator width ptbn->iBitmap = CX_SEPARATOR; } } UINT TOOLSBANDCLASS::_ProcessExternalButtons(PTBBUTTON ptbb, UINT cButtons) { cButtons = RemoveHiddenButtons(ptbb, cButtons); for (UINT i = 0; i < cButtons; i++) _PreProcessExternalTBButton(&ptbb[i]); return cButtons; } void TOOLSBANDCLASS::_GetButtons(IOleCommandTarget* pct, const GUID* pguid, HDSA hdsa) { LONG lCount; VARIANTARG v1; VariantInit(&v1); v1.vt = VT_BYREF | VT_I4; v1.plVal = &lCount; VARIANTARG v2; VariantInit(&v2); if (SUCCEEDED(pct->Exec(&IID_IExplorerToolbar, ETCMDID_GETBUTTONS, 0, &v1, &v2)) && v2.vt == VT_BYREF) { CMDMAPCUSTOMIZE cmc; TBBUTTON* pbtn = (TBBUTTON*)v2.byref; cmc.cm.guidButtonGroup = *pguid; DWORD dwFlags = PPBS_LOOKINTOOLBAR; if (!IsEqualGUID(*pguid, CLSID_CommonButtons)) dwFlags |= PPBS_EXTERNALBUTTON; for (long l = 0; l < lCount; l++) { cmc.btn = pbtn[l]; if (!(cmc.btn.fsStyle & BTNS_SEP)) { cmc.cm.nCmdID = pbtn[l].idCommand; _PreProcessButtonString(&cmc.btn, dwFlags); if (FAILED(_ConvertCmd(pguid, cmc.cm.nCmdID, NULL, (UINT*)&cmc.btn.idCommand))) { // not already in the toolbar, generate a new id cmc.btn.idCommand = _nNextCommandID++; } DSA_AppendItem(hdsa, &cmc); } else { cmc.btn.dwData = 0; } } } } void TOOLSBANDCLASS::_OnEndCustomize() { if (_pcinfo) { // loop through and make sure that any items added have the appropriate cmdmap int i; INT_PTR nCount = SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0L); _pcinfo->fAdjust = FALSE; for(i = 0; i < nCount; i++) { CMDMAP* pcm = _GetCmdMapByIndex(i); if (!pcm) { // no command map for this item // find the corresponding CMDMAP in our hdsa, clone it and give it to this button. // the command id's are the same, so get the toolbar command id, find the corresponding // one in the hdsa and clone away. TBBUTTONINFO tbbi; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_COMMAND | TBIF_BYINDEX; SendMessage(_hwnd, TB_GETBUTTONINFO, i, (LPARAM)&tbbi); int j; for (j = 0; j < DSA_GetItemCount(_pcinfo->hdsa); j++) { CMDMAPCUSTOMIZE* pcmc = (CMDMAPCUSTOMIZE*)DSA_GetItemPtr(_pcinfo->hdsa, j); ASSERT(pcmc); if (pcmc->btn.idCommand == tbbi.idCommand) { // found it! // clone the cmdmap CMDMAP *pcm = (CMDMAP*)LocalAlloc(LPTR, sizeof(CMDMAP)); if (pcm) { *pcm = pcmc->cm; tbbi.lParam = (LPARAM)pcm; tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX; SendMessage(_hwnd, TB_SETBUTTONINFO, i, (LPARAM)&tbbi); } } } } } if (_pcinfo->fDirty) _SaveRestoreToolbar(TRUE); _FreeCustomizeInfo(); _RecalcButtonWidths(); CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); pitbar->_InitEditButtonStyle(); if (g_fSmallIcons != _UseSmallIcons()) { SendShellIEBroadcastMessage(WM_WININICHANGE, 0, (LPARAM)SZ_REGKEY_SMALLICONS, 3000); // Resize the Theater Controls based upon the icon changes. IUnknown_Exec( _punkSite, &CGID_Theater, THID_RECALCSIZING, 0, NULL, NULL ); } pitbar->_UpdateToolbar(TRUE); } } void TOOLSBANDCLASS::_FreeCustomizeInfo() { if (_pcinfo) { DSA_Destroy(_pcinfo->hdsa); _pcinfo->hdsa = NULL; LocalFree(_pcinfo); _pcinfo = NULL; } } CMDMAPCUSTOMIZE* TOOLSBANDCLASS::_GetCmdMapCustomize(GUID* pguid, UINT nCmdID) { int j; for (j = 0; j < DSA_GetItemCount(_pcinfo->hdsa); j++) { CMDMAPCUSTOMIZE* pcmc = (CMDMAPCUSTOMIZE*)DSA_GetItemPtr(_pcinfo->hdsa, j); if (pcmc->cm.nCmdID == nCmdID && IsEqualGUID(*pguid, pcmc->cm.guidButtonGroup)) { return pcmc; } } return NULL; } BOOL TOOLSBANDCLASS::_BuildButtonDSA() { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); ASSERT(!_pcinfo); _pcinfo = (CUSTOMIZEINFO*)LocalAlloc(LPTR, sizeof(CUSTOMIZEINFO)); if (_pcinfo) { // build a CMDMAP array of all the buttons available _pcinfo->hdsa = DSA_Create(sizeof(CMDMAPCUSTOMIZE), 4); if (_pcinfo->hdsa) { // add the common set (back,forward, stop, refresh, home and search _GetButtons(pitbar, &CLSID_CommonButtons, _pcinfo->hdsa); _GetButtons(_pctCurrentButtonGroup, &_guidCurrentButtonGroup, _pcinfo->hdsa); return TRUE; } else { _FreeCustomizeInfo(); return FALSE; } } return FALSE; } void TOOLSBANDCLASS::_UpdateTextSettings(INT_PTR ids) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); BOOL fText, fList; switch (ids) { case IDS_TEXTLABELS: fList = FALSE; fText = TRUE; break; case IDS_PARTIALTEXT: fList = TRUE; fText = TRUE; break; case IDS_NOTEXTLABELS: fList = FALSE; // (but we really don't care) fText = FALSE; break; default: ASSERT(0); fList = FALSE; fText = FALSE; break; } pitbar->_UpdateToolsStyle(fList); // (_fCompressed == TRUE means no text labels) pitbar->_UpdateToolbarDisplay(UTD_TEXTLABEL, 0, !fText, TRUE); } const static DWORD c_aBtnAttrHelpIDs[] = { IDC_SHOWTEXT, IDH_BROWSEUI_TB_TEXTOPTNS, IDC_SMALLICONS, IDH_BROWSEUI_TB_ICONOPTNS, 0, 0 }; BOOL_PTR CALLBACK TOOLSBANDCLASS::_BtnAttrDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CInternetToolbar* pitbar = (CInternetToolbar*)GetWindowPtr(hDlg, DWLP_USER); switch (uMsg) { case WM_INITDIALOG: SetWindowLongPtr(hDlg, DWLP_USER, lParam); /* LPADJUSTDLGDATA pointer */ return TRUE; case WM_COMMAND: if (GET_WM_COMMAND_ID(wParam, lParam) == IDC_SHOWTEXT) { if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELENDOK || GET_WM_COMMAND_CMD(wParam, lParam) == CBN_CLOSEUP) { // what'd they pick? HWND hwndText = GET_WM_COMMAND_HWND(wParam, lParam); INT_PTR iSel = SendMessage(hwndText, CB_GETCURSEL, 0, 0); INT_PTR idsSel = SendMessage(hwndText, CB_GETITEMDATA, iSel, 0); pitbar->_btb._UpdateTextSettings(idsSel); return TRUE; } } break; case WM_CONTEXTMENU: SHWinHelpOnDemandWrap((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)(LPTSTR) c_aBtnAttrHelpIDs); return TRUE; case WM_HELP: SHWinHelpOnDemandWrap((HWND) ((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile, HELP_WM_HELP, (DWORD_PTR)(LPTSTR) c_aBtnAttrHelpIDs); return TRUE; case WM_DESTROY: { #define SZ_YES TEXT("yes") #define SZ_NO TEXT("no") HWND hwndIcons = GetDlgItem(hDlg, IDC_SMALLICONS); if (TPTR(hwndIcons)) { INT_PTR iSel = SendMessage(hwndIcons, CB_GETCURSEL, 0, 0); BOOL fSmallIcons = (SendMessage(hwndIcons, CB_GETITEMDATA, iSel, 0) == IDS_SMALLICONS); LPCTSTR szData; DWORD cbData; if (fSmallIcons) { szData = SZ_YES; cbData = sizeof(SZ_YES); } else { szData = SZ_NO; cbData = sizeof(SZ_NO); } SHRegSetUSValue(SZ_REGKEY_SMALLICONS, SZ_REGVALUE_SMALLICONS, REG_SZ, (void*)szData, cbData, SHREGSET_FORCE_HKCU); } } return TRUE; } return FALSE; } void TOOLSBANDCLASS::_PopulateComboBox(HWND hwnd, const int iResource[], UINT cResources) { TCHAR sz[256]; // loop through iResource[], load each string resource and insert into combobox for (UINT i = 0; i < cResources; i++) { if (MLLoadString(iResource[i], sz, ARRAYSIZE(sz))) { INT_PTR iIndex = SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)sz); SendMessage(hwnd, CB_SETITEMDATA, iIndex, iResource[i]); } } } void TOOLSBANDCLASS::_SetComboSelection(HWND hwnd, int iCurOption) { INT_PTR cItems = SendMessage(hwnd, CB_GETCOUNT, 0, 0); while (cItems--) { INT_PTR iItemData = SendMessage(hwnd, CB_GETITEMDATA, cItems, 0); if (iItemData == iCurOption) { SendMessage(hwnd, CB_SETCURSEL, cItems, 0); break; } else { // iCurOption should be in list somewhere; // assert that we're not done looking ASSERT(cItems); } } } void TOOLSBANDCLASS::_SetDialogSelections(HWND hDlg, BOOL fSmallIcons) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); int iCurOption; HWND hwnd; hwnd = GetDlgItem(hDlg, IDC_SHOWTEXT); if (pitbar->_fCompressed) iCurOption = IDS_NOTEXTLABELS; else if (IS_LIST_STYLE(_hwnd)) iCurOption = IDS_PARTIALTEXT; else iCurOption = IDS_TEXTLABELS; _SetComboSelection(hwnd, iCurOption); if (pitbar->_fTheater) SHSetWindowBits(hwnd, GWL_STYLE, WS_DISABLED, WS_DISABLED); hwnd = GetDlgItem(hDlg, IDC_SMALLICONS); iCurOption = (fSmallIcons ? IDS_SMALLICONS : IDS_LARGEICONS); _SetComboSelection(hwnd, iCurOption); } static const int c_iTextOptions[] = { IDS_TEXTLABELS, IDS_PARTIALTEXT, IDS_NOTEXTLABELS, }; static const int c_iIconOptions[] = { IDS_SMALLICONS, IDS_LARGEICONS, }; void TOOLSBANDCLASS::_PopulateDialog(HWND hDlg) { HWND hwnd; hwnd = GetDlgItem(hDlg, IDC_SHOWTEXT); _PopulateComboBox(hwnd, c_iTextOptions, ARRAYSIZE(c_iTextOptions)); hwnd = GetDlgItem(hDlg, IDC_SMALLICONS); _PopulateComboBox(hwnd, c_iIconOptions, ARRAYSIZE(c_iIconOptions)); } void TOOLSBANDCLASS::_OnBeginCustomize(LPNMTBCUSTOMIZEDLG pnm) { CInternetToolbar* pitbar = IToClass(CInternetToolbar, _btb, this); HWND hwnd = (HWND) GetProp(pnm->hDlg, SZ_PROP_CUSTDLG); if (!hwnd) { // // hasn't been initialized. // // we need to check this because this init will be called // when the user hits reset as well hwnd = CreateDialogParam(MLGetHinst(), MAKEINTRESOURCE(DLG_TEXTICONOPTIONS), pnm->hDlg, _BtnAttrDlgProc, (LPARAM)pitbar); if (hwnd) { // store hwnd of our dialog as property on tb cust dialog SetProp(pnm->hDlg, SZ_PROP_CUSTDLG, hwnd); // populate dialog controls _PopulateDialog(hwnd); // initialize dialog control selection states _SetDialogSelections(hwnd, g_fSmallIcons); RECT rc, rcWnd, rcClient; GetWindowRect(pnm->hDlg, &rcWnd); GetClientRect(pnm->hDlg, &rcClient); GetWindowRect(hwnd, &rc); // enlarge tb dialog to make room for our dialog SetWindowPos(pnm->hDlg, NULL, rcWnd.left, rcWnd.top + 64, RECTWIDTH(rcWnd), RECTHEIGHT(rcWnd) + RECTHEIGHT(rc), SWP_NOZORDER); // position our dialog at the bottom of the tb dialog SetWindowPos(hwnd, HWND_TOP, rcClient.left, rcClient.bottom, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); } } if (_BuildButtonDSA()) { _pcinfo->fAdjust = TRUE; } } class CBitmapPreload : public IRunnableTask { public: STDMETHOD ( QueryInterface ) ( REFIID riid, void ** ppvObj ); STDMETHOD_( ULONG, AddRef ) (); STDMETHOD_( ULONG, Release ) (); STDMETHOD (Run)( void ); STDMETHOD (Kill)( BOOL fWait ); STDMETHOD (Suspend)( ); STDMETHOD (Resume)( ); STDMETHOD_( ULONG, IsRunning )( void ); protected: friend HRESULT CBitmapPreload_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi); CBitmapPreload(); ~CBitmapPreload(); LONG m_cRef; LONG m_lState; }; STDAPI CBitmapPreload_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi) { // aggregation checking and *ppunk zeroing are handled in class factory ASSERT(pUnkOuter == NULL); CBitmapPreload* pbp = new CBitmapPreload(); if (pbp) { *ppunk = SAFECAST(pbp, IRunnableTask*); return S_OK; } else { *ppunk = NULL; // redundant but doesn't hurt return E_OUTOFMEMORY; } } CBitmapPreload::CBitmapPreload() : m_cRef(1) { m_lState = IRTIR_TASK_NOT_RUNNING; } CBitmapPreload::~CBitmapPreload() { } STDMETHODIMP CBitmapPreload::QueryInterface (REFIID riid, void ** ppv) { static const QITAB qit[] = { QITABENT(CBitmapPreload, IRunnableTask), { 0 }, }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_( ULONG ) CBitmapPreload:: AddRef () { return InterlockedIncrement( &m_cRef ); } STDMETHODIMP_( ULONG ) CBitmapPreload:: Release () { ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement( &m_cRef ); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CBitmapPreload::Run ( void ) { if ( m_lState != IRTIR_TASK_NOT_RUNNING ) { return E_FAIL; } InterlockedExchange( &m_lState, IRTIR_TASK_RUNNING ); CInternetToolbar_Preload( ); InterlockedExchange( &m_lState, IRTIR_TASK_FINISHED ); return NOERROR; } STDMETHODIMP CBitmapPreload::Kill ( BOOL fWait ) { return E_NOTIMPL; } STDMETHODIMP CBitmapPreload::Suspend ( ) { return E_NOTIMPL; } STDMETHODIMP CBitmapPreload::Resume ( ) { return E_NOTIMPL; } STDMETHODIMP_( ULONG ) CBitmapPreload:: IsRunning ( void ) { return m_lState; } //+------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- CInternetToolbar::CEditVerb::CEditVerb() { ASSERT(_nElements == 0); ASSERT(_nDefault == 0); ASSERT(_pVerb == NULL); ASSERT(_lpfnOldWndProc == NULL); ASSERT(_pszDefaultEditor == NULL); ASSERT(_fInitEditor == FALSE); } //+------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- CInternetToolbar::CEditVerb::~CEditVerb() { if (_pVerb) RemoveAll(); SetStr(&_pszDefaultEditor, NULL); } //+------------------------------------------------------------------------- // Removes all cached edit verbs and associated memory //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::RemoveAll() { if (_nElements > 0) { for (UINT i=0; i < _nElements; ++i) { EDITVERB& rVerb = _pVerb[i]; SetStr(&rVerb.pszDesc, NULL); SetStr(&rVerb.pszMenuText, NULL); SetStr(&rVerb.pszExe, NULL); if (rVerb.hkeyProgID) { RegCloseKey(rVerb.hkeyProgID); } _ClearMSAAMenuInfo(rVerb); } LocalFree(_pVerb); _pVerb = NULL; _nElements = 0; _nDefault = 0; } } void _AddToOpenWithList(HKEY hkeyProgid, LPCWSTR pszVerb, LPCWSTR pszFileExt) { ASSERT(hkeyProgid); ASSERT(pszVerb); ASSERT(pszFileExt); // First get the name of the exe WCHAR szPath[MAX_PATH]; if (SUCCEEDED(AssocQueryStringByKey(ASSOCF_VERIFY, ASSOCSTR_EXECUTABLE, hkeyProgid, pszVerb, szPath, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szPath))))) { // Now see if it is in the openwith list for the given file extension LPCWSTR pszExe = PathFindFileName(szPath); WCHAR szKey[MAX_PATH]; wnsprintf(szKey, ARRAYSIZE(szKey), L"%s\\OpenWithList\\%s", pszFileExt, pszExe); HKEY hkey; DWORD dwDisp; if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, L"", REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &dwDisp)) { // If we create a new key, we then need to check that verb is registered // for this app if (dwDisp == REG_CREATED_NEW_KEY) { AssocMakeApplicationByKey(ASSOCMAKEF_VERIFY, hkeyProgid, pszVerb); } RegCloseKey(hkey); } } } //+------------------------------------------------------------------------- // Check registry for a default mhtml editor. If a new editor is detected, // it is added to the mhtml openwith list. //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::_InitDefaultMHTMLEditor() { // // Check for a default MHTML editor. // HKEY hkeyEdit = NULL; if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DEFAULT_MHTML_EDITOR, 0, KEY_READ | KEY_WRITE, &hkeyEdit)) { // Migrate hklm setting to hkcu HKEY hkeySrc; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DEFAULT_MHTML_EDITOR, 0, KEY_READ, &hkeySrc)) { HKEY hkeyDest; // read/write needed if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DEFAULT_MHTML_EDITOR, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkeyDest, NULL)) { SHCopyKey(hkeySrc, NULL, hkeyDest, 0); hkeyEdit = hkeyDest; } RegCloseKey(hkeySrc); } } if (hkeyEdit) { // If the mhtml editor has changed, copy it into the mhtml openwithlist DWORD dwType; WCHAR szCurrent[MAX_PATH]; DWORD cb = sizeof(szCurrent); if (ERROR_SUCCESS == SHGetValue(hkeyEdit, L"shell\\edit\\command", NULL, &dwType, szCurrent, &cb) && dwType == REG_SZ) { WCHAR szLast[MAX_PATH]; DWORD cb = sizeof(szLast); if (ERROR_SUCCESS != SHGetValue(hkeyEdit, NULL, L"Last", &dwType, szLast, &cb) || (dwType == REG_SZ && StrCmp(szLast, szCurrent) != 0)) { // Copy the MHTML editor into our MHTML openwithlist _AddToOpenWithList(hkeyEdit, L"edit", L".mhtml"); // Remember that we migrated this key. Copying to the openwithlist can be slow // because we need to hit the disk to verify the exe name. So it's worth the effort // to avoid doing this unecessarily. SHSetValue(hkeyEdit, NULL, L"Last", REG_SZ, szCurrent, CbFromCch(lstrlen(szCurrent) +1)); } } RegCloseKey(hkeyEdit); } } //+------------------------------------------------------------------------- // Check registry for the friendly name of the default html editor. This // editor is configured by inetcpl or by office 2000. If necessary, the // associated verb is moved to the OpenWithList for .htm files. //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::InitDefaultEditor(HKEY hkey) { // // First see if the default editor is in HKCU // HKEY hkeyEdit = hkey; if (hkey || ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DEFAULT_HTML_EDITOR, 0, KEY_READ | KEY_WRITE, &hkeyEdit)) { // // See if we have a default editor selected // WCHAR szBuf[MAX_PATH]; DWORD cbBuf = sizeof(szBuf); if (ERROR_SUCCESS == SHGetValue(hkeyEdit, NULL, L"Description", NULL, szBuf, &cbBuf)) { // We got it! Save the friendly name. PathRemoveBlanks(szBuf); SetStr(&_pszDefaultEditor, szBuf); } else { // No default editor description, so check to see if an edit verb was added. // (Office/inetcpl deletes the description key to signal to us that something changed). IQueryAssociations *pqa; if (SUCCEEDED(AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa)))) { if (SUCCEEDED(pqa->Init(0, NULL, hkeyEdit, NULL)) && ( SUCCEEDED(pqa->GetString(ASSOCF_VERIFY, ASSOCSTR_FRIENDLYAPPNAME, L"edit", szBuf, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szBuf)))) || SUCCEEDED(pqa->GetString(ASSOCF_VERIFY, ASSOCSTR_FRIENDLYAPPNAME, NULL, szBuf, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szBuf)))))) { PathRemoveBlanks(szBuf); // Save the name of the default editor SetStr(&_pszDefaultEditor, szBuf); SHSetValue(hkeyEdit, NULL, L"Description", REG_SZ, szBuf, CbFromCch(lstrlen(szBuf) +1)); // Add it to our openwithlist for .htm files _AddToOpenWithList(hkeyEdit, L"edit", L".htm"); } pqa->Release(); } } // Close the key if it wasn't passed in if (hkeyEdit && NULL == hkey) { RegCloseKey(hkeyEdit); } } // During setup, Office places the orginial edit verb in HKLM. We need to copy this to HKCU. else if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DEFAULT_HTML_EDITOR, 0, KEY_READ, &hkeyEdit)) { // Migrate this key into HKCU HKEY hkeyDest; // read/write necessary if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DEFAULT_HTML_EDITOR, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkeyDest, NULL)) { SHCopyKey(hkeyEdit, NULL, hkeyDest, 0); // Try again InitDefaultEditor(hkeyDest); RegCloseKey(hkeyDest); } RegCloseKey(hkeyEdit); } // // Check for a default MHTML editor. // if (hkey == NULL) // Don't do on recursion { _InitDefaultMHTMLEditor(); } } BOOL _GetAppKey(LPCWSTR pszApp, HKEY *phkApp) { ASSERT(pszApp && *pszApp); WCHAR szKey[MAX_PATH]; StrCpyN(szKey, L"Applications\\", ARRAYSIZE(szKey)); StrCatBuff(szKey, pszApp, SIZECHARS(szKey)); return (NOERROR == RegOpenKeyEx( HKEY_CLASSES_ROOT, szKey, 0L, MAXIMUM_ALLOWED, phkApp)); } //+------------------------------------------------------------------------- // Make sure that notepad is registered in the OpenWithList for .htm files. // This is called when this dll is registered (at setup time) //-------------------------------------------------------------------------- void AddNotepadToOpenWithList() { // Add notepad to the openwith list for .htm files HKEY hkeyOpenWith; DWORD dwDisp; // write access not necessary if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CLASSES_ROOT, L".htm\\OpenWithList\\notepad.exe", 0, L"", REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hkeyOpenWith, &dwDisp)) { RegCloseKey(hkeyOpenWith); } } //+------------------------------------------------------------------------- // Returns the friendly name of the default HTML editor //-------------------------------------------------------------------------- LPCTSTR CInternetToolbar::CEditVerb::_GetDefaultEditor() { // Do a lazy init of the default editor if (!_fInitEditor) { InitDefaultEditor(); _fInitEditor = TRUE; } return _pszDefaultEditor; } //+------------------------------------------------------------------------- // Gets the path of the exe associated with the verb and stores the // result in rVerb. The caller is responsible for freeing the string // returned. //-------------------------------------------------------------------------- LPCTSTR CInternetToolbar::CEditVerb::_GetExePath(EDITVERB& rVerb) { // If we already have the path, simply return it if (NULL == rVerb.pszExe) { ASSERT(rVerb.hkeyProgID); TCHAR sz[MAX_PATH]; if (SUCCEEDED(AssocQueryStringByKey(ASSOCF_VERIFY, ASSOCSTR_EXECUTABLE, rVerb.hkeyProgID, rVerb.fUseOpenVerb ? NULL : L"edit", sz, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(sz))))) rVerb.pszExe = StrDup(sz); } return rVerb.pszExe; } //+------------------------------------------------------------------------- // Returns TRUE if path of the exe associated with the verb is not found in // any of the existing verbs. //-------------------------------------------------------------------------- BOOL CInternetToolbar::CEditVerb::_IsUnique(EDITVERB& rNewVerb) { // Get the friendly name of the new element LPCTSTR pszNewDesc = _GetDescription(rNewVerb); if (NULL == pszNewDesc) { // Executable must not exist return FALSE; } // Scan existing elements for the same executable for (UINT i=0; i < _nElements; ++i) { LPCTSTR pszDesc = _GetDescription(_pVerb[i]); if (pszDesc && (StrCmpI(pszNewDesc, pszDesc) == 0)) { // Match found, so free the friendly name for the new verb SetStr(&rNewVerb.pszDesc, NULL); // If the new item shows its icon on the button, make the duplicate // do the same. if (rNewVerb.fShowIcon) { _pVerb[i].fShowIcon = TRUE; _nDefault = i; } return FALSE; } } return TRUE; } //+------------------------------------------------------------------------- // Some programs such as msothmed.exe act as stubs that redirect the edit // command to the appropriate executable. This function returns true if // the path contains the name of a known stub. //-------------------------------------------------------------------------- BOOL CInternetToolbar::CEditVerb::_IsHtmlStub ( LPCWSTR pszPath ) { BOOL fRet = FALSE; // Get the MULTISZ list of known redirectors TCHAR szRedir[MAX_PATH]; ZeroMemory(szRedir, sizeof(szRedir)); // Protect against non-multisz strings in the reg DWORD dwType; DWORD cb = sizeof(szRedir) - 4; if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_DEFAULT_HTML_EDITOR, L"Stubs", &dwType, szRedir, &cb)) { // Nothing in registry, so default to ignore the Office redirector StrCpyN(szRedir, L"msohtmed.exe\0", ARRAYSIZE(szRedir)); } // See if the path contains the name of a redirectors // Note that PathFindFileName doesn't work well for pathes with parameters so we just // check for the exe name in the path) for (LPTSTR p = szRedir; *p != NULL; p += lstrlen(p) + 1) { if (StrStrI(pszPath, p)) { fRet = TRUE; break; } } return fRet; } //+------------------------------------------------------------------------- // Adds a new edit verb. Returns a pointer to the new verb if it // successfully added. //-------------------------------------------------------------------------- CInternetToolbar::CEditVerb::EDITVERB* CInternetToolbar::CEditVerb::_Add ( HKEY hkeyProgID, // location of of verb BOOL fPermitOpenVerb, // permit open as well as edit verb BOOL fCheckForOfficeApp,// redirect to office app BOOL fShowIcon // if button face icon should be customized ) { EDITVERB* pNewVerb = NULL; if (hkeyProgID) { BOOL fUseOpenVerb = FALSE; // // See if an appropriate verb exists. // TCHAR szCommand[MAX_PATH]; HRESULT hr = AssocQueryStringByKey(0, ASSOCSTR_COMMAND, hkeyProgID, L"edit", szCommand, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szCommand))); if (FAILED(hr) && fPermitOpenVerb) { hr = AssocQueryStringByKey(0, ASSOCSTR_COMMAND, hkeyProgID, NULL, szCommand, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szCommand))); if (SUCCEEDED(hr)) { fUseOpenVerb = TRUE; } } // If no verb or if this is the office redirector, ignore this progid // Otherwise we can get two entries that do the same thing. if (FAILED(hr) || _IsHtmlStub(szCommand)) { RegCloseKey(hkeyProgID); return NULL; } if (fCheckForOfficeApp) { ASSERT(*szCommand); // // HACK: Office2000 needs us to call a special proxy to get around thier DDE bugs and // to check the HTML document for the name of the original document. These problems // should be fixed in the apps themselves. // // So if this is an office app, we will redirect to the appropriate progid. Note that // we don't need to do this if a progid was from the html meta tag because this progid // already supports the proxy. // struct OfficeHackery {LPCWSTR pszApp; LPCWSTR pszProgID;}; // Must not have been a progid passed in. static const OfficeHackery exeToProgID[] = { {L"winword", L"Word.Document"}, {L"excel", L"Excel.Sheet"}, {L"powerpnt", L"PowerPoint.Slide"}, {L"msaccess", L"Access.Application"}, {L"frontpg", L"FrontPage.Editor.Document"}, }; for (int i=0; i < ARRAYSIZE(exeToProgID); ++i) { if (StrStrI(szCommand, exeToProgID[i].pszApp)) { // Match found! HKEY hkeyOffice = NULL; if (SUCCEEDED(AssocQueryKey(0, ASSOCKEY_SHELLEXECCLASS, exeToProgID[i].pszProgID, NULL, &hkeyOffice))) { // Redirect to the office progid RegCloseKey(hkeyProgID); hkeyProgID = hkeyOffice; // The office apps always use the open verb fUseOpenVerb = TRUE; // The icon is shown on the button face for office apps fShowIcon = TRUE; } break; } } } EDITVERB newVerb = {0}; newVerb.hkeyProgID = hkeyProgID; newVerb.fUseOpenVerb = fUseOpenVerb; newVerb.fShowIcon = fShowIcon; // Ignore it if we have another verb to the same exe. if (!_IsUnique(newVerb)) { RegCloseKey(hkeyProgID); } else { EDITVERB* pVerbsNew; if (_pVerb == NULL) { pVerbsNew = (EDITVERB*)LocalAlloc(LPTR, sizeof(EDITVERB)); ASSERT(_nElements == 0); } else { pVerbsNew = (EDITVERB*)LocalReAlloc(_pVerb, (_nElements+1) * sizeof(EDITVERB), LMEM_MOVEABLE | LMEM_ZEROINIT); } if (pVerbsNew == NULL) { RegCloseKey(hkeyProgID); } else { _pVerb = pVerbsNew; pNewVerb = &_pVerb[_nElements]; *pNewVerb = newVerb; // // If the description of the executable matches that of the default editor, make // it our default edit verb. If we are not checking for the office app, we // can assume that this verb was from a progid in an html file and we will also // make it our default. // LPCWSTR pszDefDesc = _GetDefaultEditor(); LPCWSTR pszNewDesc = _GetDescription(*pNewVerb); if (!fCheckForOfficeApp || (pszDefDesc && pszNewDesc && StrCmp(pszDefDesc, pNewVerb->pszDesc) == 0)) { _nDefault = _nElements; } ++_nElements; } } } return pNewVerb; } //+------------------------------------------------------------------------- // Adds a new edit verb. Returns TRUE if a verb was successfully added. //-------------------------------------------------------------------------- BOOL CInternetToolbar::CEditVerb::Add ( LPTSTR pszProgID // program id or file extension associated with verb ) { ASSERT(pszProgID); BOOL fRet = FALSE; BOOL fFileExt = (pszProgID[0] == TEXT('.')); // // Open the associated reg key and try to add it to our list of verbs // BOOL fUseOpenVerb = FALSE; HKEY hkeyProgID = NULL; BOOL fPermitOpenVerb = !fFileExt; BOOL fShowIcon = !fFileExt; // If a progid was passed in, we will show the icon on the button face if (SUCCEEDED(AssocQueryKey(0, ASSOCKEY_SHELLEXECCLASS, pszProgID, NULL, &hkeyProgID))) { EDITVERB* pNewVerb = _Add(hkeyProgID, fPermitOpenVerb, fFileExt, fShowIcon); if (pNewVerb) { fRet = TRUE; } } // // If a file extension was passed in, we also add the alternative editors from the // OpenWithList // if (fFileExt) { WCHAR szOpenWith[MAX_PATH]; StrCpyN(szOpenWith, pszProgID, ARRAYSIZE(szOpenWith)); StrCatBuff(szOpenWith, L"\\OpenWithList", ARRAYSIZE(szOpenWith)); HKEY hkeyOpenWithList; // See if there is an OpenWithList if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szOpenWith, 0, KEY_READ, &hkeyOpenWithList)) { DWORD dwIndex = 0; DWORD dwSize = ARRAYSIZE(szOpenWith); HKEY hkeyOpenWith = NULL; while (ERROR_SUCCESS == RegEnumKeyEx(hkeyOpenWithList, dwIndex, szOpenWith, &dwSize, NULL, NULL, NULL, NULL)) { if (_GetAppKey(szOpenWith, &hkeyOpenWith)) { // We only permit the edit verbs from here EDITVERB* pNewVerb = _Add(hkeyOpenWith, FALSE, TRUE, FALSE); if (pNewVerb) { fRet = TRUE; } ++dwIndex; // Note that we don't close hkeyOpenWith here. It is either closed if it was not added, or // it will be closed later. } else { // Invalid entry, so try to fix it (may be old format): // // In IE5.0 we use to store the friendly names of apps in the openwithlist. For shell compatibility, we need // to convert these entries to store the exe name instead: // // ----> permanent entries are stored un HKCR // HKCR // \.Ext // \OpenWithList // \app.exe // // ----> and applications or the system can write app association here // \Applications // \APP.EXE // \shell... // \foo.exe // \shell... // if (ERROR_SUCCESS == RegOpenKeyEx(hkeyOpenWithList, szOpenWith, 0, KEY_READ, &hkeyOpenWith)) { _AddToOpenWithList(hkeyOpenWith, L"edit", L".htm"); // Remove the invalid entry if (ERROR_SUCCESS != SHDeleteKey(hkeyOpenWith, L"")) { // NOTE (andrewgu): ie5.5 b#108551 - on locked-down nt5 this will fail // and if dwIndex is not incremented, will result in an infinite loop. dwIndex++; } RegCloseKey(hkeyOpenWith); } } dwSize = ARRAYSIZE(szOpenWith); } RegCloseKey(hkeyOpenWithList); } // // If a ".htm" or ".html" was passed in, add our default html editor // if ((StrCmpI(pszProgID, L".htm") == 0 || StrCmpI(pszProgID, L".html") == 0) && _GetDefaultEditor()) { HKEY hkeyDefault; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DEFAULT_HTML_EDITOR, 0, KEY_READ, &hkeyDefault)) { if (_Add(hkeyDefault, TRUE, TRUE, FALSE)) { fRet = TRUE; } } } } return fRet; } //+------------------------------------------------------------------------- // Returns the tooltip for the default edit verb //-------------------------------------------------------------------------- BOOL CInternetToolbar::CEditVerb::GetToolTip ( LPTSTR pszToolTip, UINT cchMax, BOOL fStripAmpersands ) { if (_nElements == 0) { return FALSE; } // Use the menu text for the tooltip. _FormatMenuText(_nDefault); // Copy text stripping out any ampersands LPWSTR pszDest = pszToolTip; LPWSTR pszSrc = _GetVerb(_nDefault).pszMenuText; if (0 < cchMax) { // Leave room for the null terminator while (0 < --cchMax) { // strip out '&' if (fStripAmpersands) { while (*pszSrc == L'&') { ++pszSrc; } } if ( !(*pszDest++ = *pszSrc++) ) { --pszDest; break; } } if (0 == cchMax) *pszDest = L'\0'; ASSERT(*pszDest == 0); // // In some locals, the accelerator is identified in brackets at the // end of the string, so if we strip ampersands, we strip these too. // if (fStripAmpersands && --pszDest >= pszToolTip && *pszDest == L')') { while (--pszDest >= pszToolTip) { if (*pszDest == L'(') { *pszDest = L'\0'; break; } } } } return TRUE; } //+------------------------------------------------------------------------- // "Lazy-fetches" the verb info, and returns the desired info. //-------------------------------------------------------------------------- CInternetToolbar::CEditVerb::EDITVERB& CInternetToolbar::CEditVerb::_GetVerb(UINT nIndex) { ASSERT(nIndex < _nElements); // We fetch the info when first asked for it. if (!_pVerb[nIndex].fInit) { _FetchInfo(nIndex); _pVerb[nIndex].fInit = TRUE; } return _pVerb[nIndex]; } //+------------------------------------------------------------------------- // Gets the name of the app associated with the verb. //-------------------------------------------------------------------------- LPCTSTR CInternetToolbar::CEditVerb::_GetDescription(EDITVERB& rVerb) { // If we already have a description, we are done if (NULL == rVerb.pszDesc) { ASSERT(rVerb.hkeyProgID); TCHAR sz[MAX_PATH]; if (SUCCEEDED(AssocQueryStringByKey(ASSOCF_VERIFY, ASSOCSTR_FRIENDLYAPPNAME, rVerb.hkeyProgID, rVerb.fUseOpenVerb ? NULL : L"edit", sz, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(sz))))) { rVerb.pszDesc = StrDup(sz); if (rVerb.pszDesc) { // Remove preceeding and trailing blanks PathRemoveBlanks(rVerb.pszDesc); } } } return rVerb.pszDesc; } //+------------------------------------------------------------------------- // Reads the info associated with the progid at the given index. This // function allows us to do a lazy fetch of the info when requested. //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::_FetchInfo(UINT nIndex) { ASSERT(nIndex < _nElements); ASSERT(_pVerb[nIndex].hkeyProgID != NULL); EDITVERB& rVerb = _pVerb[nIndex]; // // Get the path to the edit verb's exe // if (_GetExePath(rVerb)) { ASSERT(rVerb.pszExe); // Note that we fetched the friendly name earlier ASSERT(rVerb.pszDesc); // Now get the icon rVerb.iIcon = Shell_GetCachedImageIndex(rVerb.pszExe, 0, 0); } else { rVerb.iIcon = -1; } } //+------------------------------------------------------------------------- // SetMSAAMenuInfo() // // Fills in MSAAMenuInfo part of EDITVERB from the other fields of the rVerb //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::_SetMSAAMenuInfo( EDITVERB& rVerb ) { rVerb.m_MSAA.m_CharLen = lstrlen( rVerb.pszMenuText ); rVerb.m_MSAA.m_pWStr = rVerb.pszMenuText; // Finally, add MSAAINFO signature... rVerb.m_MSAA.m_MSAASig = MSAA_MENU_SIG; } //+------------------------------------------------------------------------- // ClearMSAAMenuInfo() // // Clean up MSAAMenuInfo - specifically, release the allocated // UNICODE string, if appropriate... //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::_ClearMSAAMenuInfo( EDITVERB& rVerb ) { // Paranoia - clear signature... rVerb.m_MSAA.m_MSAASig = 0; } //+------------------------------------------------------------------------- // Shows the edit pop-up menu. //-------------------------------------------------------------------------- BOOL CInternetToolbar::CEditVerb::ShowEditMenu(POINT pt, HWND hwnd, LPTSTR pszURL) { BOOL bRet = FALSE; HMENU hmEdit = CreatePopupMenu(); if (hmEdit) { UINT idCmd = FCIDM_EDITFIRST; UINT nMax = FCIDM_EDITLAST - FCIDM_EDITFIRST; // Add each verb to the menu for (UINT i=0; i<_nElements && i < nMax; ++i) { EDITVERB& rVerb = _GetVerb(i); _FormatMenuText(i); rVerb.idCmd = idCmd; AppendMenu(hmEdit, MF_OWNERDRAW, idCmd, (LPCTSTR) &rVerb ); // Fix up MSAAMenuInfo part... _SetMSAAMenuInfo( rVerb ); ++idCmd; } // Temporarily subclass the hwnd to intercept the owner-draw messages if (SetProp(hwnd, SZ_EDITVERB_PROP, this)) { ASSERT(!_lpfnOldWndProc); _lpfnOldWndProc = (WNDPROC) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) _WndProc); idCmd = ITBar_TrackPopupMenuEx(hmEdit, TPM_RETURNCMD, pt.x, pt.y, hwnd, NULL); SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)_lpfnOldWndProc); _lpfnOldWndProc = NULL; RemoveProp(hwnd, SZ_EDITVERB_PROP); if (InRange(idCmd, FCIDM_EDITFIRST, FCIDM_EDITLAST)) { // Execute the selected edit verb _Edit(pszURL, idCmd - FCIDM_EDITFIRST); } } DestroyMenu(hmEdit); } return bRet; } //+------------------------------------------------------------------------- // Creates a menu string from the progid's description //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::_FormatMenuText(UINT nIndex) { ASSERT(nIndex < _nElements); EDITVERB& rVerb = _GetVerb(nIndex); if (rVerb.pszMenuText == NULL) { if (_GetDescription(rVerb)) { TCHAR szFormat[100]; TCHAR szMenuText[200]; MLLoadString(IDS_EDITWITH, szFormat, ARRAYSIZE(szFormat)); wnsprintf(szMenuText, ARRAYSIZE(szMenuText), szFormat, rVerb.pszDesc); SetStr(&((EDITVERB&)rVerb).pszMenuText, szMenuText); } else { // Things are really messed up ASSERT(FALSE); SetStr(&((EDITVERB&)rVerb).pszMenuText, TEXT("")); } } } //+------------------------------------------------------------------------- // Executes the edit verb indicated by nIndex. //-------------------------------------------------------------------------- void CInternetToolbar::CEditVerb::_Edit ( LPCTSTR pszURL, // url assocated with the verb UINT nIndex // verb to execute ) { ASSERT(pszURL); if (nIndex >= _nElements) { return; } EDITVERB& rVerb = _pVerb[nIndex]; int fMask = SEE_MASK_CLASSKEY; SHELLEXECUTEINFO sei = {0}; TCHAR szCacheFileName[MAX_PATH + MAX_URL_STRING + 2]; memset(szCacheFileName, 0, sizeof(szCacheFileName)); if (PathIsURL(pszURL)) { // We pass the url if the app has register that it wants this if ((WhichPlatform() == PLATFORM_BROWSERONLY) && DoesAppWantUrl(rVerb.pszExe)) { // // Old versions of shell32 (PLATFORM_BROWSERONLY) ignore the SEE_MASK_FILEANDURL // flag, so on these platforms we check ourselves to see if the app // wants the url instead of the cache file name. // StrCpyN(szCacheFileName, pszURL, ARRAYSIZE(szCacheFileName)); sei.lpFile = szCacheFileName; } else { // (reinerf) // Some apps (FrontPad, Office99, etc) want the URL passed to // them instead of the cache filename. We therefore create a string // that has the URL name after the null: // // "CacheFileName/0UrlName" // // and pass it as the lpFile parameter to shellexecute. // We also pass SEE_MASK_FILEANDURL, so shellexecute can // recognize this case. // int iLength; if (FAILED(URLToCacheFile(pszURL, szCacheFileName, ARRAYSIZE(szCacheFileName)))) { // Frontpage express crashes if we pass a null file name, so if the app doesn't // prefer the url instead, we bail. if (!DoesAppWantUrl(rVerb.pszExe)) { return; } } iLength = lstrlen(szCacheFileName); // copy in the URL name StrCpyN(&szCacheFileName[iLength + 1], pszURL, ARRAYSIZE(szCacheFileName) - (iLength + 1)); // add the mask so shellexecute knows to check for the URL, if necessary. fMask |= SEE_MASK_FILEANDURL; sei.lpFile = szCacheFileName; } } else { // Not a URL, so pass the filename StrCpyN(szCacheFileName, pszURL, ARRAYSIZE(szCacheFileName)); sei.lpFile = szCacheFileName; } // Hack for IE5 bug 50033 - Can remove when fpxpress fixes mru buffer overrun _GetExePath(rVerb); if(StrStr(rVerb.pszExe, TEXT("fpxpress.exe")) != NULL) szCacheFileName[256] = TEXT('\0'); sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.fMask = fMask; sei.hwnd = NULL; sei.lpVerb = rVerb.fUseOpenVerb ? NULL : TEXT("edit"); sei.lpDirectory = NULL; sei.nShow = SW_SHOWNORMAL; sei.hInstApp = NULL; sei.hkeyClass= rVerb.hkeyProgID; // // The office guys want us to call a special proxy to get around some DDE problems // and to sniff the html file for the original document name. Hackers! So let's // see if it is registered. // HKEY hkeyProxy = NULL; if (ERROR_SUCCESS == RegOpenKeyEx(rVerb.hkeyProgID, TEXT("HTML Handler"), 0, KEY_READ, &hkeyProxy)) { DWORD cch; if (SUCCEEDED(AssocQueryStringByKey(0, ASSOCSTR_COMMAND, hkeyProxy, L"edit", NULL, &cch))) { sei.lpVerb = L"edit"; sei.hkeyClass = hkeyProxy; } else if (SUCCEEDED(AssocQueryStringByKey(0, ASSOCSTR_COMMAND, hkeyProxy, NULL, NULL, &cch))) { sei.lpVerb = NULL; sei.hkeyClass = hkeyProxy; } } // executing "edit" on the URL or the file in the cache. // UTF problems going from the URL to the filename shouldnt happen since we're forcing it to come from // the cache -- GetUrlCacheEntryInfoEx will hit the disk to get a valid cache entry so people wont be able // to spoof the URL somehow to fake up a bad shellexecute. ShellExecuteEx(&sei); if (hkeyProxy) { RegCloseKey(hkeyProxy); } } //+------------------------------------------------------------------------- // This window procedure intercepts owner-draw menu messages when the edit // pop-up menu is displayed. //-------------------------------------------------------------------------- LRESULT CALLBACK CInternetToolbar::CEditVerb::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CEditVerb* pThis = (CEditVerb*)GetProp(hwnd, SZ_EDITVERB_PROP); if (!pThis) return DefWindowProcWrap(hwnd, uMsg, wParam, lParam); switch(uMsg) { case WM_DRAWITEM: case WM_MEASUREITEM: { UINT idCmd; switch (uMsg) { case WM_DRAWITEM: idCmd = ((EDITVERB*)((DRAWITEMSTRUCT*)lParam)->itemData)->idCmd; break; case WM_MEASUREITEM: idCmd = ((EDITVERB*)((MEASUREITEMSTRUCT*)lParam)->itemData)->idCmd; break; } if (InRange(idCmd, FCIDM_EDITFIRST, FCIDM_EDITLAST)) { // do our own measuring UINT index = idCmd - FCIDM_EDITFIRST; const EDITVERB& rVerb = pThis->_GetVerb(index); // We don't want the same accelerator on all items, // so remove underlines WCHAR wzBuf[MAX_PATH]; UINT cchMax = ARRAYSIZE(wzBuf); LPWSTR pszTo = wzBuf; LPWSTR pszFrom = rVerb.pszMenuText; if (pszFrom) { while (0 < --cchMax) { if (*pszFrom == L'&') { pszFrom++; continue; } if ( !(*pszTo++ = *pszFrom++) ) { --pszTo; break; } } if (0 == cchMax) *pszTo = L'\0'; // // In some locals, the accelerator is identified in brackets at the // end of the string, so if we strip ampersands, we strip these too. // if (--pszTo >= wzBuf && *pszTo == L')') { while (--pszTo >= wzBuf) { if (*pszTo == L'(') { *pszTo = L'\0'; break; } } } } else { wzBuf[0] = 0; } switch (uMsg) { case WM_MEASUREITEM: MeasureMenuItem((MEASUREITEMSTRUCT *)lParam, wzBuf); break; case WM_DRAWITEM: int iIcon = (rVerb.iIcon != -1) ? rVerb.iIcon : 0; DrawMenuItem((LPDRAWITEMSTRUCT)lParam, wzBuf, iIcon); break; } } } default: return CallWindowProc(pThis->_lpfnOldWndProc, hwnd, uMsg, wParam, lParam); } return 0L; }