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