4 * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
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.
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.
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
22 Implements the navigation band of the cabinet window
26 #include <commoncontrols.h>
27 #include <shlwapi_undoc.h>
30 HRESULT
CreateAddressEditBox(REFIID riid
, void **ppv
);
33 HRESULT WINAPI
SHGetImageList(
41 ****Add command handler for show/hide Go button to OnWinEvent
42 ****Add tooltip notify handler
43 **Properly implement GetBandInfo
44 **Add support for showing/hiding Go button
45 **Fix so Go button will be shown/hidden properly on load
46 **Add correct text to Go button
47 **Implement TranslateAcceleratorIO
49 Implement QueryService
54 CAddressBand::CAddressBand()
59 fGoButtonShown
= false;
63 CAddressBand::~CAddressBand()
67 void CAddressBand::FocusChange(BOOL bFocus
)
71 //Inform the input object site that the focus has changed.
75 fSite
->OnFocusChangeIS((IDockingWindow
*)this, bFocus
);
80 HRESULT STDMETHODCALLTYPE
CAddressBand::GetBandInfo(DWORD dwBandID
, DWORD dwViewMode
, DESKBANDINFO
*pdbi
)
82 if (pdbi
->dwMask
& DBIM_MINSIZE
)
84 pdbi
->ptMinSize
.x
= 400;
85 pdbi
->ptMinSize
.y
= 22;
87 if (pdbi
->dwMask
& DBIM_MAXSIZE
)
89 pdbi
->ptMaxSize
.x
= 0;
90 pdbi
->ptMaxSize
.y
= 0;
92 if (pdbi
->dwMask
& DBIM_INTEGRAL
)
94 pdbi
->ptIntegral
.x
= 0;
95 pdbi
->ptIntegral
.y
= 0;
97 if (pdbi
->dwMask
& DBIM_ACTUAL
)
99 pdbi
->ptActual
.x
= 400;
100 pdbi
->ptActual
.y
= 22;
102 if (pdbi
->dwMask
& DBIM_TITLE
)
103 wcscpy(pdbi
->wszTitle
, L
"Address");
104 if (pdbi
->dwMask
& DBIM_MODEFLAGS
)
105 pdbi
->dwModeFlags
= DBIMF_UNDELETEABLE
;
106 if (pdbi
->dwMask
& DBIM_BKCOLOR
)
111 HRESULT STDMETHODCALLTYPE
CAddressBand::SetSite(IUnknown
*pUnkSite
)
113 CComPtr
<IBrowserService
> browserService
;
114 CComPtr
<IOleWindow
> oleWindow
;
115 CComPtr
<IShellService
> shellService
;
116 CComPtr
<IUnknown
> offset34
;
119 static const TBBUTTON buttonInfo
[] = { {0, 1, TBSTATE_ENABLED
, 0} };
120 HIMAGELIST normalImagelist
;
121 HIMAGELIST hotImageList
;
122 HINSTANCE shellInstance
;
125 if (pUnkSite
== NULL
)
127 hResult
= AtlUnadvise(fSite
, DIID_DWebBrowserEvents
, fAdviseCookie
);
134 hResult
= pUnkSite
->QueryInterface(IID_PPV_ARG(IDockingWindowSite
, &fSite
));
138 // get window handle of parent
140 hResult
= IUnknown_GetWindow(pUnkSite
, &parentWindow
);
142 if (!::IsWindow(parentWindow
))
145 // create combo box ex
146 combobox
= CreateWindowEx(WS_EX_TOOLWINDOW
, WC_COMBOBOXEXW
, NULL
, WS_CHILD
| WS_VISIBLE
|
147 WS_CLIPCHILDREN
| WS_TABSTOP
| CCS_NODIVIDER
| CCS_NOMOVEY
| CBS_OWNERDRAWFIXED
,
148 0, 0, 500, 250, parentWindow
, (HMENU
)0xa205, _AtlBaseModule
.GetModuleInstance(), 0);
149 if (combobox
== NULL
)
151 SubclassWindow(combobox
);
153 SendMessage(CBEM_SETEXTENDEDSTYLE
,
154 CBES_EX_CASESENSITIVE
| CBES_EX_NOSIZELIMIT
, CBES_EX_CASESENSITIVE
| CBES_EX_NOSIZELIMIT
);
156 fEditControl
= reinterpret_cast<HWND
>(SendMessage(CBEM_GETEDITCONTROL
, 0, 0));
157 fComboBox
= reinterpret_cast<HWND
>(SendMessage(CBEM_GETCOMBOCONTROL
, 0, 0));
159 hResult
= CoCreateInstance(CLSID_AddressEditBox
, NULL
, CLSCTX_INPROC_SERVER
,
160 IID_PPV_ARG(IAddressEditBox
, &fAddressEditBox
));
166 // instantiate new version
167 hResult
= CreateAddressEditBox(IID_PPV_ARG(IAddressEditBox
, &fAddressEditBox
));
172 hResult
= fAddressEditBox
->QueryInterface(IID_PPV_ARG(IShellService
, &shellService
));
175 hResult
= fAddressEditBox
->Init(combobox
, fEditControl
, 8, pUnkSite
/*(IAddressBand *)this*/);
178 hResult
= shellService
->SetOwner(pUnkSite
);
182 // TODO: properly initialize this from registry
183 fGoButtonShown
= true;
185 shellInstance
= GetModuleHandle(_T("shell32.dll"));
186 normalImagelist
= ImageList_LoadImageW(shellInstance
, MAKEINTRESOURCE(IDB_GOBUTTON_NORMAL
),
187 20, 0, RGB(255, 0, 255), IMAGE_BITMAP
, LR_CREATEDIBSECTION
);
188 hotImageList
= ImageList_LoadImageW(shellInstance
, MAKEINTRESOURCE(IDB_GOBUTTON_HOT
),
189 20, 0, RGB(255, 0, 255), IMAGE_BITMAP
, LR_CREATEDIBSECTION
);
191 fGoButton
= CreateWindowEx(WS_EX_TOOLWINDOW
, TOOLBARCLASSNAMEW
, 0, WS_CHILD
| WS_CLIPSIBLINGS
|
192 WS_CLIPCHILDREN
| TBSTYLE_LIST
| TBSTYLE_FLAT
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
|
193 CCS_NOPARENTALIGN
| CCS_NORESIZE
,
194 0, 0, 0, 0, m_hWnd
, NULL
, _AtlBaseModule
.GetModuleInstance(), NULL
);
195 SendMessage(fGoButton
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
196 SendMessage(fGoButton
, TB_SETMAXTEXTROWS
, 1, 0);
198 SendMessage(fGoButton
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(normalImagelist
));
200 SendMessage(fGoButton
, TB_SETHOTIMAGELIST
, 0, reinterpret_cast<LPARAM
>(hotImageList
));
201 SendMessage(fGoButton
, TB_ADDSTRINGW
,
202 reinterpret_cast<WPARAM
>(_AtlBaseModule
.GetResourceInstance()), IDS_GOBUTTONLABEL
);
203 SendMessage(fGoButton
, TB_ADDBUTTONSW
, 1, (LPARAM
)&buttonInfo
);
206 HRESULT hr
= SHGetImageList(SHIL_SMALL
, IID_PPV_ARG(IImageList
, &piml
));
207 if (FAILED_UNEXPECTEDLY(hr
))
209 SendMessageW(combobox
, CBEM_SETIMAGELIST
, 0, 0);
213 SendMessageW(combobox
, CBEM_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(piml
));
216 // take advice to watch events
217 hResult
= IUnknown_QueryService(pUnkSite
, SID_SShellBrowser
, IID_PPV_ARG(IBrowserService
, &browserService
));
218 if (SUCCEEDED(hResult
))
220 hResult
= AtlAdvise(browserService
, static_cast<IDispatch
*>(this), DIID_DWebBrowserEvents
, &fAdviseCookie
);
226 HRESULT STDMETHODCALLTYPE
CAddressBand::GetSite(REFIID riid
, void **ppvSite
)
230 return fSite
->QueryInterface(riid
, ppvSite
);
233 HRESULT STDMETHODCALLTYPE
CAddressBand::GetWindow(HWND
*lphwnd
)
241 HRESULT STDMETHODCALLTYPE
CAddressBand::ContextSensitiveHelp(BOOL fEnterMode
)
246 HRESULT STDMETHODCALLTYPE
CAddressBand::CloseDW(DWORD dwReserved
)
258 HRESULT STDMETHODCALLTYPE
CAddressBand::ResizeBorderDW(
259 const RECT
*prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
)
264 HRESULT STDMETHODCALLTYPE
CAddressBand::ShowDW(BOOL fShow
)
276 HRESULT STDMETHODCALLTYPE
CAddressBand::QueryStatus(
277 const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[ ], OLECMDTEXT
*pCmdText
)
279 CComPtr
<IOleCommandTarget
> oleCommandTarget
;
282 hResult
= fAddressEditBox
->QueryInterface(IID_PPV_ARG(IOleCommandTarget
, &oleCommandTarget
));
285 return oleCommandTarget
->QueryStatus(pguidCmdGroup
, cCmds
, prgCmds
, pCmdText
);
288 HRESULT STDMETHODCALLTYPE
CAddressBand::Exec(const GUID
*pguidCmdGroup
,
289 DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
295 HRESULT STDMETHODCALLTYPE
CAddressBand::HasFocusIO()
297 if (GetFocus() == fEditControl
|| SendMessage(CB_GETDROPPEDSTATE
, 0, 0))
302 HRESULT STDMETHODCALLTYPE
CAddressBand::TranslateAcceleratorIO(LPMSG lpMsg
)
304 if (lpMsg
->hwnd
== fEditControl
)
306 switch (lpMsg
->message
)
316 TranslateMessage(lpMsg
);
317 DispatchMessage(lpMsg
);
323 HRESULT STDMETHODCALLTYPE
CAddressBand::UIActivateIO(BOOL fActivate
, LPMSG lpMsg
)
325 CComPtr
<IInputObjectSite
> inputObjectSite
;
330 hResult
= fSite
->QueryInterface(IID_PPV_ARG(IInputObjectSite
, &inputObjectSite
));
333 hResult
= inputObjectSite
->OnFocusChangeIS(static_cast<IDeskBand
*>(this), fActivate
);
339 HRESULT STDMETHODCALLTYPE
CAddressBand::OnWinEvent(
340 HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
342 CComPtr
<IWinEventHandler
> winEventHandler
;
347 case WM_WININICHANGE
:
350 if (wParam
== IDM_TOOLBARS_GOBUTTON
)
352 // toggle whether the Go button is displayed
353 // setting is Yes or No, stored in key "Software\Microsoft\Internet Explorer\Main" in value ShowGoButton
354 // broadcast change notification to all explorer windows
358 hResult
= fAddressEditBox
->QueryInterface(IID_PPV_ARG(IWinEventHandler
, &winEventHandler
));
361 return winEventHandler
->OnWinEvent(hWnd
, uMsg
, wParam
, lParam
, theResult
);
364 HRESULT STDMETHODCALLTYPE
CAddressBand::IsWindowOwner(HWND hWnd
)
366 CComPtr
<IWinEventHandler
> winEventHandler
;
371 hResult
= fAddressEditBox
->QueryInterface(IID_PPV_ARG(IWinEventHandler
, &winEventHandler
));
374 return winEventHandler
->IsWindowOwner(hWnd
);
379 HRESULT STDMETHODCALLTYPE
CAddressBand::FileSysChange(long param8
, long paramC
)
381 CComPtr
<IAddressBand
> addressBand
;
384 hResult
= fAddressEditBox
->QueryInterface(IID_PPV_ARG(IAddressBand
, &addressBand
));
387 return addressBand
->FileSysChange(param8
, paramC
);
390 HRESULT STDMETHODCALLTYPE
CAddressBand::Refresh(long param8
)
392 CComPtr
<IAddressBand
> addressBand
;
395 hResult
= fAddressEditBox
->QueryInterface(IID_PPV_ARG(IAddressBand
, &addressBand
));
398 return addressBand
->Refresh(param8
);
401 HRESULT STDMETHODCALLTYPE
CAddressBand::QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
)
406 HRESULT STDMETHODCALLTYPE
CAddressBand::OnFocusChangeIS(IUnknown
*punkObj
, BOOL fSetFocus
)
411 HRESULT STDMETHODCALLTYPE
CAddressBand::GetClassID(CLSID
*pClassID
)
413 if (pClassID
== NULL
)
415 *pClassID
= CLSID_SH_AddressBand
;
419 HRESULT STDMETHODCALLTYPE
CAddressBand::IsDirty()
424 HRESULT STDMETHODCALLTYPE
CAddressBand::Load(IStream
*pStm
)
430 HRESULT STDMETHODCALLTYPE
CAddressBand::Save(IStream
*pStm
, BOOL fClearDirty
)
436 HRESULT STDMETHODCALLTYPE
CAddressBand::GetSizeMax(ULARGE_INTEGER
*pcbSize
)
442 HRESULT STDMETHODCALLTYPE
CAddressBand::GetTypeInfoCount(UINT
*pctinfo
)
447 HRESULT STDMETHODCALLTYPE
CAddressBand::GetTypeInfo(UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
452 HRESULT STDMETHODCALLTYPE
CAddressBand::GetIDsOfNames(REFIID riid
, LPOLESTR
*rgszNames
, UINT cNames
,
453 LCID lcid
, DISPID
*rgDispId
)
458 HRESULT STDMETHODCALLTYPE
CAddressBand::Invoke(DISPID dispIdMember
, REFIID riid
, LCID lcid
, WORD wFlags
,
459 DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
461 CComPtr
<IBrowserService
> isb
;
462 CComPtr
<IShellFolder
> sf
;
464 INT indexClosed
, indexOpen
, itemExists
, oldIndex
;
466 COMBOBOXEXITEMW item
;
467 PIDLIST_ABSOLUTE absolutePIDL
;
468 LPCITEMIDLIST pidlChild
;
469 LPITEMIDLIST pidlPrevious
;
473 if (pDispParams
== NULL
)
476 switch (dispIdMember
)
478 case DISPID_NAVIGATECOMPLETE2
:
479 case DISPID_DOCUMENTCOMPLETE
:
481 oldIndex
= SendMessage(m_hWnd
, CB_GETCURSEL
, 0, 0);
483 item
.mask
= CBEIF_LPARAM
;
485 itemExists
= SendMessage(m_hWnd
, CBEM_GETITEM
, 0, reinterpret_cast<LPARAM
>(&item
));
488 pidlPrevious
= reinterpret_cast<LPITEMIDLIST
>(item
.lParam
);
491 hr
= IUnknown_QueryService(fSite
, SID_STopLevelBrowser
, IID_PPV_ARG(IBrowserService
, &isb
));
494 isb
->GetPidl(&absolutePIDL
);
496 SHBindToParent(absolutePIDL
, IID_PPV_ARG(IShellFolder
, &sf
), &pidlChild
);
498 sf
->GetDisplayNameOf(pidlChild
, SHGDN_FORADDRESSBAR
| SHGDN_FORPARSING
, &ret
);
500 StrRetToBufW(&ret
, pidlChild
, buf
, 4095);
502 indexClosed
= SHMapPIDLToSystemImageListIndex(sf
, pidlChild
, &indexOpen
);
504 item
.mask
= CBEIF_IMAGE
| CBEIF_SELECTEDIMAGE
| CBEIF_TEXT
| CBEIF_LPARAM
;
506 item
.iImage
= indexClosed
;
507 item
.iSelectedImage
= indexOpen
;
509 item
.lParam
= reinterpret_cast<LPARAM
>(absolutePIDL
);
513 result
= SendMessage(m_hWnd
, CBEM_SETITEM
, 0, reinterpret_cast<LPARAM
>(&item
));
517 ILFree(pidlPrevious
);
522 oldIndex
= SendMessage(m_hWnd
, CBEM_INSERTITEM
, 0, reinterpret_cast<LPARAM
>(&item
));
525 DbgPrint("ERROR %d\n", GetLastError());
528 SendMessage(m_hWnd
, CB_SETCURSEL
, -1, 0);
529 SendMessage(m_hWnd
, CB_SETCURSEL
, oldIndex
, 0);
531 //fAddressEditBox->SetCurrentDir(index);
538 LRESULT
CAddressBand::OnNotifyClick(WPARAM wParam
, NMHDR
*notifyHeader
, BOOL
&bHandled
)
540 if (notifyHeader
->hwndFrom
== fGoButton
)
542 fAddressEditBox
->ParseNow(0);
543 fAddressEditBox
->Execute(0);
548 LRESULT
CAddressBand::OnTipText(UINT idControl
, NMHDR
*notifyHeader
, BOOL
&bHandled
)
550 if (notifyHeader
->hwndFrom
== fGoButton
)
553 // Go to "destination path"
558 LRESULT
CAddressBand::OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
565 if (fGoButtonShown
== false)
572 parentWindow
= GetParent();
573 ::MapWindowPoints(m_hWnd
, parentWindow
, &pt
, 1);
574 OffsetWindowOrgEx(reinterpret_cast<HDC
>(wParam
), pt
.x
, pt
.y
, &ptOrig
);
575 result
= SendMessage(parentWindow
, WM_ERASEBKGND
, wParam
, 0);
576 SetWindowOrgEx(reinterpret_cast<HDC
>(wParam
), ptOrig
.x
, ptOrig
.y
, NULL
);
585 LRESULT
CAddressBand::OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
595 if (fGoButtonShown
== false)
601 newHeight
= HIWORD(lParam
);
602 newWidth
= LOWORD(lParam
);
604 SendMessage(fGoButton
, TB_GETITEMRECT
, 0, reinterpret_cast<LPARAM
>(&buttonBounds
));
605 buttonWidth
= buttonBounds
.right
- buttonBounds
.left
;
606 buttonHeight
= buttonBounds
.bottom
- buttonBounds
.top
;
608 DefWindowProc(WM_SIZE
, wParam
, MAKELONG(newWidth
- buttonWidth
- 2, newHeight
));
609 ::GetWindowRect(fComboBox
, &comboBoxBounds
);
610 ::SetWindowPos(fGoButton
, NULL
, newWidth
- buttonWidth
, (comboBoxBounds
.bottom
- comboBoxBounds
.top
- buttonHeight
) / 2,
611 buttonWidth
, buttonHeight
, SWP_NOOWNERZORDER
| SWP_SHOWWINDOW
| SWP_NOACTIVATE
| SWP_NOZORDER
);
613 goButtonBounds
.left
= newWidth
- buttonWidth
;
614 goButtonBounds
.top
= 0;
615 goButtonBounds
.right
= newWidth
- buttonWidth
;
616 goButtonBounds
.bottom
= newHeight
;
617 InvalidateRect(&goButtonBounds
, TRUE
);
619 SendMessage(fComboBox
, CB_SETDROPPEDWIDTH
, 200, 0);
623 LRESULT
CAddressBand::OnWindowPosChanging(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
&bHandled
)
630 WINDOWPOS positionInfoCopy
;
640 positionInfoCopy
= *reinterpret_cast<WINDOWPOS
*>(lParam
);
641 newHeight
= positionInfoCopy
.cy
;
642 newWidth
= positionInfoCopy
.cx
;
643 SendMessage(fGoButton
, TB_GETITEMRECT
, 0, reinterpret_cast<LPARAM
>(&buttonBounds
));
645 buttonWidth
= buttonBounds
.right
- buttonBounds
.left
;
646 buttonHeight
= buttonBounds
.bottom
- buttonBounds
.top
;
647 positionInfoCopy
.cx
= newWidth
- 2 - buttonWidth
;
648 DefWindowProc(WM_WINDOWPOSCHANGING
, wParam
, reinterpret_cast<LPARAM
>(&positionInfoCopy
));
649 ::GetWindowRect(fComboBox
, &comboBoxBounds
);
650 ::SetWindowPos(fGoButton
, NULL
, newWidth
- buttonWidth
, (comboBoxBounds
.bottom
- comboBoxBounds
.top
- buttonHeight
) / 2,
651 buttonWidth
, buttonHeight
, SWP_NOOWNERZORDER
| SWP_SHOWWINDOW
| SWP_NOACTIVATE
| SWP_NOZORDER
);
653 goButtonBounds
.left
= newWidth
- buttonWidth
;
654 goButtonBounds
.top
= 0;
655 goButtonBounds
.right
= newWidth
- buttonWidth
;
656 goButtonBounds
.bottom
= newHeight
;
657 InvalidateRect(&goButtonBounds
, TRUE
);
659 SendMessage(fComboBox
, CB_SETDROPPEDWIDTH
, 200, 0);
663 HRESULT
CreateAddressBand(REFIID riid
, void **ppv
)
665 CComObject
<CAddressBand
> *theMenuBar
;
671 ATLTRY (theMenuBar
= new CComObject
<CAddressBand
>);
672 if (theMenuBar
== NULL
)
673 return E_OUTOFMEMORY
;
674 hResult
= theMenuBar
->QueryInterface(riid
, reinterpret_cast<void **>(ppv
));