1 /*
2  * ReactOS Explorer
3  *
4  * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 /*
22 Implements a class that knows how to hold and manage the menu band, brand band,
23 toolbar, and address band for an explorer window
24 */
25 
26 #include "precomp.h"
27 
28 #if 1
29 
30 interface IAugmentedShellFolder : public IShellFolder
31 {
32     STDMETHOD(AddNameSpace)(LPGUID, IShellFolder *, LPCITEMIDLIST, ULONG) PURE;
33     STDMETHOD(GetNameSpaceID)(LPCITEMIDLIST, LPGUID) PURE;
34     STDMETHOD(QueryNameSpace)(ULONG, LPGUID, IShellFolder **) PURE;
35     STDMETHOD(EnumNameSpace)(ULONG, PULONG) PURE;
36 };
37 
38 #endif
39 
40 // navigation controls and menubar just send a message to parent window
41 /*
42 TODO:
43 ****Implement BandProxy methods
44 ****Add QueryStatus handler for built-in bands
45 ****Enable/Disable up, search, and folders commands appropriately
46   **Why are explorer toolbar separators a nonstandard width?
47   **Remove "(Empty)" item from Favorites menu. Probably something missing in CMenuCallback::CallbackSM
48   **Chevron menu on menuband doesn't work
49   **Fix CInternetToolbar::QueryBand to be generic
50 
51 ****Fix context menu to strip divider when menu shown for menu band
52 ****Fix context menu to have items checked appropriately
53 ****Implement -1 command id update
54 ****When bands are rearranged, resize the internet toolbar and fix height of brand band
55 ****Right clicking on the browse back and forward toolbar buttons displays the same as pulldown menus
56     Implement show/hide of bands
57     Why is the background color of my toolbars different from explorer?
58     Internet Toolbar command handler should get the target for the command and call Exec on the target.
59         For commands built in to the Internet Toolbar, its Exec handles the command
60     When window width is changed, brand band flashes badly
61     Add all bands with correct ids (system bands now add with correct ids)
62     Implement IBandSite
63     Implement remaining IExplorerToolbar methods
64     Fix toolbar buttons to enable/disable correctly
65     After toolbar is customized, it may be necessary to patch the widths of separators
66     Add theme support
67     Check sizes and spacing of toolbars against Explorer
68     Implement resizing of the dock bar
69     Add missing icons for toolbar items
70     Draw History item in forward/back dropdown menus with icon
71     Fix toolbar customize dialog to not include separators as possible selections
72     Implement save/restore of toolbar state
73     Refactor drop down menu code to use a common function since code is so similar
74 */
75 
76 extern HRESULT WINAPI SHBindToFolder(LPCITEMIDLIST path, IShellFolder **newFolder);
77 
78 struct ITBARSTATE
79 {
80     static const UINT SIG = ('R' << 0) | ('O' << 8) | ('S' << 16) | (('i' ^ 't' ^ 'b') << 24);
81     UINT cbSize;
82     UINT Signature; // Note: Windows has something else here (12 bytes)
83     UINT StdToolbar : 1;
84     UINT Addressbar : 1;
85     UINT Linksbar : 1;
86     UINT Throbber : 1; // toastytech.com/files/throboff.html
87     UINT Menubar : 1; // ..\Explorer\Advanced\AlwaysShowMenus for NT6?
88     // Note: Windows 8/10 stores the Ribbon state in ..\Explorer\Ribbon
89 };
90 
91 HRESULT IUnknown_RelayWinEvent(IUnknown * punk, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
92 {
93     CComPtr<IWinEventHandler> menuWinEventHandler;
94     HRESULT hResult = punk->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
95     if (FAILED_UNEXPECTEDLY(hResult))
96         return hResult;
97     hResult = menuWinEventHandler->IsWindowOwner(hWnd);
98     if (FAILED_UNEXPECTEDLY(hResult))
99         return hResult;
100     if (hResult == S_OK)
101         return menuWinEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
102     return S_FALSE;
103 }
104 
105 HRESULT IUnknown_ShowDW(IUnknown * punk, BOOL fShow)
106 {
107     CComPtr<IDockingWindow> dockingWindow;
108     HRESULT hResult = punk->QueryInterface(IID_PPV_ARG(IDockingWindow, &dockingWindow));
109     if (FAILED_UNEXPECTEDLY(hResult))
110         return hResult;
111     hResult = dockingWindow->ShowDW(fShow);
112     if (FAILED_UNEXPECTEDLY(hResult))
113         return hResult;
114     return S_OK;
115 }
116 
117 HRESULT IUnknown_CloseDW(IUnknown * punk, DWORD dwReserved)
118 {
119     CComPtr<IDockingWindow> dockingWindow;
120     HRESULT hResult = punk->QueryInterface(IID_PPV_ARG(IDockingWindow, &dockingWindow));
121     if (FAILED_UNEXPECTEDLY(hResult))
122         return hResult;
123     hResult = dockingWindow->CloseDW(dwReserved);
124     if (FAILED_UNEXPECTEDLY(hResult))
125         return hResult;
126     return S_OK;
127 }
128 
129 class CInternetToolbar;
130 
131 class CDockSite :
132     public CComObjectRootEx<CComMultiThreadModelNoCS>,
133     public IDockingWindowSite,
134     public IInputObjectSite,
135     public IOleCommandTarget,
136     public IServiceProvider
137 {
138 public:
139     enum {
140         ITF_NOGRIPPER = 1,
141         ITF_NOTITLE = 2,
142         ITF_NEWBANDALWAYS = 4,
143         ITF_GRIPPERALWAYS = 8,
144         ITF_FIXEDSIZE = 16
145     };
146 private:
147     CComPtr<IUnknown>                       fContainedBand;         // the band inside us
148     CInternetToolbar                        *fToolbar;              // our browser
149     HWND                                    fRebarWindow;
150     HWND                                    fChildWindow;
151     int                                     fBandID;
152 public:
153     int                                     fFlags;
154 private:
155     bool                                    fInitialized;
156     // fields of DESKBANDINFO must be preserved between calls to GetBandInfo
157     DESKBANDINFO                            fDeskBandInfo;
158 public:
159     CDockSite();
160     ~CDockSite();
161     HRESULT Initialize(IUnknown *containedBand, CInternetToolbar *browser, HWND hwnd, int bandID, int flags);
162     HRESULT GetRBBandInfo(REBARBANDINFOW &bandInfo);
163     IUnknown* GetContainedBand() const { return fContainedBand.p; } // Not ref. counted
164 private:
165 
166     // *** IOleWindow methods ***
167     STDMETHOD(GetWindow)(HWND *lphwnd) override;
168     STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode) override;
169 
170     // *** IDockingWindow methods ***
171     STDMETHOD(GetBorderDW)(IUnknown* punkObj, LPRECT prcBorder) override;
172     STDMETHOD(RequestBorderSpaceDW)(IUnknown* punkObj, LPCBORDERWIDTHS pbw) override;
173     STDMETHOD(SetBorderSpaceDW)(IUnknown* punkObj, LPCBORDERWIDTHS pbw) override;
174 
175     // *** IInputObjectSite specific methods ***
176     STDMETHOD(OnFocusChangeIS)(IUnknown *punkObj, BOOL fSetFocus) override;
177 
178     // *** IOleCommandTarget specific methods ***
179     STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup, ULONG cCmds,
180         OLECMD prgCmds[  ], OLECMDTEXT *pCmdText) override;
181     STDMETHOD(Exec)(const GUID *pguidCmdGroup, DWORD nCmdID,
182         DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) override;
183 
184     // *** IServiceProvider methods ***
185     STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void **ppvObject) override;
186 
187 BEGIN_COM_MAP(CDockSite)
188     COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
189     COM_INTERFACE_ENTRY_IID(IID_IDockingWindowSite, IDockingWindowSite)
190     COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite)
191     COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
192     COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
193 END_COM_MAP()
194 };
195 
196 CDockSite::CDockSite()
197 {
198     fToolbar = NULL;
199     fRebarWindow = NULL;
200     fChildWindow = NULL;
201     fBandID = 0;
202     fFlags = 0;
203     fInitialized = false;
204     memset(&fDeskBandInfo, 0, sizeof(fDeskBandInfo));
205 }
206 
207 CDockSite::~CDockSite()
208 {
209 }
210 
211 HRESULT CDockSite::Initialize(IUnknown *containedBand, CInternetToolbar *browser, HWND hwnd, int bandID, int flags)
212 {
213     TCHAR                                   textBuffer[40];
214     REBARBANDINFOW                          bandInfo;
215     HRESULT                                 hResult;
216 
217     fContainedBand = containedBand;
218     fToolbar = browser;
219     fRebarWindow = hwnd;
220     fBandID = bandID;
221     fFlags = flags;
222     hResult = IUnknown_SetSite(containedBand, static_cast<IOleWindow *>(this));
223     if (FAILED_UNEXPECTEDLY(hResult))
224         return hResult;
225     hResult = IUnknown_GetWindow(containedBand, &fChildWindow);
226     if (FAILED_UNEXPECTEDLY(hResult))
227         return hResult;
228 
229     memset(&bandInfo, 0, sizeof(bandInfo));
230     bandInfo.cbSize = sizeof(bandInfo);
231     bandInfo.lpText = textBuffer;
232     bandInfo.cch = sizeof(textBuffer) / sizeof(TCHAR);
233     hResult = GetRBBandInfo(bandInfo);
234 
235     SendMessage(fRebarWindow, RB_GETBANDCOUNT, 0, 0);
236     SendMessage(fRebarWindow, RB_INSERTBANDW, -1, (LPARAM)&bandInfo);
237     fInitialized = true;
238     return S_OK;
239 }
240 
241 HRESULT CDockSite::GetRBBandInfo(REBARBANDINFOW &bandInfo)
242 {
243     CComPtr<IDeskBand>                      deskBand;
244     HRESULT                                 hResult;
245 
246     hResult = fContainedBand->QueryInterface(IID_PPV_ARG(IDeskBand, &deskBand));
247     if (FAILED_UNEXPECTEDLY(hResult))
248         return hResult;
249 
250     fDeskBandInfo.dwMask = DBIM_BKCOLOR | DBIM_MODEFLAGS | DBIM_TITLE | DBIM_ACTUAL |
251         DBIM_INTEGRAL | DBIM_MAXSIZE | DBIM_MINSIZE;
252     hResult = deskBand->GetBandInfo(fBandID, 0, &fDeskBandInfo);
253     // result of call is ignored
254 
255     bandInfo.fMask = RBBIM_LPARAM | RBBIM_IDEALSIZE | RBBIM_ID | RBBIM_CHILDSIZE | RBBIM_CHILD |
256         RBBIM_TEXT | RBBIM_STYLE;
257 
258     bandInfo.fStyle = RBBS_FIXEDBMP;
259     if (fDeskBandInfo.dwModeFlags & DBIMF_VARIABLEHEIGHT)
260         bandInfo.fStyle |= RBBS_VARIABLEHEIGHT;
261     if (fDeskBandInfo.dwModeFlags & DBIMF_USECHEVRON)
262         bandInfo.fStyle |= RBBS_USECHEVRON;
263     if (fDeskBandInfo.dwModeFlags & DBIMF_BREAK)
264         bandInfo.fStyle |= RBBS_BREAK;
265     if (fDeskBandInfo.dwModeFlags & DBIMF_TOPALIGN)
266         bandInfo.fStyle |= RBBS_TOPALIGN;
267     if ((fFlags & ITF_NOGRIPPER) || fToolbar->pSettings->fLocked)
268         bandInfo.fStyle |= RBBS_NOGRIPPER;
269     if (fFlags & ITF_NOTITLE)
270         bandInfo.fStyle |= RBBS_HIDETITLE;
271     if ((fFlags & ITF_GRIPPERALWAYS) && !fToolbar->pSettings->fLocked)
272         bandInfo.fStyle |= RBBS_GRIPPERALWAYS;
273     if (fFlags & ITF_FIXEDSIZE)
274         bandInfo.fStyle |= RBBS_FIXEDSIZE;
275 
276     if (fDeskBandInfo.dwModeFlags & DBIMF_BKCOLOR)
277     {
278         bandInfo.fMask |= RBBIM_COLORS;
279         bandInfo.clrFore = CLR_DEFAULT;
280         bandInfo.clrBack = fDeskBandInfo.crBkgnd;
281     }
282     wcsncpy(bandInfo.lpText, fDeskBandInfo.wszTitle, bandInfo.cch);
283     bandInfo.hwndChild = fChildWindow;
284     bandInfo.cxMinChild = fDeskBandInfo.ptMinSize.x;
285     bandInfo.cyMinChild = fDeskBandInfo.ptMinSize.y;
286     bandInfo.wID = fBandID;
287     bandInfo.cyChild = fDeskBandInfo.ptActual.y;
288     bandInfo.cyMaxChild = fDeskBandInfo.ptMaxSize.y;
289     bandInfo.cyIntegral = fDeskBandInfo.ptIntegral.y;
290     bandInfo.cxIdeal = fDeskBandInfo.ptActual.x;
291     bandInfo.lParam = reinterpret_cast<LPARAM>(static_cast<CDockSite*>(this));
292     return S_OK;
293 }
294 
295 HRESULT STDMETHODCALLTYPE CDockSite::GetWindow(HWND *lphwnd)
296 {
297     if (lphwnd == NULL)
298         return E_POINTER;
299     *lphwnd = fRebarWindow;
300     return S_OK;
301 }
302 
303 HRESULT STDMETHODCALLTYPE CDockSite::ContextSensitiveHelp(BOOL fEnterMode)
304 {
305     return E_NOTIMPL;
306 }
307 
308 HRESULT STDMETHODCALLTYPE CDockSite::GetBorderDW(IUnknown* punkObj, LPRECT prcBorder)
309 {
310     return E_NOTIMPL;
311 }
312 
313 HRESULT STDMETHODCALLTYPE CDockSite::RequestBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw)
314 {
315     return E_NOTIMPL;
316 }
317 
318 HRESULT STDMETHODCALLTYPE CDockSite::SetBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw)
319 {
320     return E_NOTIMPL;
321 }
322 
323 HRESULT STDMETHODCALLTYPE CDockSite::OnFocusChangeIS (IUnknown *punkObj, BOOL fSetFocus)
324 {
325     return E_NOTIMPL;
326 }
327 
328 HRESULT STDMETHODCALLTYPE CDockSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
329     OLECMD prgCmds[  ], OLECMDTEXT *pCmdText)
330 {
331     return E_NOTIMPL;
332 }
333 
334 HRESULT STDMETHODCALLTYPE CDockSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
335     VARIANT *pvaIn, VARIANT *pvaOut)
336 {
337     TCHAR                                   textBuffer[40];
338     REBARBANDINFOW                          bandInfo;
339     int                                     index;
340     HRESULT                                 hResult;
341 
342     if (IsEqualIID(*pguidCmdGroup, CGID_DeskBand))
343     {
344         switch (nCmdID)
345         {
346             case DBID_BANDINFOCHANGED:
347                 if (fInitialized == false)
348                     return S_OK;
349                 if (V_VT(pvaIn) != VT_I4)
350                     return E_INVALIDARG;
351                 if (V_I4(pvaIn) != fBandID)
352                     return E_FAIL;
353                 // deskband information changed
354                 // call GetBandInfo and refresh information in rebar
355                 memset(&bandInfo, 0, sizeof(bandInfo));
356                 bandInfo.cbSize = sizeof(bandInfo);
357                 bandInfo.lpText = textBuffer;
358                 bandInfo.cch = sizeof(textBuffer) / sizeof(TCHAR);
359                 hResult = GetRBBandInfo(bandInfo);
360                 if (FAILED_UNEXPECTEDLY(hResult))
361                     return hResult;
362                 index = (int)SendMessage(fRebarWindow, RB_IDTOINDEX, fBandID, 0);
363                 SendMessage(fRebarWindow, RB_SETBANDINFOW, index, (LPARAM)&bandInfo);
364                 return S_OK;
365         }
366     }
367     return E_FAIL;
368 }
369 
370 HRESULT STDMETHODCALLTYPE CDockSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
371 {
372     if (IsEqualIID(guidService, SID_SMenuBandParent))
373         return this->QueryInterface(riid, ppvObject);
374 
375     return fToolbar->QueryService(guidService, riid, ppvObject);
376 }
377 
378 CMenuCallback::CMenuCallback()
379 {
380 }
381 
382 CMenuCallback::~CMenuCallback()
383 {
384 }
385 
386 static HRESULT BindToDesktop(LPCITEMIDLIST pidl, IShellFolder ** ppsfResult)
387 {
388     HRESULT hr;
389     CComPtr<IShellFolder> psfDesktop;
390 
391     *ppsfResult = NULL;
392 
393     hr = SHGetDesktopFolder(&psfDesktop);
394     if (FAILED(hr))
395         return hr;
396 
397     hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfResult));
398 
399     return hr;
400 }
401 
402 static HRESULT GetFavoritesFolder(IShellFolder ** ppsfFavorites, LPITEMIDLIST * ppidl)
403 {
404     HRESULT hr;
405     LPITEMIDLIST pidlUserFavorites;
406     LPITEMIDLIST pidlCommonFavorites;
407     CComPtr<IShellFolder> psfUserFavorites;
408     CComPtr<IShellFolder> psfCommonFavorites;
409     CComPtr<IAugmentedShellFolder> pasf;
410 
411     if (ppsfFavorites)
412         *ppsfFavorites = NULL;
413 
414     if (ppidl)
415         *ppidl = NULL;
416 
417     hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidlUserFavorites);
418     if (FAILED(hr))
419     {
420         WARN("Failed to get the USER favorites folder. Trying to run with just the COMMON one.\n");
421 
422         hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_FAVORITES, &pidlCommonFavorites);
423         if (FAILED_UNEXPECTEDLY(hr))
424             return hr;
425 
426         TRACE("COMMON favorites obtained.\n");
427         *ppidl = pidlCommonFavorites;
428         hr = BindToDesktop(pidlCommonFavorites, ppsfFavorites);
429         return hr;
430     }
431 
432     hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_FAVORITES, &pidlCommonFavorites);
433     if (FAILED_UNEXPECTEDLY(hr))
434     {
435         WARN("Failed to get the COMMON favorites folder. Will use only the USER contents.\n");
436         *ppidl = pidlCommonFavorites;
437         hr = BindToDesktop(pidlUserFavorites, ppsfFavorites);
438         return hr;
439     }
440 
441     TRACE("Both COMMON and USER favorites folders obtained, merging them...\n");
442 
443     hr = BindToDesktop(pidlUserFavorites, &psfUserFavorites);
444     if (FAILED_UNEXPECTEDLY(hr))
445         return hr;
446 
447     hr = BindToDesktop(pidlCommonFavorites, &psfCommonFavorites);
448     if (FAILED_UNEXPECTEDLY(hr))
449         return hr;
450 
451     hr = CMergedFolder_CreateInstance(IID_PPV_ARG(IAugmentedShellFolder, &pasf));
452     if (FAILED_UNEXPECTEDLY(hr))
453     {
454         *ppsfFavorites = psfUserFavorites.Detach();
455         *ppidl = pidlUserFavorites;
456         ILFree(pidlCommonFavorites);
457         return hr;
458     }
459 
460     hr = pasf->AddNameSpace(NULL, psfUserFavorites, pidlUserFavorites, 0xFF00);
461     if (FAILED_UNEXPECTEDLY(hr))
462         return hr;
463 
464     hr = pasf->AddNameSpace(NULL, psfCommonFavorites, pidlCommonFavorites, 0);
465     if (FAILED_UNEXPECTEDLY(hr))
466         return hr;
467 
468     hr = pasf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsfFavorites));
469     pasf.Release();
470 
471     // TODO: obtain the folder's PIDL
472 
473     ILFree(pidlCommonFavorites);
474     ILFree(pidlUserFavorites);
475 
476     return hr;
477 }
478 
479 HRESULT STDMETHODCALLTYPE CMenuCallback::GetObject(LPSMDATA psmd, REFIID riid, void **ppvObject)
480 {
481     CComPtr<IShellMenu>                     parentMenu;
482     CComPtr<IShellMenu>                     newMenu;
483     CComPtr<IShellFolder>                   favoritesFolder;
484     LPITEMIDLIST                            favoritesPIDL;
485     HWND                                    ownerWindow;
486     HMENU                                   parentHMenu;
487     HMENU                                   favoritesHMenu;
488     HKEY                                    orderRegKey;
489     DWORD                                   disposition;
490     HRESULT                                 hResult;
491     static const TCHAR szFavoritesKey[] =
492         _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites");
493 
494     if (!IsEqualIID(riid, IID_IShellMenu))
495         return E_FAIL;
496     if (psmd->uId != FCIDM_MENU_FAVORITES)
497         return E_FAIL;
498 
499     // create favorites menu
500     hResult = psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &parentMenu));
501     if (FAILED_UNEXPECTEDLY(hResult))
502         return hResult;
503     hResult = parentMenu->GetMenu(&parentHMenu, &ownerWindow, NULL);
504     if (FAILED_UNEXPECTEDLY(hResult))
505         return hResult;
506     favoritesHMenu = GetSubMenu(parentHMenu, 3);
507     if (favoritesHMenu == NULL)
508         return E_FAIL;
509 
510     if (fFavoritesMenu.p == NULL)
511     {
512         hResult = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &newMenu));
513         if (FAILED_UNEXPECTEDLY(hResult))
514             return hResult;
515         hResult = newMenu->Initialize(this, FCIDM_MENU_FAVORITES, -1, SMINIT_VERTICAL | SMINIT_CACHED);
516         if (FAILED_UNEXPECTEDLY(hResult))
517             return hResult;
518 
519         RegCreateKeyEx(HKEY_CURRENT_USER, szFavoritesKey,
520                 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &orderRegKey, &disposition);
521 
522         hResult = GetFavoritesFolder(&favoritesFolder, &favoritesPIDL);
523         if (FAILED_UNEXPECTEDLY(hResult))
524             return hResult;
525 
526         hResult = newMenu->SetShellFolder(favoritesFolder, favoritesPIDL, orderRegKey, SMSET_BOTTOM | SMINIT_CACHED | SMINV_ID);
527         if (favoritesPIDL)
528             ILFree(favoritesPIDL);
529 
530         if (FAILED(hResult))
531             return hResult;
532 
533         fFavoritesMenu = newMenu;
534     }
535 
536     hResult = fFavoritesMenu->SetMenu(favoritesHMenu, ownerWindow, SMSET_TOP | SMSET_DONTOWN);
537     if (FAILED_UNEXPECTEDLY(hResult))
538         return hResult;
539 
540     return fFavoritesMenu->QueryInterface(riid, ppvObject);
541 }
542 
543 HRESULT STDMETHODCALLTYPE CMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
544 {
545     switch (uMsg)
546     {
547         case SMC_INITMENU:
548             break;
549         case SMC_CREATE:
550             break;
551         case SMC_EXITMENU:
552             break;
553         case SMC_GETINFO:
554         {
555             SMINFO *infoPtr = reinterpret_cast<SMINFO *>(lParam);
556             if ((infoPtr->dwMask & SMIM_FLAGS) != 0)
557             {
558                 if (psmd->uId == FCIDM_MENU_FAVORITES)
559                 {
560                     infoPtr->dwFlags |= SMIF_DROPCASCADE;
561                 }
562                 else
563                 {
564                     infoPtr->dwFlags |= SMIF_TRACKPOPUP;
565                 }
566             }
567             if ((infoPtr->dwMask & SMIM_ICON) != 0)
568                 infoPtr->iIcon = -1;
569             return S_OK;
570         }
571         case SMC_GETSFINFO:
572             break;
573         case SMC_GETOBJECT:
574             return GetObject(psmd, *reinterpret_cast<IID *>(wParam), reinterpret_cast<void **>(lParam));
575         case SMC_GETSFOBJECT:
576             break;
577         case SMC_EXEC:
578             PostMessageW(psmd->hwnd, WM_COMMAND, psmd->uId, 0);
579             break;
580         case SMC_SFEXEC:
581             SHInvokeDefaultCommand(psmd->hwnd, psmd->psf, psmd->pidlItem);
582             break;
583         case SMC_SFSELECTITEM:
584             break;
585         case 13:
586             // return tooltip
587             break;
588         case SMC_REFRESH:
589             break;
590         case SMC_DEMOTE:
591             break;
592         case SMC_PROMOTE:
593             break;
594         case 0x13:
595             break;
596         case SMC_DEFAULTICON:
597             break;
598         case SMC_NEWITEM:
599             break;
600         case SMC_CHEVRONEXPAND:
601             break;
602         case SMC_DISPLAYCHEVRONTIP:
603             break;
604         case SMC_SETSFOBJECT:
605             break;
606         case SMC_SHCHANGENOTIFY:
607             break;
608         case SMC_CHEVRONGETTIP:
609             break;
610         case SMC_SFDDRESTRICTED:
611             break;
612         case 0x35:
613             break;
614         case 49:
615             break;
616         case 0x10000000:
617             break;
618     }
619     return S_FALSE;
620 }
621 
622 CInternetToolbar::CInternetToolbar()
623 {
624     fMainReBar = NULL;
625     fMenuBandWindow = NULL;
626     fNavigationWindow = NULL;
627     fMenuCallback = new CComObject<CMenuCallback>();
628     fToolbarWindow = NULL;
629     fAdviseCookie = 0;
630     pSettings = NULL;
631     fIgnoreChanges = FALSE;
632 }
633 
634 CInternetToolbar::~CInternetToolbar()
635 {
636 }
637 
638 void CInternetToolbar::AddDockItem(IUnknown *newItem, int bandID, int flags)
639 {
640     CComPtr<CDockSite> newSite;
641 
642     newSite = new CComObject<CDockSite>;
643     newSite->Initialize(newItem, this, fMainReBar, bandID, flags);
644 }
645 
646 HRESULT CInternetToolbar::EnumBands(UINT Index, int *pBandId, IUnknown **ppUnkBand)
647 {
648     REBARBANDINFOW rbbi;
649     rbbi.cbSize = sizeof(rbbi);
650     rbbi.fMask = RBBIM_ID | RBBIM_LPARAM;
651     rbbi.cch = 0;
652     if (!::SendMessageW(fMainReBar, RB_GETBANDINFOW, Index, (LPARAM)&rbbi))
653         return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
654     *pBandId = rbbi.wID;
655     if (!rbbi.lParam)
656         return E_UNEXPECTED;
657     *ppUnkBand = ((CDockSite*)(rbbi.lParam))->GetContainedBand(); // Not ref. counted
658     return *ppUnkBand ? S_OK : S_FALSE;
659 }
660 
661 HRESULT CInternetToolbar::ReserveBorderSpace(LONG maxHeight)
662 {
663     CComPtr<IDockingWindowSite>             dockingWindowSite;
664     RECT                                    availableBorderSpace;
665 
666     HRESULT hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite));
667     if (FAILED_UNEXPECTEDLY(hResult))
668         return hResult;
669     hResult = dockingWindowSite->GetBorderDW(static_cast<IDockingWindow *>(this), &availableBorderSpace);
670     if (FAILED_UNEXPECTEDLY(hResult))
671         return hResult;
672 
673     if (maxHeight && availableBorderSpace.bottom - availableBorderSpace.top > maxHeight)
674     {
675         availableBorderSpace.bottom = availableBorderSpace.top + maxHeight;
676     }
677 
678     return ResizeBorderDW(&availableBorderSpace, fSite, FALSE);
679 }
680 
681 HRESULT CInternetToolbar::CreateMenuBar(IShellMenu **pMenuBar)
682 {
683     CComPtr<IShellMenu>                     menubar;
684     CComPtr<IShellMenuCallback>             callback;
685     VARIANT                                 menuOut;
686     HWND                                    ownerWindow;
687     HRESULT                                 hResult;
688 
689     if (!pMenuBar)
690         return E_POINTER;
691 
692     *pMenuBar = NULL;
693 
694     hResult = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &menubar));
695     if (FAILED_UNEXPECTEDLY(hResult))
696         return hResult;
697 
698     hResult = fMenuCallback->QueryInterface(IID_PPV_ARG(IShellMenuCallback, &callback));
699     if (FAILED_UNEXPECTEDLY(hResult))
700         return hResult;
701 
702     hResult = menubar->Initialize(callback, -1, ANCESTORDEFAULT, SMINIT_HORIZONTAL | SMINIT_TOPLEVEL);
703     if (FAILED_UNEXPECTEDLY(hResult))
704         return hResult;
705 
706     // Set Menu
707     {
708         hResult = IUnknown_Exec(fSite, CGID_Explorer, 0x35, 0, NULL, &menuOut);
709         if (FAILED_UNEXPECTEDLY(hResult))
710             return hResult;
711 
712         if (V_VT(&menuOut) != VT_INT_PTR || V_INTREF(&menuOut) == NULL)
713             return E_FAIL;
714 
715         hResult = IUnknown_GetWindow(fSite, &ownerWindow);
716         if (FAILED_UNEXPECTEDLY(hResult))
717             return hResult;
718 
719         HMENU hMenuBar = (HMENU) V_INTREF(&menuOut);
720 
721         // FIXME: Figure out the proper way to do this.
722         HMENU hMenuFavs = GetSubMenu(hMenuBar, 3);
723         if (hMenuFavs)
724         {
725             DeleteMenu(hMenuFavs, IDM_FAVORITES_EMPTY, MF_BYCOMMAND);
726         }
727 
728         hResult = menubar->SetMenu(hMenuBar, ownerWindow, SMSET_DONTOWN);
729         if (FAILED_UNEXPECTEDLY(hResult))
730             return hResult;
731     }
732 
733     hResult = IUnknown_Exec(menubar, CGID_MenuBand, 3, 1, NULL, NULL);
734     if (FAILED_UNEXPECTEDLY(hResult))
735         return hResult;
736 
737     *pMenuBar = menubar.Detach();
738 
739     return S_OK;
740 }
741 
742 HRESULT CInternetToolbar::LockUnlockToolbars(bool locked)
743 {
744     if (locked != !!pSettings->fLocked)
745     {
746         pSettings->fLocked = (BOOL)locked;
747         pSettings->Save();
748         RefreshLockedToolbarState();
749     }
750     return S_OK;
751 }
752 
753 void CInternetToolbar::RefreshLockedToolbarState()
754 {
755     REBARBANDINFOW                          rebarBandInfo;
756     int                                     bandCount;
757     CDockSite                               *dockSite;
758 
759     rebarBandInfo.cbSize = sizeof(rebarBandInfo);
760     rebarBandInfo.fMask = RBBIM_STYLE | RBBIM_LPARAM;
761     bandCount = (int)SendMessage(fMainReBar, RB_GETBANDCOUNT, 0, 0);
762     for (INT x  = 0; x < bandCount; x++)
763     {
764         SendMessage(fMainReBar, RB_GETBANDINFOW, x, (LPARAM)&rebarBandInfo);
765         dockSite = reinterpret_cast<CDockSite *>(rebarBandInfo.lParam);
766         if (dockSite != NULL)
767         {
768             rebarBandInfo.fStyle &= ~(RBBS_NOGRIPPER | RBBS_GRIPPERALWAYS);
769             if ((dockSite->fFlags & CDockSite::ITF_NOGRIPPER) || pSettings->fLocked)
770                 rebarBandInfo.fStyle |= RBBS_NOGRIPPER;
771             if ((dockSite->fFlags & CDockSite::ITF_GRIPPERALWAYS) && !pSettings->fLocked)
772                 rebarBandInfo.fStyle |= RBBS_GRIPPERALWAYS;
773             SendMessage(fMainReBar, RB_SETBANDINFOW, x, (LPARAM)&rebarBandInfo);
774         }
775     }
776     ReserveBorderSpace(0);
777 }
778 
779 HRESULT CInternetToolbar::SetState(const GUID *pguidCmdGroup, long commandID, OLECMD* pcmd)
780 {
781     long state = 0;
782     if (pcmd->cmdf & OLECMDF_ENABLED)
783         state |= TBSTATE_ENABLED;
784     if (pcmd->cmdf & OLECMDF_LATCHED)
785         state |= TBSTATE_CHECKED;
786     return SetState(pguidCmdGroup, commandID, state);
787 }
788 
789 HRESULT CInternetToolbar::CommandStateChanged(bool newValue, int commandID)
790 {
791     HRESULT                                 hResult;
792 
793     hResult = S_OK;
794     switch (commandID)
795     {
796         case -1:
797             // loop through buttons
798             //for buttons in CLSID_CommonButtons
799             //    if up, QueryStatus for up state and update it
800             //
801             //for buttons in fCommandCategory, update with QueryStatus of fCommandTarget
802 
803             OLECMD commandList[4];
804             commandList[0].cmdID = 0x1c;
805             commandList[1].cmdID = 0x1d;
806             commandList[2].cmdID = 0x1e;
807             commandList[3].cmdID = 0x23;
808             IUnknown_QueryStatus(fSite, CGID_Explorer, 4, commandList, NULL);
809             SetState(&CLSID_CommonButtons, gSearchCommandID, &commandList[0]);
810             SetState(&CLSID_CommonButtons, gFoldersCommandID, &commandList[3]);
811             //SetState(&CLSID_CommonButtons, gFavoritesCommandID, &commandList[2]);
812             //SetState(&CLSID_CommonButtons, gHistoryCommandID, &commandList[1]);
813 
814             break;
815         case 1:
816             // forward
817             hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_FORWARD, newValue ? TBSTATE_ENABLED : 0);
818             break;
819         case 2:
820             // back
821             hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_BACK, newValue ? TBSTATE_ENABLED : 0);
822             break;
823         case 3:
824             // up
825             hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_UPONELEVEL, newValue ? TBSTATE_ENABLED : 0);
826             break;
827     }
828     return hResult;
829 }
830 
831 HRESULT CInternetToolbar::CreateAndInitBandProxy()
832 {
833     CComPtr<IServiceProvider>               serviceProvider;
834     HRESULT                                 hResult;
835 
836     hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
837     if (FAILED_UNEXPECTEDLY(hResult))
838         return hResult;
839     hResult = serviceProvider->QueryService(SID_IBandProxy, IID_PPV_ARG(IBandProxy, &fBandProxy));
840     if (FAILED_UNEXPECTEDLY(hResult))
841     {
842         hResult = CBandProxy_CreateInstance(IID_PPV_ARG(IBandProxy, &fBandProxy));
843         if (FAILED_UNEXPECTEDLY(hResult))
844             return hResult;
845         hResult = fBandProxy->SetSite(fSite);
846         if (FAILED_UNEXPECTEDLY(hResult))
847             return hResult;
848     }
849     return S_OK;
850 }
851 
852 HRESULT STDMETHODCALLTYPE CInternetToolbar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
853 {
854     return E_NOTIMPL;
855 }
856 
857 HRESULT STDMETHODCALLTYPE CInternetToolbar::HasFocusIO()
858 {
859     HRESULT hr = S_FALSE;
860 
861     if (fMenuBar)
862         hr = IUnknown_HasFocusIO(fMenuBar);
863     if (hr != S_FALSE)
864         return hr;
865 
866     if (fControlsBar)
867         hr = IUnknown_HasFocusIO(fControlsBar);
868     if (hr != S_FALSE)
869         return hr;
870 
871     if (fNavigationBar)
872         hr = IUnknown_HasFocusIO(fNavigationBar);
873     if (hr != S_FALSE)
874         return hr;
875 
876     return S_FALSE;
877 }
878 
879 HRESULT STDMETHODCALLTYPE CInternetToolbar::TranslateAcceleratorIO(LPMSG lpMsg)
880 {
881     HRESULT hr = S_FALSE;
882 
883     if (fMenuBar)
884         hr = IUnknown_TranslateAcceleratorIO(fMenuBar, lpMsg);
885     if (hr == S_OK)
886         return hr;
887 
888     if (fControlsBar)
889         hr = IUnknown_TranslateAcceleratorIO(fControlsBar, lpMsg);
890     if (hr == S_OK)
891         return hr;
892 
893     if (fNavigationBar)
894         hr = IUnknown_TranslateAcceleratorIO(fNavigationBar, lpMsg);
895     if (hr == S_OK)
896         return hr;
897 
898     return S_FALSE;
899 }
900 
901 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetWindow(HWND *lphwnd)
902 {
903     if (lphwnd == NULL)
904         return E_POINTER;
905     *lphwnd = m_hWnd;
906     return S_OK;
907 }
908 
909 HRESULT STDMETHODCALLTYPE CInternetToolbar::ContextSensitiveHelp(BOOL fEnterMode)
910 {
911     return E_NOTIMPL;
912 }
913 
914 HRESULT STDMETHODCALLTYPE CInternetToolbar::ShowDW(BOOL fShow)
915 {
916     HRESULT                     hResult;
917 
918     // show the bar here
919     if (fShow)
920     {
921         hResult = ReserveBorderSpace();
922         if (FAILED_UNEXPECTEDLY(hResult))
923             return hResult;
924     }
925 
926     // TODO: Why should showing the IDockingWindow change all bands? Related to CORE-17236 and CORE-19659.
927     int id;
928     IUnknown *pUnk;
929     for (UINT i = 0; SUCCEEDED(EnumBands(i, &id, &pUnk)); ++i)
930     {
931         if (!pUnk)
932             continue;
933         BOOL visible = fShow && IsBandVisible(id) != S_FALSE;
934         hResult = IUnknown_ShowDW(pUnk, visible);
935         FAILED_UNEXPECTEDLY(hResult);
936     }
937     return S_OK;
938 }
939 
940 HRESULT STDMETHODCALLTYPE CInternetToolbar::CloseDW(DWORD dwReserved)
941 {
942     HRESULT                     hResult;
943 
944     if (fMenuBar)
945     {
946         hResult = IUnknown_CloseDW(fMenuBar, dwReserved);
947         if (FAILED_UNEXPECTEDLY(hResult))
948             return hResult;
949         ReleaseCComPtrExpectZero(fMenuBar);
950     }
951     if (fControlsBar)
952     {
953         hResult = IUnknown_CloseDW(fControlsBar, dwReserved);
954         if (FAILED_UNEXPECTEDLY(hResult))
955             return hResult;
956         ReleaseCComPtrExpectZero(fControlsBar);
957     }
958     if (fNavigationBar)
959     {
960         hResult = IUnknown_CloseDW(fNavigationBar, dwReserved);
961         if (FAILED_UNEXPECTEDLY(hResult))
962             return hResult;
963         ReleaseCComPtrExpectZero(fNavigationBar);
964     }
965     if (fLogoBar)
966     {
967         hResult = IUnknown_CloseDW(fLogoBar, dwReserved);
968         if (FAILED_UNEXPECTEDLY(hResult))
969             return hResult;
970         ReleaseCComPtrExpectZero(fLogoBar);
971     }
972 
973     SetSite(NULL);
974     return S_OK;
975 }
976 
977 HRESULT STDMETHODCALLTYPE CInternetToolbar::ResizeBorderDW(LPCRECT prcBorder,
978     IUnknown *punkToolbarSite, BOOL fReserved)
979 {
980     RECT neededBorderSpace;
981     RECT availableBorderSpace = *prcBorder;
982 
983     SendMessage(fMainReBar, RB_SIZETORECT, RBSTR_CHANGERECT, reinterpret_cast<LPARAM>(&availableBorderSpace));
984 
985     // RBSTR_CHANGERECT does not seem to set the proper size in the rect.
986     // Let's make sure we fetch the actual size properly.
987     ::GetWindowRect(fMainReBar, &availableBorderSpace);
988     neededBorderSpace.left = 0;
989     neededBorderSpace.top = availableBorderSpace.bottom - availableBorderSpace.top;
990     if (!pSettings->fLocked)
991         neededBorderSpace.top += 3;
992     neededBorderSpace.right = 0;
993     neededBorderSpace.bottom = 0;
994 
995     CComPtr<IDockingWindowSite> dockingWindowSite;
996 
997     HRESULT hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite));
998     if (FAILED_UNEXPECTEDLY(hResult))
999         return hResult;
1000 
1001     hResult = dockingWindowSite->RequestBorderSpaceDW(static_cast<IDockingWindow *>(this), &neededBorderSpace);
1002     if (FAILED_UNEXPECTEDLY(hResult))
1003         return hResult;
1004 
1005     hResult = dockingWindowSite->SetBorderSpaceDW(static_cast<IDockingWindow *>(this), &neededBorderSpace);
1006     if (FAILED_UNEXPECTEDLY(hResult))
1007         return hResult;
1008 
1009     return S_OK;
1010 }
1011 
1012 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetClassID(CLSID *pClassID)
1013 {
1014     if (pClassID == NULL)
1015         return E_POINTER;
1016     *pClassID = CLSID_InternetToolbar;
1017     return S_OK;
1018 }
1019 
1020 HRESULT CInternetToolbar::SetDirty()
1021 {
1022     if (fIgnoreChanges)
1023         return S_OK;
1024     IUnknown_Exec(fSite, CGID_ShellBrowser, IDM_NOTIFYITBARDIRTY, 0, NULL, NULL);
1025     return S_OK;
1026 }
1027 
1028 HRESULT STDMETHODCALLTYPE CInternetToolbar::IsDirty()
1029 {
1030     return E_NOTIMPL;
1031 }
1032 
1033 HRESULT STDMETHODCALLTYPE CInternetToolbar::Load(IStream *pStm)
1034 {
1035     fIgnoreChanges = TRUE;
1036     HRESULT hr = InitNew();
1037     ITBARSTATE state;
1038     if (SUCCEEDED(hr))
1039     {
1040         hr = S_FALSE;
1041         ULONG cb = sizeof(state);
1042         if (pStm->Read(&state, cb, &cb) == S_OK && state.Signature == state.SIG)
1043         {
1044             SetBandVisibility(ITBBID_MENUBAND, state.Menubar);
1045             SetBandVisibility(ITBBID_TOOLSBAND, state.StdToolbar);
1046             SetBandVisibility(ITBBID_ADDRESSBAND, state.Addressbar);
1047             //SetBandVisibility(ITBBID_?, state.Linksbar);
1048             //SetBandVisibility(ITBBID_?, state.Throbber);
1049             hr = S_OK;
1050         }
1051     }
1052     fIgnoreChanges = FALSE;
1053     return hr;
1054 }
1055 
1056 HRESULT STDMETHODCALLTYPE CInternetToolbar::Save(IStream *pStm, BOOL fClearDirty)
1057 {
1058     ITBARSTATE state = { sizeof(state), state.SIG };
1059     state.Menubar = IsBandVisible(ITBBID_MENUBAND) == S_OK;
1060     state.StdToolbar = IsBandVisible(ITBBID_TOOLSBAND) == S_OK;
1061     state.Addressbar = IsBandVisible(ITBBID_ADDRESSBAND) == S_OK;
1062     state.Linksbar = FALSE;
1063     return pStm->Write(&state, sizeof(state), NULL);
1064 }
1065 
1066 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetSizeMax(ULARGE_INTEGER *pcbSize)
1067 {
1068     return E_NOTIMPL;
1069 }
1070 
1071 HRESULT STDMETHODCALLTYPE CInternetToolbar::InitNew()
1072 {
1073     CComPtr<IShellMenu>                     menuBar;
1074     CComPtr<IUnknown>                       logoBar;
1075     CComPtr<IUnknown>                       toolsBar;
1076     CComPtr<IUnknown>                       navigationBar;
1077     HRESULT                                 hResult;
1078 
1079     /* Create and attach the menubar to the rebar */
1080     hResult = CreateMenuBar(&menuBar);
1081     if (FAILED_UNEXPECTEDLY(hResult))
1082         return hResult;
1083     AddDockItem(menuBar, ITBBID_MENUBAND, CDockSite::ITF_NOTITLE | CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
1084 
1085     hResult = IUnknown_GetWindow(menuBar, &fMenuBandWindow);
1086     fMenuBar.Attach(menuBar.Detach());                  // transfer the ref count
1087 
1088     // FIXME: The ROS Rebar does not properly support fixed-size items such as the brandband,
1089     // and it will put them in their own row, sized to take up the whole row.
1090 #if 0
1091     /* Create and attach the brand/logo to the rebar */
1092     hResult = CBrandBand_CreateInstance(IID_PPV_ARG(IUnknown, &logoBar));
1093     if (FAILED_UNEXPECTEDLY(hResult))
1094         return hResult;
1095     AddDockItem(logoBar, ITBBID_BRANDBAND, CDockSite::ITF_NOGRIPPER | CDockSite::ITF_NOTITLE | CDockSite::ITF_FIXEDSIZE);
1096     fLogoBar.Attach(logoBar.Detach());                  // transfer the ref count
1097 #endif
1098 
1099     /* Create and attach the standard toolbar to the rebar */
1100     hResult = CToolsBand_CreateInstance(IID_PPV_ARG(IUnknown, &toolsBar));
1101     if (FAILED_UNEXPECTEDLY(hResult))
1102         return hResult;
1103     AddDockItem(toolsBar, ITBBID_TOOLSBAND, CDockSite::ITF_NOTITLE | CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
1104     fControlsBar.Attach(toolsBar.Detach());             // transfer the ref count
1105     hResult = IUnknown_GetWindow(fControlsBar, &fToolbarWindow);
1106     if (FAILED_UNEXPECTEDLY(hResult))
1107         return hResult;
1108 
1109     /* Create and attach the address/navigation toolbar to the rebar */
1110     hResult = CAddressBand_CreateInstance(IID_PPV_ARG(IUnknown, &navigationBar));
1111     if (FAILED_UNEXPECTEDLY(hResult))
1112         return hResult;
1113     AddDockItem(navigationBar, ITBBID_ADDRESSBAND, CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
1114     fNavigationBar.Attach(navigationBar.Detach());
1115     hResult = IUnknown_GetWindow(fNavigationBar, &fNavigationWindow);
1116 
1117     return S_OK;
1118 }
1119 
1120 HRESULT CInternetToolbar::IsBandVisible(int BandID)
1121 {
1122     int index = (int)SendMessage(fMainReBar, RB_IDTOINDEX, BandID, 0);
1123 
1124     REBARBANDINFOW bandInfo = {sizeof(REBARBANDINFOW), RBBIM_STYLE};
1125     SendMessage(fMainReBar, RB_GETBANDINFOW, index, (LPARAM)&bandInfo);
1126 
1127     return (bandInfo.fStyle & RBBS_HIDDEN) ? S_FALSE : S_OK;
1128 }
1129 
1130 HRESULT CInternetToolbar::SetBandVisibility(int BandID, int Show)
1131 {
1132     int index = (int)SendMessage(fMainReBar, RB_IDTOINDEX, BandID, 0);
1133     REBARBANDINFOW bandInfo = {sizeof(REBARBANDINFOW), RBBIM_STYLE | RBBIM_CHILD};
1134     if (!SendMessage(fMainReBar, RB_GETBANDINFOW, index, (LPARAM)&bandInfo))
1135         return E_FAIL;
1136 
1137     if (Show < 0)
1138         bandInfo.fStyle ^= RBBS_HIDDEN; // Toggle
1139     else if (Show)
1140         bandInfo.fStyle &= ~RBBS_HIDDEN;
1141     else
1142         bandInfo.fStyle |= RBBS_HIDDEN;
1143 
1144     bandInfo.fMask &= ~RBBIM_CHILD;
1145     ::ShowWindow(bandInfo.hwndChild, (bandInfo.fStyle & RBBS_HIDDEN) ? SW_HIDE : SW_SHOW); // CORE-17236
1146     SendMessage(fMainReBar, RB_SETBANDINFOW, index, (LPARAM)&bandInfo);
1147 
1148     ReserveBorderSpace(0);
1149     SetDirty();
1150     return S_OK;
1151 }
1152 
1153 HRESULT CInternetToolbar::ToggleBandVisibility(int BandID)
1154 {
1155     return SetBandVisibility(BandID, -1);
1156 }
1157 
1158 HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryStatus(const GUID *pguidCmdGroup,
1159     ULONG cCmds, OLECMD prgCmds[  ], OLECMDTEXT *pCmdText)
1160 {
1161     if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
1162     {
1163         while (cCmds != 0)
1164         {
1165             switch (prgCmds->cmdID)
1166             {
1167                 case ITID_TEXTLABELS:       // Text Labels state
1168                     prgCmds->cmdf = OLECMDF_SUPPORTED;
1169                     break;
1170                 case ITID_TOOLBARBANDSHOWN: // toolbar visibility
1171                     prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
1172                     if (IsBandVisible(ITBBID_TOOLSBAND) == S_OK)
1173                         prgCmds->cmdf |= OLECMDF_LATCHED;
1174                     break;
1175                 case ITID_ADDRESSBANDSHOWN: // address bar visibility
1176                     prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
1177                     if (IsBandVisible(ITBBID_ADDRESSBAND) == S_OK)
1178                         prgCmds->cmdf |= OLECMDF_LATCHED;
1179                     break;
1180                 case ITID_LINKSBANDSHOWN:   // links bar visibility
1181                     prgCmds->cmdf = 0;
1182                     break;
1183                 case ITID_MENUBANDSHOWN:    // Menubar band visibility
1184                     prgCmds->cmdf = OLECMDF_SUPPORTED;
1185                     if (fMenuBar)
1186                         prgCmds->cmdf |= OLECMDF_LATCHED;
1187                     break;
1188                 case ITID_AUTOHIDEENABLED:  // Auto hide enabled/disabled
1189                     prgCmds->cmdf = 0;
1190                     break;
1191                 case ITID_CUSTOMIZEENABLED: // customize enabled
1192                     prgCmds->cmdf = OLECMDF_SUPPORTED;
1193                     break;
1194                 case ITID_TOOLBARLOCKED:    // lock toolbars
1195                     prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
1196                     if (pSettings->fLocked)
1197                         prgCmds->cmdf |= OLECMDF_LATCHED;
1198                     break;
1199                 default:
1200                     prgCmds->cmdf = 0;
1201                     break;
1202             }
1203             prgCmds++;
1204             cCmds--;
1205         }
1206         return S_OK;
1207     }
1208     return E_FAIL;
1209 }
1210 
1211 HRESULT STDMETHODCALLTYPE CInternetToolbar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
1212     DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1213 {
1214     if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
1215     {
1216         switch (nCmdID)
1217         {
1218             case 1:
1219                 // what do I do here?
1220                 return S_OK;
1221             case ITID_TEXTLABELS:
1222                 // toggle text labels
1223                 return S_OK;
1224             case ITID_TOOLBARBANDSHOWN:
1225                 return ToggleBandVisibility(ITBBID_TOOLSBAND);
1226             case ITID_ADDRESSBANDSHOWN:
1227                 return ToggleBandVisibility(ITBBID_ADDRESSBAND);
1228             case ITID_LINKSBANDSHOWN:
1229                 // toggle links band visibility
1230                 return S_OK;
1231             case ITID_CUSTOMIZEENABLED:
1232                 // run customize
1233                 return S_OK;
1234             case ITID_TOOLBARLOCKED:
1235                 return LockUnlockToolbars(!pSettings->fLocked);
1236         }
1237     }
1238     return E_FAIL;
1239 }
1240 
1241 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetTypeInfoCount(UINT *pctinfo)
1242 {
1243     return E_NOTIMPL;
1244 }
1245 
1246 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1247 {
1248     return E_NOTIMPL;
1249 }
1250 
1251 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
1252     LCID lcid, DISPID *rgDispId)
1253 {
1254     return E_NOTIMPL;
1255 }
1256 
1257 HRESULT STDMETHODCALLTYPE CInternetToolbar::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
1258     WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1259 {
1260     HRESULT                                 hResult;
1261 
1262     switch(dispIdMember)
1263     {
1264         case DISPID_BEFORENAVIGATE:
1265             hResult = S_OK;
1266             break;
1267         case DISPID_DOWNLOADCOMPLETE:
1268             hResult = S_OK;
1269             break;
1270         case DISPID_COMMANDSTATECHANGE:
1271             if (pDispParams->cArgs != 2)
1272                 return E_INVALIDARG;
1273             if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL || V_VT(&pDispParams->rgvarg[1]) != VT_I4)
1274                 return E_INVALIDARG;
1275             return CommandStateChanged(V_BOOL(&pDispParams->rgvarg[0]) != VARIANT_FALSE,
1276                 V_I4(&pDispParams->rgvarg[1]));
1277         case DISPID_DOWNLOADBEGIN:
1278             hResult = S_OK;
1279             break;
1280         case DISPID_NAVIGATECOMPLETE2:
1281             hResult = S_OK;
1282             break;
1283         case DISPID_DOCUMENTCOMPLETE:
1284             hResult = S_OK;
1285             break;
1286     }
1287     return S_OK;
1288 }
1289 
1290 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetCommandTarget(IUnknown *theTarget, GUID *category, long param14)
1291 {
1292     HRESULT                                 hResult;
1293 
1294     TRACE("SetCommandTarget %p category %s param %d\n", theTarget, wine_dbgstr_guid(category), param14);
1295 
1296     fCommandTarget.Release();
1297     hResult = theTarget->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &fCommandTarget));
1298     if (FAILED_UNEXPECTEDLY(hResult))
1299         return hResult;
1300     fCommandCategory = *category;
1301     return S_OK;
1302 }
1303 
1304 HRESULT STDMETHODCALLTYPE CInternetToolbar::Unknown1()
1305 {
1306     return E_NOTIMPL;
1307 }
1308 
1309 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddButtons(const GUID *pguidCmdGroup, long buttonCount, TBBUTTON *buttons)
1310 {
1311     return E_NOTIMPL;
1312 }
1313 
1314 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddString(const GUID *pguidCmdGroup,
1315     HINSTANCE param10, LPCTSTR param14, long *param18)
1316 {
1317     long                                    result;
1318 
1319     result = (long)::SendMessage(fToolbarWindow, TB_ADDSTRINGW,
1320             reinterpret_cast<WPARAM>(param10), reinterpret_cast<LPARAM>(param14));
1321     *param18 = result;
1322     if (result == -1)
1323         return E_FAIL;
1324     return S_OK;
1325 }
1326 
1327 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetButton(const GUID *pguidCmdGroup, long param10, long param14)
1328 {
1329     return E_NOTIMPL;
1330 }
1331 
1332 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetState(const GUID *pguidCmdGroup, long commandID, long *theState)
1333 {
1334     if (theState == NULL)
1335         return E_POINTER;
1336     // map the command id
1337     *theState = (long)::SendMessage(fToolbarWindow, TB_GETSTATE, commandID, 0);
1338     return S_OK;
1339 }
1340 
1341 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetState(const GUID *pguidCmdGroup, long commandID, long theState)
1342 {
1343     // map the command id
1344     ::SendMessage(fToolbarWindow, TB_SETSTATE, commandID, MAKELONG(theState, 0));
1345     return S_OK;
1346 }
1347 
1348 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddBitmap(const GUID *pguidCmdGroup, long param10, long buttonCount,
1349     TBADDBITMAP *lParam, long *newIndex, COLORREF param20)
1350 {
1351     return E_NOTIMPL;
1352 }
1353 
1354 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBitmapSize(long *paramC)
1355 {
1356     if (paramC == NULL)
1357         return E_POINTER;
1358     *paramC = MAKELONG(24, 24);
1359     return S_OK;
1360 }
1361 
1362 HRESULT STDMETHODCALLTYPE CInternetToolbar::SendToolbarMsg(const GUID *pguidCmdGroup, UINT uMsg,
1363     WPARAM wParam, LPARAM lParam, LRESULT *result)
1364 {
1365     if (fToolbarWindow)
1366     {
1367         LRESULT res = ::SendMessageW(fToolbarWindow, uMsg, wParam, lParam);
1368         if (result)
1369             *result = res;
1370         return S_OK;
1371     }
1372     return E_NOTIMPL;
1373 }
1374 
1375 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetImageList(const GUID *pguidCmdGroup, HIMAGELIST param10,
1376     HIMAGELIST param14, HIMAGELIST param18)
1377 {
1378     return E_NOTIMPL;
1379 }
1380 
1381 HRESULT STDMETHODCALLTYPE CInternetToolbar::ModifyButton(const GUID *pguidCmdGroup, long param10, long param14)
1382 {
1383     return E_NOTIMPL;
1384 }
1385 
1386 HRESULT STDMETHODCALLTYPE CInternetToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
1387 {
1388     return E_NOTIMPL;
1389 }
1390 
1391 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetSite(IUnknown *pUnkSite)
1392 {
1393     CComPtr<IBrowserService>                browserService;
1394     HWND                                    ownerWindow;
1395     HWND                                    dockContainer;
1396     HRESULT                                 hResult;
1397 
1398     if (pUnkSite == NULL)
1399     {
1400         hResult = AtlUnadvise(fSite, DIID_DWebBrowserEvents, fAdviseCookie);
1401         ::DestroyWindow(fMainReBar);
1402         DestroyWindow();
1403         fSite.Release();
1404     }
1405     else
1406     {
1407         // get window handle of owner
1408         hResult = IUnknown_GetWindow(pUnkSite, &ownerWindow);
1409         if (FAILED_UNEXPECTEDLY(hResult))
1410             return hResult;
1411         if (ownerWindow == NULL)
1412             return E_FAIL;
1413 
1414         // Get settings from owner window
1415         ::SendMessageW(ownerWindow, BWM_GETSETTINGSPTR, 0, (LPARAM)&pSettings);
1416 
1417         // create dock container
1418         fSite = pUnkSite;
1419         dockContainer = SHCreateWorkerWindowW(0, ownerWindow, 0,
1420             WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, NULL, 0);
1421         if (dockContainer == NULL)
1422             return E_FAIL;
1423         SubclassWindow(dockContainer);
1424 
1425         // create rebar in dock container
1426         DWORD style = WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
1427                       RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_REGISTERDROP | RBS_AUTOSIZE | RBS_DBLCLKTOGGLE |
1428                       CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_TOP;
1429         DWORD exStyle = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_TOOLWINDOW;
1430         fMainReBar = CreateWindowEx(exStyle, REBARCLASSNAMEW, NULL, style,
1431                             0, 0, 700, 60, dockContainer, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
1432         if (fMainReBar == NULL)
1433             return E_FAIL;
1434 
1435         // take advice to watch events
1436         hResult = IUnknown_QueryService(pUnkSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
1437         hResult = AtlAdvise(browserService, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &fAdviseCookie);
1438     }
1439     return S_OK;
1440 }
1441 
1442 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetSite(REFIID riid, void **ppvSite)
1443 {
1444     if (ppvSite == NULL)
1445         return E_POINTER;
1446     if (fSite.p != NULL)
1447         return fSite->QueryInterface(riid, ppvSite);
1448     *ppvSite = NULL;
1449     return S_OK;
1450 }
1451 
1452 HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1453 {
1454     HRESULT                                 hResult;
1455 
1456     if (IsEqualIID(guidService, IID_IBandSite))
1457         return this->QueryInterface(riid, ppvObject);
1458     if (IsEqualIID(guidService, SID_IBandProxy))
1459     {
1460         if (fBandProxy.p == NULL)
1461         {
1462             hResult = CreateAndInitBandProxy();
1463             if (FAILED_UNEXPECTEDLY(hResult))
1464                 return hResult;
1465         }
1466         return fBandProxy->QueryInterface(riid, ppvObject);
1467     }
1468     return IUnknown_QueryService(fSite, guidService, riid, ppvObject);
1469 }
1470 
1471 HRESULT STDMETHODCALLTYPE CInternetToolbar::OnWinEvent(
1472     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1473 {
1474     HRESULT                                 hResult;
1475 
1476     if (fMenuBar)
1477     {
1478         hResult = IUnknown_RelayWinEvent(fMenuBar, hWnd, uMsg, wParam, lParam, theResult);
1479         if (hResult != S_FALSE)
1480             return hResult;
1481     }
1482 
1483     if (fNavigationBar)
1484     {
1485         hResult = IUnknown_RelayWinEvent(fNavigationBar, hWnd, uMsg, wParam, lParam, theResult);
1486         if (hResult != S_FALSE)
1487             return hResult;
1488     }
1489 
1490     if (fLogoBar)
1491     {
1492         hResult = IUnknown_RelayWinEvent(fLogoBar, hWnd, uMsg, wParam, lParam, theResult);
1493         if (hResult != S_FALSE)
1494             return hResult;
1495     }
1496 
1497     return S_FALSE;
1498 }
1499 
1500 HRESULT STDMETHODCALLTYPE CInternetToolbar::IsWindowOwner(HWND hWnd)
1501 {
1502     UNIMPLEMENTED;
1503     return E_NOTIMPL;
1504 }
1505 
1506 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddBand(IUnknown *punk)
1507 {
1508     UNIMPLEMENTED;
1509     return E_NOTIMPL;
1510 }
1511 
1512 HRESULT STDMETHODCALLTYPE CInternetToolbar::EnumBands(UINT uBand, DWORD *pdwBandID)
1513 {
1514     if (uBand == ~0ul)
1515         return ::SendMessage(fMainReBar, RB_GETBANDCOUNT, 0, 0);
1516     int id;
1517     IUnknown *pUnkUnused;
1518     HRESULT hr = EnumBands(uBand, &id, &pUnkUnused);
1519     if (SUCCEEDED(hr))
1520         *pdwBandID = id;
1521     return hr;
1522 }
1523 
1524 HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryBand(DWORD dwBandID,
1525     IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName)
1526 {
1527     if (ppstb == NULL)
1528         return E_POINTER;
1529     if (dwBandID == ITBBID_MENUBAND && fMenuBar.p != NULL)
1530         return fMenuBar->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
1531     //if (dwBandID == ITBBID_BRANDBAND && fLogoBar.p != NULL)
1532     //    return fLogoBar->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
1533     *ppstb = NULL;
1534     return E_FAIL;
1535 }
1536 
1537 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
1538 {
1539     UNIMPLEMENTED;
1540     return E_NOTIMPL;
1541 }
1542 
1543 HRESULT STDMETHODCALLTYPE CInternetToolbar::RemoveBand(DWORD dwBandID)
1544 {
1545     UNIMPLEMENTED;
1546     return E_NOTIMPL;
1547 }
1548 
1549 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBandObject(DWORD dwBandID, REFIID riid, void **ppv)
1550 {
1551     UNIMPLEMENTED;
1552     return E_NOTIMPL;
1553 }
1554 
1555 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
1556 {
1557     UNIMPLEMENTED;
1558     return E_NOTIMPL;
1559 }
1560 
1561 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
1562 {
1563     UNIMPLEMENTED;
1564     return E_NOTIMPL;
1565 }
1566 
1567 LRESULT CInternetToolbar::OnTravelBack(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1568 {
1569     CComPtr<IWebBrowser>                    webBrowser;
1570     HRESULT                                 hResult;
1571 
1572     hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IWebBrowser, &webBrowser));
1573     if (FAILED_UNEXPECTEDLY(hResult))
1574         return 0;
1575     hResult = webBrowser->GoBack();
1576     return 1;
1577 }
1578 
1579 LRESULT CInternetToolbar::OnTravelForward(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1580 {
1581     CComPtr<IWebBrowser>                    webBrowser;
1582     HRESULT                                 hResult;
1583 
1584     hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IWebBrowser, &webBrowser));
1585     if (FAILED_UNEXPECTEDLY(hResult))
1586         return 0;
1587     hResult = webBrowser->GoForward();
1588     return 1;
1589 }
1590 
1591 LRESULT CInternetToolbar::OnUpLevel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1592 {
1593     IUnknown_Exec(fSite, CGID_ShellBrowser, IDM_GOTO_UPONELEVEL, 0, NULL, NULL);
1594     return 1;
1595 }
1596 
1597 LRESULT CInternetToolbar::OnSearch(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1598 {
1599     IUnknown_Exec(fSite, CGID_Explorer, 0x1c, 1, NULL, NULL);
1600     return 1;
1601 }
1602 
1603 LRESULT CInternetToolbar::OnFolders(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1604 {
1605     IUnknown_Exec(fSite, CGID_Explorer, 0x23, 0, NULL, NULL);
1606     return 1;
1607 }
1608 
1609 LRESULT CInternetToolbar::OnForwardToCommandTarget(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1610 {
1611     HRESULT                                 hResult;
1612 
1613     if (fCommandTarget.p != NULL)
1614     {
1615         hResult = fCommandTarget->Exec(&fCommandCategory, wID, 0, NULL, NULL);
1616         if (FAILED(hResult))
1617         {
1618             ::SendMessageW(::GetParent(m_hWnd), WM_COMMAND, wID, 0);
1619         }
1620     }
1621     return 1;
1622 }
1623 
1624 LRESULT CInternetToolbar::OnMenuDropDown(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1625 {
1626     CComPtr<IBrowserService>                browserService;
1627     CComPtr<IOleCommandTarget>              commandTarget;
1628     CComPtr<ITravelLog>                     travelLog;
1629     NMTOOLBARW                              *notifyInfo;
1630     RECT                                    bounds;
1631     HMENU                                   newMenu;
1632     TPMPARAMS                               params;
1633     int                                     selectedItem;
1634     VARIANT                                 parmIn;
1635     OLECMD                                  commandInfo;
1636     HRESULT                                 hResult;
1637     wchar_t                                 templateString[200];
1638 
1639     notifyInfo = (NMTOOLBARW *)pNMHDR;
1640     if (notifyInfo->hdr.hwndFrom != fToolbarWindow)
1641     {
1642         // not from the toolbar, keep looking for a message handler
1643         bHandled = FALSE;
1644         return 0;
1645     }
1646     SendMessage(fToolbarWindow, TB_GETRECT, notifyInfo->iItem, reinterpret_cast<LPARAM>(&bounds));
1647     ::MapWindowPoints(fToolbarWindow, NULL, reinterpret_cast<POINT *>(&bounds), 2);
1648     switch (notifyInfo->iItem)
1649     {
1650         case IDM_GOTO_BACK:
1651             newMenu = CreatePopupMenu();
1652             hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
1653             hResult = browserService->GetTravelLog(&travelLog);
1654             hResult = travelLog->InsertMenuEntries(browserService, newMenu, 0, 1, 9, TLMENUF_BACK);
1655             commandInfo.cmdID = 0x1d;
1656             hResult = IUnknown_QueryStatus(browserService, CGID_Explorer, 1, &commandInfo, NULL);
1657             if ((commandInfo.cmdf & (OLECMDF_ENABLED | OLECMDF_LATCHED)) == OLECMDF_ENABLED &&
1658                 travelLog->CountEntries(browserService) > 1)
1659             {
1660                 AppendMenuW(newMenu, MF_SEPARATOR, -1, L"");
1661 
1662                 if (LoadStringW(_AtlBaseModule.GetResourceInstance(),
1663                                 IDS_HISTORYTEXT, templateString, sizeof(templateString) / sizeof(wchar_t)) == 0)
1664                     StringCbCopyW(templateString, sizeof(templateString), L"&History\tCtrl+H");
1665 
1666                 AppendMenuW(newMenu, MF_STRING /* | MF_OWNERDRAW */, IDM_EXPLORERBAR_HISTORY, templateString);
1667             }
1668             params.cbSize = sizeof(params);
1669             params.rcExclude = bounds;
1670             selectedItem = TrackPopupMenuEx(newMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
1671                                     bounds.left, bounds.bottom, m_hWnd, &params);
1672             if (selectedItem == IDM_EXPLORERBAR_HISTORY)
1673             {
1674                 V_VT(&parmIn) = VT_I4;
1675                 V_I4(&parmIn) = 1;
1676                 Exec(&CGID_Explorer, 0x1d, 2, &parmIn, NULL);
1677             }
1678             else if (selectedItem != 0)
1679                 hResult = travelLog->Travel(browserService, -selectedItem);
1680             DestroyMenu(newMenu);
1681             break;
1682         case IDM_GOTO_FORWARD:
1683             newMenu = CreatePopupMenu();
1684             hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
1685             hResult = browserService->GetTravelLog(&travelLog);
1686             hResult = travelLog->InsertMenuEntries(browserService, newMenu, 0, 1, 9, TLMENUF_FORE);
1687             commandInfo.cmdID = 0x1d;
1688             hResult = IUnknown_QueryStatus(browserService, CGID_Explorer, 1, &commandInfo, NULL);
1689             if ((commandInfo.cmdf & (OLECMDF_ENABLED | OLECMDF_LATCHED)) == OLECMDF_ENABLED &&
1690                 travelLog->CountEntries(browserService) > 1)
1691             {
1692                 AppendMenuW(newMenu, MF_SEPARATOR, -1, L"");
1693 
1694                 if (LoadStringW(_AtlBaseModule.GetResourceInstance(),
1695                                 IDS_HISTORYTEXT, templateString, sizeof(templateString) / sizeof(wchar_t)) == 0)
1696                     StringCbCopyW(templateString, sizeof(templateString), L"&History\tCtrl+H");
1697 
1698                 AppendMenuW(newMenu, MF_STRING /* | MF_OWNERDRAW */, IDM_EXPLORERBAR_HISTORY, templateString);
1699             }
1700             params.cbSize = sizeof(params);
1701             params.rcExclude = bounds;
1702             selectedItem = TrackPopupMenuEx(newMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
1703                                     bounds.left, bounds.bottom, m_hWnd, &params);
1704             if (selectedItem == IDM_EXPLORERBAR_HISTORY)
1705             {
1706                 V_VT(&parmIn) = VT_I4;
1707                 V_I4(&parmIn) = 1;
1708                 Exec(&CGID_Explorer, 0x1d, 2, &parmIn, NULL);
1709             }
1710             else if (selectedItem != 0)
1711                 hResult = travelLog->Travel(browserService, selectedItem);
1712             DestroyMenu(newMenu);
1713             break;
1714         case gViewsCommandID:
1715             VARIANT                     inValue;
1716             CComVariant                 outValue;
1717             HRESULT                     hResult;
1718 
1719             V_VT(&inValue) = VT_INT_PTR;
1720             V_INTREF(&inValue) = reinterpret_cast<INT *>(&bounds);
1721 
1722             if (fCommandTarget.p != NULL)
1723                 hResult = fCommandTarget->Exec(&fCommandCategory, FCIDM_SHVIEW_AUTOARRANGE, 1, &inValue, &outValue);
1724             // pvaOut is VT_I4 with value 0x403
1725             break;
1726     }
1727     return TBDDRET_DEFAULT;
1728 }
1729 
1730 LRESULT CInternetToolbar::OnQueryInsert(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1731 {
1732     return 1;
1733 }
1734 
1735 LRESULT CInternetToolbar::OnQueryDelete(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1736 {
1737     return 1;
1738 }
1739 
1740 LRESULT CInternetToolbar::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1741 {
1742     HMENU                                   contextMenuBar;
1743     HMENU                                   contextMenu;
1744     POINT                                   clickLocation;
1745     int                                     command;
1746     RBHITTESTINFO                           hitTestInfo;
1747     REBARBANDINFOW                          rebarBandInfo;
1748     int                                     bandID;
1749 
1750     clickLocation.x = LOWORD(lParam);
1751     clickLocation.y = HIWORD(lParam);
1752     hitTestInfo.pt = clickLocation;
1753     ScreenToClient(&hitTestInfo.pt);
1754     SendMessage(fMainReBar, RB_HITTEST, 0, (LPARAM)&hitTestInfo);
1755     if (hitTestInfo.iBand == -1)
1756         return 0;
1757 
1758     rebarBandInfo.cbSize = sizeof(rebarBandInfo);
1759     rebarBandInfo.fMask = RBBIM_ID;
1760     SendMessage(fMainReBar, RB_GETBANDINFOW, hitTestInfo.iBand, (LPARAM)&rebarBandInfo);
1761     bandID = rebarBandInfo.wID;
1762     contextMenuBar = LoadMenu(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(IDM_CABINET_CONTEXTMENU));
1763     contextMenu = GetSubMenu(contextMenuBar, 0);
1764     switch (bandID)
1765     {
1766         case ITBBID_MENUBAND:   // menu band
1767             DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
1768             DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
1769             DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
1770             break;
1771         case ITBBID_BRANDBAND:  // brand band
1772             DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
1773             DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
1774             DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
1775             break;
1776         case ITBBID_TOOLSBAND:  // tools band
1777             DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
1778             DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
1779             break;
1780         case ITBBID_ADDRESSBAND:    // navigation band
1781             DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
1782             DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
1783             break;
1784         default:
1785             break;
1786     }
1787 
1788     SHEnableMenuItem(contextMenu, IDM_TOOLBARS_LINKSBAR, FALSE);
1789 
1790     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_STANDARDBUTTONS, IsBandVisible(ITBBID_TOOLSBAND) == S_OK);
1791     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_ADDRESSBAR, IsBandVisible(ITBBID_ADDRESSBAND) == S_OK);
1792     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_LINKSBAR, FALSE);
1793     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_CUSTOMIZE, FALSE);
1794     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_LOCKTOOLBARS, pSettings->fLocked);
1795     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_GOBUTTON, pSettings->fShowGoButton);
1796 
1797     // TODO: use GetSystemMetrics(SM_MENUDROPALIGNMENT) to determine menu alignment
1798     command = TrackPopupMenu(contextMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
1799                 clickLocation.x, clickLocation.y, 0, m_hWnd, NULL);
1800     switch (command)
1801     {
1802         case IDM_TOOLBARS_STANDARDBUTTONS:  // standard buttons
1803             ToggleBandVisibility(ITBBID_TOOLSBAND);
1804             break;
1805         case IDM_TOOLBARS_ADDRESSBAR:   // address bar
1806             ToggleBandVisibility(ITBBID_ADDRESSBAND);
1807             break;
1808         case IDM_TOOLBARS_LINKSBAR: // links
1809             break;
1810         case IDM_TOOLBARS_LOCKTOOLBARS: // lock the toolbars
1811             LockUnlockToolbars(!pSettings->fLocked);
1812             break;
1813         case IDM_TOOLBARS_CUSTOMIZE:    // customize
1814             SendMessage(fToolbarWindow, TB_CUSTOMIZE, 0, 0);
1815             break;
1816         case IDM_TOOLBARS_GOBUTTON:
1817             SendMessage(fNavigationWindow, WM_COMMAND, IDM_TOOLBARS_GOBUTTON, 0);
1818             break;
1819     }
1820 
1821     DestroyMenu(contextMenuBar);
1822     return 1;
1823 }
1824 
1825 LRESULT CInternetToolbar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1826 {
1827     if (wParam != SIZE_MINIMIZED)
1828     {
1829         ::SetWindowPos(fMainReBar, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
1830             SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
1831     }
1832     return 1;
1833 }
1834 
1835 LRESULT CInternetToolbar::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1836 {
1837     if ((short)lParam != HTCLIENT || (HWND)wParam != m_hWnd)
1838     {
1839         bHandled = FALSE;
1840         return 0;
1841     }
1842     SetCursor(LoadCursor(NULL, IDC_SIZENS));
1843     return 1;
1844 }
1845 
1846 LRESULT CInternetToolbar::OnTipText(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1847 {
1848     CComPtr<IBrowserService>                browserService;
1849     CComPtr<ITravelLog>                     travelLog;
1850     TOOLTIPTEXTW                            *pTTTW;
1851     UINT                                    nID;
1852     HRESULT                                 hResult;
1853     wchar_t                                 tempString[300];
1854 
1855     pTTTW = reinterpret_cast<TOOLTIPTEXTW *>(pNMHDR);
1856     if ((pTTTW->uFlags & TTF_IDISHWND) != 0)
1857         nID = ::GetDlgCtrlID((HWND)pNMHDR->idFrom);
1858     else
1859         nID = (UINT)pNMHDR->idFrom;
1860 
1861     if (nID != 0)
1862     {
1863         if (nID == (UINT)IDM_GOTO_BACK || nID == (UINT)IDM_GOTO_FORWARD)
1864         {
1865             // TODO: Should this call QueryService?
1866             hResult = fSite->QueryInterface(IID_PPV_ARG(IBrowserService, &browserService));
1867             hResult = browserService->GetTravelLog(&travelLog);
1868             hResult = travelLog->GetToolTipText(browserService,
1869                 (nID == (UINT)IDM_GOTO_BACK) ? TLOG_BACK : TLOG_FORE,
1870                 0, tempString, 299);
1871             if (FAILED_UNEXPECTEDLY(hResult))
1872             {
1873                 bHandled = FALSE;
1874                 return 0;
1875             }
1876         }
1877         else
1878             tempString[0] = 0;
1879         wcsncpy (pTTTW->szText, tempString, sizeof(pTTTW->szText) / sizeof(wchar_t));
1880         ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
1881             SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1882         return 0;
1883     }
1884     return 0;
1885 }
1886 
1887 LRESULT CInternetToolbar::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1888 {
1889     LRESULT theResult;
1890     HRESULT hResult;
1891 
1892     hResult = OnWinEvent((HWND) lParam, uMsg, wParam, lParam, &theResult);
1893 
1894     bHandled = hResult == S_OK;
1895 
1896     return FAILED_UNEXPECTEDLY(hResult) ? 0 : theResult;
1897 }
1898 LRESULT CInternetToolbar::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1899 {
1900     NMHDR   *notifyHeader;
1901     LRESULT theResult;
1902     HRESULT hResult;
1903 
1904     notifyHeader = reinterpret_cast<NMHDR *>(lParam);
1905 
1906     hResult = OnWinEvent(notifyHeader->hwndFrom, uMsg, wParam, lParam, &theResult);
1907 
1908     bHandled = hResult == S_OK;
1909 
1910     return FAILED_UNEXPECTEDLY(hResult) ? 0 : theResult;
1911 }
1912 
1913 LRESULT CInternetToolbar::OnLDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1914 {
1915     bHandled = FALSE;
1916     if (pSettings->fLocked)
1917         return 0;
1918 
1919     if (wParam & MK_CONTROL)
1920         return 0;
1921 
1922     fSizing = TRUE;
1923 
1924     DWORD msgp = GetMessagePos();
1925 
1926     fStartPosition.x = GET_X_LPARAM(msgp);
1927     fStartPosition.y = GET_Y_LPARAM(msgp);
1928 
1929     RECT rc;
1930     GetWindowRect(&rc);
1931 
1932     fStartHeight = rc.bottom - rc.top;
1933 
1934     SetCapture();
1935 
1936     bHandled = TRUE;
1937     return 0;
1938 }
1939 
1940 LRESULT CInternetToolbar::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1941 {
1942     bHandled = FALSE;
1943     if (!fSizing)
1944         return 0;
1945 
1946     DWORD msgp = GetMessagePos();
1947 
1948     POINT pt;
1949     pt.x = GET_X_LPARAM(msgp);
1950     pt.y = GET_Y_LPARAM(msgp);
1951 
1952     ReserveBorderSpace(fStartHeight - fStartPosition.y + pt.y);
1953 
1954     bHandled = TRUE;
1955     return 0;
1956 }
1957 
1958 LRESULT CInternetToolbar::OnLUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1959 {
1960     bHandled = FALSE;
1961     if (!fSizing)
1962         return 0;
1963 
1964     OnMouseMove(uMsg, wParam, lParam, bHandled);
1965 
1966     fSizing = FALSE;
1967 
1968     ReleaseCapture();
1969 
1970     return 0;
1971 }
1972 
1973 LRESULT CInternetToolbar::OnWinIniChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1974 {
1975     HRESULT hr;
1976     HWND hwndMenu;
1977 
1978     hr = IUnknown_GetWindow(fMenuBar, &hwndMenu);
1979     if (FAILED_UNEXPECTEDLY(hr))
1980         return 0;
1981 
1982     CComPtr<IWinEventHandler> menuWinEventHandler;
1983     hr = fMenuBar->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
1984     if (FAILED_UNEXPECTEDLY(hr))
1985         return 0;
1986 
1987     LRESULT lres;
1988     hr = menuWinEventHandler->OnWinEvent(hwndMenu, uMsg, wParam, lParam, &lres);
1989     if (FAILED_UNEXPECTEDLY(hr))
1990         return 0;
1991 
1992     return lres;
1993 }
1994 
1995 LRESULT CInternetToolbar::OnSettingsChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1996 {
1997     /* Refresh toolbar locked state */
1998     RefreshLockedToolbarState();
1999 
2000     return 0;
2001 }
2002 
2003 HRESULT CInternetToolbar::GetStream(UINT StreamFor, DWORD Stgm, IStream **ppS)
2004 {
2005     WCHAR path[MAX_PATH];
2006     LPCWSTR subkey = NULL;
2007     switch (StreamFor)
2008     {
2009     case ITBARSTREAM_SHELLBROWSER: subkey = L"ShellBrowser"; break;
2010     case ITBARSTREAM_WEBBROWSER: subkey = L"WebBrowser"; break;
2011     case ITBARSTREAM_EXPLORER: subkey = L"Explorer"; break;
2012     default: return E_INVALIDARG;
2013     }
2014     wsprintfW(path, L"Software\\Microsoft\\Internet Explorer\\Toolbar\\%s", subkey);
2015     *ppS = SHOpenRegStream2W(HKEY_CURRENT_USER, path, L"RosITBarLayout", Stgm); // ROS prefix until we figure out the correct format
2016     return *ppS ? S_OK : E_FAIL;
2017 }
2018