[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); 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 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 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, PIDLIST_RELATIVE *ppidl,
DWORD *pdwAttributes) 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", TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName), this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
pchEaten, ppidl, pdwAttributes); pchEaten, ppidl, pdwAttributes);
@ -302,78 +514,98 @@ HRESULT WINAPI CDesktopFolder::ParseDisplayName(
if (!lpszDisplayName) if (!lpszDisplayName)
return E_INVALIDARG; return E_INVALIDARG;
if (pchEaten) if (!*lpszDisplayName)
*pchEaten = 0; /* strange but like the original */ {
*ppidl = _ILCreateMyComputer();
urldata.cbSize = sizeof(urldata); return (*ppidl ? S_OK : E_OUTOFMEMORY);
}
if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':') if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
{ {
return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes); return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl,
pdwAttributes);
} }
else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
HRESULT hr = E_INVALIDARG;
CComHeapPtr<ITEMIDLIST> pidlParent;
CComPtr<IShellFolder> pParentFolder;
if (_GetParentForParsing(lpszDisplayName, pbc, &pParentFolder, &pidlParent))
{ {
/* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */ if (pchEaten)
pidlTemp = _ILCreateMyComputer (); *pchEaten = 0;
szNext = lpszDisplayName;
} hr = _ChildParseDisplayName(pParentFolder,
else if (PathIsUNCW(lpszDisplayName)) pidlParent,
{ hwndOwner,
pidlTemp = _ILCreateNetwork(); pbc,
szNext = lpszDisplayName; lpszDisplayName,
} pchEaten,
else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) ) ppidl,
{ pdwAttributes);
*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)) if (SUCCEEDED(hr))
{
if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES))
{
LPITEMIDLIST pidlAlias;
if (SUCCEEDED(Shell_TranslateIDListAlias(*ppidl, NULL, &pidlAlias, 0xFFFF)))
{
ILFree(*ppidl);
*ppidl = pidlAlias;
}
}
return hr;
}
}
if (Shell_FailForceReturn(hr))
return hr; return hr;
return m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes); if (BindCtx_ContainsObject(pbc, STR_DONT_PARSE_RELATIVE))
} return E_INVALIDARG;
else
pidlTemp = _ILCreateMyComputer();
szNext = NULL; 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 (SUCCEEDED(hr) && pidlTemp) if (m_DesktopFSFolder)
{ {
if (szNext && *szNext) hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner,
{ pbc,
hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, lpszDisplayName,
&pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes); pchEaten,
} ppidl,
else pdwAttributes);
{
if (pdwAttributes && *pdwAttributes)
{
GetAttributesOf(1, &pidlTemp, pdwAttributes);
}
}
} }
if (SUCCEEDED(hr)) if (FAILED(hr) && m_SharedDesktopFSFolder)
*ppidl = pidlTemp; {
else hr = m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner,
*ppidl = NULL; 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); TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);

View file

@ -23,6 +23,73 @@
#ifndef _CDESKTOPFOLDER_H_ #ifndef _CDESKTOPFOLDER_H_
#define _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 : class CDesktopFolder :
public CComCoClass<CDesktopFolder, &CLSID_ShellDesktop>, public CComCoClass<CDesktopFolder, &CLSID_ShellDesktop>,
public CComObjectRootEx<CComMultiThreadModelNoCS>, public CComObjectRootEx<CComMultiThreadModelNoCS>,
@ -37,11 +104,37 @@ class CDesktopFolder :
CComPtr<IShellFolder2> m_SharedDesktopFSFolder; CComPtr<IShellFolder2> m_SharedDesktopFSFolder;
CComPtr<IShellFolder2> m_regFolder; 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 */ LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
LPITEMIDLIST pidlRoot; /* absolute pidl */ LPITEMIDLIST pidlRoot; /* absolute pidl */
HRESULT _GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf); 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: public:
CDesktopFolder(); CDesktopFolder();
~CDesktopFolder(); ~CDesktopFolder();

View file

@ -153,4 +153,62 @@ public:
END_MSG_MAP() 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__ */ #endif /* _PRECOMP_H__ */

View file

@ -31,6 +31,316 @@ OpenEffectiveToken(
return ret; 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) * SHSetFolderPathA (SHELL32.231)
* *

View file

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

View file

