[SHELL32][SDK] Fix ParseDisplayName Part 1 (#6721)

JIRA issue: CORE-19495
- Implement SHParseDisplayName and
  CDesktopFolder::ParseDisplayName.
- Add CStubFolderBase, CShellUrlStub, CFileUrlStub,
  CIDListUrlStub, and CHttpUrlStub helper classes.
- Add SHGetSpecialFolderID and
  Shell_ParseSpecialFolder helper functions.
- Add BindCtx_ContainsObject,
  BindCtx_GetUIWindow, 
  BindCtx_RegisterObjectParam, SHBindToObject,
  SHBindToObjectEx, SHCoInitializeAnyApartment,
  SHGetAttributes, SHGetNameAndFlagsW,
  SHIsFileSysBindCtx, SHSkipJunctionBinding,
  Shell_DisplayNameOf, and Shell_FailForceReturn
  helper functions.
- Modify CSIDL data.
This commit is contained in:
Katayama Hirofumi MZ 2024-04-10 09:32:13 +09:00 committed by GitHub
parent e85ef799fe
commit d05dcf6a02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 862 additions and 95 deletions

View file

@ -24,6 +24,223 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
STDMETHODIMP
CShellUrlStub::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
{
LPWSTR pch;
INT cch, csidl;
HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
PARSEDURLW ParsedURL = { sizeof(ParsedURL) };
::ParseURLW(lpszDisplayName, &ParsedURL);
DWORD attrs = (pdwAttributes ? *pdwAttributes : 0) | SFGAO_STREAM;
if (ParsedURL.pszSuffix[0] == L':' && ParsedURL.pszSuffix[1] == L':')
{
CComPtr<IShellFolder> psfDesktop;
hr = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hr))
{
CComPtr<IBindCtx> pBindCtx;
hr = ::CreateBindCtx(0, &pBindCtx);
if (SUCCEEDED(hr))
{
BIND_OPTS BindOps = { sizeof(BindOps) };
BindOps.grfMode = STGM_CREATE;
pBindCtx->SetBindOptions(&BindOps);
hr = psfDesktop->ParseDisplayName(hwndOwner, pBindCtx,
(LPWSTR)ParsedURL.pszSuffix,
pchEaten, ppidl, &attrs);
}
}
}
else
{
csidl = Shell_ParseSpecialFolder(ParsedURL.pszSuffix, &pch, &cch);
if (csidl == -1)
{
ERR("\n");
return hr;
}
CComHeapPtr<ITEMIDLIST> pidlLocation;
hr = SHGetFolderLocation(hwndOwner, (csidl | CSIDL_FLAG_CREATE), NULL, 0, &pidlLocation);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
if (pch && *pch)
{
CComPtr<IShellFolder> psfFolder;
hr = SHBindToObject(NULL, pidlLocation, IID_PPV_ARG(IShellFolder, &psfFolder));
if (SUCCEEDED(hr))
{
CComHeapPtr<ITEMIDLIST> pidlNew;
hr = psfFolder->ParseDisplayName(hwndOwner, pbc, pch, pchEaten, &pidlNew, &attrs);
if (SUCCEEDED(hr))
{
hr = SHILCombine(pidlLocation, pidlNew, ppidl);
if (pchEaten)
*pchEaten += cch;
}
}
}
else
{
if (attrs)
hr = SHGetNameAndFlagsW(pidlLocation, 0, NULL, 0, &attrs);
if (SUCCEEDED(hr))
{
if (pchEaten)
*pchEaten = cch;
*ppidl = pidlLocation.Detach();
}
}
}
// FIXME: SHWindowsPolicy
if (SUCCEEDED(hr) && (attrs & SFGAO_STREAM) &&
!BindCtx_ContainsObject(pbc, STR_PARSE_SHELL_PROTOCOL_TO_FILE_OBJECTS))
{
ILFree(*ppidl);
*ppidl = NULL;
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
if (pdwAttributes)
*pdwAttributes = attrs;
// FIXME: SHWindowsPolicy
if (FAILED(hr) && !Shell_FailForceReturn(hr))
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
return hr;
}
STDMETHODIMP
CFileUrlStub::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
{
WCHAR szPath[MAX_PATH];
DWORD cchPath = _countof(szPath);
HRESULT hr = PathCreateFromUrlW(lpszDisplayName, szPath, &cchPath, 0);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
CComPtr<IShellFolder> psfDesktop;
hr = SHGetDesktopFolder(&psfDesktop);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return psfDesktop->ParseDisplayName(hwndOwner, pbc, szPath, pchEaten, ppidl, pdwAttributes);
}
STDMETHODIMP
CIDListUrlStub::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
{
return E_NOTIMPL; // FIXME
}
STDMETHODIMP
CHttpUrlStub::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
{
return E_NOTIMPL; // FIXME
}
BOOL CDesktopFolder::_TryUrlJunctions(
LPCWSTR pcszURL,
IBindCtx *pBindCtx,
IShellFolder **ppShellFolder,
LPITEMIDLIST *ppidl)
{
PARSEDURLW ParsedURL = { sizeof(ParsedURL) };
::ParseURLW(pcszURL, &ParsedURL);
*ppShellFolder = NULL;
switch (ParsedURL.nScheme)
{
case URL_SCHEME_FILE:
*ppShellFolder = &m_FileUrlStub;
break;
case URL_SCHEME_HTTP:
case URL_SCHEME_HTTPS:
if (!BindCtx_ContainsObject(pBindCtx, STR_PARSE_PREFER_FOLDER_BROWSING))
break;
*ppShellFolder = &m_HttpUrlStub;
break;
case URL_SCHEME_SHELL:
*ppShellFolder = &m_ShellUrlStub;
break;
case URL_SCHEME_MSSHELLROOTED:
*ppShellFolder = NULL; // FIXME
break;
case URL_SCHEME_MSSHELLIDLIST:
*ppShellFolder = &m_IDListUrlStub;
break;
default:
break;
}
return !!*ppShellFolder;
}
BOOL CDesktopFolder::_GetParentForParsing(
LPCWSTR pszPath,
IBindCtx *pbc,
IShellFolder **ppParentFolder,
LPITEMIDLIST *ppidlParent)
{
WCHAR wch = *pszPath;
if (((L'A' <= wch && wch <= L'Z') || (L'a' <= wch && wch <= L'z')) && (pszPath[1] == ':'))
*ppidlParent = _ILCreateMyComputer();
else if (PathIsUNCW(pszPath))
*ppidlParent = _ILCreateNetwork();
else if (UrlIsW(pszPath, URLIS_URL) && !SHSkipJunctionBinding(pbc, NULL))
_TryUrlJunctions(pszPath, pbc, ppParentFolder, ppidlParent);
if (!*ppParentFolder && *ppidlParent)
SHBindToObject(NULL, *ppidlParent, IID_PPV_ARG(IShellFolder, ppParentFolder));
return *ppParentFolder != NULL;
}
HRESULT CDesktopFolder::_ChildParseDisplayName(
IShellFolder *pParentFolder,
LPCITEMIDLIST pidlParent,
HWND hwndOwner,
IBindCtx *pBindCtx,
LPWSTR lpszDisplayName,
DWORD *pchEaten,
LPITEMIDLIST *ppidl,
DWORD *pdwAttributes)
{
LPITEMIDLIST pidlChild;
HRESULT hr = pParentFolder->ParseDisplayName(hwndOwner, pBindCtx, lpszDisplayName,
pchEaten, &pidlChild, pdwAttributes);
if (FAILED(hr))
return hr;
if (pidlParent)
{
*ppidl = ILCombine(pidlParent, pidlChild);
ILFree(pidlChild);
}
else
{
*ppidl = pidlChild;
}
return (*ppidl ? S_OK : E_OUTOFMEMORY);
}
/*
CDesktopFolder should create two file system folders internally, one representing the
user's desktop folder, and the other representing the common desktop folder. It should
@ -285,11 +502,6 @@ HRESULT WINAPI CDesktopFolder::ParseDisplayName(
PIDLIST_RELATIVE *ppidl,
DWORD *pdwAttributes)
{
LPCWSTR szNext = NULL;
LPITEMIDLIST pidlTemp = NULL;
PARSEDURLW urldata;
HRESULT hr = S_OK;
TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
pchEaten, ppidl, pdwAttributes);
@ -302,78 +514,98 @@ HRESULT WINAPI CDesktopFolder::ParseDisplayName(
if (!lpszDisplayName)
return E_INVALIDARG;
if (pchEaten)
*pchEaten = 0; /* strange but like the original */
urldata.cbSize = sizeof(urldata);
if (!*lpszDisplayName)
{
*ppidl = _ILCreateMyComputer();
return (*ppidl ? S_OK : E_OUTOFMEMORY);
}
if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
{
return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
}
else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
{
/* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
pidlTemp = _ILCreateMyComputer ();
szNext = lpszDisplayName;
}
else if (PathIsUNCW(lpszDisplayName))
{
pidlTemp = _ILCreateNetwork();
szNext = lpszDisplayName;
}
else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
{
*ppidl = pidlTemp;
return S_OK;
}
else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
{
if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
{
TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
pidlTemp = _ILCreateGuidFromStrW(urldata.pszSuffix + 2);
}
else
return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
}
else
{
if (*lpszDisplayName)
{
/* it's a filesystem path on the desktop. Let a FSFolder parse it */
hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
if (SUCCEEDED(hr))
return hr;
return m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
}
else
pidlTemp = _ILCreateMyComputer();
szNext = NULL;
return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl,
pdwAttributes);
}
if (SUCCEEDED(hr) && pidlTemp)
HRESULT hr = E_INVALIDARG;
CComHeapPtr<ITEMIDLIST> pidlParent;
CComPtr<IShellFolder> pParentFolder;
if (_GetParentForParsing(lpszDisplayName, pbc, &pParentFolder, &pidlParent))
{
if (szNext && *szNext)
if (pchEaten)
*pchEaten = 0;
hr = _ChildParseDisplayName(pParentFolder,
pidlParent,
hwndOwner,
pbc,
lpszDisplayName,
pchEaten,
ppidl,
pdwAttributes);
if (SUCCEEDED(hr))
{
hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
&pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
}
else
{
if (pdwAttributes && *pdwAttributes)
if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES))
{
GetAttributesOf(1, &pidlTemp, pdwAttributes);
LPITEMIDLIST pidlAlias;
if (SUCCEEDED(Shell_TranslateIDListAlias(*ppidl, NULL, &pidlAlias, 0xFFFF)))
{
ILFree(*ppidl);
*ppidl = pidlAlias;
}
}
return hr;
}
}
if (SUCCEEDED(hr))
*ppidl = pidlTemp;
else
*ppidl = NULL;
if (Shell_FailForceReturn(hr))
return hr;
if (BindCtx_ContainsObject(pbc, STR_DONT_PARSE_RELATIVE))
return E_INVALIDARG;
if (SHIsFileSysBindCtx(pbc, NULL) == S_OK)
return hr;
BIND_OPTS BindOps = { sizeof(BindOps) };
BOOL bCreate = FALSE;
if (pbc && SUCCEEDED(pbc->GetBindOptions(&BindOps)) && (BindOps.grfMode & STGM_CREATE))
{
BindOps.grfMode &= ~STGM_CREATE;
bCreate = TRUE;
pbc->SetBindOptions(&BindOps);
}
if (m_DesktopFSFolder)
{
hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner,
pbc,
lpszDisplayName,
pchEaten,
ppidl,
pdwAttributes);
}
if (FAILED(hr) && m_SharedDesktopFSFolder)
{
hr = m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner,
pbc,
lpszDisplayName,
pchEaten,
ppidl,
pdwAttributes);
}
if (FAILED(hr) && bCreate && m_DesktopFSFolder)
{
BindOps.grfMode |= STGM_CREATE;
pbc->SetBindOptions(&BindOps);
hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner,
pbc,
lpszDisplayName,
pchEaten,
ppidl,
pdwAttributes);
}
TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);

