https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2cbac3d049c7b3b1e6833…
commit 2cbac3d049c7b3b1e6833ab092a8a2cff9a7771f
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Mon Oct 8 00:42:02 2018 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)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-transl…
- // 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-transl…
+ * 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