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     virtual HRESULT STDMETHODCALLTYPE AddNameSpace(LPGUID, IShellFolder *, LPCITEMIDLIST, ULONG) = 0;
33     virtual HRESULT STDMETHODCALLTYPE GetNameSpaceID(LPCITEMIDLIST, LPGUID) = 0;
34     virtual HRESULT STDMETHODCALLTYPE QueryNameSpace(ULONG, LPGUID, IShellFolder **) = 0;
35     virtual HRESULT STDMETHODCALLTYPE EnumNameSpace(ULONG, PULONG) = 0;
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     virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
154     virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
155 
156     // *** IDockingWindow methods ***
157     virtual HRESULT STDMETHODCALLTYPE GetBorderDW(IUnknown* punkObj, LPRECT prcBorder);
158     virtual HRESULT STDMETHODCALLTYPE RequestBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw);
159     virtual HRESULT STDMETHODCALLTYPE SetBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw);
160 
161     // *** IInputObjectSite specific methods ***
162     virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus);
163 
164     // *** IOleCommandTarget specific methods ***
165     virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
166         OLECMD prgCmds[  ], OLECMDTEXT *pCmdText);
167     virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
168         DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
169 
170     // *** IServiceProvider methods ***
171     virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
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->fLocked)
254         bandInfo.fStyle |= RBBS_NOGRIPPER;
255     if (fFlags & ITF_NOTITLE)
256         bandInfo.fStyle |= RBBS_HIDETITLE;
257     if (fFlags & ITF_GRIPPERALWAYS && !fToolbar->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     fLocked = SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Toolbar",
611                                    L"Locked",
612                                    FALSE,
613                                    TRUE);
614 
615     fMainReBar = NULL;
616     fMenuBandWindow = NULL;
617     fNavigationWindow = NULL;
618     fMenuCallback = new CComObject<CMenuCallback>();
619     fToolbarWindow = NULL;
620     fAdviseCookie = 0;
621 }
622 
623 CInternetToolbar::~CInternetToolbar()
624 {
625 }
626 
627 void CInternetToolbar::AddDockItem(IUnknown *newItem, int bandID, int flags)
628 {
629     CComPtr<CDockSite> newSite;
630 
631     newSite = new CComObject<CDockSite>;
632     newSite->Initialize(newItem, this, fMainReBar, bandID, flags);
633 }
634 
635 HRESULT CInternetToolbar::ReserveBorderSpace(LONG maxHeight)
636 {
637     CComPtr<IDockingWindowSite>             dockingWindowSite;
638     RECT                                    availableBorderSpace;
639 
640     HRESULT hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite));
641     if (FAILED_UNEXPECTEDLY(hResult))
642         return hResult;
643     hResult = dockingWindowSite->GetBorderDW(static_cast<IDockingWindow *>(this), &availableBorderSpace);
644     if (FAILED_UNEXPECTEDLY(hResult))
645         return hResult;
646 
647     if (maxHeight && availableBorderSpace.bottom - availableBorderSpace.top > maxHeight)
648     {
649         availableBorderSpace.bottom = availableBorderSpace.top + maxHeight;
650     }
651 
652     return ResizeBorderDW(&availableBorderSpace, fSite, FALSE);
653 }
654 
655 HRESULT CInternetToolbar::CreateMenuBar(IShellMenu **pMenuBar)
656 {
657     CComPtr<IShellMenu>                     menubar;
658     CComPtr<IShellMenuCallback>             callback;
659     VARIANT                                 menuOut;
660     HWND                                    ownerWindow;
661     HRESULT                                 hResult;
662 
663     if (!pMenuBar)
664         return E_POINTER;
665 
666     *pMenuBar = NULL;
667 
668     hResult = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &menubar));
669     if (FAILED_UNEXPECTEDLY(hResult))
670         return hResult;
671 
672     hResult = fMenuCallback->QueryInterface(IID_PPV_ARG(IShellMenuCallback, &callback));
673     if (FAILED_UNEXPECTEDLY(hResult))
674         return hResult;
675 
676     hResult = menubar->Initialize(callback, -1, ANCESTORDEFAULT, SMINIT_HORIZONTAL | SMINIT_TOPLEVEL);
677     if (FAILED_UNEXPECTEDLY(hResult))
678         return hResult;
679 
680     // Set Menu
681     {
682         hResult = IUnknown_Exec(fSite, CGID_Explorer, 0x35, 0, NULL, &menuOut);
683         if (FAILED_UNEXPECTEDLY(hResult))
684             return hResult;
685 
686         if (V_VT(&menuOut) != VT_INT_PTR || V_INTREF(&menuOut) == NULL)
687             return E_FAIL;
688 
689         hResult = IUnknown_GetWindow(fSite, &ownerWindow);
690         if (FAILED_UNEXPECTEDLY(hResult))
691             return hResult;
692 
693         HMENU hMenuBar = (HMENU) V_INTREF(&menuOut);
694 
695         // FIXME: Figure out the proper way to do this.
696         HMENU hMenuFavs = GetSubMenu(hMenuBar, 3);
697         if (hMenuFavs)
698         {
699             DeleteMenu(hMenuFavs, IDM_FAVORITES_EMPTY, MF_BYCOMMAND);
700         }
701 
702         hResult = menubar->SetMenu(hMenuBar, ownerWindow, SMSET_DONTOWN);
703         if (FAILED_UNEXPECTEDLY(hResult))
704             return hResult;
705     }
706 
707     hResult = IUnknown_Exec(menubar, CGID_MenuBand, 3, 1, NULL, NULL);
708     if (FAILED_UNEXPECTEDLY(hResult))
709         return hResult;
710 
711     *pMenuBar = menubar.Detach();
712 
713     return S_OK;
714 }
715 
716 HRESULT CInternetToolbar::LockUnlockToolbars(bool locked)
717 {
718     REBARBANDINFOW                          rebarBandInfo;
719     int                                     bandCount;
720     CDockSite                               *dockSite;
721     HRESULT                                 hResult;
722 
723     if (locked != fLocked)
724     {
725         DWORD dwLocked = locked ? 1 : 0;
726         SHRegSetUSValueW(L"Software\\Microsoft\\Internet Explorer\\Toolbar",
727                          L"Locked",
728                          REG_DWORD,
729                          &dwLocked,
730                          sizeof(dwLocked),
731                          SHREGSET_FORCE_HKCU);
732         fLocked = locked;
733 
734         rebarBandInfo.cbSize = sizeof(rebarBandInfo);
735         rebarBandInfo.fMask = RBBIM_STYLE | RBBIM_LPARAM;
736         bandCount = (int)SendMessage(fMainReBar, RB_GETBANDCOUNT, 0, 0);
737         for (INT x  = 0; x < bandCount; x++)
738         {
739             SendMessage(fMainReBar, RB_GETBANDINFOW, x, (LPARAM)&rebarBandInfo);
740             dockSite = reinterpret_cast<CDockSite *>(rebarBandInfo.lParam);
741             if (dockSite != NULL)
742             {
743                 rebarBandInfo.fStyle &= ~(RBBS_NOGRIPPER | RBBS_GRIPPERALWAYS);
744                 if (dockSite->fFlags & CDockSite::ITF_NOGRIPPER || fLocked)
745                     rebarBandInfo.fStyle |= RBBS_NOGRIPPER;
746                 if (dockSite->fFlags & CDockSite::ITF_GRIPPERALWAYS && !fLocked)
747                     rebarBandInfo.fStyle |= RBBS_GRIPPERALWAYS;
748                 SendMessage(fMainReBar, RB_SETBANDINFOW, x, (LPARAM)&rebarBandInfo);
749             }
750         }
751         hResult = ReserveBorderSpace(0);
752 
753         // TODO: refresh view menu?
754     }
755     return S_OK;
756 }
757 
758 HRESULT CInternetToolbar::SetState(const GUID *pguidCmdGroup, long commandID, OLECMD* pcmd)
759 {
760     long state = 0;
761     if (pcmd->cmdf & OLECMDF_ENABLED)
762         state |= TBSTATE_ENABLED;
763     if (pcmd->cmdf & OLECMDF_LATCHED)
764         state |= TBSTATE_CHECKED;
765     return SetState(pguidCmdGroup, commandID, state);
766 }
767 
768 HRESULT CInternetToolbar::CommandStateChanged(bool newValue, int commandID)
769 {
770     HRESULT                                 hResult;
771 
772     hResult = S_OK;
773     switch (commandID)
774     {
775         case -1:
776             // loop through buttons
777             //for buttons in CLSID_CommonButtons
778             //    if up, QueryStatus for up state and update it
779             //
780             //for buttons in fCommandCategory, update with QueryStatus of fCommandTarget
781 
782             OLECMD commandList[4];
783             commandList[0].cmdID = 0x1c;
784             commandList[1].cmdID = 0x1d;
785             commandList[2].cmdID = 0x1e;
786             commandList[3].cmdID = 0x23;
787             IUnknown_QueryStatus(fSite, CGID_Explorer, 4, commandList, NULL);
788             SetState(&CLSID_CommonButtons, gSearchCommandID, &commandList[0]);
789             SetState(&CLSID_CommonButtons, gFoldersCommandID, &commandList[3]);
790             //SetState(&CLSID_CommonButtons, gFavoritesCommandID, &commandList[2]);
791             //SetState(&CLSID_CommonButtons, gHistoryCommandID, &commandList[1]);
792 
793             break;
794         case 1:
795             // forward
796             hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_FORWARD, newValue ? TBSTATE_ENABLED : 0);
797             break;
798         case 2:
799             // back
800             hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_BACK, newValue ? TBSTATE_ENABLED : 0);
801             break;
802         case 3:
803             // up
804             hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_UPONELEVEL, newValue ? TBSTATE_ENABLED : 0);
805             break;
806     }
807     return hResult;
808 }
809 
810 HRESULT CInternetToolbar::CreateAndInitBandProxy()
811 {
812     CComPtr<IServiceProvider>               serviceProvider;
813     HRESULT                                 hResult;
814 
815     hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
816     if (FAILED_UNEXPECTEDLY(hResult))
817         return hResult;
818     hResult = serviceProvider->QueryService(SID_IBandProxy, IID_PPV_ARG(IBandProxy, &fBandProxy));
819     if (FAILED_UNEXPECTEDLY(hResult))
820     {
821         hResult = CBandProxy_CreateInstance(IID_PPV_ARG(IBandProxy, &fBandProxy));
822         if (FAILED_UNEXPECTEDLY(hResult))
823             return hResult;
824         hResult = fBandProxy->SetSite(fSite);
825         if (FAILED_UNEXPECTEDLY(hResult))
826             return hResult;
827     }
828     return S_OK;
829 }
830 
831 HRESULT STDMETHODCALLTYPE CInternetToolbar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
832 {
833     return E_NOTIMPL;
834 }
835 
836 HRESULT STDMETHODCALLTYPE CInternetToolbar::HasFocusIO()
837 {
838     HRESULT hr = S_FALSE;
839 
840     if (fMenuBar)
841         hr = IUnknown_HasFocusIO(fMenuBar);
842     if (hr != S_FALSE)
843         return hr;
844 
845     if (fControlsBar)
846         hr = IUnknown_HasFocusIO(fControlsBar);
847     if (hr != S_FALSE)
848         return hr;
849 
850     if (fNavigationBar)
851         hr = IUnknown_HasFocusIO(fNavigationBar);
852     if (hr != S_FALSE)
853         return hr;
854 
855     return S_FALSE;
856 }
857 
858 HRESULT STDMETHODCALLTYPE CInternetToolbar::TranslateAcceleratorIO(LPMSG lpMsg)
859 {
860     HRESULT hr = S_FALSE;
861 
862     if (fMenuBar)
863         hr = IUnknown_TranslateAcceleratorIO(fMenuBar, lpMsg);
864     if (hr == S_OK)
865         return hr;
866 
867     if (fControlsBar)
868         hr = IUnknown_TranslateAcceleratorIO(fControlsBar, lpMsg);
869     if (hr == S_OK)
870         return hr;
871 
872     if (fNavigationBar)
873         hr = IUnknown_TranslateAcceleratorIO(fNavigationBar, lpMsg);
874     if (hr == S_OK)
875         return hr;
876 
877     return S_FALSE;
878 }
879 
880 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetWindow(HWND *lphwnd)
881 {
882     if (lphwnd == NULL)
883         return E_POINTER;
884     *lphwnd = m_hWnd;
885     return S_OK;
886 }
887 
888 HRESULT STDMETHODCALLTYPE CInternetToolbar::ContextSensitiveHelp(BOOL fEnterMode)
889 {
890     return E_NOTIMPL;
891 }
892 
893 HRESULT STDMETHODCALLTYPE CInternetToolbar::ShowDW(BOOL fShow)
894 {
895     HRESULT                     hResult;
896 
897     // show the bar here
898     if (fShow)
899     {
900         hResult = ReserveBorderSpace();
901         if (FAILED_UNEXPECTEDLY(hResult))
902             return hResult;
903     }
904 
905     if (fMenuBar)
906     {
907         hResult = IUnknown_ShowDW(fMenuBar, fShow);
908         if (FAILED_UNEXPECTEDLY(hResult))
909             return hResult;
910     }
911 
912     if (fControlsBar)
913     {
914         hResult = IUnknown_ShowDW(fControlsBar, fShow);
915         if (FAILED_UNEXPECTEDLY(hResult))
916             return hResult;
917     }
918     if (fNavigationBar)
919     {
920         hResult = IUnknown_ShowDW(fNavigationBar, fShow);
921         if (FAILED_UNEXPECTEDLY(hResult))
922             return hResult;
923     }
924     if (fLogoBar)
925     {
926         hResult = IUnknown_ShowDW(fLogoBar, fShow);
927         if (FAILED_UNEXPECTEDLY(hResult))
928             return hResult;
929     }
930     return S_OK;
931 }
932 
933 HRESULT STDMETHODCALLTYPE CInternetToolbar::CloseDW(DWORD dwReserved)
934 {
935     HRESULT                     hResult;
936 
937     if (fMenuBar)
938     {
939         hResult = IUnknown_CloseDW(fMenuBar, dwReserved);
940         if (FAILED_UNEXPECTEDLY(hResult))
941             return hResult;
942         ReleaseCComPtrExpectZero(fMenuBar);
943     }
944     if (fControlsBar)
945     {
946         hResult = IUnknown_CloseDW(fControlsBar, dwReserved);
947         if (FAILED_UNEXPECTEDLY(hResult))
948             return hResult;
949         ReleaseCComPtrExpectZero(fControlsBar);
950     }
951     if (fNavigationBar)
952     {
953         hResult = IUnknown_CloseDW(fNavigationBar, dwReserved);
954         if (FAILED_UNEXPECTEDLY(hResult))
955             return hResult;
956         ReleaseCComPtrExpectZero(fNavigationBar);
957     }
958     if (fLogoBar)
959     {
960         hResult = IUnknown_CloseDW(fLogoBar, dwReserved);
961         if (FAILED_UNEXPECTEDLY(hResult))
962             return hResult;
963         ReleaseCComPtrExpectZero(fLogoBar);
964     }
965 
966     SetSite(NULL);
967     return S_OK;
968 }
969 
970 HRESULT STDMETHODCALLTYPE CInternetToolbar::ResizeBorderDW(LPCRECT prcBorder,
971     IUnknown *punkToolbarSite, BOOL fReserved)
972 {
973     RECT neededBorderSpace;
974     RECT availableBorderSpace = *prcBorder;
975 
976     SendMessage(fMainReBar, RB_SIZETORECT, RBSTR_CHANGERECT, reinterpret_cast<LPARAM>(&availableBorderSpace));
977 
978     // RBSTR_CHANGERECT does not seem to set the proper size in the rect.
979     // Let's make sure we fetch the actual size properly.
980     ::GetWindowRect(fMainReBar, &availableBorderSpace);
981     neededBorderSpace.left = 0;
982     neededBorderSpace.top = availableBorderSpace.bottom - availableBorderSpace.top;
983     if (!fLocked)
984         neededBorderSpace.top += 3;
985     neededBorderSpace.right = 0;
986     neededBorderSpace.bottom = 0;
987 
988     CComPtr<IDockingWindowSite> dockingWindowSite;
989 
990     HRESULT hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite));
991     if (FAILED_UNEXPECTEDLY(hResult))
992         return hResult;
993 
994     hResult = dockingWindowSite->RequestBorderSpaceDW(static_cast<IDockingWindow *>(this), &neededBorderSpace);
995     if (FAILED_UNEXPECTEDLY(hResult))
996         return hResult;
997 
998     hResult = dockingWindowSite->SetBorderSpaceDW(static_cast<IDockingWindow *>(this), &neededBorderSpace);
999     if (FAILED_UNEXPECTEDLY(hResult))
1000         return hResult;
1001 
1002     return S_OK;
1003 }
1004 
1005 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetClassID(CLSID *pClassID)
1006 {
1007     if (pClassID == NULL)
1008         return E_POINTER;
1009     *pClassID = CLSID_InternetToolbar;
1010     return S_OK;
1011 }
1012 
1013 HRESULT STDMETHODCALLTYPE CInternetToolbar::IsDirty()
1014 {
1015     return E_NOTIMPL;
1016 }
1017 
1018 HRESULT STDMETHODCALLTYPE CInternetToolbar::Load(IStream *pStm)
1019 {
1020     return E_NOTIMPL;
1021 }
1022 
1023 HRESULT STDMETHODCALLTYPE CInternetToolbar::Save(IStream *pStm, BOOL fClearDirty)
1024 {
1025     return E_NOTIMPL;
1026 }
1027 
1028 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetSizeMax(ULARGE_INTEGER *pcbSize)
1029 {
1030     return E_NOTIMPL;
1031 }
1032 
1033 HRESULT STDMETHODCALLTYPE CInternetToolbar::InitNew()
1034 {
1035     CComPtr<IShellMenu>                     menuBar;
1036     CComPtr<IUnknown>                       logoBar;
1037     CComPtr<IUnknown>                       toolsBar;
1038     CComPtr<IUnknown>                       navigationBar;
1039     HRESULT                                 hResult;
1040 
1041     /* Create and attach the menubar to the rebar */
1042     hResult = CreateMenuBar(&menuBar);
1043     if (FAILED_UNEXPECTEDLY(hResult))
1044         return hResult;
1045     AddDockItem(menuBar, ITBBID_MENUBAND, CDockSite::ITF_NOTITLE | CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
1046 
1047     hResult = IUnknown_GetWindow(menuBar, &fMenuBandWindow);
1048     fMenuBar.Attach(menuBar.Detach());                  // transfer the ref count
1049 
1050     // FIXME: The ROS Rebar does not properly support fixed-size items such as the brandband,
1051     // and it will put them in their own row, sized to take up the whole row.
1052 #if 0
1053     /* Create and attach the brand/logo to the rebar */
1054     hResult = CBrandBand_CreateInstance(IID_PPV_ARG(IUnknown, &logoBar));
1055     if (FAILED_UNEXPECTEDLY(hResult))
1056         return hResult;
1057     AddDockItem(logoBar, ITBBID_BRANDBAND, CDockSite::ITF_NOGRIPPER | CDockSite::ITF_NOTITLE | CDockSite::ITF_FIXEDSIZE);
1058     fLogoBar.Attach(logoBar.Detach());                  // transfer the ref count
1059 #endif
1060 
1061     /* Create and attach the standard toolbar to the rebar */
1062     hResult = CToolsBand_CreateInstance(IID_PPV_ARG(IUnknown, &toolsBar));
1063     if (FAILED_UNEXPECTEDLY(hResult))
1064         return hResult;
1065     AddDockItem(toolsBar, ITBBID_TOOLSBAND, CDockSite::ITF_NOTITLE | CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
1066     fControlsBar.Attach(toolsBar.Detach());             // transfer the ref count
1067     hResult = IUnknown_GetWindow(fControlsBar, &fToolbarWindow);
1068     if (FAILED_UNEXPECTEDLY(hResult))
1069         return hResult;
1070 
1071     /* Create and attach the address/navigation toolbar to the rebar */
1072     hResult = CAddressBand_CreateInstance(IID_PPV_ARG(IUnknown, &navigationBar));
1073     if (FAILED_UNEXPECTEDLY(hResult))
1074         return hResult;
1075     AddDockItem(navigationBar, ITBBID_ADDRESSBAND, CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
1076     fNavigationBar.Attach(navigationBar.Detach());
1077     hResult = IUnknown_GetWindow(fNavigationBar, &fNavigationWindow);
1078 
1079     return S_OK;
1080 }
1081 
1082 HRESULT CInternetToolbar::IsBandVisible(int BandID)
1083 {
1084     int index = (int)SendMessage(fMainReBar, RB_IDTOINDEX, BandID, 0);
1085 
1086     REBARBANDINFOW bandInfo = {sizeof(REBARBANDINFOW), RBBIM_STYLE};
1087     SendMessage(fMainReBar, RB_GETBANDINFOW, index, (LPARAM)&bandInfo);
1088 
1089     return (bandInfo.fStyle & RBBS_HIDDEN) ? S_FALSE : S_OK;
1090 }
1091 
1092 HRESULT CInternetToolbar::ToggleBandVisibility(int BandID)
1093 {
1094     int index = (int)SendMessage(fMainReBar, RB_IDTOINDEX, BandID, 0);
1095 
1096     REBARBANDINFOW bandInfo = {sizeof(REBARBANDINFOW), RBBIM_STYLE};
1097     SendMessage(fMainReBar, RB_GETBANDINFOW, index, (LPARAM)&bandInfo);
1098 
1099     if (bandInfo.fStyle & RBBS_HIDDEN)
1100         bandInfo.fStyle &= ~RBBS_HIDDEN;
1101     else
1102         bandInfo.fStyle |= RBBS_HIDDEN;
1103 
1104     SendMessage(fMainReBar, RB_SETBANDINFOW, index, (LPARAM)&bandInfo);
1105 
1106     ReserveBorderSpace(0);
1107     return S_OK;
1108 }
1109 
1110 HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryStatus(const GUID *pguidCmdGroup,
1111     ULONG cCmds, OLECMD prgCmds[  ], OLECMDTEXT *pCmdText)
1112 {
1113     if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
1114     {
1115         while (cCmds != 0)
1116         {
1117             switch (prgCmds->cmdID)
1118             {
1119                 case ITID_TEXTLABELS:       // Text Labels state
1120                     prgCmds->cmdf = OLECMDF_SUPPORTED;
1121                     break;
1122                 case ITID_TOOLBARBANDSHOWN: // toolbar visibility
1123                     prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
1124                     if (IsBandVisible(ITBBID_TOOLSBAND) == S_OK)
1125                         prgCmds->cmdf |= OLECMDF_LATCHED;
1126                     break;
1127                 case ITID_ADDRESSBANDSHOWN: // address bar visibility
1128                     prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
1129                     if (IsBandVisible(ITBBID_ADDRESSBAND) == S_OK)
1130                         prgCmds->cmdf |= OLECMDF_LATCHED;
1131                     break;
1132                 case ITID_LINKSBANDSHOWN:   // links bar visibility
1133                     prgCmds->cmdf = 0;
1134                     break;
1135                 case ITID_MENUBANDSHOWN:    // Menubar band visibility
1136                     prgCmds->cmdf = OLECMDF_SUPPORTED;
1137                     if (fMenuBar)
1138                         prgCmds->cmdf |= OLECMDF_LATCHED;
1139                     break;
1140                 case ITID_AUTOHIDEENABLED:  // Auto hide enabled/disabled
1141                     prgCmds->cmdf = 0;
1142                     break;
1143                 case ITID_CUSTOMIZEENABLED: // customize enabled
1144                     prgCmds->cmdf = OLECMDF_SUPPORTED;
1145                     break;
1146                 case ITID_TOOLBARLOCKED:    // lock toolbars
1147                     prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
1148                     if (fLocked)
1149                         prgCmds->cmdf |= OLECMDF_LATCHED;
1150                     break;
1151                 default:
1152                     prgCmds->cmdf = 0;
1153                     break;
1154             }
1155             prgCmds++;
1156             cCmds--;
1157         }
1158         return S_OK;
1159     }
1160     return E_FAIL;
1161 }
1162 
1163 HRESULT STDMETHODCALLTYPE CInternetToolbar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
1164     DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1165 {
1166     if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
1167     {
1168         switch (nCmdID)
1169         {
1170             case 1:
1171                 // what do I do here?
1172                 return S_OK;
1173             case ITID_TEXTLABELS:
1174                 // toggle text labels
1175                 return S_OK;
1176             case ITID_TOOLBARBANDSHOWN:
1177                 return ToggleBandVisibility(ITBBID_TOOLSBAND);
1178             case ITID_ADDRESSBANDSHOWN:
1179                 return ToggleBandVisibility(ITBBID_ADDRESSBAND);
1180             case ITID_LINKSBANDSHOWN:
1181                 // toggle links band visibility
1182                 return S_OK;
1183             case ITID_CUSTOMIZEENABLED:
1184                 // run customize
1185                 return S_OK;
1186             case ITID_TOOLBARLOCKED:
1187                 return LockUnlockToolbars(!fLocked);
1188         }
1189     }
1190     return E_FAIL;
1191 }
1192 
1193 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetTypeInfoCount(UINT *pctinfo)
1194 {
1195     return E_NOTIMPL;
1196 }
1197 
1198 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1199 {
1200     return E_NOTIMPL;
1201 }
1202 
1203 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
1204     LCID lcid, DISPID *rgDispId)
1205 {
1206     return E_NOTIMPL;
1207 }
1208 
1209 HRESULT STDMETHODCALLTYPE CInternetToolbar::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
1210     WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1211 {
1212     HRESULT                                 hResult;
1213 
1214     switch(dispIdMember)
1215     {
1216         case DISPID_BEFORENAVIGATE:
1217             hResult = S_OK;
1218             break;
1219         case DISPID_DOWNLOADCOMPLETE:
1220             hResult = S_OK;
1221             break;
1222         case DISPID_COMMANDSTATECHANGE:
1223             if (pDispParams->cArgs != 2)
1224                 return E_INVALIDARG;
1225             if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL || V_VT(&pDispParams->rgvarg[1]) != VT_I4)
1226                 return E_INVALIDARG;
1227             return CommandStateChanged(V_BOOL(&pDispParams->rgvarg[0]) != VARIANT_FALSE,
1228                 V_I4(&pDispParams->rgvarg[1]));
1229         case DISPID_DOWNLOADBEGIN:
1230             hResult = S_OK;
1231             break;
1232         case DISPID_NAVIGATECOMPLETE2:
1233             hResult = S_OK;
1234             break;
1235         case DISPID_DOCUMENTCOMPLETE:
1236             hResult = S_OK;
1237             break;
1238     }
1239     return S_OK;
1240 }
1241 
1242 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetCommandTarget(IUnknown *theTarget, GUID *category, long param14)
1243 {
1244     HRESULT                                 hResult;
1245 
1246     TRACE("SetCommandTarget %p category %s param %d\n", theTarget, wine_dbgstr_guid(category), param14);
1247 
1248     fCommandTarget.Release();
1249     hResult = theTarget->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &fCommandTarget));
1250     if (FAILED_UNEXPECTEDLY(hResult))
1251         return hResult;
1252     fCommandCategory = *category;
1253     return S_OK;
1254 }
1255 
1256 HRESULT STDMETHODCALLTYPE CInternetToolbar::Unknown1()
1257 {
1258     return E_NOTIMPL;
1259 }
1260 
1261 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddButtons(const GUID *pguidCmdGroup, long buttonCount, TBBUTTON *buttons)
1262 {
1263     return E_NOTIMPL;
1264 }
1265 
1266 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddString(const GUID *pguidCmdGroup,
1267     HINSTANCE param10, LPCTSTR param14, long *param18)
1268 {
1269     long                                    result;
1270 
1271     result = (long)::SendMessage(fToolbarWindow, TB_ADDSTRINGW,
1272             reinterpret_cast<WPARAM>(param10), reinterpret_cast<LPARAM>(param14));
1273     *param18 = result;
1274     if (result == -1)
1275         return E_FAIL;
1276     return S_OK;
1277 }
1278 
1279 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetButton(const GUID *pguidCmdGroup, long param10, long param14)
1280 {
1281     return E_NOTIMPL;
1282 }
1283 
1284 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetState(const GUID *pguidCmdGroup, long commandID, long *theState)
1285 {
1286     if (theState == NULL)
1287         return E_POINTER;
1288     // map the command id
1289     *theState = (long)::SendMessage(fToolbarWindow, TB_GETSTATE, commandID, 0);
1290     return S_OK;
1291 }
1292 
1293 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetState(const GUID *pguidCmdGroup, long commandID, long theState)
1294 {
1295     // map the command id
1296     ::SendMessage(fToolbarWindow, TB_SETSTATE, commandID, MAKELONG(theState, 0));
1297     return S_OK;
1298 }
1299 
1300 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddBitmap(const GUID *pguidCmdGroup, long param10, long buttonCount,
1301     TBADDBITMAP *lParam, long *newIndex, COLORREF param20)
1302 {
1303     return E_NOTIMPL;
1304 }
1305 
1306 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBitmapSize(long *paramC)
1307 {
1308     if (paramC == NULL)
1309         return E_POINTER;
1310     *paramC = MAKELONG(24, 24);
1311     return S_OK;
1312 }
1313 
1314 HRESULT STDMETHODCALLTYPE CInternetToolbar::SendToolbarMsg(const GUID *pguidCmdGroup, UINT uMsg,
1315     WPARAM wParam, LPARAM lParam, LRESULT *result)
1316 {
1317     return E_NOTIMPL;
1318 }
1319 
1320 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetImageList(const GUID *pguidCmdGroup, HIMAGELIST param10,
1321     HIMAGELIST param14, HIMAGELIST param18)
1322 {
1323     return E_NOTIMPL;
1324 }
1325 
1326 HRESULT STDMETHODCALLTYPE CInternetToolbar::ModifyButton(const GUID *pguidCmdGroup, long param10, long param14)
1327 {
1328     return E_NOTIMPL;
1329 }
1330 
1331 HRESULT STDMETHODCALLTYPE CInternetToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
1332 {
1333     return E_NOTIMPL;
1334 }
1335 
1336 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetSite(IUnknown *pUnkSite)
1337 {
1338     CComPtr<IBrowserService>                browserService;
1339     HWND                                    ownerWindow;
1340     HWND                                    dockContainer;
1341     HRESULT                                 hResult;
1342 
1343     if (pUnkSite == NULL)
1344     {
1345         hResult = AtlUnadvise(fSite, DIID_DWebBrowserEvents, fAdviseCookie);
1346         ::DestroyWindow(fMainReBar);
1347         DestroyWindow();
1348         fSite.Release();
1349     }
1350     else
1351     {
1352         // get window handle of owner
1353         hResult = IUnknown_GetWindow(pUnkSite, &ownerWindow);
1354         if (FAILED_UNEXPECTEDLY(hResult))
1355             return hResult;
1356         if (ownerWindow == NULL)
1357             return E_FAIL;
1358 
1359         // create dock container
1360         fSite = pUnkSite;
1361         dockContainer = SHCreateWorkerWindowW(0, ownerWindow, 0,
1362             WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, NULL, 0);
1363         if (dockContainer == NULL)
1364             return E_FAIL;
1365         SubclassWindow(dockContainer);
1366 
1367         // create rebar in dock container
1368         DWORD style = WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
1369                       RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_REGISTERDROP | RBS_AUTOSIZE | RBS_DBLCLKTOGGLE |
1370                       CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_TOP;
1371         DWORD exStyle = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_TOOLWINDOW;
1372         fMainReBar = CreateWindowEx(exStyle, REBARCLASSNAMEW, NULL, style,
1373                             0, 0, 700, 60, dockContainer, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
1374         if (fMainReBar == NULL)
1375             return E_FAIL;
1376 
1377         // take advice to watch events
1378         hResult = IUnknown_QueryService(pUnkSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
1379         hResult = AtlAdvise(browserService, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &fAdviseCookie);
1380     }
1381     return S_OK;
1382 }
1383 
1384 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetSite(REFIID riid, void **ppvSite)
1385 {
1386     if (ppvSite == NULL)
1387         return E_POINTER;
1388     if (fSite.p != NULL)
1389         return fSite->QueryInterface(riid, ppvSite);
1390     *ppvSite = NULL;
1391     return S_OK;
1392 }
1393 
1394 HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1395 {
1396     HRESULT                                 hResult;
1397 
1398     if (IsEqualIID(guidService, IID_IBandSite))
1399         return this->QueryInterface(riid, ppvObject);
1400     if (IsEqualIID(guidService, SID_IBandProxy))
1401     {
1402         if (fBandProxy.p == NULL)
1403         {
1404             hResult = CreateAndInitBandProxy();
1405             if (FAILED_UNEXPECTEDLY(hResult))
1406                 return hResult;
1407         }
1408         return fBandProxy->QueryInterface(riid, ppvObject);
1409     }
1410     return IUnknown_QueryService(fSite, guidService, riid, ppvObject);
1411 }
1412 
1413 HRESULT STDMETHODCALLTYPE CInternetToolbar::OnWinEvent(
1414     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1415 {
1416     HRESULT                                 hResult;
1417 
1418     if (fMenuBar)
1419     {
1420         hResult = IUnknown_RelayWinEvent(fMenuBar, hWnd, uMsg, wParam, lParam, theResult);
1421         if (hResult != S_FALSE)
1422             return hResult;
1423     }
1424 
1425     if (fNavigationBar)
1426     {
1427         hResult = IUnknown_RelayWinEvent(fNavigationBar, hWnd, uMsg, wParam, lParam, theResult);
1428         if (hResult != S_FALSE)
1429             return hResult;
1430     }
1431 
1432     if (fLogoBar)
1433     {
1434         hResult = IUnknown_RelayWinEvent(fLogoBar, hWnd, uMsg, wParam, lParam, theResult);
1435         if (hResult != S_FALSE)
1436             return hResult;
1437     }
1438 
1439     return S_FALSE;
1440 }
1441 
1442 HRESULT STDMETHODCALLTYPE CInternetToolbar::IsWindowOwner(HWND hWnd)
1443 {
1444     UNIMPLEMENTED;
1445     return E_NOTIMPL;
1446 }
1447 
1448 HRESULT STDMETHODCALLTYPE CInternetToolbar::AddBand(IUnknown *punk)
1449 {
1450     UNIMPLEMENTED;
1451     return E_NOTIMPL;
1452 }
1453 
1454 HRESULT STDMETHODCALLTYPE CInternetToolbar::EnumBands(UINT uBand, DWORD *pdwBandID)
1455 {
1456     UNIMPLEMENTED;
1457     return E_NOTIMPL;
1458 }
1459 
1460 HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryBand(DWORD dwBandID,
1461     IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName)
1462 {
1463     if (ppstb == NULL)
1464         return E_POINTER;
1465     if (dwBandID == ITBBID_MENUBAND && fMenuBar.p != NULL)
1466         return fMenuBar->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
1467     //if (dwBandID == ITBBID_BRANDBAND && fLogoBar.p != NULL)
1468     //    return fLogoBar->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
1469     *ppstb = NULL;
1470     return E_FAIL;
1471 }
1472 
1473 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
1474 {
1475     UNIMPLEMENTED;
1476     return E_NOTIMPL;
1477 }
1478 
1479 HRESULT STDMETHODCALLTYPE CInternetToolbar::RemoveBand(DWORD dwBandID)
1480 {
1481     UNIMPLEMENTED;
1482     return E_NOTIMPL;
1483 }
1484 
1485 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBandObject(DWORD dwBandID, REFIID riid, void **ppv)
1486 {
1487     UNIMPLEMENTED;
1488     return E_NOTIMPL;
1489 }
1490 
1491 HRESULT STDMETHODCALLTYPE CInternetToolbar::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
1492 {
1493     UNIMPLEMENTED;
1494     return E_NOTIMPL;
1495 }
1496 
1497 HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
1498 {
1499     UNIMPLEMENTED;
1500     return E_NOTIMPL;
1501 }
1502 
1503 LRESULT CInternetToolbar::OnTravelBack(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1504 {
1505     CComPtr<IWebBrowser>                    webBrowser;
1506     HRESULT                                 hResult;
1507 
1508     hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IWebBrowser, &webBrowser));
1509     if (FAILED_UNEXPECTEDLY(hResult))
1510         return 0;
1511     hResult = webBrowser->GoBack();
1512     return 1;
1513 }
1514 
1515 LRESULT CInternetToolbar::OnTravelForward(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1516 {
1517     CComPtr<IWebBrowser>                    webBrowser;
1518     HRESULT                                 hResult;
1519 
1520     hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IWebBrowser, &webBrowser));
1521     if (FAILED_UNEXPECTEDLY(hResult))
1522         return 0;
1523     hResult = webBrowser->GoForward();
1524     return 1;
1525 }
1526 
1527 LRESULT CInternetToolbar::OnUpLevel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1528 {
1529     IUnknown_Exec(fSite, CGID_ShellBrowser, IDM_GOTO_UPONELEVEL, 0, NULL, NULL);
1530     return 1;
1531 }
1532 
1533 LRESULT CInternetToolbar::OnSearch(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1534 {
1535     IUnknown_Exec(fSite, CGID_Explorer, 0x1c, 1, NULL, NULL);
1536     return 1;
1537 }
1538 
1539 LRESULT CInternetToolbar::OnFolders(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1540 {
1541     IUnknown_Exec(fSite, CGID_Explorer, 0x23, 0, NULL, NULL);
1542     return 1;
1543 }
1544 
1545 LRESULT CInternetToolbar::OnForwardToCommandTarget(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
1546 {
1547     HRESULT                                 hResult;
1548 
1549     if (fCommandTarget.p != NULL)
1550     {
1551         hResult = fCommandTarget->Exec(&fCommandCategory, wID, 0, NULL, NULL);
1552         if (FAILED(hResult))
1553         {
1554             ::SendMessageW(::GetParent(m_hWnd), WM_COMMAND, wID, 0);
1555         }
1556     }
1557     return 1;
1558 }
1559 
1560 LRESULT CInternetToolbar::OnMenuDropDown(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1561 {
1562     CComPtr<IBrowserService>                browserService;
1563     CComPtr<IOleCommandTarget>              commandTarget;
1564     CComPtr<ITravelLog>                     travelLog;
1565     NMTOOLBARW                              *notifyInfo;
1566     RECT                                    bounds;
1567     HMENU                                   newMenu;
1568     TPMPARAMS                               params;
1569     int                                     selectedItem;
1570     VARIANT                                 parmIn;
1571     OLECMD                                  commandInfo;
1572     HRESULT                                 hResult;
1573     wchar_t                                 templateString[200];
1574 
1575     notifyInfo = (NMTOOLBARW *)pNMHDR;
1576     if (notifyInfo->hdr.hwndFrom != fToolbarWindow)
1577     {
1578         // not from the toolbar, keep looking for a message handler
1579         bHandled = FALSE;
1580         return 0;
1581     }
1582     SendMessage(fToolbarWindow, TB_GETRECT, notifyInfo->iItem, reinterpret_cast<LPARAM>(&bounds));
1583     ::MapWindowPoints(fToolbarWindow, NULL, reinterpret_cast<POINT *>(&bounds), 2);
1584     switch (notifyInfo->iItem)
1585     {
1586         case IDM_GOTO_BACK:
1587             newMenu = CreatePopupMenu();
1588             hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
1589             hResult = browserService->GetTravelLog(&travelLog);
1590             hResult = travelLog->InsertMenuEntries(browserService, newMenu, 0, 1, 9, TLMENUF_BACK);
1591             commandInfo.cmdID = 0x1d;
1592             hResult = IUnknown_QueryStatus(browserService, CGID_Explorer, 1, &commandInfo, NULL);
1593             if ((commandInfo.cmdf & (OLECMDF_ENABLED | OLECMDF_LATCHED)) == OLECMDF_ENABLED &&
1594                 travelLog->CountEntries(browserService) > 1)
1595             {
1596                 AppendMenuW(newMenu, MF_SEPARATOR, -1, L"");
1597 
1598                 if (LoadStringW(_AtlBaseModule.GetResourceInstance(),
1599                                 IDS_HISTORYTEXT, templateString, sizeof(templateString) / sizeof(wchar_t)) == 0)
1600                     StringCbCopyW(templateString, sizeof(templateString), L"&History\tCtrl+H");
1601 
1602                 AppendMenuW(newMenu, MF_STRING /* | MF_OWNERDRAW */, IDM_EXPLORERBAR_HISTORY, templateString);
1603             }
1604             params.cbSize = sizeof(params);
1605             params.rcExclude = bounds;
1606             selectedItem = TrackPopupMenuEx(newMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
1607                                     bounds.left, bounds.bottom, m_hWnd, &params);
1608             if (selectedItem == IDM_EXPLORERBAR_HISTORY)
1609             {
1610                 V_VT(&parmIn) = VT_I4;
1611                 V_I4(&parmIn) = 1;
1612                 Exec(&CGID_Explorer, 0x1d, 2, &parmIn, NULL);
1613             }
1614             else if (selectedItem != 0)
1615                 hResult = travelLog->Travel(browserService, -selectedItem);
1616             DestroyMenu(newMenu);
1617             break;
1618         case IDM_GOTO_FORWARD:
1619             newMenu = CreatePopupMenu();
1620             hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
1621             hResult = browserService->GetTravelLog(&travelLog);
1622             hResult = travelLog->InsertMenuEntries(browserService, newMenu, 0, 1, 9, TLMENUF_FORE);
1623             commandInfo.cmdID = 0x1d;
1624             hResult = IUnknown_QueryStatus(browserService, CGID_Explorer, 1, &commandInfo, NULL);
1625             if ((commandInfo.cmdf & (OLECMDF_ENABLED | OLECMDF_LATCHED)) == OLECMDF_ENABLED &&
1626                 travelLog->CountEntries(browserService) > 1)
1627             {
1628                 AppendMenuW(newMenu, MF_SEPARATOR, -1, L"");
1629 
1630                 if (LoadStringW(_AtlBaseModule.GetResourceInstance(),
1631                                 IDS_HISTORYTEXT, templateString, sizeof(templateString) / sizeof(wchar_t)) == 0)
1632                     StringCbCopyW(templateString, sizeof(templateString), L"&History\tCtrl+H");
1633 
1634                 AppendMenuW(newMenu, MF_STRING /* | MF_OWNERDRAW */, IDM_EXPLORERBAR_HISTORY, templateString);
1635             }
1636             params.cbSize = sizeof(params);
1637             params.rcExclude = bounds;
1638             selectedItem = TrackPopupMenuEx(newMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
1639                                     bounds.left, bounds.bottom, m_hWnd, &params);
1640             if (selectedItem == IDM_EXPLORERBAR_HISTORY)
1641             {
1642                 V_VT(&parmIn) = VT_I4;
1643                 V_I4(&parmIn) = 1;
1644                 Exec(&CGID_Explorer, 0x1d, 2, &parmIn, NULL);
1645             }
1646             else if (selectedItem != 0)
1647                 hResult = travelLog->Travel(browserService, selectedItem);
1648             DestroyMenu(newMenu);
1649             break;
1650         case gViewsCommandID:
1651             VARIANT                     inValue;
1652             CComVariant                 outValue;
1653             HRESULT                     hResult;
1654 
1655             V_VT(&inValue) = VT_INT_PTR;
1656             V_INTREF(&inValue) = reinterpret_cast<INT *>(&bounds);
1657 
1658             if (fCommandTarget.p != NULL)
1659                 hResult = fCommandTarget->Exec(&fCommandCategory, FCIDM_SHVIEW_AUTOARRANGE, 1, &inValue, &outValue);
1660             // pvaOut is VT_I4 with value 0x403
1661             break;
1662     }
1663     return TBDDRET_DEFAULT;
1664 }
1665 
1666 LRESULT CInternetToolbar::OnQueryInsert(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1667 {
1668     return 1;
1669 }
1670 
1671 LRESULT CInternetToolbar::OnQueryDelete(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1672 {
1673     return 1;
1674 }
1675 
1676 LRESULT CInternetToolbar::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1677 {
1678     HMENU                                   contextMenuBar;
1679     HMENU                                   contextMenu;
1680     POINT                                   clickLocation;
1681     int                                     command;
1682     RBHITTESTINFO                           hitTestInfo;
1683     REBARBANDINFOW                          rebarBandInfo;
1684     int                                     bandID;
1685     BOOL                                    goButtonChecked;
1686 
1687     clickLocation.x = LOWORD(lParam);
1688     clickLocation.y = HIWORD(lParam);
1689     hitTestInfo.pt = clickLocation;
1690     ScreenToClient(&hitTestInfo.pt);
1691     SendMessage(fMainReBar, RB_HITTEST, 0, (LPARAM)&hitTestInfo);
1692     if (hitTestInfo.iBand == -1)
1693         return 0;
1694     rebarBandInfo.cbSize = sizeof(rebarBandInfo);
1695     rebarBandInfo.fMask = RBBIM_ID;
1696     SendMessage(fMainReBar, RB_GETBANDINFOW, hitTestInfo.iBand, (LPARAM)&rebarBandInfo);
1697     bandID = rebarBandInfo.wID;
1698     contextMenuBar = LoadMenu(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(IDM_CABINET_CONTEXTMENU));
1699     contextMenu = GetSubMenu(contextMenuBar, 0);
1700     switch (bandID)
1701     {
1702         case ITBBID_MENUBAND:   // menu 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_BRANDBAND:  // brand band
1708             DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
1709             DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
1710             DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
1711             break;
1712         case ITBBID_TOOLSBAND:  // tools band
1713             DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
1714             DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
1715             break;
1716         case ITBBID_ADDRESSBAND:    // navigation band
1717             DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
1718             DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
1719             break;
1720         default:
1721             break;
1722     }
1723 
1724     SHEnableMenuItem(contextMenu, IDM_TOOLBARS_LINKSBAR, FALSE);
1725 
1726     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_STANDARDBUTTONS, IsBandVisible(ITBBID_TOOLSBAND) == S_OK);
1727     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_ADDRESSBAR, IsBandVisible(ITBBID_ADDRESSBAND) == S_OK);
1728     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_LINKSBAR, FALSE);
1729     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_CUSTOMIZE, FALSE);
1730     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_LOCKTOOLBARS, fLocked);
1731     goButtonChecked = SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
1732     SHCheckMenuItem(contextMenu, IDM_TOOLBARS_GOBUTTON, goButtonChecked);
1733 
1734     // TODO: use GetSystemMetrics(SM_MENUDROPALIGNMENT) to determine menu alignment
1735     command = TrackPopupMenu(contextMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
1736                 clickLocation.x, clickLocation.y, 0, m_hWnd, NULL);
1737     switch (command)
1738     {
1739         case IDM_TOOLBARS_STANDARDBUTTONS:  // standard buttons
1740             ToggleBandVisibility(ITBBID_TOOLSBAND);
1741             break;
1742         case IDM_TOOLBARS_ADDRESSBAR:   // address bar
1743             ToggleBandVisibility(ITBBID_ADDRESSBAND);
1744             break;
1745         case IDM_TOOLBARS_LINKSBAR: // links
1746             break;
1747         case IDM_TOOLBARS_LOCKTOOLBARS: // lock the toolbars
1748             LockUnlockToolbars(!fLocked);
1749             break;
1750         case IDM_TOOLBARS_CUSTOMIZE:    // customize
1751             SendMessage(fToolbarWindow, TB_CUSTOMIZE, 0, 0);
1752             break;
1753         case IDM_TOOLBARS_GOBUTTON:
1754             SendMessage(fNavigationWindow, WM_COMMAND, IDM_TOOLBARS_GOBUTTON, 0);
1755             break;
1756     }
1757 
1758     DestroyMenu(contextMenuBar);
1759     return 1;
1760 }
1761 
1762 LRESULT CInternetToolbar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1763 {
1764     if (wParam != SIZE_MINIMIZED)
1765     {
1766         ::SetWindowPos(fMainReBar, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
1767             SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
1768     }
1769     return 1;
1770 }
1771 
1772 LRESULT CInternetToolbar::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1773 {
1774     if ((short)lParam != HTCLIENT || (HWND)wParam != m_hWnd)
1775     {
1776         bHandled = FALSE;
1777         return 0;
1778     }
1779     SetCursor(LoadCursor(NULL, IDC_SIZENS));
1780     return 1;
1781 }
1782 
1783 LRESULT CInternetToolbar::OnTipText(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
1784 {
1785     CComPtr<IBrowserService>                browserService;
1786     CComPtr<ITravelLog>                     travelLog;
1787     TOOLTIPTEXTW                            *pTTTW;
1788     UINT                                    nID;
1789     HRESULT                                 hResult;
1790     wchar_t                                 tempString[300];
1791 
1792     pTTTW = reinterpret_cast<TOOLTIPTEXTW *>(pNMHDR);
1793     if ((pTTTW->uFlags & TTF_IDISHWND) != 0)
1794         nID = ::GetDlgCtrlID((HWND)pNMHDR->idFrom);
1795     else
1796         nID = (UINT)pNMHDR->idFrom;
1797 
1798     if (nID != 0)
1799     {
1800         if (nID == (UINT)IDM_GOTO_BACK || nID == (UINT)IDM_GOTO_FORWARD)
1801         {
1802             // TODO: Should this call QueryService?
1803             hResult = fSite->QueryInterface(IID_PPV_ARG(IBrowserService, &browserService));
1804             hResult = browserService->GetTravelLog(&travelLog);
1805             hResult = travelLog->GetToolTipText(browserService,
1806                 (nID == (UINT)IDM_GOTO_BACK) ? TLOG_BACK : TLOG_FORE,
1807                 0, tempString, 299);
1808             if (FAILED_UNEXPECTEDLY(hResult))
1809             {
1810                 bHandled = FALSE;
1811                 return 0;
1812             }
1813         }
1814         else
1815             tempString[0] = 0;
1816         wcsncpy (pTTTW->szText, tempString, sizeof(pTTTW->szText) / sizeof(wchar_t));
1817         ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
1818             SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1819         return 0;
1820     }
1821     return 0;
1822 }
1823 
1824 LRESULT CInternetToolbar::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1825 {
1826     LRESULT theResult;
1827     HRESULT hResult;
1828 
1829     hResult = OnWinEvent((HWND) lParam, uMsg, wParam, lParam, &theResult);
1830 
1831     bHandled = hResult == S_OK;
1832 
1833     return FAILED_UNEXPECTEDLY(hResult) ? 0 : theResult;
1834 }
1835 LRESULT CInternetToolbar::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1836 {
1837     NMHDR   *notifyHeader;
1838     LRESULT theResult;
1839     HRESULT hResult;
1840 
1841     notifyHeader = reinterpret_cast<NMHDR *>(lParam);
1842 
1843     hResult = OnWinEvent(notifyHeader->hwndFrom, uMsg, wParam, lParam, &theResult);
1844 
1845     bHandled = hResult == S_OK;
1846 
1847     return FAILED_UNEXPECTEDLY(hResult) ? 0 : theResult;
1848 }
1849 
1850 LRESULT CInternetToolbar::OnLDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1851 {
1852     bHandled = FALSE;
1853     if (fLocked)
1854         return 0;
1855 
1856     if (wParam & MK_CONTROL)
1857         return 0;
1858 
1859     fSizing = TRUE;
1860 
1861     DWORD msgp = GetMessagePos();
1862 
1863     fStartPosition.x = GET_X_LPARAM(msgp);
1864     fStartPosition.y = GET_Y_LPARAM(msgp);
1865 
1866     RECT rc;
1867     GetWindowRect(&rc);
1868 
1869     fStartHeight = rc.bottom - rc.top;
1870 
1871     SetCapture();
1872 
1873     bHandled = TRUE;
1874     return 0;
1875 }
1876 
1877 LRESULT CInternetToolbar::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1878 {
1879     bHandled = FALSE;
1880     if (!fSizing)
1881         return 0;
1882 
1883     DWORD msgp = GetMessagePos();
1884 
1885     POINT pt;
1886     pt.x = GET_X_LPARAM(msgp);
1887     pt.y = GET_Y_LPARAM(msgp);
1888 
1889     ReserveBorderSpace(fStartHeight - fStartPosition.y + pt.y);
1890 
1891     bHandled = TRUE;
1892     return 0;
1893 }
1894 
1895 LRESULT CInternetToolbar::OnLUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1896 {
1897     bHandled = FALSE;
1898     if (!fSizing)
1899         return 0;
1900 
1901     OnMouseMove(uMsg, wParam, lParam, bHandled);
1902 
1903     fSizing = FALSE;
1904 
1905     ReleaseCapture();
1906 
1907     return 0;
1908 }
1909 
1910 LRESULT CInternetToolbar::OnWinIniChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1911 {
1912     HRESULT hr;
1913     HWND hwndMenu;
1914 
1915     hr = IUnknown_GetWindow(fMenuBar, &hwndMenu);
1916     if (FAILED_UNEXPECTEDLY(hr))
1917         return 0;
1918 
1919     CComPtr<IWinEventHandler> menuWinEventHandler;
1920     hr = fMenuBar->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
1921     if (FAILED_UNEXPECTEDLY(hr))
1922         return 0;
1923 
1924     LRESULT lres;
1925     hr = menuWinEventHandler->OnWinEvent(hwndMenu, uMsg, wParam, lParam, &lres);
1926     if (FAILED_UNEXPECTEDLY(hr))
1927         return 0;
1928 
1929     return lres;
1930 }
1931