View file

@ -23,6 +23,73 @@
#ifndef _CDESKTOPFOLDER_H_
#define _CDESKTOPFOLDER_H_
class CStubFolderBase : public IShellFolder
{
public:
CStubFolderBase() { }
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override { return E_NOTIMPL; }
STDMETHODIMP_(ULONG) AddRef() override { return 3; }
STDMETHODIMP_(ULONG) Release() override { return 2; }
// IShellFolder methods
STDMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) override
{ return E_NOTIMPL; }
STDMETHODIMP EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override
{ return E_NOTIMPL; }
STDMETHODIMP BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override
{ return E_NOTIMPL; }
STDMETHODIMP BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override
{ return E_NOTIMPL; }
STDMETHODIMP CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) override
{ return E_NOTIMPL; }
STDMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) override
{ return E_NOTIMPL; }
STDMETHODIMP GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) override
{ return E_NOTIMPL; }
STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) override
{ return E_NOTIMPL; }
STDMETHODIMP GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) override
{ return E_NOTIMPL; }
STDMETHODIMP SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName,
DWORD dwFlags, PITEMID_CHILD *pPidlOut) override
{ return E_NOTIMPL; }
};
class CShellUrlStub : public CStubFolderBase
{
public:
STDMETHODIMP
ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) override;
};
class CFileUrlStub : public CStubFolderBase
{
public:
STDMETHODIMP
ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) override;
};
class CIDListUrlStub : public CStubFolderBase
{
public:
STDMETHODIMP
ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) override;
};
class CHttpUrlStub : public CStubFolderBase
{
public:
STDMETHODIMP
ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten,
PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) override;
};
class CDesktopFolder :
public CComCoClass<CDesktopFolder, &CLSID_ShellDesktop>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
@ -37,11 +104,37 @@ class CDesktopFolder :
CComPtr<IShellFolder2> m_SharedDesktopFSFolder;
CComPtr<IShellFolder2> m_regFolder;
// Stub URL objects
CShellUrlStub m_ShellUrlStub;
CFileUrlStub m_FileUrlStub;
CIDListUrlStub m_IDListUrlStub;
CHttpUrlStub m_HttpUrlStub;
LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
LPITEMIDLIST pidlRoot; /* absolute pidl */
HRESULT _GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf);
BOOL _TryUrlJunctions(
LPCWSTR pcszURL,
IBindCtx *pBindCtx,
IShellFolder **ppShellFolder,
LPITEMIDLIST *ppidl);
BOOL _GetParentForParsing(
LPCWSTR pszPath,
IBindCtx *pbc,
IShellFolder **ppParentFolder,
LPITEMIDLIST *ppidlParent);
HRESULT _ChildParseDisplayName(
IShellFolder *pParentFolder,
LPCITEMIDLIST pidlParent,
HWND hwndOwner,
IBindCtx *pBindCtx,
LPWSTR lpszDisplayName,
DWORD *pchEaten,
LPITEMIDLIST *ppidl,
DWORD *pdwAttributes);
public:
CDesktopFolder();
~CDesktopFolder();

