xref: /reactos/dll/win32/browseui/addressband.cpp (revision 45b08ed3)
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 the navigation band of the cabinet window
23 */
24 
25 #include "precomp.h"
26 #include <commoncontrols.h>
27 #include <shlwapi_undoc.h>
28 #include <shellapi.h>
29 
30 /*
31 TODO:
32 ****Add tooltip notify handler
33   **Properly implement GetBandInfo
34     Implement Exec
35     Implement QueryService
36     Implement Load
37     Implement Save
38 */
39 
40 CAddressBand::CAddressBand()
41 {
42     fEditControl = NULL;
43     fGoButton = NULL;
44     fComboBox = NULL;
45     fGoButtonShown = false;
46     fAdjustNeeded = 0;
47 }
48 
49 CAddressBand::~CAddressBand()
50 {
51 }
52 
53 void CAddressBand::FocusChange(BOOL bFocus)
54 {
55 //    m_bFocus = bFocus;
56 
57     //Inform the input object site that the focus has changed.
58     if (fSite)
59     {
60 #if 0
61         fSite->OnFocusChangeIS((IDockingWindow *)this, bFocus);
62 #endif
63     }
64 }
65 
66 HRESULT STDMETHODCALLTYPE CAddressBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
67 {
68     if (pdbi->dwMask & DBIM_MINSIZE)
69     {
70         if (fGoButtonShown)
71             pdbi->ptMinSize.x = 100;
72         else
73             pdbi->ptMinSize.x = 150;
74         pdbi->ptMinSize.y = 22;
75     }
76     if (pdbi->dwMask & DBIM_MAXSIZE)
77     {
78         pdbi->ptMaxSize.x = 0;
79         pdbi->ptMaxSize.y = 0;
80     }
81     if (pdbi->dwMask & DBIM_INTEGRAL)
82     {
83         pdbi->ptIntegral.x = 0;
84         pdbi->ptIntegral.y = 0;
85     }
86     if (pdbi->dwMask & DBIM_ACTUAL)
87     {
88         if (fGoButtonShown)
89             pdbi->ptActual.x = 100;
90         else
91             pdbi->ptActual.x = 150;
92         pdbi->ptActual.y = 22;
93     }
94     if (pdbi->dwMask & DBIM_TITLE)
95     {
96         if (!LoadStringW(_AtlBaseModule.GetResourceInstance(), IDS_ADDRESSBANDLABEL, pdbi->wszTitle, _countof(pdbi->wszTitle)))
97             return HRESULT_FROM_WIN32(GetLastError());
98     }
99 
100     if (pdbi->dwMask & DBIM_MODEFLAGS)
101         pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
102     if (pdbi->dwMask & DBIM_BKCOLOR)
103         pdbi->crBkgnd = 0;
104     return S_OK;
105 }
106 
107 HRESULT STDMETHODCALLTYPE CAddressBand::SetSite(IUnknown *pUnkSite)
108 {
109     CComPtr<IShellService>                  shellService;
110     HWND                                    parentWindow;
111     HWND                                    combobox;
112     HRESULT                                 hResult;
113     IImageList                              *piml;
114 
115     if (pUnkSite == NULL)
116     {
117         fSite.Release();
118         return S_OK;
119     }
120 
121     fSite.Release();
122 
123     hResult = pUnkSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &fSite));
124     if (FAILED_UNEXPECTEDLY(hResult))
125         return hResult;
126 
127     // get window handle of parent
128     parentWindow = NULL;
129     hResult = IUnknown_GetWindow(fSite, &parentWindow);
130 
131     if (!::IsWindow(parentWindow))
132         return E_FAIL;
133 
134     // create combo box ex
135     combobox = CreateWindowEx(WS_EX_TOOLWINDOW, WC_COMBOBOXEXW, NULL, WS_CHILD | WS_VISIBLE |
136         WS_CLIPCHILDREN | WS_TABSTOP | CCS_NODIVIDER | CCS_NOMOVEY | CBS_OWNERDRAWFIXED,
137                     0, 0, 500, 250, parentWindow, (HMENU)IDM_TOOLBARS_ADDRESSBAR, _AtlBaseModule.GetModuleInstance(), 0);
138     if (combobox == NULL)
139         return E_FAIL;
140     SubclassWindow(combobox);
141 
142     HRESULT hr = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &piml));
143     if (FAILED_UNEXPECTEDLY(hr))
144     {
145         SendMessageW(combobox, CBEM_SETIMAGELIST, 0, 0);
146     }
147     else
148     {
149         SendMessageW(combobox, CBEM_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(piml));
150     }
151 
152     SendMessage(CBEM_SETEXTENDEDSTYLE,
153         CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT, CBES_EX_CASESENSITIVE | CBES_EX_NOSIZELIMIT);
154 
155     fEditControl = reinterpret_cast<HWND>(SendMessage(CBEM_GETEDITCONTROL, 0, 0));
156     fComboBox = reinterpret_cast<HWND>(SendMessage(CBEM_GETCOMBOCONTROL, 0, 0));
157     hResult = CAddressEditBox_CreateInstance(IID_PPV_ARG(IAddressEditBox, &fAddressEditBox));
158     if (FAILED_UNEXPECTEDLY(hResult))
159         return hResult;
160 
161     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &shellService));
162     if (FAILED_UNEXPECTEDLY(hResult))
163         return hResult;
164     hResult = fAddressEditBox->Init(combobox, fEditControl, 8, fSite /*(IAddressBand *)this*/);
165     if (FAILED_UNEXPECTEDLY(hResult))
166         return hResult;
167     hResult = shellService->SetOwner(fSite);
168     if (FAILED_UNEXPECTEDLY(hResult))
169         return hResult;
170 
171     fGoButtonShown = SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
172     if (fGoButtonShown)
173         CreateGoButton();
174 
175     return hResult;
176 }
177 
178 HRESULT STDMETHODCALLTYPE CAddressBand::GetSite(REFIID riid, void **ppvSite)
179 {
180     if (fSite == NULL)
181         return E_FAIL;
182     return fSite->QueryInterface(riid, ppvSite);
183 }
184 
185 HRESULT STDMETHODCALLTYPE CAddressBand::GetWindow(HWND *lphwnd)
186 {
187     if (lphwnd == NULL)
188         return E_POINTER;
189     *lphwnd = m_hWnd;
190     return S_OK;
191 }
192 
193 HRESULT STDMETHODCALLTYPE CAddressBand::ContextSensitiveHelp(BOOL fEnterMode)
194 {
195     return E_NOTIMPL;
196 }
197 
198 HRESULT STDMETHODCALLTYPE CAddressBand::CloseDW(DWORD dwReserved)
199 {
200     ShowDW(FALSE);
201 
202     if (IsWindow())
203         DestroyWindow();
204 
205     m_hWnd = NULL;
206 
207     CComPtr<IShellService> pservice;
208     HRESULT hres = fAddressEditBox->QueryInterface(IID_PPV_ARG(IShellService, &pservice));
209     if (SUCCEEDED(hres ))
210         pservice->SetOwner(NULL);
211 
212     if (fAddressEditBox) fAddressEditBox.Release();
213     if (fSite) fSite.Release();
214 
215     if (m_himlNormal)
216         ImageList_Destroy(m_himlNormal);
217 
218     if (m_himlHot)
219         ImageList_Destroy(m_himlHot);
220 
221     return S_OK;
222 }
223 
224 HRESULT STDMETHODCALLTYPE CAddressBand::ResizeBorderDW(
225     const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
226 {
227     return E_NOTIMPL;
228 }
229 
230 HRESULT STDMETHODCALLTYPE CAddressBand::ShowDW(BOOL fShow)
231 {
232     if (m_hWnd)
233     {
234         if (fShow)
235             ShowWindow(SW_SHOW);
236         else
237             ShowWindow(SW_HIDE);
238     }
239     return S_OK;
240 }
241 
242 HRESULT STDMETHODCALLTYPE CAddressBand::QueryStatus(
243     const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[  ], OLECMDTEXT *pCmdText)
244 {
245     return IUnknown_QueryStatus(fAddressEditBox, *pguidCmdGroup, cCmds, prgCmds, pCmdText);
246 }
247 
248 HRESULT STDMETHODCALLTYPE CAddressBand::Exec(const GUID *pguidCmdGroup,
249     DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
250 {
251     // incomplete
252     return E_NOTIMPL;
253 }
254 
255 HRESULT STDMETHODCALLTYPE CAddressBand::HasFocusIO()
256 {
257     if (GetFocus() == fEditControl || SendMessage(CB_GETDROPPEDSTATE, 0, 0))
258         return S_OK;
259     return S_FALSE;
260 }
261 
262 HRESULT STDMETHODCALLTYPE CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg)
263 {
264     if (lpMsg->hwnd == fEditControl)
265     {
266         switch (lpMsg->message)
267         {
268         case WM_SYSKEYDOWN:
269         case WM_SYSKEYUP:
270         case WM_SYSCOMMAND:
271         case WM_SYSDEADCHAR:
272         case WM_SYSCHAR:
273             return S_FALSE;
274         }
275 
276         TranslateMessage(lpMsg);
277         DispatchMessage(lpMsg);
278         return S_OK;
279     }
280     return S_FALSE;
281 }
282 
283 HRESULT STDMETHODCALLTYPE CAddressBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
284 {
285     if (fActivate)
286     {
287         IUnknown_OnFocusChangeIS(fSite, static_cast<IDeskBand *>(this), fActivate);
288         SetFocus();
289     }
290     return S_OK;
291 }
292 
293 HRESULT STDMETHODCALLTYPE CAddressBand::OnWinEvent(
294     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
295 {
296     CComPtr<IWinEventHandler>               winEventHandler;
297     HRESULT                                 hResult;
298     RECT                                    rect;
299 
300     if (theResult)
301         *theResult = 0;
302 
303     switch (uMsg)
304     {
305         case WM_WININICHANGE:
306             break;
307         case WM_COMMAND:
308             if (wParam == IDM_TOOLBARS_GOBUTTON)
309             {
310                 fGoButtonShown = !SHRegGetBoolUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", FALSE, TRUE);
311                 SHRegSetUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main", L"ShowGoButton", REG_SZ, fGoButtonShown ? (LPVOID)L"yes" : (LPVOID)L"no", fGoButtonShown ? 8 : 6, SHREGSET_FORCE_HKCU);
312                 if (!fGoButton)
313                     CreateGoButton();
314                 ::ShowWindow(fGoButton,fGoButtonShown ? SW_HIDE : SW_SHOW);
315                 GetWindowRect(&rect);
316                 SendMessage(m_hWnd,WM_SIZE,0,MAKELPARAM(rect.right-rect.left,rect.bottom-rect.top));
317                 // broadcast change notification to all explorer windows
318             }
319             break;
320     }
321     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
322     if (FAILED_UNEXPECTEDLY(hResult))
323         return hResult;
324     return winEventHandler->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
325 }
326 
327 HRESULT STDMETHODCALLTYPE CAddressBand::IsWindowOwner(HWND hWnd)
328 {
329     CComPtr<IWinEventHandler>               winEventHandler;
330     HRESULT                                 hResult;
331 
332     if (fAddressEditBox)
333     {
334         hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
335         if (FAILED_UNEXPECTEDLY(hResult))
336             return hResult;
337         return winEventHandler->IsWindowOwner(hWnd);
338     }
339     return S_FALSE;
340 }
341 
342 HRESULT STDMETHODCALLTYPE CAddressBand::FileSysChange(long param8, long paramC)
343 {
344     CComPtr<IAddressBand>                   addressBand;
345     HRESULT                                 hResult;
346 
347     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
348     if (FAILED_UNEXPECTEDLY(hResult))
349         return hResult;
350     return addressBand->FileSysChange(param8, paramC);
351 }
352 
353 HRESULT STDMETHODCALLTYPE CAddressBand::Refresh(long param8)
354 {
355     CComPtr<IAddressBand>                   addressBand;
356     HRESULT                                 hResult;
357 
358     hResult = fAddressEditBox->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
359     if (FAILED_UNEXPECTEDLY(hResult))
360         return hResult;
361     return addressBand->Refresh(param8);
362 }
363 
364 HRESULT STDMETHODCALLTYPE CAddressBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
365 {
366     return E_NOTIMPL;
367 }
368 
369 HRESULT STDMETHODCALLTYPE CAddressBand::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
370 {
371     return E_NOTIMPL;
372 }
373 
374 HRESULT STDMETHODCALLTYPE CAddressBand::GetClassID(CLSID *pClassID)
375 {
376     if (pClassID == NULL)
377         return E_POINTER;
378     *pClassID = CLSID_SH_AddressBand;
379     return S_OK;
380 }
381 
382 HRESULT STDMETHODCALLTYPE CAddressBand::IsDirty()
383 {
384     return E_NOTIMPL;
385 }
386 
387 HRESULT STDMETHODCALLTYPE CAddressBand::Load(IStream *pStm)
388 {
389     // incomplete
390     return E_NOTIMPL;
391 }
392 
393 HRESULT STDMETHODCALLTYPE CAddressBand::Save(IStream *pStm, BOOL fClearDirty)
394 {
395     // incomplete
396     return E_NOTIMPL;
397 }
398 
399 HRESULT STDMETHODCALLTYPE CAddressBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
400 {
401     // incomplete
402     return E_NOTIMPL;
403 }
404 
405 LRESULT CAddressBand::OnNotifyClick(WPARAM wParam, NMHDR *notifyHeader, BOOL &bHandled)
406 {
407     if (notifyHeader->hwndFrom == fGoButton)
408     {
409         fAddressEditBox->Execute(0);
410     }
411     return 0;
412 }
413 
414 LRESULT CAddressBand::OnTipText(UINT idControl, NMHDR *notifyHeader, BOOL &bHandled)
415 {
416     if (notifyHeader->hwndFrom == fGoButton)
417     {
418         // TODO
419         // Go to "destination path"
420     }
421     return 0;
422 }
423 
424 LRESULT CAddressBand::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
425 {
426     POINT                                   pt;
427     POINT                                   ptOrig;
428     HWND                                    parentWindow;
429     LRESULT                                 result;
430 
431     if (fGoButtonShown == false)
432     {
433         bHandled = FALSE;
434         return 0;
435     }
436     pt.x = 0;
437     pt.y = 0;
438     parentWindow = GetParent();
439     ::MapWindowPoints(m_hWnd, parentWindow, &pt, 1);
440     OffsetWindowOrgEx(reinterpret_cast<HDC>(wParam), pt.x, pt.y, &ptOrig);
441     result = SendMessage(parentWindow, WM_ERASEBKGND, wParam, 0);
442     SetWindowOrgEx(reinterpret_cast<HDC>(wParam), ptOrig.x, ptOrig.y, NULL);
443     if (result == 0)
444     {
445         bHandled = FALSE;
446         return 0;
447     }
448     return result;
449 }
450 
451 LRESULT CAddressBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
452 {
453     RECT                                    goButtonBounds;
454     RECT                                    buttonBounds;
455     long                                    buttonWidth;
456     long                                    buttonHeight;
457     RECT                                    comboBoxBounds;
458     long                                    newHeight;
459     long                                    newWidth;
460 
461     fAdjustNeeded = 1;
462 
463     if (fGoButtonShown == false)
464     {
465         bHandled = FALSE;
466         return 0;
467     }
468 
469     newHeight = HIWORD(lParam);
470     newWidth = LOWORD(lParam);
471 
472     if (!fGoButton)
473         CreateGoButton();
474 
475     SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
476     buttonWidth = buttonBounds.right - buttonBounds.left;
477     buttonHeight = buttonBounds.bottom - buttonBounds.top;
478 
479     DefWindowProc(WM_SIZE, wParam, MAKELONG(newWidth - buttonWidth - 2, newHeight));
480     ::GetWindowRect(fComboBox, &comboBoxBounds);
481     ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
482                     buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
483 
484     goButtonBounds.left = newWidth - buttonWidth;
485     goButtonBounds.top = 0;
486     goButtonBounds.right = newWidth - buttonWidth;
487     goButtonBounds.bottom = newHeight;
488     InvalidateRect(&goButtonBounds, TRUE);
489 
490     SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
491     return 0;
492 }
493 
494 LRESULT CAddressBand::OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
495 {
496     RECT                                    goButtonBounds;
497     RECT                                    buttonBounds;
498     long                                    buttonWidth;
499     long                                    buttonHeight;
500     RECT                                    comboBoxBounds;
501     WINDOWPOS                               positionInfoCopy;
502     long                                    newHeight;
503     long                                    newWidth;
504 
505     if (!fGoButtonShown)
506     {
507         bHandled = FALSE;
508         return 0;
509     }
510 
511     if (!fGoButton)
512         CreateGoButton();
513 
514     positionInfoCopy = *reinterpret_cast<WINDOWPOS *>(lParam);
515     newHeight = positionInfoCopy.cy;
516     newWidth = positionInfoCopy.cx;
517 
518 /*
519     Sometimes when we get here newWidth = 100 which comes from GetBandInfo and is less than the 200 that we need.
520     We need room for the "Address" text (50 pixels), the "GoButton" (50 pixels), the left and right borders (30 pixels)
521     the icon (20 pixels) and the ComboBox (50 pixels) for handling the text of the current directory. This is 200 pixels.
522     When newWidth = 100 the Addressband ComboBox will only have a single character because it becomes 2 pixels wide.
523     The hack below readjusts the width to the minimum required to allow seeing the whole text and prints out a debug message.
524 */
525 
526     if ((newWidth < 200) && (newWidth != 0))
527     {
528         if (fAdjustNeeded == 1)
529         {
530             ERR("CORE-13003 HACK: Addressband ComboBox width readjusted from %ld to 200.\n", newWidth);
531             newWidth = 200;
532             fAdjustNeeded = 0;
533         }
534     }
535     SendMessage(fGoButton, TB_GETITEMRECT, 0, reinterpret_cast<LPARAM>(&buttonBounds));
536 
537     buttonWidth = buttonBounds.right - buttonBounds.left;
538     buttonHeight = buttonBounds.bottom - buttonBounds.top;
539     positionInfoCopy.cx = newWidth - 2 - buttonWidth;
540     DefWindowProc(WM_WINDOWPOSCHANGING, wParam, reinterpret_cast<LPARAM>(&positionInfoCopy));
541     ::GetWindowRect(fComboBox, &comboBoxBounds);
542     ::SetWindowPos(fGoButton, NULL, newWidth - buttonWidth, (comboBoxBounds.bottom - comboBoxBounds.top - buttonHeight) / 2,
543                     buttonWidth, buttonHeight, SWP_NOOWNERZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
544 
545     goButtonBounds.left = newWidth - buttonWidth;
546     goButtonBounds.top = 0;
547     goButtonBounds.right = newWidth - buttonWidth;
548     goButtonBounds.bottom = newHeight;
549     InvalidateRect(&goButtonBounds, TRUE);
550 
551     SendMessage(fComboBox, CB_SETDROPPEDWIDTH, 200, 0);
552     return 0;
553 }
554 
555 void CAddressBand::CreateGoButton()
556 {
557     const TBBUTTON buttonInfo [] = { { 0, 1, TBSTATE_ENABLED, 0 } };
558     HINSTANCE             shellInstance;
559 
560     shellInstance = _AtlBaseModule.GetResourceInstance();
561     m_himlNormal = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL),
562                                            20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
563     m_himlHot = ImageList_LoadImageW(shellInstance, MAKEINTRESOURCE(IDB_GOBUTTON_HOT),
564                                         20, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
565 
566     fGoButton = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAMEW, 0, WS_CHILD | WS_CLIPSIBLINGS |
567                                WS_CLIPCHILDREN | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER |
568                                CCS_NOPARENTALIGN | CCS_NORESIZE,
569                                0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
570     SendMessage(fGoButton, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
571     SendMessage(fGoButton, TB_SETMAXTEXTROWS, 1, 0);
572     if (m_himlNormal)
573         SendMessage(fGoButton, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlNormal));
574     if (m_himlHot)
575         SendMessage(fGoButton, TB_SETHOTIMAGELIST, 0, reinterpret_cast<LPARAM>(m_himlHot));
576     SendMessage(fGoButton, TB_ADDSTRINGW,
577                 reinterpret_cast<WPARAM>(_AtlBaseModule.GetResourceInstance()), IDS_GOBUTTONLABEL);
578     SendMessage(fGoButton, TB_ADDBUTTONSW, 1, (LPARAM) &buttonInfo);
579 }
580