ReactOS  0.4.15-dev-2701-g34593d9
aclistisf.cpp
Go to the documentation of this file.
1 /*
2  * Shell AutoComplete list
3  *
4  * Copyright 2015 Thomas Faber
5  * Copyright 2020-2021 Katayama Hirofumi MZ
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "precomp.h"
23 
25  : m_dwOptions(ACLO_CURRENTDIR | ACLO_MYCOMPUTER)
26  , m_iNextLocation(LT_DIRECTORY)
27  , m_fShowHidden(FALSE)
28 {
29 }
30 
32 {
33 }
34 
36 {
37  TRACE("(%p)\n", this);
38  HRESULT hr;
39  switch (m_iNextLocation)
40  {
41  case LT_DIRECTORY:
44  {
46  hr = SetLocation(pidl.Detach());
47  if (SUCCEEDED(hr))
48  {
49  TRACE("LT_DIRECTORY\n");
50  return hr;
51  }
52  }
53  // FALL THROUGH
54  case LT_DESKTOP:
57  {
61  return S_FALSE;
62  hr = SetLocation(pidl.Detach());
63  if (SUCCEEDED(hr))
64  {
65  TRACE("LT_DESKTOP\n");
66  return hr;
67  }
68  }
69  // FALL THROUGH
70  case LT_MYCOMPUTER:
73  {
77  return S_FALSE;
78  hr = SetLocation(pidl.Detach());
79  if (SUCCEEDED(hr))
80  {
81  TRACE("LT_MYCOMPUTER\n");
82  return hr;
83  }
84  }
85  // FALL THROUGH
86  case LT_FAVORITES:
89  {
93  return S_FALSE;
94  hr = SetLocation(pidl.Detach());
95  if (SUCCEEDED(hr))
96  {
97  TRACE("LT_FAVORITES\n");
98  return hr;
99  }
100  }
101  // FALL THROUGH
102  case LT_MAX:
103  default:
104  TRACE("LT_MAX\n");
105  return S_FALSE;
106  }
107 }
108 
110 {
111  TRACE("(%p, %p)\n", this, pidl);
112 
113  m_pEnumIDList.Release();
115  m_pidlLocation.Free();
116 
117  if (!pidl)
118  return E_FAIL;
119 
120  m_pidlLocation.Attach(pidl);
121 
122  CComPtr<IShellFolder> pFolder;
123  HRESULT hr = SHGetDesktopFolder(&pFolder);
124  if (FAILED_UNEXPECTEDLY(hr))
125  return hr;
126 
127  if (!ILIsEmpty(pidl))
128  {
129  hr = pFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &m_pShellFolder));
130  if (FAILED_UNEXPECTEDLY(hr))
131  return hr;
132  }
133  else
134  {
135  m_pShellFolder.Attach(pFolder.Detach());
136  }
137 
138  SHCONTF Flags = SHCONTF_FOLDERS | SHCONTF_INIT_ON_FIRST_NEXT;
139  if (m_fShowHidden)
140  Flags |= SHCONTF_INCLUDEHIDDEN;
141  if (!(m_dwOptions & ACLO_FILESYSDIRS))
142  Flags |= SHCONTF_NONFOLDERS;
143 
144  hr = m_pShellFolder->EnumObjects(NULL, Flags, &m_pEnumIDList);
145  if (hr != S_OK)
146  {
147  ERR("EnumObjects failed: 0x%lX\n", hr);
148  hr = E_FAIL;
149  }
150  return hr;
151 }
152 
154 {
155  TRACE("(%p, %p)\n", this, pidlChild);
156  pszChild.Free();
157 
158  STRRET StrRet;
159  DWORD dwFlags = SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
160  HRESULT hr = m_pShellFolder->GetDisplayNameOf(pidlChild, dwFlags, &StrRet);
161  if (FAILED(hr))
162  {
163  dwFlags = SHGDN_INFOLDER | SHGDN_FORPARSING;
164  hr = m_pShellFolder->GetDisplayNameOf(pidlChild, dwFlags, &StrRet);
165  if (FAILED_UNEXPECTEDLY(hr))
166  return hr;
167  }
168 
169  hr = StrRetToStrW(&StrRet, NULL, &pszChild);
170  if (FAILED_UNEXPECTEDLY(hr))
171  return hr;
172 
173  TRACE("pszChild: '%S'\n", static_cast<LPCWSTR>(pszChild));
174  return hr;
175 }
176 
177 HRESULT
179  CComHeapPtr<WCHAR>& pszExpanded)
180 {
181  TRACE("(%p, %p)\n", this, pidlChild);
182 
183  CComHeapPtr<WCHAR> pszChild;
184  HRESULT hr = GetDisplayName(pidlChild, pszChild);
185  if (FAILED_UNEXPECTEDLY(hr))
186  return hr;
187 
188  CStringW szRawPath, szExpanded;
190  {
191  INT cchExpand = m_szRawPath.GetLength();
192  if (StrCmpNIW(pszChild, m_szRawPath, cchExpand) != 0 ||
193  pszChild[0] != L'\\' || pszChild[1] != L'\\')
194  {
195  szRawPath = m_szRawPath;
196  szExpanded = m_szExpanded;
197  }
198  }
199  szRawPath += pszChild;
200  szExpanded += pszChild;
201 
202  SHStrDupW(szRawPath, &pszRaw);
203  SHStrDupW(szExpanded, &pszExpanded);
204  TRACE("pszRaw: '%S'\n", static_cast<LPCWSTR>(pszRaw));
205  TRACE("pszExpanded: '%S'\n", static_cast<LPCWSTR>(pszExpanded));
206  return S_OK;
207 }
208 
209 // *** IEnumString methods ***
210 STDMETHODIMP CACListISF::Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
211 {
212  TRACE("(%p, %d, %p, %p)\n", this, celt, rgelt, pceltFetched);
213 
214  if (celt == 0)
215  return S_OK;
216  if (!rgelt)
217  return S_FALSE;
218 
219  *rgelt = NULL;
220  if (pceltFetched)
221  *pceltFetched = 0;
222 
223  if (!m_pEnumIDList)
224  {
225  NextLocation();
226  if (!m_pEnumIDList)
227  return S_FALSE;
228  }
229 
230  HRESULT hr;
231  CComHeapPtr<ITEMIDLIST> pidlChild;
232  CComHeapPtr<WCHAR> pszRawPath, pszExpanded;
233 
234  do
235  {
236  for (;;)
237  {
238  pidlChild.Free();
239  hr = m_pEnumIDList->Next(1, &pidlChild, NULL);
240  if (hr != S_OK)
241  break;
242 
243  pszRawPath.Free();
244  pszExpanded.Free();
245  GetPaths(pidlChild, pszRawPath, pszExpanded);
246  if (!pszRawPath || !pszExpanded)
247  continue;
248 
249  if ((m_dwOptions & ACLO_FILESYSDIRS) && !PathIsDirectoryW(pszExpanded))
250  continue;
251  else if ((m_dwOptions & ACLO_FILESYSONLY) && !PathFileExistsW(pszExpanded))
252  continue;
253 
254  hr = S_OK;
255  break;
256  }
257  } while (hr == S_FALSE && NextLocation() == S_OK);
258 
259  if (hr == S_OK)
260  {
261  *rgelt = pszRawPath.Detach();
262  if (pceltFetched)
263  *pceltFetched = 1;
264  }
265  else
266  {
267  hr = S_FALSE;
268  }
269 
270  TRACE("*rgelt: %S\n", *rgelt);
271  return hr;
272 }
273 
275 {
276  TRACE("(%p)\n", this);
277 
279  m_szRawPath = L"";
280 
281  SHELLSTATE ss = { 0 };
283  m_fShowHidden = ss.fShowAllObjects;
284 
286  {
288  if (m_pBrowserService)
289  {
290  m_pBrowserService->GetPidl(&pidl);
291  if (pidl)
292  Initialize(pidl);
293  }
294  HRESULT hr = SetLocation(pidl.Detach());
295  if (FAILED_UNEXPECTEDLY(hr))
296  return S_FALSE;
297  }
298  return S_OK;
299 }
300 
302 {
303  TRACE("(%p, %d)\n", this, celt);
304  return E_NOTIMPL;
305 }
306 
308 {
309  TRACE("(%p, %p)\n", this, ppOut);
310  *ppOut = NULL;
311  return E_NOTIMPL;
312 }
313 
314 // *** IACList methods ***
315 STDMETHODIMP CACListISF::Expand(LPCOLESTR pszExpand)
316 {
317  TRACE("(%p, %ls)\n", this, pszExpand);
318 
319  m_szRawPath = pszExpand;
321 
322  // skip left space
323  while (*pszExpand == L' ')
324  ++pszExpand;
325 
326  // expand environment variables (%WINDIR% etc.)
327  WCHAR szExpanded[MAX_PATH], szPath1[MAX_PATH], szPath2[MAX_PATH];
328  ExpandEnvironmentStringsW(pszExpand, szExpanded, _countof(szExpanded));
329  pszExpand = szExpanded;
330 
331  // get full path
332  if (szExpanded[0] && szExpanded[1] == L':' && szExpanded[2] == 0)
333  {
334  // 'C:' --> 'C:\'
335  szExpanded[2] = L'\\';
336  szExpanded[3] = 0;
337  }
338  else
339  {
340  if (PathIsRelativeW(pszExpand) &&
342  PathCombineW(szPath2, szPath1, pszExpand))
343  {
344  pszExpand = szPath2;
345  }
346  GetFullPathNameW(pszExpand, _countof(szPath1), szPath1, NULL);
347  pszExpand = szPath1;
348  }
349 
351  m_szExpanded = pszExpand;
353  if (SUCCEEDED(hr))
354  {
355  hr = SetLocation(pidl.Detach());
356  if (FAILED_UNEXPECTEDLY(hr))
357  {
358  m_szRawPath = L"";
359  m_szExpanded = L"";
360  }
361  }
362  return hr;
363 }
364 
365 // *** IACList2 methods ***
367 {
368  TRACE("(%p, %lu)\n", this, dwFlag);
369  m_dwOptions = dwFlag;
370  return S_OK;
371 }
372 
374 {
375  TRACE("(%p, %p)\n", this, pdwFlag);
376  if (pdwFlag)
377  {
378  *pdwFlag = m_dwOptions;
379  return S_OK;
380  }
381  return E_INVALIDARG;
382 }
383 
384 // *** IShellService methods ***
386 {
387  TRACE("(%p, %p)\n", this, punkOwner);
388  m_pBrowserService.Release();
390  return S_OK;
391 }
392 
393 // *** IPersist methods ***
395 {
396  TRACE("(%p, %p)\n", this, pClassID);
397  if (pClassID == NULL)
398  return E_POINTER;
399  *pClassID = CLSID_ACListISF;
400  return S_OK;
401 }
402 
403 // *** IPersistFolder methods ***
405 {
406  TRACE("(%p, %p)\n", this, pidl);
407  m_pidlCurDir.Free();
408  if (!pidl)
409  return S_OK;
410 
411  LPITEMIDLIST pidlClone = ILClone(pidl);
412  if (!pidlClone)
413  {
414  ERR("Out of memory\n");
415  return E_OUTOFMEMORY;
416  }
417  m_pidlCurDir.Attach(pidlClone);
418  return S_OK;
419 }
420 
421 // *** ICurrentWorkingDirectory methods ***
423 {
424  TRACE("(%p, %p, %ld)\n", this, pwzPath, cchSize);
425  return E_NOTIMPL;
426 }
427 
429 {
430  TRACE("(%p, %ls, %ld)\n", this, pwzPath);
431  LPITEMIDLIST pidl = ILCreateFromPathW(pwzPath);
432  if (!pidl)
433  {
434  ERR("Out of memory\n");
435  return E_OUTOFMEMORY;
436  }
437  m_pidlCurDir.Attach(pidl);
438  return S_OK;
439 }
int GetLength() const
Definition: atlsimpstr.h:356
STDMETHODIMP Expand(LPCOLESTR pszExpand) override
Definition: aclistisf.cpp:315
CStringW m_szExpanded
Definition: aclistisf.h:47
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
#define ACLO_FILESYSONLY
Definition: shlobj.h:744
BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
Definition: path.c:1558
HRESULT hr
Definition: shlfolder.c:183
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
CComPtr< IEnumIDList > m_pEnumIDList
Definition: aclistisf.h:50
#define CSIDL_DESKTOP
Definition: shlobj.h:2012
static BOOL ILIsEmpty(_In_opt_ PCUIDLIST_RELATIVE pidl)
Definition: shlobj.h:2336
#define ACLO_FILESYSDIRS
Definition: shlobj.h:745
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1294
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
virtual STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidl) override
Definition: aclistisf.cpp:404
CComHeapPtr< ITEMIDLIST > m_pidlLocation
Definition: aclistisf.h:48
HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR *dest)
Definition: string.c:2004
virtual STDMETHODIMP GetClassID(CLSID *pClassID) override
Definition: aclistisf.cpp:394
CComPtr< IShellFolder > m_pShellFolder
Definition: aclistisf.h:51
static LPOLESTR
Definition: stg_prop.c:27
#define IID_PPV_ARG(Itype, ppType)
#define E_FAIL
Definition: ddrawi.h:102
int32_t INT
Definition: typedefs.h:58
STDMETHODIMP Reset() override
Definition: aclistisf.cpp:274
#define CSIDL_DRIVES
Definition: shlobj.h:2028
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define FALSE
Definition: types.h:117
#define ACLO_CURRENTDIR
Definition: shlobj.h:740
#define CSIDL_FAVORITES
Definition: shlobj.h:2018
if SUCCEEDED(hr)
HRESULT GetDisplayName(LPCITEMIDLIST pidlChild, CComHeapPtr< WCHAR > &pszChild)
Definition: aclistisf.cpp:153
#define STDMETHODIMP
Definition: basetyps.h:43
#define StrRet
Definition: shellclasses.h:871
#define S_FALSE
Definition: winerror.h:2357
#define E_INVALIDARG
Definition: ddrawi.h:101
STDMETHODIMP Clone(IEnumString **ppenum) override
Definition: aclistisf.cpp:307
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1756
BOOL m_fShowHidden
Definition: aclistisf.h:45
VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet)
Definition: shellord.c:201
HRESULT GetPaths(LPCITEMIDLIST pidlChild, CComHeapPtr< WCHAR > &pszRaw, CComHeapPtr< WCHAR > &pszExpanded)
Definition: aclistisf.cpp:178
#define SSF_SHOWALLOBJECTS
Definition: shlobj.h:1527
LOCATION_TYPE m_iNextLocation
Definition: aclistisf.h:44
DWORD m_dwOptions
Definition: aclistisf.h:43
#define ACLO_MYCOMPUTER
Definition: shlobj.h:741
#define TRACE(s)
Definition: solgame.cpp:4
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
HRESULT NextLocation()
Definition: aclistisf.cpp:35
__wchar_t WCHAR
Definition: xmlstorage.h:180
HRESULT WINAPI SHGetSpecialFolderLocation(HWND hwndOwner, INT nFolder, LPITEMIDLIST *ppidl)
Definition: shellpath.c:2830
LONG HRESULT
Definition: typedefs.h:79
virtual STDMETHODIMP SetOwner(IUnknown *punkOwner) override
Definition: aclistisf.cpp:385
#define _countof(array)
Definition: sndvol32.h:68
CStringW m_szRawPath
Definition: aclistisf.h:46
#define FAILED_UNEXPECTEDLY(hr)
Definition: shellutils.h:71
#define MAX_PATH
Definition: compat.h:34
unsigned long DWORD
Definition: ntddk_ex.h:95
#define ACLO_DESKTOP
Definition: shlobj.h:742
CComHeapPtr< ITEMIDLIST > m_pidlCurDir
Definition: aclistisf.h:49
STDMETHODIMP Skip(ULONG celt) override
Definition: aclistisf.cpp:301
static const WCHAR L[]
Definition: oid.c:1250
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
HRESULT SetLocation(LPITEMIDLIST pidl)
Definition: aclistisf.cpp:109
STDMETHODIMP GetDirectory(LPWSTR pwzPath, DWORD cchSize) override
Definition: aclistisf.cpp:422
STDMETHODIMP GetOptions(DWORD *pdwFlag) override
Definition: aclistisf.cpp:373
#define ERR(fmt,...)
Definition: debug.h:110
#define ACLO_FAVORITES
Definition: shlobj.h:743
#define S_OK
Definition: intsafe.h:51
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:228
STDMETHODIMP SetOptions(DWORD dwFlag) override
Definition: aclistisf.cpp:366
void Release()
Definition: atlcomcli.h:140
#define E_NOTIMPL
Definition: ddrawi.h:99
HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
Definition: pidl.c:1381
#define NULL
Definition: types.h:112
STDMETHODIMP Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) override
Definition: aclistisf.cpp:210
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:519
HRESULT QueryInterface([in] REFIID riid, [out, iid_is(riid)] void **ppvObject)
unsigned int ULONG
Definition: retypes.h:1
STDMETHODIMP SetDirectory(LPCWSTR pwzPath) override
Definition: aclistisf.cpp:428
#define ss
Definition: i386-dis.c:434
LPITEMIDLIST WINAPI ILCreateFromPathW(LPCWSTR path)
Definition: pidl.c:982
T * Detach()
Definition: atlcomcli.h:156
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define E_POINTER
Definition: winerror.h:2365
LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
Definition: path.c:189
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
static SHCONTF
Definition: ordinal.c:61
CComPtr< IBrowserService > m_pBrowserService
Definition: aclistisf.h:52
void Attach(T *lp)
Definition: atlcomcli.h:149
HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
Definition: string.c:1623
INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
Definition: string.c:311