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