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