https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2cbac3d049c7b3b1e6833a...
commit 2cbac3d049c7b3b1e6833ab092a8a2cff9a7771f Author: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org AuthorDate: Mon Oct 8 00:42:02 2018 +0200 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org CommitDate: Mon Oct 8 00:50:38 2018 +0200
[SHELL32] Finally fix the icon location path (un)expansion for shell links, and explain why I originally used SHExpandEnvironmentStringsW(). CORE-14009 CORE-14982 --- dll/win32/shell32/CShellLink.cpp | 71 +++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 16 deletions(-)
diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp index 92f62961cf..fa1adab35f 100644 --- a/dll/win32/shell32/CShellLink.cpp +++ b/dll/win32/shell32/CShellLink.cpp @@ -143,6 +143,14 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
+/* + * Allows to define whether or not Windows-compatible behaviour + * should be adopted when setting and retrieving icon location paths. + * See CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT iIcon) + * for more details. + */ +#define ICON_LINK_WINDOWS_COMPAT + #define SHLINK_LOCAL 0 #define SHLINK_REMOTE 1
@@ -1715,7 +1723,7 @@ HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation(UINT uFlags, PWSTR pszIcon uFlags |= GIL_FORSHORTCUT;
if (uFlags & GIL_DEFAULTICON) - return E_FAIL; + return S_FALSE;
hr = GetIconLocation(pszIconFile, cchMax, piIndex); if (FAILED(hr) || pszIconFile[0] == UNICODE_NULL) @@ -1849,15 +1857,12 @@ BOOL PathFullyUnExpandEnvStringsW( HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT iIcon) { HRESULT hr = E_FAIL; - WCHAR szUnExpIconPath[MAX_PATH]; - BOOL bSuccess; + WCHAR szIconPath[MAX_PATH];
TRACE("(%p)->(path=%s iicon=%u)\n", this, debugstr_w(pszIconPath), iIcon);
if (pszIconPath) { - /* Try to fully unexpand the icon path */ - /* * Check whether the user-given file path contains unexpanded * environment variables. If so, create a target environment block. @@ -1868,16 +1873,35 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT i * refer to the same place even if the would-be corresponding * environment variable could change). */ - // FIXME: http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-transla... - // if (PathFullyUnExpandEnvStringsW(pszIconPath, szUnExpIconPath, _countof(szUnExpIconPath))) - bSuccess = PathUnExpandEnvStringsW(pszIconPath, szUnExpIconPath, _countof(szUnExpIconPath)); - if (bSuccess && wcscmp(pszIconPath, szUnExpIconPath) != 0) +#ifdef ICON_LINK_WINDOWS_COMPAT + /* Try to fully unexpand the icon path */ + // if (PathFullyUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath))) + BOOL bSuccess = PathUnExpandEnvStringsW(pszIconPath, szIconPath, _countof(szIconPath)); + if (bSuccess && wcscmp(pszIconPath, szIconPath) != 0) +#else + /* + * In some situations, described in http://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-transla... + * the result of PathUnExpandEnvStringsW() could be wrong, and instead + * one would have to store the actual provided icon location path, while + * creating an icon environment block ONLY if that path already contains + * environment variables. This is what the present case is trying to implement. + */ + SHExpandEnvironmentStringsW(pszIconPath, szIconPath, _countof(szIconPath)); + if (wcscmp(pszIconPath, szIconPath) != 0) +#endif { - /* Unexpansion succeeded, so we need an icon environment block */ + /* + * The user-given file path contains unexpanded environment + * variables, so we need an icon environment block. + */ EXP_SZ_LINK buffer; LPEXP_SZ_LINK pInfo;
- pszIconPath = szUnExpIconPath; +#ifdef ICON_LINK_WINDOWS_COMPAT + /* Make pszIconPath point to the unexpanded path */ + LPCWSTR pszOrgIconPath = pszIconPath; + pszIconPath = szIconPath; +#endif pInfo = (LPEXP_SZ_LINK)SHFindDataBlock(m_pDBList, EXP_SZ_ICON_SIG); if (pInfo) { @@ -1902,8 +1926,8 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT i buffer.dwSignature = EXP_SZ_ICON_SIG; }
- lstrcpynW(pInfo->szwTarget, szUnExpIconPath, _countof(pInfo->szwTarget)); - WideCharToMultiByte(CP_ACP, 0, szUnExpIconPath, -1, + lstrcpynW(pInfo->szwTarget, pszIconPath, _countof(pInfo->szwTarget)); + WideCharToMultiByte(CP_ACP, 0, pszIconPath, -1, pInfo->szTarget, _countof(pInfo->szTarget), NULL, NULL);
hr = S_OK; @@ -1911,16 +1935,31 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetIconLocation(LPCWSTR pszIconPath, INT i hr = AddDataBlock(pInfo); if (hr == S_OK) m_Header.dwFlags |= SLDF_HAS_EXP_ICON_SZ; + +#ifdef ICON_LINK_WINDOWS_COMPAT + /* Set pszIconPath back to the original one */ + pszIconPath = pszOrgIconPath; +#else + /* Now, make pszIconPath point to the expanded path */ + pszIconPath = szIconPath; +#endif } else { - /* Unexpansion failed, so we need to remove any icon environment block */ + /* + * The user-given file path does not contain unexpanded environment + * variables, so we need to remove any icon environment block. + */ m_Header.dwFlags &= ~SLDF_HAS_EXP_ICON_SZ; RemoveDataBlock(EXP_SZ_ICON_SIG); + + /* pszIconPath points to the user path */ } }
- /* Store the original icon path location (this one may contain unexpanded environment strings) */ +#ifdef ICON_LINK_WINDOWS_COMPAT + /* Store the original icon path location (may contain unexpanded environment strings) */ +#endif if (pszIconPath) { m_Header.dwFlags &= ~SLDF_HAS_ICONLOCATION; @@ -2404,7 +2443,7 @@ HRESULT STDMETHODCALLTYPE CShellLink::SetPath(LPCWSTR pszFile) if (hr == S_OK) m_Header.dwFlags |= SLDF_HAS_EXP_SZ;
- /* Now, make pszFile point to the expanded buffer */ + /* Now, make pszFile point to the expanded path */ pszFile = szPath; } else