View file

@ -153,4 +153,62 @@ public:
END_MSG_MAP()
};
HRESULT
Shell_TranslateIDListAlias(
_In_ LPCITEMIDLIST pidl,
_In_ HANDLE hToken,
_Out_ LPITEMIDLIST *ppidlAlias,
_In_ DWORD dwFlags);
BOOL BindCtx_ContainsObject(_In_ IBindCtx *pBindCtx, _In_ LPCWSTR pszName);
BOOL SHSkipJunctionBinding(_In_ IBindCtx *pbc, _In_ CLSID *pclsid);
HRESULT SHIsFileSysBindCtx(_In_ IBindCtx *pBindCtx, _Out_opt_ WIN32_FIND_DATAW **ppFindData);
BOOL Shell_FailForceReturn(_In_ HRESULT hr);
EXTERN_C INT
Shell_ParseSpecialFolder(_In_ LPCWSTR pszStart, _Out_ LPWSTR *ppch, _Out_ INT *pcch);
HRESULT
Shell_DisplayNameOf(
_In_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ DWORD dwFlags,
_Out_ LPWSTR pszBuf,
_In_ UINT cchBuf);
HRESULT SHBindToObject(
_In_opt_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ REFIID riid,
_Out_ void **ppvObj);
HRESULT
SHBindToObjectEx(
_In_opt_ IShellFolder *pShellFolder,
_In_ LPCITEMIDLIST pidl,
_In_opt_ IBindCtx *pBindCtx,
_In_ REFIID riid,
_Out_ void **ppvObj);
DWORD
SHGetAttributes(_In_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ DWORD dwAttributes);
HRESULT SHCoInitializeAnyApartment(VOID);
HRESULT
SHGetNameAndFlagsW(
_In_ LPCITEMIDLIST pidl,
_In_ DWORD dwFlags,
_Out_opt_ LPWSTR pszText,
_In_ UINT cchBuf,
_Inout_opt_ DWORD *pdwAttributes);
EXTERN_C HWND BindCtx_GetUIWindow(_In_ IBindCtx *pBindCtx);
EXTERN_C HRESULT
BindCtx_RegisterObjectParam(
_In_ IBindCtx *pBindCtx,
_In_ LPOLESTR pszKey,
_In_opt_ IUnknown *punk,
_Out_ LPBC *ppbc);
#endif /* _PRECOMP_H__ */