@ -1104,14 +1104,14 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x03 - CSIDL_CONTROLS (.CPL files) */ { /* 0x03 - CSIDL_CONTROLS (.CPL files) */
&FOLDERID_ControlPanelFolder, &FOLDERID_ControlPanelFolder,
CSIDL_Type_SystemPath, CSIDL_Type_SystemPath,
NULL, L"ControlPanelFolder",
NULL, NULL,
-IDI_SHELL_CONTROL_PANEL -IDI_SHELL_CONTROL_PANEL
}, },
{ /* 0x04 - CSIDL_PRINTERS */ { /* 0x04 - CSIDL_PRINTERS */
&FOLDERID_PrintersFolder, &FOLDERID_PrintersFolder,
CSIDL_Type_SystemPath, CSIDL_Type_SystemPath,
NULL, L"PrintersFolder",
NULL, NULL,
-IDI_SHELL_PRINTERS_FOLDER -IDI_SHELL_PRINTERS_FOLDER
}, },
@ -1151,7 +1151,7 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */ { /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */
&FOLDERID_RecycleBinFolder, &FOLDERID_RecycleBinFolder,
CSIDL_Type_Disallowed, CSIDL_Type_Disallowed,
NULL, L"RecycleBinFolder",
NULL NULL
}, },
{ /* 0x0b - CSIDL_STARTMENU */ { /* 0x0b - CSIDL_STARTMENU */
@ -1210,14 +1210,14 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x11 - CSIDL_DRIVES */ { /* 0x11 - CSIDL_DRIVES */
&FOLDERID_ComputerFolder, &FOLDERID_ComputerFolder,
CSIDL_Type_Disallowed, CSIDL_Type_Disallowed,
NULL, L"MyComputerFolder",
NULL, NULL,
-IDI_SHELL_COMPUTER_FOLDER -IDI_SHELL_COMPUTER_FOLDER
}, },
{ /* 0x12 - CSIDL_NETWORK */ { /* 0x12 - CSIDL_NETWORK */
&FOLDERID_NetworkFolder, &FOLDERID_NetworkFolder,
CSIDL_Type_Disallowed, CSIDL_Type_Disallowed,
NULL, L"NetworkPlacesFolder",
NULL, NULL,
-IDI_SHELL_NETWORK_FOLDER -IDI_SHELL_NETWORK_FOLDER
}, },
@ -1341,21 +1341,21 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x24 - CSIDL_WINDOWS */ { /* 0x24 - CSIDL_WINDOWS */
&FOLDERID_Windows, &FOLDERID_Windows,
CSIDL_Type_WindowsPath, CSIDL_Type_WindowsPath,
NULL, L"Windows",
NULL, NULL,
-IDI_SHELL_SYSTEM_GEAR -IDI_SHELL_SYSTEM_GEAR
}, },
{ /* 0x25 - CSIDL_SYSTEM */ { /* 0x25 - CSIDL_SYSTEM */
&FOLDERID_System, &FOLDERID_System,
CSIDL_Type_SystemPath, CSIDL_Type_SystemPath,
NULL, L"System",
NULL, NULL,
-IDI_SHELL_SYSTEM_GEAR -IDI_SHELL_SYSTEM_GEAR
}, },
{ /* 0x26 - CSIDL_PROGRAM_FILES */ { /* 0x26 - CSIDL_PROGRAM_FILES */
&FOLDERID_ProgramFiles, &FOLDERID_ProgramFiles,
CSIDL_Type_CurrVer, CSIDL_Type_CurrVer,
L"ProgramFilesDir", L"ProgramFiles",
MAKEINTRESOURCEW(IDS_PROGRAM_FILES), MAKEINTRESOURCEW(IDS_PROGRAM_FILES),
#ifdef __REACTOS__ #ifdef __REACTOS__
0 0
@ -1390,21 +1390,21 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x2a - CSIDL_PROGRAM_FILESX86 */ { /* 0x2a - CSIDL_PROGRAM_FILESX86 */
&FOLDERID_ProgramFilesX86, &FOLDERID_ProgramFilesX86,
CSIDL_Type_CurrVer, CSIDL_Type_CurrVer,
L"ProgramFilesDir (x86)", L"ProgramFilesX86",
L"Program Files (x86)", L"Program Files (x86)",
-IDI_SHELL_PROGRAMS_FOLDER -IDI_SHELL_PROGRAMS_FOLDER
}, },
{ /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */ { /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */
&FOLDERID_ProgramFilesCommon, &FOLDERID_ProgramFilesCommon,
CSIDL_Type_CurrVer, CSIDL_Type_CurrVer,
L"CommonFilesDir", L"ProgramFilesCommon",
MAKEINTRESOURCEW(IDS_PROGRAM_FILES_COMMON), MAKEINTRESOURCEW(IDS_PROGRAM_FILES_COMMON),
-IDI_SHELL_PROGRAMS_FOLDER -IDI_SHELL_PROGRAMS_FOLDER
}, },
{ /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */ { /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */
&FOLDERID_ProgramFilesCommonX86, &FOLDERID_ProgramFilesCommonX86,
CSIDL_Type_CurrVer, CSIDL_Type_CurrVer,
L"CommonFilesDir (x86)", L"ProgramFilesCommonX86",
L"Program Files (x86)\\Common Files", L"Program Files (x86)\\Common Files",
-IDI_SHELL_PROGRAMS_FOLDER -IDI_SHELL_PROGRAMS_FOLDER
}, },
@ -1436,7 +1436,7 @@ static const CSIDL_DATA CSIDL_Data[] =
{ /* 0x31 - CSIDL_CONNECTIONS */ { /* 0x31 - CSIDL_CONNECTIONS */
&FOLDERID_ConnectionsFolder, &FOLDERID_ConnectionsFolder,
CSIDL_Type_Disallowed, CSIDL_Type_Disallowed,
NULL, L"ConnectionsFolder",
NULL, NULL,
-IDI_SHELL_NETWORK_CONNECTIONS -IDI_SHELL_NETWORK_CONNECTIONS
}, },
@ -1842,6 +1842,43 @@ static const CSIDL_DATA CSIDL_Data[] =
#endif #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__ #ifndef __REACTOS__
static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest); static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest);
#else #else

View file

@ -219,6 +219,12 @@ interface IShellFolder : IUnknown
cpp_quote("#define SFGAO_STORAGECAPMASK 0x70C50008L") cpp_quote("#define SFGAO_STORAGECAPMASK 0x70C50008L")
cpp_quote("#define SFGAO_PKEYSFGAOMASK 0x81044000L") 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; typedef ULONG SFGAOF;
HRESULT ParseDisplayName( HRESULT ParseDisplayName(

View file

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