https://git.reactos.org/?p=reactos.git;a=commitdiff;h=24833a6dde324dddce1a7…
commit 24833a6dde324dddce1a7316ffaefc0233daf903
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sat Oct 17 17:49:24 2020 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Oct 17 17:49:24 2020 +0900
[BROWSEUI] Implement CLSID_ACListISF (#3298)
Implement enumeration of IShellFolder items of auto-completion. CORE-9281
---
dll/win32/browseui/aclistisf.cpp | 352 +++++++++++++++++++++++++++++++++++++--
dll/win32/browseui/aclistisf.h | 52 ++++--
2 files changed, 375 insertions(+), 29 deletions(-)
diff --git a/dll/win32/browseui/aclistisf.cpp b/dll/win32/browseui/aclistisf.cpp
index 72045b3a14e..533a7af814b 100644
--- a/dll/win32/browseui/aclistisf.cpp
+++ b/dll/win32/browseui/aclistisf.cpp
@@ -2,6 +2,7 @@
* Shell AutoComplete list
*
* Copyright 2015 Thomas Faber
+ * Copyright 2020 Katayama Hirofumi MZ
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,8 +21,10 @@
#include "precomp.h"
-CACListISF::CACListISF() :
- m_dwOptions(0)
+CACListISF::CACListISF()
+ : m_dwOptions(ACLO_CURRENTDIR | ACLO_MYCOMPUTER)
+ , m_iNextLocation(LT_DIRECTORY)
+ , m_fShowHidden(FALSE)
{
}
@@ -29,26 +32,290 @@ CACListISF::~CACListISF()
{
}
+HRESULT CACListISF::NextLocation()
+{
+ TRACE("(%p)\n", this);
+ HRESULT hr;
+ switch (m_iNextLocation)
+ {
+ case LT_DIRECTORY:
+ m_iNextLocation = LT_DESKTOP;
+ if (!ILIsEmpty(m_pidlCurDir) && (m_dwOptions & ACLO_CURRENTDIR))
+ {
+ CComHeapPtr<ITEMIDLIST> pidl(ILClone(m_pidlCurDir));
+ hr = SetLocation(pidl.Detach());
+ if (SUCCEEDED(hr))
+ {
+ TRACE("LT_DIRECTORY\n");
+ return hr;
+ }
+ }
+ // FALL THROUGH
+ case LT_DESKTOP:
+ m_iNextLocation = LT_MYCOMPUTER;
+ if (m_dwOptions & ACLO_DESKTOP)
+ {
+ CComHeapPtr<ITEMIDLIST> pidl;
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return S_FALSE;
+ hr = SetLocation(pidl.Detach());
+ if (SUCCEEDED(hr))
+ {
+ TRACE("LT_DESKTOP\n");
+ return hr;
+ }
+ }
+ // FALL THROUGH
+ case LT_MYCOMPUTER:
+ m_iNextLocation = LT_FAVORITES;
+ if (m_dwOptions & ACLO_MYCOMPUTER)
+ {
+ CComHeapPtr<ITEMIDLIST> pidl;
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidl);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return S_FALSE;
+ hr = SetLocation(pidl.Detach());
+ if (SUCCEEDED(hr))
+ {
+ TRACE("LT_MYCOMPUTER\n");
+ return hr;
+ }
+ }
+ // FALL THROUGH
+ case LT_FAVORITES:
+ m_iNextLocation = LT_MAX;
+ if (m_dwOptions & ACLO_FAVORITES)
+ {
+ CComHeapPtr<ITEMIDLIST> pidl;
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return S_FALSE;
+ hr = SetLocation(pidl.Detach());
+ if (SUCCEEDED(hr))
+ {
+ TRACE("LT_FAVORITES\n");
+ return hr;
+ }
+ }
+ // FALL THROUGH
+ case LT_MAX:
+ default:
+ TRACE("LT_MAX\n");
+ return S_FALSE;
+ }
+}
+
+HRESULT CACListISF::SetLocation(LPITEMIDLIST pidl)
+{
+ TRACE("(%p, %p)\n", this, pidl);
+
+ m_pEnumIDList.Release();
+ m_pShellFolder.Release();
+ m_pidlLocation.Free();
+
+ if (!pidl)
+ return E_FAIL;
+
+ m_pidlLocation.Attach(pidl);
+
+ CComPtr<IShellFolder> pFolder;
+ HRESULT hr = SHGetDesktopFolder(&pFolder);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ if (!ILIsEmpty(pidl))
+ {
+ hr = pFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder,
&m_pShellFolder));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ }
+ else
+ {
+ m_pShellFolder.Attach(pFolder.Detach());
+ }
+
+ SHCONTF Flags = SHCONTF_FOLDERS | SHCONTF_INIT_ON_FIRST_NEXT;
+ if (m_fShowHidden)
+ Flags |= SHCONTF_INCLUDEHIDDEN;
+ if (!(m_dwOptions & ACLO_FILESYSDIRS))
+ Flags |= SHCONTF_NONFOLDERS;
+
+ hr = m_pShellFolder->EnumObjects(NULL, Flags, &m_pEnumIDList);
+ if (hr != S_OK)
+ {
+ ERR("EnumObjects failed: 0x%lX\n", hr);
+ hr = E_FAIL;
+ }
+ return hr;
+}
+
+HRESULT CACListISF::GetDisplayName(LPCITEMIDLIST pidlChild, CComHeapPtr<WCHAR>&
pszChild)
+{
+ TRACE("(%p, %p)\n", this, pidlChild);
+ pszChild.Free();
+
+ STRRET StrRet;
+ DWORD dwFlags = SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
+ HRESULT hr = m_pShellFolder->GetDisplayNameOf(pidlChild, dwFlags, &StrRet);
+ if (FAILED(hr))
+ {
+ dwFlags = SHGDN_INFOLDER | SHGDN_FORPARSING;
+ hr = m_pShellFolder->GetDisplayNameOf(pidlChild, dwFlags, &StrRet);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ }
+
+ hr = StrRetToStrW(&StrRet, NULL, &pszChild);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ TRACE("pszChild: '%S'\n", static_cast<LPCWSTR>(pszChild));
+ return hr;
+}
+
+HRESULT CACListISF::GetPathName(LPCITEMIDLIST pidlChild, CComHeapPtr<WCHAR>&
pszPath)
+{
+ TRACE("(%p, %p)\n", this, pidlChild);
+
+ CComHeapPtr<WCHAR> pszChild;
+ HRESULT hr = GetDisplayName(pidlChild, pszChild);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CStringW szPath;
+ if (m_szExpand.GetLength() && m_iNextLocation == LT_DIRECTORY)
+ {
+ INT cchExpand = m_szExpand.GetLength();
+ if (StrCmpNIW(pszChild, m_szExpand, cchExpand) != 0 ||
+ pszChild[0] != L'\\' || pszChild[1] != L'\\')
+ {
+ szPath = m_szExpand;
+ }
+ }
+ szPath += pszChild;
+
+ INT cchMax = szPath.GetLength() + 1;
+ CComHeapPtr<WCHAR> pszFullPath;
+ if (!pszFullPath.Allocate(cchMax))
+ {
+ ERR("Out of memory\n");
+ return E_OUTOFMEMORY;
+ }
+
+ StringCchCopyW(pszFullPath, cchMax, szPath);
+ pszPath.Attach(pszFullPath.Detach());
+ TRACE("pszPath: '%S'\n", static_cast<LPCWSTR>(pszPath));
+ return S_OK;
+}
+
// *** IEnumString methods ***
-HRESULT STDMETHODCALLTYPE CACListISF::Next(ULONG celt, LPOLESTR *rgelt, ULONG
*pceltFetched)
+STDMETHODIMP CACListISF::Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
{
TRACE("(%p, %d, %p, %p)\n", this, celt, rgelt, pceltFetched);
- return E_NOTIMPL;
+
+ if (celt == 0)
+ return S_OK;
+ if (!rgelt)
+ return S_FALSE;
+
+ *rgelt = NULL;
+ if (pceltFetched)
+ *pceltFetched = 0;
+
+ if (!m_pEnumIDList)
+ {
+ NextLocation();
+ if (!m_pEnumIDList)
+ return S_FALSE;
+ }
+
+ HRESULT hr;
+ CComHeapPtr<ITEMIDLIST> pidlChild;
+ CComHeapPtr<WCHAR> pszPathName;
+
+ do
+ {
+ for (;;)
+ {
+ pidlChild.Free();
+ hr = m_pEnumIDList->Next(1, &pidlChild, NULL);
+ if (hr != S_OK)
+ break;
+
+ pszPathName.Free();
+ GetPathName(pidlChild, pszPathName);
+ if (!pszPathName)
+ continue;
+
+ if (m_dwOptions & (ACLO_FILESYSONLY | ACLO_FILESYSDIRS))
+ {
+ DWORD attrs = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
+ hr = m_pShellFolder->GetAttributesOf(1, const_cast<LPCITEMIDLIST
*>(&pidlChild), &attrs);
+ if (SUCCEEDED(hr))
+ {
+ if (!(attrs & (SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR)))
+ continue;
+ }
+ }
+
+ if ((m_dwOptions & ACLO_FILESYSDIRS) &&
!PathIsDirectoryW(pszPathName))
+ continue;
+
+ hr = S_OK;
+ break;
+ }
+ } while (hr == S_FALSE && NextLocation() == S_OK);
+
+ if (hr == S_OK)
+ {
+ *rgelt = pszPathName.Detach();
+ if (pceltFetched)
+ *pceltFetched = 1;
+ }
+ else
+ {
+ hr = S_FALSE;
+ }
+
+ TRACE("*rgelt: %S\n", *rgelt);
+ return hr;
}
-HRESULT STDMETHODCALLTYPE CACListISF::Reset()
+STDMETHODIMP CACListISF::Reset()
{
TRACE("(%p)\n", this);
- return E_NOTIMPL;
+
+ m_iNextLocation = LT_DIRECTORY;
+ m_szExpand = L"";
+
+ SHELLSTATE ss = { 0 };
+ SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
+ m_fShowHidden = ss.fShowAllObjects;
+
+ if (m_dwOptions & ACLO_CURRENTDIR)
+ {
+ CComHeapPtr<ITEMIDLIST> pidl;
+ if (m_pBrowserService)
+ {
+ m_pBrowserService->GetPidl(&pidl);
+ if (pidl)
+ Initialize(pidl);
+ }
+ HRESULT hr = SetLocation(pidl.Detach());
+ if (FAILED_UNEXPECTEDLY(hr))
+ return S_FALSE;
+ }
+ return S_OK;
}
-HRESULT STDMETHODCALLTYPE CACListISF::Skip(ULONG celt)
+STDMETHODIMP CACListISF::Skip(ULONG celt)
{
TRACE("(%p, %d)\n", this, celt);
return E_NOTIMPL;
}
-HRESULT STDMETHODCALLTYPE CACListISF::Clone(IEnumString **ppOut)
+STDMETHODIMP CACListISF::Clone(IEnumString **ppOut)
{
TRACE("(%p, %p)\n", this, ppOut);
*ppOut = NULL;
@@ -56,36 +323,54 @@ HRESULT STDMETHODCALLTYPE CACListISF::Clone(IEnumString **ppOut)
}
// *** IACList methods ***
-HRESULT STDMETHODCALLTYPE CACListISF::Expand(LPCOLESTR pszExpand)
+STDMETHODIMP CACListISF::Expand(LPCOLESTR pszExpand)
{
TRACE("(%p, %ls)\n", this, pszExpand);
- return E_NOTIMPL;
+
+ m_szExpand = pszExpand;
+
+ m_iNextLocation = LT_DIRECTORY;
+ CComHeapPtr<ITEMIDLIST> pidl;
+ HRESULT hr = SHParseDisplayName(m_szExpand, NULL, &pidl, NULL, NULL);
+ if (SUCCEEDED(hr))
+ {
+ hr = SetLocation(pidl.Detach());
+ if (FAILED_UNEXPECTEDLY(hr))
+ m_szExpand = L"";
+ }
+ return hr;
}
// *** IACList2 methods ***
-HRESULT STDMETHODCALLTYPE CACListISF::SetOptions(DWORD dwFlag)
+STDMETHODIMP CACListISF::SetOptions(DWORD dwFlag)
{
TRACE("(%p, %lu)\n", this, dwFlag);
m_dwOptions = dwFlag;
return S_OK;
}
-HRESULT STDMETHODCALLTYPE CACListISF::GetOptions(DWORD* pdwFlag)
+STDMETHODIMP CACListISF::GetOptions(DWORD* pdwFlag)
{
TRACE("(%p, %p)\n", this, pdwFlag);
- *pdwFlag = m_dwOptions;
- return S_OK;
+ if (pdwFlag)
+ {
+ *pdwFlag = m_dwOptions;
+ return S_OK;
+ }
+ return E_INVALIDARG;
}
// *** IShellService methods ***
-HRESULT STDMETHODCALLTYPE CACListISF::SetOwner(IUnknown *punkOwner)
+STDMETHODIMP CACListISF::SetOwner(IUnknown *punkOwner)
{
TRACE("(%p, %p)\n", this, punkOwner);
- return E_NOTIMPL;
+ m_pBrowserService.Release();
+ punkOwner->QueryInterface(IID_PPV_ARG(IBrowserService, &m_pBrowserService));
+ return S_OK;
}
// *** IPersist methods ***
-HRESULT STDMETHODCALLTYPE CACListISF::GetClassID(CLSID *pClassID)
+STDMETHODIMP CACListISF::GetClassID(CLSID *pClassID)
{
TRACE("(%p, %p)\n", this, pClassID);
if (pClassID == NULL)
@@ -95,8 +380,39 @@ HRESULT STDMETHODCALLTYPE CACListISF::GetClassID(CLSID *pClassID)
}
// *** IPersistFolder methods ***
-HRESULT STDMETHODCALLTYPE CACListISF::Initialize(PCIDLIST_ABSOLUTE pidl)
+STDMETHODIMP CACListISF::Initialize(PCIDLIST_ABSOLUTE pidl)
{
TRACE("(%p, %p)\n", this, pidl);
+ m_pidlCurDir.Free();
+ if (!pidl)
+ return S_OK;
+
+ LPITEMIDLIST pidlClone = ILClone(pidl);
+ if (!pidlClone)
+ {
+ ERR("Out of memory\n");
+ return E_OUTOFMEMORY;
+ }
+ m_pidlCurDir.Attach(pidlClone);
+ return S_OK;
+}
+
+// *** ICurrentWorkingDirectory methods ***
+STDMETHODIMP CACListISF::GetDirectory(LPWSTR pwzPath, DWORD cchSize)
+{
+ TRACE("(%p, %p, %ld)\n", this, pwzPath, cchSize);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CACListISF::SetDirectory(LPCWSTR pwzPath)
+{
+ TRACE("(%p, %ls, %ld)\n", this, pwzPath);
+ LPITEMIDLIST pidl = ILCreateFromPathW(pwzPath);
+ if (!pidl)
+ {
+ ERR("Out of memory\n");
+ return E_OUTOFMEMORY;
+ }
+ m_pidlCurDir.Attach(pidl);
return S_OK;
}
diff --git a/dll/win32/browseui/aclistisf.h b/dll/win32/browseui/aclistisf.h
index ddb530946da..abc63efd45c 100644
--- a/dll/win32/browseui/aclistisf.h
+++ b/dll/win32/browseui/aclistisf.h
@@ -2,6 +2,7 @@
* Shell AutoComplete list
*
* Copyright 2015 Thomas Faber
+ * Copyright 2020 Katayama Hirofumi MZ
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,40 +26,68 @@ class CACListISF :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IEnumString,
public IACList2,
+ public ICurrentWorkingDirectory,
public IShellService,
public IPersistFolder
{
private:
+ enum LOCATION_TYPE
+ {
+ LT_DIRECTORY,
+ LT_DESKTOP,
+ LT_MYCOMPUTER,
+ LT_FAVORITES,
+ LT_MAX
+ };
+
DWORD m_dwOptions;
+ LOCATION_TYPE m_iNextLocation;
+ BOOL m_fShowHidden;
+ CStringW m_szExpand;
+ CComHeapPtr<ITEMIDLIST> m_pidlLocation;
+ CComHeapPtr<ITEMIDLIST> m_pidlCurDir;
+ CComPtr<IEnumIDList> m_pEnumIDList;
+ CComPtr<IShellFolder> m_pShellFolder;
+ CComPtr<IBrowserService> m_pBrowserService;
public:
CACListISF();
~CACListISF();
+ HRESULT NextLocation();
+ HRESULT SetLocation(LPITEMIDLIST pidl);
+ HRESULT GetDisplayName(LPCITEMIDLIST pidlChild, CComHeapPtr<WCHAR>&
pszChild);
+ HRESULT GetPathName(LPCITEMIDLIST pidlChild, CComHeapPtr<WCHAR>& pszPath);
+
// *** IEnumString methods ***
- virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPOLESTR *rgelt, ULONG
*pceltFetched);
- virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt);
- virtual HRESULT STDMETHODCALLTYPE Reset();
- virtual HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppenum);
+ STDMETHODIMP Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) override;
+ STDMETHODIMP Skip(ULONG celt) override;
+ STDMETHODIMP Reset() override;
+ STDMETHODIMP Clone(IEnumString **ppenum) override;
// *** IACList methods ***
- virtual HRESULT STDMETHODCALLTYPE Expand(LPCOLESTR pszExpand);
+ STDMETHODIMP Expand(LPCOLESTR pszExpand) override;
// *** IACList2 methods ***
- virtual HRESULT STDMETHODCALLTYPE SetOptions(DWORD dwFlag);
- virtual HRESULT STDMETHODCALLTYPE GetOptions(DWORD* pdwFlag);
+ STDMETHODIMP SetOptions(DWORD dwFlag) override;
+ STDMETHODIMP GetOptions(DWORD* pdwFlag) override;
+
+ // FIXME: These virtual keywords below should be removed.
// *** IShellService methods ***
- virtual HRESULT STDMETHODCALLTYPE SetOwner(IUnknown *);
+ virtual STDMETHODIMP SetOwner(IUnknown *punkOwner) override;
// *** IPersist methods ***
- virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
+ virtual STDMETHODIMP GetClassID(CLSID *pClassID) override;
// *** IPersistFolder methods ***
- virtual HRESULT STDMETHODCALLTYPE Initialize(PCIDLIST_ABSOLUTE pidl);
+ virtual STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidl) override;
-public:
+ // *** ICurrentWorkingDirectory methods ***
+ STDMETHODIMP GetDirectory(LPWSTR pwzPath, DWORD cchSize) override;
+ STDMETHODIMP SetDirectory(LPCWSTR pwzPath) override;
+public:
DECLARE_REGISTRY_RESOURCEID(IDR_ACLISTISF)
DECLARE_NOT_AGGREGATABLE(CACListISF)
@@ -72,5 +101,6 @@ public:
// Windows doesn't return this
//COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
+ COM_INTERFACE_ENTRY_IID(IID_ICurrentWorkingDirectory, ICurrentWorkingDirectory)
END_COM_MAP()
};