View file

@ -31,6 +31,316 @@ OpenEffectiveToken(
return ret;
}
HRESULT
Shell_TranslateIDListAlias(
_In_ LPCITEMIDLIST pidl,
_In_ HANDLE hToken,
_Out_ LPITEMIDLIST *ppidlAlias,
_In_ DWORD dwFlags)
{
return E_FAIL; //FIXME
}
BOOL BindCtx_ContainsObject(_In_ IBindCtx *pBindCtx, _In_ LPCWSTR pszName)
{
CComPtr<IUnknown> punk;
if (!pBindCtx || FAILED(pBindCtx->GetObjectParam(const_cast<LPWSTR>(pszName), &punk)))
return FALSE;
return TRUE;
}
BOOL SHSkipJunctionBinding(_In_ IBindCtx *pbc, _In_ CLSID *pclsid)
{
if (!pbc)
return FALSE;
BIND_OPTS BindOps = { sizeof(BindOps) };
if (SUCCEEDED(pbc->GetBindOptions(&BindOps)) && BindOps.grfFlags == OLECONTF_LINKS)
return TRUE;
return pclsid && SHSkipJunction(pbc, pclsid);
}
HRESULT SHIsFileSysBindCtx(_In_ IBindCtx *pBindCtx, _Out_opt_ WIN32_FIND_DATAW **ppFindData)
{
CComPtr<IUnknown> punk;
CComPtr<IFileSystemBindData> pBindData;
if (!pBindCtx || FAILED(pBindCtx->GetObjectParam((LPWSTR)STR_FILE_SYS_BIND_DATA, &punk)))
return S_FALSE;
if (FAILED(punk->QueryInterface(IID_PPV_ARG(IFileSystemBindData, &pBindData))))
return S_FALSE;
HRESULT hr = S_OK;
if (ppFindData)
{
*ppFindData = (WIN32_FIND_DATAW*)LocalAlloc(LPTR, sizeof(WIN32_FIND_DATAW));
if (*ppFindData)
pBindData->GetFindData(*ppFindData);
else
hr = E_OUTOFMEMORY;
}
return hr;
}
BOOL Shell_FailForceReturn(_In_ HRESULT hr)
{
DWORD code = HRESULT_CODE(hr);
switch (code)
{
case ERROR_BAD_NETPATH:
case ERROR_BAD_NET_NAME:
case ERROR_CANCELLED:
return TRUE;
default:
return (ERROR_FILE_NOT_FOUND <= code && code <= ERROR_PATH_NOT_FOUND);
}
}
HRESULT
SHBindToObjectEx(
_In_opt_ IShellFolder *pShellFolder,
_In_ LPCITEMIDLIST pidl,
_In_opt_ IBindCtx *pBindCtx,
_In_ REFIID riid,
_Out_ void **ppvObj)
{
CComPtr<IShellFolder> psfDesktop;
*ppvObj = NULL;
if (!pShellFolder)
{
SHGetDesktopFolder(&psfDesktop);
if (!psfDesktop)
return E_FAIL;
pShellFolder = psfDesktop;
}
HRESULT hr;
if (_ILIsDesktop(pidl))
hr = pShellFolder->QueryInterface(riid, ppvObj);
else
hr = pShellFolder->BindToObject(pidl, pBindCtx, riid, ppvObj);
if (SUCCEEDED(hr) && !*ppvObj)
hr = E_FAIL;
return hr;
}
HRESULT SHBindToObject(
_In_opt_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ REFIID riid,
_Out_ void **ppvObj)
{
return SHBindToObjectEx(psf, pidl, NULL, riid, ppvObj);
}
HRESULT
Shell_DisplayNameOf(
_In_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ DWORD dwFlags,
_Out_ LPWSTR pszBuf,
_In_ UINT cchBuf)
{
*pszBuf = UNICODE_NULL;
STRRET sr;
HRESULT hr = psf->GetDisplayNameOf(pidl, dwFlags, &sr);
if (FAILED(hr))
return hr;
return StrRetToBufW(&sr, pidl, pszBuf, cchBuf);
}
DWORD
SHGetAttributes(_In_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ DWORD dwAttributes)
{
LPCITEMIDLIST pidlLast;
if (psf)
{
psf->AddRef();
pidlLast = pidl;
}
else
{
SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
}
if (!psf)
return 0;
DWORD oldAttrs = dwAttributes;
if (FAILED(psf->GetAttributesOf(1, &pidlLast, &dwAttributes)))
dwAttributes = 0;
else
dwAttributes &= oldAttrs;
if ((dwAttributes & SFGAO_FOLDER) &&
(dwAttributes & SFGAO_STREAM) &&
!(dwAttributes & SFGAO_STORAGEANCESTOR) &&
(oldAttrs & SFGAO_STORAGEANCESTOR) &&
(SHGetObjectCompatFlags(psf, NULL) & 0x200))
{
dwAttributes &= ~(SFGAO_STREAM | SFGAO_STORAGEANCESTOR);
dwAttributes |= SFGAO_STORAGEANCESTOR;
}
if (psf)
psf->Release();
return dwAttributes;
}
HRESULT SHCoInitializeAnyApartment(VOID)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (FAILED(hr))
hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
return hr;
}
HRESULT
SHGetNameAndFlagsW(
_In_ LPCITEMIDLIST pidl,
_In_ DWORD dwFlags,
_Out_opt_ LPWSTR pszText,
_In_ UINT cchBuf,
_Inout_opt_ DWORD *pdwAttributes)
{
if (pszText)
*pszText = UNICODE_NULL;
HRESULT hrCoInit = SHCoInitializeAnyApartment();
CComPtr<IShellFolder> psfFolder;
LPCITEMIDLIST ppidlLast;
HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfFolder), &ppidlLast);
if (SUCCEEDED(hr))
{
if (pszText)
hr = Shell_DisplayNameOf(psfFolder, ppidlLast, dwFlags, pszText, cchBuf);
if (SUCCEEDED(hr))
{
if (pdwAttributes)
*pdwAttributes = SHGetAttributes(psfFolder, ppidlLast, *pdwAttributes);
}
}
if (SUCCEEDED(hrCoInit))
CoUninitialize();
return hr;
}
EXTERN_C HWND
BindCtx_GetUIWindow(_In_ IBindCtx *pBindCtx)
{
HWND hWnd = NULL;
CComPtr<IUnknown> punk;
if (pBindCtx && SUCCEEDED(pBindCtx->GetObjectParam((LPWSTR)L"UI During Binding", &punk)))
IUnknown_GetWindow(punk, &hWnd);
return hWnd;
}
class CDummyOleWindow : public IOleWindow
{
protected:
LONG m_cRefs;
HWND m_hWnd;
public:
CDummyOleWindow() : m_cRefs(1), m_hWnd(NULL) { }
virtual ~CDummyOleWindow() { }
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj) override
{
static const QITAB c_tab[] =
{
QITABENT(CDummyOleWindow, IOleWindow),
{ NULL }
};
return ::QISearch(this, c_tab, riid, ppvObj);
}
STDMETHODIMP_(ULONG) AddRef() override
{
return ++m_cRefs;
}
STDMETHODIMP_(ULONG) Release() override
{
if (--m_cRefs == 0)
{
delete this;
return 0;
}
return m_cRefs;
}
// IOleWindow methods
STDMETHODIMP GetWindow(HWND *phWnd) override
{
*phWnd = m_hWnd;
if (!m_hWnd)
return E_NOTIMPL;
return S_OK;
}
STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override
{
return E_NOTIMPL;
}
};
EXTERN_C HRESULT
BindCtx_RegisterObjectParam(
_In_ IBindCtx *pBindCtx,
_In_ LPOLESTR pszKey,
_In_opt_ IUnknown *punk,
_Out_ LPBC *ppbc)
{
HRESULT hr = S_OK;
CDummyOleWindow *pUnknown = NULL;
*ppbc = pBindCtx;
if (pBindCtx)
{
pBindCtx->AddRef();
}
else
{
hr = CreateBindCtx(0, ppbc);
if (FAILED(hr))
return hr;
}
if (!punk)
punk = pUnknown = new CDummyOleWindow();
hr = (*ppbc)->RegisterObjectParam(pszKey, punk);
if (pUnknown)
pUnknown->Release();
if (FAILED(hr))
{
(*ppbc)->Release();
*ppbc = NULL;
}
return hr;
}
/*************************************************************************
* SHSetFolderPathA (SHELL32.231)
*

View file

@ -54,6 +54,15 @@ extern BOOL WINAPI Free(LPVOID);
static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl);
static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl);
EXTERN_C HWND BindCtx_GetUIWindow(_In_ IBindCtx *pBindCtx);
EXTERN_C HRESULT
BindCtx_RegisterObjectParam(
_In_ IBindCtx *pBindCtx,
_In_ LPOLESTR pszKey,
_In_opt_ IUnknown *punk,
_Out_ LPBC *ppbc);
/*************************************************************************
* ILGetDisplayNameExA
*
@ -1396,39 +1405,59 @@ HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCI
HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc,
LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
{
HRESULT hr;
LPWSTR pszNameDup;
IShellFolder *psfDesktop;
HRESULT hr=E_FAIL;
ULONG dwAttr=sfgaoIn;
IBindCtx *pBindCtx = NULL;
if(!ppidl)
return E_INVALIDARG;
TRACE("(%s, %p, %p, 0x%X, %p)\n", pszName, pbc, ppidl, sfgaoIn, psfgaoOut);
if (!pszName)
{
*ppidl = NULL;
return E_INVALIDARG;
}
*ppidl = NULL;
if (psfgaoOut)
*psfgaoOut = 0;
pszNameDup = StrDupW(pszName);
if (!pszNameDup)
return E_OUTOFMEMORY;
psfDesktop = NULL;
hr = SHGetDesktopFolder(&psfDesktop);
if (FAILED(hr))
{
*ppidl = NULL;
LocalFree(pszNameDup);
return hr;
}
hr = IShellFolder_ParseDisplayName(psfDesktop, (HWND)NULL, pbc, (LPOLESTR)pszName, (ULONG *)NULL, ppidl, &dwAttr);
IShellFolder_Release(psfDesktop);
if (!pbc)
{
hr = BindCtx_RegisterObjectParam(NULL, STR_PARSE_TRANSLATE_ALIASES, NULL, &pBindCtx);
pbc = pBindCtx;
}
if (SUCCEEDED(hr))
{
if (psfgaoOut) *psfgaoOut = dwAttr;
}
else
{
*ppidl = NULL;
ULONG sfgao = sfgaoIn, cchEaten;
HWND hwndUI = BindCtx_GetUIWindow(pbc);
hr = psfDesktop->lpVtbl->ParseDisplayName(psfDesktop,
hwndUI,
pbc,
pszNameDup,
&cchEaten,
ppidl,
(psfgaoOut ? &sfgao : NULL));
if (SUCCEEDED(hr) && psfgaoOut)
*psfgaoOut = (sfgao & sfgaoIn);
}
LocalFree(pszNameDup);
if (psfDesktop)
psfDesktop->lpVtbl->Release(psfDesktop);
if (pBindCtx)
pBindCtx->lpVtbl->Release(pBindCtx);
return hr;
}

View file

@ -1104,14 +1104,14 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x03 - CSIDL_CONTROLS (.CPL files) */
&FOLDERID_ControlPanelFolder,
CSIDL_Type_SystemPath,
NULL,
L"ControlPanelFolder",
NULL,
-IDI_SHELL_CONTROL_PANEL
},
{ /* 0x04 - CSIDL_PRINTERS */
&FOLDERID_PrintersFolder,
CSIDL_Type_SystemPath,
NULL,
L"PrintersFolder",
NULL,
-IDI_SHELL_PRINTERS_FOLDER
},
@ -1151,7 +1151,7 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */
&FOLDERID_RecycleBinFolder,
CSIDL_Type_Disallowed,
NULL,
L"RecycleBinFolder",
NULL
},
{ /* 0x0b - CSIDL_STARTMENU */
@ -1210,14 +1210,14 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x11 - CSIDL_DRIVES */
&FOLDERID_ComputerFolder,
CSIDL_Type_Disallowed,
NULL,
L"MyComputerFolder",
NULL,
-IDI_SHELL_COMPUTER_FOLDER
},
{ /* 0x12 - CSIDL_NETWORK */
&FOLDERID_NetworkFolder,
CSIDL_Type_Disallowed,
NULL,
L"NetworkPlacesFolder",
NULL,
-IDI_SHELL_NETWORK_FOLDER
},
@ -1341,21 +1341,21 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x24 - CSIDL_WINDOWS */
&FOLDERID_Windows,
CSIDL_Type_WindowsPath,
NULL,
L"Windows",
NULL,
-IDI_SHELL_SYSTEM_GEAR
},
{ /* 0x25 - CSIDL_SYSTEM */
&FOLDERID_System,
CSIDL_Type_SystemPath,
NULL,
L"System",
NULL,
-IDI_SHELL_SYSTEM_GEAR
},
{ /* 0x26 - CSIDL_PROGRAM_FILES */
&FOLDERID_ProgramFiles,
CSIDL_Type_CurrVer,
L"ProgramFilesDir",
L"ProgramFiles",
MAKEINTRESOURCEW(IDS_PROGRAM_FILES),
#ifdef __REACTOS__
0
@ -1390,21 +1390,21 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x2a - CSIDL_PROGRAM_FILESX86 */
&FOLDERID_ProgramFilesX86,
CSIDL_Type_CurrVer,
L"ProgramFilesDir (x86)",
L"ProgramFilesX86",
L"Program Files (x86)",
-IDI_SHELL_PROGRAMS_FOLDER
},
{ /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */
&FOLDERID_ProgramFilesCommon,
CSIDL_Type_CurrVer,
L"CommonFilesDir",
L"ProgramFilesCommon",
MAKEINTRESOURCEW(IDS_PROGRAM_FILES_COMMON),
-IDI_SHELL_PROGRAMS_FOLDER
},
{ /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */
&FOLDERID_ProgramFilesCommonX86,
CSIDL_Type_CurrVer,
L"CommonFilesDir (x86)",
L"ProgramFilesCommonX86",
L"Program Files (x86)\\Common Files",
-IDI_SHELL_PROGRAMS_FOLDER
},
@ -1436,7 +1436,7 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x31 - CSIDL_CONNECTIONS */
&FOLDERID_ConnectionsFolder,
CSIDL_Type_Disallowed,
NULL,
L"ConnectionsFolder",
NULL,
-IDI_SHELL_NETWORK_CONNECTIONS
},
@ -1842,6 +1842,43 @@ static const CSIDL_DATA CSIDL_Data[] =
#endif
};
INT SHGetSpecialFolderID(_In_ LPCWSTR pszName)
{
UINT csidl;
for (csidl = 0; csidl < _countof(CSIDL_Data); ++csidl)
{
const CSIDL_DATA *pData = &CSIDL_Data[csidl];
if (pData->szValueName && lstrcmpiW(pszName, pData->szValueName) == 0)
return csidl;
}
return -1;
}
INT Shell_ParseSpecialFolder(_In_ LPCWSTR pszStart, _Out_ LPWSTR *ppch, _Out_ INT *pcch)
{
LPCWSTR pszPath, pchBackslash;
WCHAR szPath[MAX_PATH];
pchBackslash = StrChrW(pszStart, L'\\');
if (pchBackslash)
{
*ppch = (LPWSTR)(pchBackslash + 1);
*pcch = (pchBackslash - pszStart) + 1;
StrCpyNW(szPath, pszStart, max(*pcch, _countof(szPath)));
pszPath = szPath;
}
else
{
*ppch = NULL;
*pcch = lstrlenW(pszStart);
pszPath = pszStart;
}
return SHGetSpecialFolderID(pszPath);
}
#ifndef __REACTOS__
static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest);
#else

