/*
This class handles the combo box of the address band.
*/
+
#include "precomp.h"
+
/*
TODO:
- Add auto completion support
- Subclass windows in Init method
- Connect to browser connection point
- Handle navigation complete messages to set edit box text
Handle listbox dropdown message and fill contents
Add drag and drop of icon in edit box
- Handle enter in edit box to browse to typed path
Handle change notifies to update appropriately
- Add handling of enter in edit box
Fix so selection in combo listbox navigates
- Fix so editing text and typing enter navigates
*/
CAddressEditBox::CAddressEditBox() :
- fEditWindow(NULL, this, 1),
- fComboBoxExWindow(NULL, this, 2)
+ fCombobox(NULL, this, 1),
+ fEditWindow(NULL, this, 1),
+ fSite(NULL)
{
}
{
}
-HRESULT STDMETHODCALLTYPE CAddressEditBox::SetOwner(IUnknown *)
+HRESULT STDMETHODCALLTYPE CAddressEditBox::SetOwner(IUnknown *pOwner)
{
+ if (!pOwner)
+ {
+ CComPtr<IBrowserService> browserService;
+ HRESULT hResult = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
+ if (SUCCEEDED(hResult))
+ AtlUnadvise(browserService, DIID_DWebBrowserEvents, fAdviseCookie);
+ fSite = NULL;
+ }
// connect to browser connection point
return 0;
}
HRESULT STDMETHODCALLTYPE CAddressEditBox::Init(HWND comboboxEx, HWND editControl, long param14, IUnknown *param18)
{
- fComboBoxExWindow.SubclassWindow(comboboxEx);
+ CComPtr<IBrowserService> browserService;
+
+ fCombobox.SubclassWindow(comboboxEx);
fEditWindow.SubclassWindow(editControl);
- return S_OK;
+ fSite = param18;
+
+ SHAutoComplete(fEditWindow.m_hWnd, SHACF_FILESYSTEM | SHACF_URLALL | SHACF_USETAB);
+
+ // take advice to watch events
+ HRESULT hResult = IUnknown_QueryService(param18, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
+ if (SUCCEEDED(hResult))
+ {
+ hResult = AtlAdvise(browserService, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &fAdviseCookie);
+ }
+
+ return hResult;
}
HRESULT STDMETHODCALLTYPE CAddressEditBox::SetCurrentDir(long paramC)
HRESULT STDMETHODCALLTYPE CAddressEditBox::ParseNow(long paramC)
{
- return E_NOTIMPL;
+ ULONG eaten;
+ ULONG attributes;
+ HRESULT hr;
+ HWND topLevelWindow;
+ PIDLIST_ABSOLUTE pidlCurrent= NULL;
+ PIDLIST_RELATIVE pidlRelative = NULL;
+ CComPtr<IShellFolder> psfCurrent;
+
+ CComPtr<IBrowserService> pbs;
+ hr = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &pbs));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = IUnknown_GetWindow(pbs, &topLevelWindow);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ /* Get the path to browse and expand it if needed */
+ LPWSTR input;
+ int inputLength = fCombobox.GetWindowTextLength() + 2;
+
+ input = new WCHAR[inputLength];
+ fCombobox.GetWindowText(input, inputLength);
+
+ LPWSTR address;
+ int addressLength = ExpandEnvironmentStrings(input, NULL, 0);
+
+ if (addressLength <= 0)
+ {
+ address = input;
+ }
+ else
+ {
+ addressLength += 2;
+ address = new WCHAR[addressLength];
+ if (!ExpandEnvironmentStrings(input, address, addressLength))
+ {
+ delete[] address;
+ address = input;
+ }
+ }
+
+ /* Try to parse a relative path and if it fails, try to browse an absolute path */
+ CComPtr<IShellFolder> psfDesktop;
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED_UNEXPECTEDLY(hr))
+ goto cleanup;
+
+ hr = pbs->GetPidl(&pidlCurrent);
+ if (FAILED_UNEXPECTEDLY(hr))
+ goto cleanup;
+
+ hr = psfDesktop->BindToObject(pidlCurrent, NULL, IID_PPV_ARG(IShellFolder, &psfCurrent));
+ if (FAILED_UNEXPECTEDLY(hr))
+ goto cleanup;
+
+ hr = psfCurrent->ParseDisplayName(topLevelWindow, NULL, address, &eaten, &pidlRelative, &attributes);
+ if (SUCCEEDED(hr))
+ {
+ pidlLastParsed = ILCombine(pidlCurrent, pidlRelative);
+ ILFree(pidlRelative);
+ goto cleanup;
+ }
+
+ /* We couldn't parse a relative path, attempt to parse an absolute path */
+ hr = psfDesktop->ParseDisplayName(topLevelWindow, NULL, address, &eaten, &pidlLastParsed, &attributes);
+
+cleanup:
+ if (pidlCurrent)
+ ILFree(pidlCurrent);
+ if (address != input)
+ delete [] address;
+ delete [] input;
+
+ return hr;
}
HRESULT STDMETHODCALLTYPE CAddressEditBox::Execute(long paramC)
{
- return E_NOTIMPL;
+ HRESULT hr;
+
+ /*
+ * Parse the path is it wasn't parsed
+ */
+ if (!pidlLastParsed)
+ ParseNow(0);
+
+ if (!pidlLastParsed)
+ return E_FAIL;
+
+ /*
+ * Get the IShellBrowser and IBrowserService interfaces of the shell browser
+ */
+ CComPtr<IShellBrowser> pisb;
+ hr = IUnknown_QueryService(fSite, SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &pisb));
+ if (FAILED(hr))
+ return hr;
+
+ CComPtr<IBrowserService> pbs;
+ pisb->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs));
+ if (FAILED(hr))
+ return hr;
+
+ /*
+ * Get the current pidl of the shellbrowser and check if it is the same with the parsed one
+ */
+ PIDLIST_ABSOLUTE pidl;
+ hr = pbs->GetPidl(&pidl);
+ if (FAILED(hr))
+ return hr;
+
+ CComPtr<IShellFolder> psf;
+ hr = SHGetDesktopFolder(&psf);
+ if (FAILED(hr))
+ return hr;
+
+ hr = psf->CompareIDs(0, pidl, pidlLastParsed);
+
+ SHFree(pidl);
+ if (hr == 0)
+ return S_OK;
+
+ /*
+ * Attempt to browse to the parsed pidl
+ */
+ hr = pisb->BrowseObject(pidlLastParsed, 0);
+ if (SUCCEEDED(hr))
+ return hr;
+
+ /*
+ * Browsing to the pidl failed so it's not a folder. So invoke its defaule command.
+ */
+ HWND topLevelWindow;
+ hr = IUnknown_GetWindow(pisb, &topLevelWindow);
+ if (FAILED(hr))
+ return hr;
+
+ LPCITEMIDLIST pidlChild;
+ CComPtr<IShellFolder> sf;
+ hr = SHBindToParent(pidlLastParsed, IID_PPV_ARG(IShellFolder, &sf), &pidlChild);
+ if (FAILED(hr))
+ return hr;
+
+ hr = SHInvokeDefaultCommand(topLevelWindow, sf, pidlChild);
+ if (FAILED(hr))
+ return hr;
+
+ return hr;
}
HRESULT STDMETHODCALLTYPE CAddressEditBox::Save(long paramC)
HRESULT STDMETHODCALLTYPE CAddressEditBox::OnWinEvent(
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
{
- // handle fill of listbox here
- return E_NOTIMPL;
+ LPNMHDR hdr;
+
+ *theResult = 0;
+
+ switch (uMsg)
+ {
+ case WM_NOTIFY:
+ hdr = (LPNMHDR) lParam;
+ if (hdr->code == CBEN_ENDEDIT)
+ {
+ NMCBEENDEDITW *endEdit = (NMCBEENDEDITW*) lParam;
+ if (endEdit->iWhy == CBENF_RETURN)
+ {
+ Execute(0);
+ }
+ else if (endEdit->iWhy == CBENF_ESCAPE)
+ {
+ /* Reset the contents of the combo box */
+ }
+ }
+ break;
+ }
+ return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressEditBox::IsWindowOwner(HWND hWnd)
{
- return E_NOTIMPL;
+ if (fCombobox.m_hWnd == hWnd)
+ return S_OK;
+ if (fEditWindow.m_hWnd == hWnd)
+ return S_OK;
+ return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CAddressEditBox::QueryStatus(
HRESULT STDMETHODCALLTYPE CAddressEditBox::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
- // on navigate complete, change edit section of combobox
- return E_NOTIMPL;
+ CComPtr<IBrowserService> isb;
+ CComPtr<IShellFolder> sf;
+ HRESULT hr;
+ INT indexClosed, indexOpen, itemExists, oldIndex;
+ DWORD result;
+ COMBOBOXEXITEMW item;
+ PIDLIST_ABSOLUTE absolutePIDL;
+ LPCITEMIDLIST pidlChild;
+ LPITEMIDLIST pidlPrevious;
+ STRRET ret;
+ WCHAR buf[4096];
+
+ if (pDispParams == NULL)
+ return E_INVALIDARG;
+
+ switch (dispIdMember)
+ {
+ case DISPID_NAVIGATECOMPLETE2:
+ case DISPID_DOCUMENTCOMPLETE:
+ pidlLastParsed = NULL;
+
+ oldIndex = fCombobox.SendMessage(CB_GETCURSEL, 0, 0);
+
+ itemExists = FALSE;
+ pidlPrevious = NULL;
+
+ ZeroMemory(&item, sizeof(item));
+ item.mask = CBEIF_LPARAM;
+ item.iItem = 0;
+ if (fCombobox.SendMessage(CBEM_GETITEM, 0, reinterpret_cast<LPARAM>(&item)))
+ {
+ pidlPrevious = reinterpret_cast<LPITEMIDLIST>(item.lParam);
+ if (pidlPrevious)
+ itemExists = TRUE;
+ }
+
+ hr = IUnknown_QueryService(fSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &isb));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = isb->GetPidl(&absolutePIDL);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = SHBindToParent(absolutePIDL, IID_PPV_ARG(IShellFolder, &sf), &pidlChild);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = sf->GetDisplayNameOf(pidlChild, SHGDN_FORADDRESSBAR | SHGDN_FORPARSING, &ret);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = StrRetToBufW(&ret, pidlChild, buf, 4095);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ indexClosed = SHMapPIDLToSystemImageListIndex(sf, pidlChild, &indexOpen);
+
+ item.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT | CBEIF_LPARAM;
+ item.iItem = 0;
+ item.iImage = indexClosed;
+ item.iSelectedImage = indexOpen;
+ item.pszText = buf;
+ item.lParam = reinterpret_cast<LPARAM>(absolutePIDL);
+
+ if (itemExists)
+ {
+ result = fCombobox.SendMessage(CBEM_SETITEM, 0, reinterpret_cast<LPARAM>(&item));
+ oldIndex = 0;
+
+ if (result)
+ {
+ ILFree(pidlPrevious);
+ }
+ }
+ else
+ {
+ oldIndex = fCombobox.SendMessage(CBEM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&item));
+
+ if (oldIndex < 0)
+ DbgPrint("ERROR %d\n", GetLastError());
+ }
+
+ fCombobox.SendMessage(CB_SETCURSEL, -1, 0);
+ fCombobox.SendMessage(CB_SETCURSEL, oldIndex, 0);
+
+ //fAddressEditBox->SetCurrentDir(index);
+ }
+ return S_OK;
}
HRESULT STDMETHODCALLTYPE CAddressEditBox::GetClassID(CLSID *pClassID)
{
return E_NOTIMPL;
}
-
-HRESULT CreateAddressEditBox(REFIID riid, void **ppv)
-{
- CComObject<CAddressEditBox> *theMenuBar;
- HRESULT hResult;
-
- if (ppv == NULL)
- return E_POINTER;
- *ppv = NULL;
- ATLTRY (theMenuBar = new CComObject<CAddressEditBox>);
- if (theMenuBar == NULL)
- return E_OUTOFMEMORY;
- hResult = theMenuBar->QueryInterface(riid, reinterpret_cast<void **>(ppv));
- if (FAILED(hResult))
- {
- delete theMenuBar;
- return hResult;
- }
- return S_OK;
-}