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 This class handles the combo box of the address band.
29 Add drag and drop of icon in edit box
30 Handle change notifies to update appropriately
33 CAddressEditBox::CAddressEditBox() :
34 fCombobox(NULL
, this, 1),
35 fEditWindow(NULL
, this, 1),
41 CAddressEditBox::~CAddressEditBox()
44 ILFree(pidlLastParsed
);
47 HRESULT STDMETHODCALLTYPE
CAddressEditBox::SetOwner(IUnknown
*pOwner
)
51 CComPtr
<IBrowserService
> browserService
;
52 HRESULT hResult
= IUnknown_QueryService(fSite
, SID_SShellBrowser
, IID_PPV_ARG(IBrowserService
, &browserService
));
53 if (SUCCEEDED(hResult
))
54 AtlUnadvise(browserService
, DIID_DWebBrowserEvents
, fAdviseCookie
);
57 // connect to browser connection point
61 HRESULT STDMETHODCALLTYPE
CAddressEditBox::FileSysChange(long param8
, long paramC
)
66 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Refresh(long param8
)
71 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Init(HWND comboboxEx
, HWND editControl
, long param14
, IUnknown
*param18
)
73 CComPtr
<IBrowserService
> browserService
;
75 fCombobox
.SubclassWindow(comboboxEx
);
76 fEditWindow
.SubclassWindow(editControl
);
78 hComboBoxEx
= comboboxEx
;
80 SHAutoComplete(fEditWindow
.m_hWnd
, SHACF_FILESYSTEM
| SHACF_URLALL
| SHACF_USETAB
);
82 // take advice to watch events
83 HRESULT hResult
= IUnknown_QueryService(param18
, SID_SShellBrowser
, IID_PPV_ARG(IBrowserService
, &browserService
));
84 if (SUCCEEDED(hResult
))
86 hResult
= AtlAdvise(browserService
, static_cast<IDispatch
*>(this), DIID_DWebBrowserEvents
, &fAdviseCookie
);
92 HRESULT STDMETHODCALLTYPE
CAddressEditBox::SetCurrentDir(long paramC
)
97 HRESULT STDMETHODCALLTYPE
CAddressEditBox::ParseNow(long paramC
)
103 PIDLIST_ABSOLUTE pidlCurrent
= NULL
;
104 PIDLIST_RELATIVE pidlRelative
= NULL
;
105 CComPtr
<IShellFolder
> psfCurrent
;
107 CComPtr
<IBrowserService
> pbs
;
108 hr
= IUnknown_QueryService(fSite
, SID_SShellBrowser
, IID_PPV_ARG(IBrowserService
, &pbs
));
109 if (FAILED_UNEXPECTEDLY(hr
))
112 hr
= IUnknown_GetWindow(pbs
, &topLevelWindow
);
113 if (FAILED_UNEXPECTEDLY(hr
))
116 /* Get the path to browse and expand it if needed */
118 int inputLength
= fCombobox
.GetWindowTextLength() + 2;
120 input
= new WCHAR
[inputLength
];
121 fCombobox
.GetWindowText(input
, inputLength
);
124 int addressLength
= ExpandEnvironmentStrings(input
, NULL
, 0);
126 if (addressLength
<= 0)
133 address
= new WCHAR
[addressLength
];
134 if (!ExpandEnvironmentStrings(input
, address
, addressLength
))
141 /* Try to parse a relative path and if it fails, try to browse an absolute path */
142 CComPtr
<IShellFolder
> psfDesktop
;
143 hr
= SHGetDesktopFolder(&psfDesktop
);
144 if (FAILED_UNEXPECTEDLY(hr
))
147 hr
= pbs
->GetPidl(&pidlCurrent
);
148 if (FAILED_UNEXPECTEDLY(hr
))
151 hr
= psfDesktop
->BindToObject(pidlCurrent
, NULL
, IID_PPV_ARG(IShellFolder
, &psfCurrent
));
152 if (FAILED_UNEXPECTEDLY(hr
))
155 hr
= psfCurrent
->ParseDisplayName(topLevelWindow
, NULL
, address
, &eaten
, &pidlRelative
, &attributes
);
158 pidlLastParsed
= ILCombine(pidlCurrent
, pidlRelative
);
159 ILFree(pidlRelative
);
163 /* We couldn't parse a relative path, attempt to parse an absolute path */
164 hr
= psfDesktop
->ParseDisplayName(topLevelWindow
, NULL
, address
, &eaten
, &pidlLastParsed
, &attributes
);
169 if (address
!= input
)
176 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Execute(long paramC
)
181 * Parse the path is it wasn't parsed
190 * Get the IShellBrowser and IBrowserService interfaces of the shell browser
192 CComPtr
<IShellBrowser
> pisb
;
193 hr
= IUnknown_QueryService(fSite
, SID_SShellBrowser
, IID_PPV_ARG(IShellBrowser
, &pisb
));
197 CComPtr
<IBrowserService
> pbs
;
198 pisb
->QueryInterface(IID_PPV_ARG(IBrowserService
, &pbs
));
203 * Get the current pidl of the shellbrowser and check if it is the same with the parsed one
205 PIDLIST_ABSOLUTE pidl
;
206 hr
= pbs
->GetPidl(&pidl
);
210 CComPtr
<IShellFolder
> psf
;
211 hr
= SHGetDesktopFolder(&psf
);
215 hr
= psf
->CompareIDs(0, pidl
, pidlLastParsed
);
222 * Attempt to browse to the parsed pidl
224 hr
= pisb
->BrowseObject(pidlLastParsed
, 0);
229 * Browsing to the pidl failed so it's not a folder. So invoke its defaule command.
232 hr
= IUnknown_GetWindow(pisb
, &topLevelWindow
);
236 LPCITEMIDLIST pidlChild
;
237 CComPtr
<IShellFolder
> sf
;
238 hr
= SHBindToParent(pidlLastParsed
, IID_PPV_ARG(IShellFolder
, &sf
), &pidlChild
);
242 hr
= SHInvokeDefaultCommand(topLevelWindow
, sf
, pidlChild
);
249 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Save(long paramC
)
254 HRESULT STDMETHODCALLTYPE
CAddressEditBox::OnWinEvent(
255 HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
265 if (HIWORD(wParam
) == CBN_SELCHANGE
)
267 UINT selectedIndex
= SendMessageW((HWND
)lParam
, CB_GETCURSEL
, 0, 0);
268 pidlLastParsed
= ILClone((LPITEMIDLIST
)SendMessageW((HWND
)lParam
, CB_GETITEMDATA
, selectedIndex
, 0));
275 hdr
= (LPNMHDR
) lParam
;
276 if (hdr
->code
== CBEN_ENDEDIT
)
278 NMCBEENDEDITW
*endEdit
= (NMCBEENDEDITW
*) lParam
;
279 if (endEdit
->iWhy
== CBENF_RETURN
)
283 else if (endEdit
->iWhy
== CBENF_ESCAPE
)
285 /* Reset the contents of the combo box */
288 else if (hdr
->code
== CBEN_DELETEITEM
)
290 PNMCOMBOBOXEX pCBEx
= (PNMCOMBOBOXEX
) lParam
;
291 LPITEMIDLIST itemPidl
= (LPITEMIDLIST
)pCBEx
->ceItem
.lParam
;
303 HRESULT STDMETHODCALLTYPE
CAddressEditBox::IsWindowOwner(HWND hWnd
)
305 if (fCombobox
.m_hWnd
== hWnd
)
307 if (fEditWindow
.m_hWnd
== hWnd
)
312 HRESULT STDMETHODCALLTYPE
CAddressEditBox::QueryStatus(
313 const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[ ], OLECMDTEXT
*pCmdText
)
318 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
,
319 DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
324 HRESULT STDMETHODCALLTYPE
CAddressEditBox::GetTypeInfoCount(UINT
*pctinfo
)
329 HRESULT STDMETHODCALLTYPE
CAddressEditBox::GetTypeInfo(UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
334 HRESULT STDMETHODCALLTYPE
CAddressEditBox::GetIDsOfNames(
335 REFIID riid
, LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
340 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Invoke(DISPID dispIdMember
, REFIID riid
, LCID lcid
,
341 WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
343 CComPtr
<IBrowserService
> isb
;
344 CComPtr
<IShellFolder
> sf
;
346 PIDLIST_ABSOLUTE absolutePIDL
;
347 LPCITEMIDLIST pidlChild
;
351 if (pDispParams
== NULL
)
354 switch (dispIdMember
)
356 case DISPID_NAVIGATECOMPLETE2
:
357 case DISPID_DOCUMENTCOMPLETE
:
360 ILFree(pidlLastParsed
);
361 pidlLastParsed
= NULL
;
363 /* Get the current pidl of the browser */
364 hr
= IUnknown_QueryService(fSite
, SID_STopLevelBrowser
, IID_PPV_ARG(IBrowserService
, &isb
));
365 if (FAILED_UNEXPECTEDLY(hr
))
368 hr
= isb
->GetPidl(&absolutePIDL
);
369 if (FAILED_UNEXPECTEDLY(hr
))
372 /* Fill the combobox */
373 PopulateComboBox(absolutePIDL
);
375 /* Find the current item in the combobox and select it */
376 CComPtr
<IShellFolder
> psfDesktop
;
377 hr
= SHGetDesktopFolder(&psfDesktop
);
378 if (FAILED_UNEXPECTEDLY(hr
))
381 hr
= psfDesktop
->GetDisplayNameOf(absolutePIDL
, SHGDN_FORADDRESSBAR
, &ret
);
382 if (FAILED_UNEXPECTEDLY(hr
))
385 hr
= StrRetToBufW(&ret
, absolutePIDL
, buf
, 4095);
386 if (FAILED_UNEXPECTEDLY(hr
))
389 int index
= SendMessageW(hComboBoxEx
, CB_FINDSTRINGEXACT
, 0, (LPARAM
)buf
);
391 SendMessageW(hComboBoxEx
, CB_SETCURSEL
, index
, 0);
393 /* Add the item that will be visible when the combobox is not expanded */
394 hr
= SHBindToParent(absolutePIDL
, IID_PPV_ARG(IShellFolder
, &sf
), &pidlChild
);
395 if (FAILED_UNEXPECTEDLY(hr
))
398 hr
= sf
->GetDisplayNameOf(pidlChild
, SHGDN_FORADDRESSBAR
| SHGDN_FORPARSING
, &ret
);
399 if (FAILED_UNEXPECTEDLY(hr
))
402 hr
= StrRetToBufW(&ret
, pidlChild
, buf
, 4095);
403 if (FAILED_UNEXPECTEDLY(hr
))
406 INT indexClosed
, indexOpen
;
407 indexClosed
= SHMapPIDLToSystemImageListIndex(sf
, pidlChild
, &indexOpen
);
409 COMBOBOXEXITEMW item
= {0};
410 item
.mask
= CBEIF_IMAGE
| CBEIF_SELECTEDIMAGE
| CBEIF_TEXT
| CBEIF_LPARAM
;
412 item
.iImage
= indexClosed
;
413 item
.iSelectedImage
= indexOpen
;
415 item
.lParam
= reinterpret_cast<LPARAM
>(absolutePIDL
);
416 fCombobox
.SendMessage(CBEM_SETITEM
, 0, reinterpret_cast<LPARAM
>(&item
));
421 HRESULT STDMETHODCALLTYPE
CAddressEditBox::GetClassID(CLSID
*pClassID
)
423 if (pClassID
== NULL
)
425 *pClassID
= CLSID_AddressEditBox
;
429 HRESULT STDMETHODCALLTYPE
CAddressEditBox::IsDirty()
434 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Load(IStream
*pStm
)
439 HRESULT STDMETHODCALLTYPE
CAddressEditBox::Save(IStream
*pStm
, BOOL fClearDirty
)
444 HRESULT STDMETHODCALLTYPE
CAddressEditBox::GetSizeMax(ULARGE_INTEGER
*pcbSize
)
449 void CAddressEditBox::PopulateComboBox(LPITEMIDLIST pidlCurrent
)
456 index
= SendMessageW(hComboBoxEx
, CB_GETCOUNT
, 0, 0);
457 for (int i
= 0; i
< index
; i
++)
458 SendMessageW(hComboBoxEx
, CBEM_DELETEITEM
, i
, 0);
459 SendMessageW(hComboBoxEx
, CB_RESETCONTENT
, 0, 0);
461 /* Calculate the indent level. No need to clone the pidl */
467 pidl
= ILGetNext(pidl
);
472 /* Add every id from the pidl in the combo box */
473 pidl
= ILClone(pidlCurrent
);
476 AddComboBoxItem(pidl
, 0, index
);
477 ILRemoveLastID(pidl
);
479 } while (index
>= 0);
482 /* Add the items of the desktop */
483 FillOneLevel(0, 1, indent
);
485 /* Add the items of My Computer */
486 hr
= SHGetSpecialFolderLocation(0, CSIDL_DRIVES
, &pidl
);
487 if (FAILED_UNEXPECTEDLY(hr
))
490 for(LPITEMIDLIST i
= GetItemData(0); i
; i
= GetItemData(index
))
492 if (ILIsEqual(i
, pidl
))
494 FillOneLevel(index
, 2, indent
);
502 void CAddressEditBox::AddComboBoxItem(LPITEMIDLIST pidl
, int index
, int indent
)
507 LPCITEMIDLIST pidlChild
;
508 CComPtr
<IShellFolder
> sf
;
509 hr
= SHBindToParent(pidl
, IID_PPV_ARG(IShellFolder
, &sf
), &pidlChild
);
510 if (FAILED_UNEXPECTEDLY(hr
))
514 hr
= sf
->GetDisplayNameOf(pidlChild
, SHGDN_FORADDRESSBAR
, &strret
);
515 if (FAILED_UNEXPECTEDLY(hr
))
518 hr
= StrRetToBufW(&strret
, pidlChild
, buf
, 4095);
519 if (FAILED_UNEXPECTEDLY(hr
))
522 COMBOBOXEXITEMW item
= {0};
523 item
.mask
= CBEIF_LPARAM
| CBEIF_INDENT
| CBEIF_SELECTEDIMAGE
| CBEIF_IMAGE
| CBEIF_TEXT
;
524 item
.iImage
= SHMapPIDLToSystemImageListIndex(sf
, pidlChild
, &item
.iSelectedImage
);
526 item
.lParam
= (LPARAM
)(ILClone(pidl
));
527 item
.iIndent
= indent
;
529 SendMessageW(hComboBoxEx
, CBEM_INSERTITEMW
, 0, (LPARAM
)&item
);
532 void CAddressEditBox::FillOneLevel(int index
, int levelIndent
, int indent
)
537 LPITEMIDLIST pidl
, pidl2
, pidl3
, pidl4
;
540 pidl
= GetItemData(index
);
541 pidl2
= GetItemData(count
);
544 CComPtr
<IShellFolder
> psfDesktop
;
545 CComPtr
<IShellFolder
> psfItem
;
547 hr
= SHGetDesktopFolder(&psfDesktop
);
548 if (FAILED_UNEXPECTEDLY(hr
))
553 psfItem
= psfDesktop
;
557 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfItem
));
558 if (FAILED_UNEXPECTEDLY(hr
))
562 CComPtr
<IEnumIDList
> pEnumIDList
;
563 hr
= psfItem
->EnumObjects(0, SHCONTF_FOLDERS
| SHCONTF_INCLUDEHIDDEN
, &pEnumIDList
);
564 if (FAILED_UNEXPECTEDLY(hr
))
569 hr
= pEnumIDList
->Next(1, &pidl3
, &numObj
);
570 if(hr
!= S_OK
|| !numObj
)
573 pidl4
= ILCombine(pidl
, pidl3
);
574 if (pidl2
&& ILIsEqual(pidl4
, pidl2
))
575 count
+= (indent
- levelIndent
);
577 AddComboBoxItem(pidl4
, count
, levelIndent
);
585 LPITEMIDLIST
CAddressEditBox::GetItemData(int index
)
587 COMBOBOXEXITEMW item
;
589 memset(&item
, 0, sizeof(COMBOBOXEXITEMW
));
590 item
.mask
= CBEIF_LPARAM
;
592 SendMessageW(hComboBoxEx
, CBEM_GETITEMW
, 0, (LPARAM
)&item
);
593 return (LPITEMIDLIST
)item
.lParam
;