View file

@ -219,6 +219,12 @@ interface IShellFolder : IUnknown
cpp_quote("#define SFGAO_STORAGECAPMASK 0x70C50008L")
cpp_quote("#define SFGAO_PKEYSFGAOMASK 0x81044000L")
cpp_quote("#define STR_PARSE_SHELL_PROTOCOL_TO_FILE_OBJECTS L\"Parse Shell Protocol To File Objects\"")
cpp_quote("#define STR_FILE_SYS_BIND_DATA L\"File System Bind Data\"")
cpp_quote("#define STR_PARSE_PREFER_FOLDER_BROWSING L\"Parse Prefer Folder Browsing\"")
cpp_quote("#define STR_PARSE_TRANSLATE_ALIASES L\"Parse Translate Aliases\"")
cpp_quote("#define STR_DONT_PARSE_RELATIVE L\"Don't Parse Relative\"")
typedef ULONG SFGAOF;
HRESULT ParseDisplayName(

View file

@ -322,6 +322,8 @@ IContextMenu_Invoke(
_In_ LPCSTR lpVerb,
_In_ UINT uFlags);
DWORD WINAPI SHGetObjectCompatFlags(IUnknown *pUnk, const CLSID *clsid);
#ifdef __cplusplus
} /* extern "C" */
#endif /* defined(__cplusplus) */