[BROWSEUI] -CAddressEditBox: Populate address bar combobox. Patch by Barrett Karish with improvements by me to fix leaks and add error checks. CORE-10988

svn path=/trunk/; revision=75670
This commit is contained in:
Giannis Adamopoulos 2017-08-25 15:03:25 +00:00
parent 58ef11fbed
commit 9cf9a89aa0
2 changed files with 218 additions and 56 deletions

View file

@ -26,21 +26,22 @@ This class handles the combo box of the address band.
/* /*
TODO: TODO:
Handle listbox dropdown message and fill contents
Add drag and drop of icon in edit box Add drag and drop of icon in edit box
Handle change notifies to update appropriately Handle change notifies to update appropriately
Fix so selection in combo listbox navigates
*/ */
CAddressEditBox::CAddressEditBox() : CAddressEditBox::CAddressEditBox() :
fCombobox(NULL, this, 1), fCombobox(NULL, this, 1),
fEditWindow(NULL, this, 1), fEditWindow(NULL, this, 1),
fSite(NULL) fSite(NULL),
pidlLastParsed(NULL)
{ {
} }
CAddressEditBox::~CAddressEditBox() CAddressEditBox::~CAddressEditBox()
{ {
if (pidlLastParsed)
ILFree(pidlLastParsed);
} }
HRESULT STDMETHODCALLTYPE CAddressEditBox::SetOwner(IUnknown *pOwner) HRESULT STDMETHODCALLTYPE CAddressEditBox::SetOwner(IUnknown *pOwner)
@ -74,6 +75,7 @@ HRESULT STDMETHODCALLTYPE CAddressEditBox::Init(HWND comboboxEx, HWND editContro
fCombobox.SubclassWindow(comboboxEx); fCombobox.SubclassWindow(comboboxEx);
fEditWindow.SubclassWindow(editControl); fEditWindow.SubclassWindow(editControl);
fSite = param18; fSite = param18;
hComboBoxEx = comboboxEx;
SHAutoComplete(fEditWindow.m_hWnd, SHACF_FILESYSTEM | SHACF_URLALL | SHACF_USETAB); SHAutoComplete(fEditWindow.m_hWnd, SHACF_FILESYSTEM | SHACF_URLALL | SHACF_USETAB);
@ -258,21 +260,42 @@ HRESULT STDMETHODCALLTYPE CAddressEditBox::OnWinEvent(
switch (uMsg) switch (uMsg)
{ {
case WM_NOTIFY: case WM_COMMAND:
hdr = (LPNMHDR) lParam;
if (hdr->code == CBEN_ENDEDIT)
{ {
NMCBEENDEDITW *endEdit = (NMCBEENDEDITW*) lParam; if (HIWORD(wParam) == CBN_SELCHANGE)
if (endEdit->iWhy == CBENF_RETURN)
{ {
UINT selectedIndex = SendMessageW((HWND)lParam, CB_GETCURSEL, 0, 0);
pidlLastParsed = ILClone((LPITEMIDLIST)SendMessageW((HWND)lParam, CB_GETITEMDATA, selectedIndex, 0));
Execute(0); Execute(0);
} }
else if (endEdit->iWhy == CBENF_ESCAPE) break;
{ }
/* Reset the contents of the combo box */ 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 */
}
}
else if (hdr->code == CBEN_DELETEITEM)
{
PNMCOMBOBOXEX pCBEx = (PNMCOMBOBOXEX) lParam;
LPITEMIDLIST itemPidl = (LPITEMIDLIST)pCBEx->ceItem.lParam;
if (itemPidl)
{
ILFree(itemPidl);
}
}
break;
} }
break;
} }
return S_OK; return S_OK;
} }
@ -320,12 +343,8 @@ HRESULT STDMETHODCALLTYPE CAddressEditBox::Invoke(DISPID dispIdMember, REFIID ri
CComPtr<IBrowserService> isb; CComPtr<IBrowserService> isb;
CComPtr<IShellFolder> sf; CComPtr<IShellFolder> sf;
HRESULT hr; HRESULT hr;
INT indexClosed, indexOpen, itemExists, oldIndex;
DWORD result;
COMBOBOXEXITEMW item;
PIDLIST_ABSOLUTE absolutePIDL; PIDLIST_ABSOLUTE absolutePIDL;
LPCITEMIDLIST pidlChild; LPCITEMIDLIST pidlChild;
LPITEMIDLIST pidlPrevious;
STRRET ret; STRRET ret;
WCHAR buf[4096]; WCHAR buf[4096];
@ -336,23 +355,12 @@ HRESULT STDMETHODCALLTYPE CAddressEditBox::Invoke(DISPID dispIdMember, REFIID ri
{ {
case DISPID_NAVIGATECOMPLETE2: case DISPID_NAVIGATECOMPLETE2:
case DISPID_DOCUMENTCOMPLETE: case DISPID_DOCUMENTCOMPLETE:
if (pidlLastParsed)
ILFree(pidlLastParsed);
pidlLastParsed = NULL; pidlLastParsed = NULL;
oldIndex = fCombobox.SendMessage(CB_GETCURSEL, 0, 0); /* Get the current pidl of the browser */
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)); hr = IUnknown_QueryService(fSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &isb));
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
@ -361,6 +369,28 @@ HRESULT STDMETHODCALLTYPE CAddressEditBox::Invoke(DISPID dispIdMember, REFIID ri
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
/* Fill the combobox */
PopulateComboBox(absolutePIDL);
/* Find the current item in the combobox and select it */
CComPtr<IShellFolder> psfDesktop;
hr = SHGetDesktopFolder(&psfDesktop);
if (FAILED_UNEXPECTEDLY(hr))
return S_OK;
hr = psfDesktop->GetDisplayNameOf(absolutePIDL, SHGDN_FORADDRESSBAR, &ret);
if (FAILED_UNEXPECTEDLY(hr))
return S_OK;
hr = StrRetToBufW(&ret, absolutePIDL, buf, 4095);
if (FAILED_UNEXPECTEDLY(hr))
return S_OK;
int index = SendMessageW(hComboBoxEx, CB_FINDSTRINGEXACT, 0, (LPARAM)buf);
if (index != -1)
SendMessageW(hComboBoxEx, CB_SETCURSEL, index, 0);
/* Add the item that will be visible when the combobox is not expanded */
hr = SHBindToParent(absolutePIDL, IID_PPV_ARG(IShellFolder, &sf), &pidlChild); hr = SHBindToParent(absolutePIDL, IID_PPV_ARG(IShellFolder, &sf), &pidlChild);
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
@ -373,37 +403,17 @@ HRESULT STDMETHODCALLTYPE CAddressEditBox::Invoke(DISPID dispIdMember, REFIID ri
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
INT indexClosed, indexOpen;
indexClosed = SHMapPIDLToSystemImageListIndex(sf, pidlChild, &indexOpen); indexClosed = SHMapPIDLToSystemImageListIndex(sf, pidlChild, &indexOpen);
COMBOBOXEXITEMW item = {0};
item.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT | CBEIF_LPARAM; item.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT | CBEIF_LPARAM;
item.iItem = 0; item.iItem = -1;
item.iImage = indexClosed; item.iImage = indexClosed;
item.iSelectedImage = indexOpen; item.iSelectedImage = indexOpen;
item.pszText = buf; item.pszText = buf;
item.lParam = reinterpret_cast<LPARAM>(absolutePIDL); item.lParam = reinterpret_cast<LPARAM>(absolutePIDL);
fCombobox.SendMessage(CBEM_SETITEM, 0, reinterpret_cast<LPARAM>(&item));
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; return S_OK;
} }
@ -435,3 +445,150 @@ HRESULT STDMETHODCALLTYPE CAddressEditBox::GetSizeMax(ULARGE_INTEGER *pcbSize)
{ {
return E_NOTIMPL; return E_NOTIMPL;
} }
void CAddressEditBox::PopulateComboBox(LPITEMIDLIST pidlCurrent)
{
HRESULT hr;
LPITEMIDLIST pidl;
int indent = 0;
int index;
index = SendMessageW(hComboBoxEx, CB_GETCOUNT, 0, 0);
for (int i = 0; i < index; i++)
SendMessageW(hComboBoxEx, CBEM_DELETEITEM, i, 0);
SendMessageW(hComboBoxEx, CB_RESETCONTENT, 0, 0);
/* Calculate the indent level. No need to clone the pidl */
pidl = pidlCurrent;
do
{
if(!pidl->mkid.cb)
break;
pidl = ILGetNext(pidl);
indent++;
} while (pidl);
index = indent;
/* Add every id from the pidl in the combo box */
pidl = ILClone(pidlCurrent);
do
{
AddComboBoxItem(pidl, 0, index);
ILRemoveLastID(pidl);
index--;
} while (index >= 0);
ILFree(pidl);
/* Add the items of the desktop */
FillOneLevel(0, 1, indent);
/* Add the items of My Computer */
hr = SHGetSpecialFolderLocation(0, CSIDL_DRIVES, &pidl);
if (FAILED_UNEXPECTEDLY(hr))
return;
for(LPITEMIDLIST i = GetItemData(0); i; i = GetItemData(index))
{
if (ILIsEqual(i, pidl))
{
FillOneLevel(index, 2, indent);
break;
}
index++;
}
ILFree(pidl);
}
void CAddressEditBox::AddComboBoxItem(LPITEMIDLIST pidl, int index, int indent)
{
HRESULT hr;
WCHAR buf[4096];
LPCITEMIDLIST pidlChild;
CComPtr<IShellFolder> sf;
hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &sf), &pidlChild);
if (FAILED_UNEXPECTEDLY(hr))
return;
STRRET strret;
hr = sf->GetDisplayNameOf(pidlChild, SHGDN_FORADDRESSBAR, &strret);
if (FAILED_UNEXPECTEDLY(hr))
return;
hr = StrRetToBufW(&strret, pidlChild, buf, 4095);
if (FAILED_UNEXPECTEDLY(hr))
return;
COMBOBOXEXITEMW item = {0};
item.mask = CBEIF_LPARAM | CBEIF_INDENT | CBEIF_SELECTEDIMAGE | CBEIF_IMAGE | CBEIF_TEXT;
item.iImage = SHMapPIDLToSystemImageListIndex(sf, pidlChild, &item.iSelectedImage);
item.pszText = buf;
item.lParam = (LPARAM)(ILClone(pidl));
item.iIndent = indent;
item.iItem = index;
SendMessageW(hComboBoxEx, CBEM_INSERTITEMW, 0, (LPARAM)&item);
}
void CAddressEditBox::FillOneLevel(int index, int levelIndent, int indent)
{
HRESULT hr;
ULONG numObj;
int count;
LPITEMIDLIST pidl, pidl2, pidl3, pidl4;
count = index + 1;
pidl = GetItemData(index);
pidl2 = GetItemData(count);
if(pidl)
{
CComPtr<IShellFolder> psfDesktop;
CComPtr<IShellFolder> psfItem;
hr = SHGetDesktopFolder(&psfDesktop);
if (FAILED_UNEXPECTEDLY(hr))
return;
if (!pidl->mkid.cb)
{
psfItem = psfDesktop;
}
else
{
hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfItem));
if (FAILED_UNEXPECTEDLY(hr))
return;
}
CComPtr<IEnumIDList> pEnumIDList;
hr = psfItem->EnumObjects(0, SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN, &pEnumIDList);
if (FAILED_UNEXPECTEDLY(hr))
return;
do
{
hr = pEnumIDList->Next(1, &pidl3, &numObj);
if(hr != S_OK || !numObj)
break;
pidl4 = ILCombine(pidl, pidl3);
if (pidl2 && ILIsEqual(pidl4, pidl2))
count += (indent - levelIndent);
else
AddComboBoxItem(pidl4, count, levelIndent);
count++;
ILFree(pidl3);
ILFree(pidl4);
} while (true);
}
}
LPITEMIDLIST CAddressEditBox::GetItemData(int index)
{
COMBOBOXEXITEMW item;
memset(&item, 0, sizeof(COMBOBOXEXITEMW));
item.mask = CBEIF_LPARAM;
item.iItem = index;
SendMessageW(hComboBoxEx, CBEM_GETITEMW, 0, (LPARAM)&item);
return (LPITEMIDLIST)item.lParam;
}

View file

@ -38,10 +38,15 @@ private:
DWORD fAdviseCookie; DWORD fAdviseCookie;
CComPtr<IUnknown> fSite; CComPtr<IUnknown> fSite;
LPITEMIDLIST pidlLastParsed; LPITEMIDLIST pidlLastParsed;
HWND hComboBoxEx;
public: public:
CAddressEditBox(); CAddressEditBox();
~CAddressEditBox(); ~CAddressEditBox();
private: private:
void PopulateComboBox(LPITEMIDLIST pidl);
void AddComboBoxItem(LPITEMIDLIST pidl, int index, int indent);
void FillOneLevel(int index, int levelIndent, int indent);
LPITEMIDLIST GetItemData(int index);
public: public:
// *** IShellService methods *** // *** IShellService methods ***
virtual HRESULT STDMETHODCALLTYPE SetOwner(IUnknown *); virtual HRESULT STDMETHODCALLTYPE SetOwner(IUnknown *);