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