https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7b081be46de966e3fe6c2…
commit 7b081be46de966e3fe6c2aa47a5a26deb7541e8a
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Sat Sep 14 13:10:49 2024 +0200
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Sep 14 13:10:49 2024 +0200
[SHELL32][MKSHELLLINK] Support EXP_SPECIAL_FOLDER datablock in shortcuts (#7158)
CORE-19692
---
dll/win32/shell32/CShellLink.cpp | 16 +++++++
dll/win32/shell32/folders/CFSFolder.cpp | 36 +++++++++------
sdk/tools/mkshelllink/mkshelllink.c | 79 +++++++++++++++++++++++++++++++--
3 files changed, 113 insertions(+), 18 deletions(-)
diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp
index d438fa204ff..bf2b5be44d5 100644
--- a/dll/win32/shell32/CShellLink.cpp
+++ b/dll/win32/shell32/CShellLink.cpp
@@ -746,6 +746,22 @@ HRESULT STDMETHODCALLTYPE CShellLink::Load(IStream *stm)
if (FAILED(hr)) // FIXME: Should we fail?
return hr;
+ LPEXP_SPECIAL_FOLDER pSpecial = (LPEXP_SPECIAL_FOLDER)SHFindDataBlock(m_pDBList,
EXP_SPECIAL_FOLDER_SIG);
+ if (pSpecial && pSpecial->cbSize == sizeof(*pSpecial) &&
ILGetSize(m_pPidl) > pSpecial->cbOffset)
+ {
+ if (LPITEMIDLIST folder = SHCloneSpecialIDList(NULL,
pSpecial->idSpecialFolder, FALSE))
+ {
+ LPITEMIDLIST pidl = ILCombine(folder, (LPITEMIDLIST)((char*)m_pPidl +
pSpecial->cbOffset));
+ if (pidl)
+ {
+ ILFree(m_pPidl);
+ m_pPidl = pidl;
+ TRACE("Replaced pidl base with CSIDL %u up to %ub.\n",
pSpecial->idSpecialFolder, pSpecial->cbOffset);
+ }
+ ILFree(folder);
+ }
+ }
+
if (TRACE_ON(shell))
{
#if (NTDDI_VERSION < NTDDI_LONGHORN)
diff --git a/dll/win32/shell32/folders/CFSFolder.cpp
b/dll/win32/shell32/folders/CFSFolder.cpp
index bde0d6dbb42..3c7bb8f2d03 100644
--- a/dll/win32/shell32/folders/CFSFolder.cpp
+++ b/dll/win32/shell32/folders/CFSFolder.cpp
@@ -14,8 +14,20 @@ WINE_DEFAULT_DEBUG_CHANNEL (shell);
static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID*
pclsidFolder);
+static LPCWSTR GetItemFileName(PCUITEMID_CHILD pidl, LPWSTR Buf, UINT cchMax)
+{
+ FileStructW* pDataW = _ILGetFileStructW(pidl);
+ if (pDataW)
+ return pDataW->wszName;
+ LPPIDLDATA pdata = _ILGetDataPointer(pidl);
+ if ((pdata->type & PT_VALUEW) == PT_VALUEW)
+ return (LPWSTR)pdata->u.file.szNames;
+ if (_ILSimpleGetTextW(pidl, Buf, cchMax))
+ return Buf;
+ return NULL;
+}
-HKEY OpenKeyFromFileType(LPWSTR pExtension, LPCWSTR KeyName)
+static HKEY OpenKeyFromFileType(LPCWSTR pExtension, LPCWSTR KeyName)
{
HKEY hkey;
@@ -45,7 +57,7 @@ HKEY OpenKeyFromFileType(LPWSTR pExtension, LPCWSTR KeyName)
return hkey;
}
-LPWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl)
+static LPCWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl, LPWSTR Buf, UINT cchMax)
{
if (!_ILIsValue(pidl))
{
@@ -53,23 +65,17 @@ LPWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl)
return NULL;
}
- FileStructW* pDataW = _ILGetFileStructW(pidl);
- if (!pDataW)
- {
- ERR("Invalid pidl!\n");
- return NULL;
- }
-
- LPWSTR pExtension = PathFindExtensionW(pDataW->wszName);
+ LPCWSTR name = GetItemFileName(pidl, Buf, cchMax);
+ LPCWSTR pExtension = name ? PathFindExtensionW(name) : NULL;
if (!pExtension || *pExtension == UNICODE_NULL)
{
- WARN("No extension for %S!\n", pDataW->wszName);
+ WARN("No extension for %S!\n", name);
return NULL;
}
return pExtension;
}
-HRESULT GetCLSIDForFileTypeFromExtension(LPWSTR pExtension, LPCWSTR KeyName, CLSID*
pclsid)
+static HRESULT GetCLSIDForFileTypeFromExtension(LPCWSTR pExtension, LPCWSTR KeyName,
CLSID* pclsid)
{
HKEY hkeyProgId = OpenKeyFromFileType(pExtension, KeyName);
if (!hkeyProgId)
@@ -126,7 +132,8 @@ HRESULT GetCLSIDForFileTypeFromExtension(LPWSTR pExtension, LPCWSTR
KeyName, CLS
HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid)
{
- LPWSTR pExtension = ExtensionFromPidl(pidl);
+ WCHAR buf[256];
+ LPCWSTR pExtension = ExtensionFromPidl(pidl, buf, _countof(buf));
if (!pExtension)
return S_FALSE;
@@ -289,7 +296,8 @@ HRESULT CFSExtractIcon_CreateInstance(IShellFolder * psf,
LPCITEMIDLIST pidl, RE
}
else
{
- LPWSTR pExtension = ExtensionFromPidl(pidl);
+ WCHAR extbuf[256];
+ LPCWSTR pExtension = ExtensionFromPidl(pidl, extbuf, _countof(extbuf));
HKEY hkey = pExtension ? OpenKeyFromFileType(pExtension,
L"DefaultIcon") : NULL;
if (!hkey)
WARN("Could not open DefaultIcon key!\n");
diff --git a/sdk/tools/mkshelllink/mkshelllink.c b/sdk/tools/mkshelllink/mkshelllink.c
index 2cb921e567b..c01ad361db8 100644
--- a/sdk/tools/mkshelllink/mkshelllink.c
+++ b/sdk/tools/mkshelllink/mkshelllink.c
@@ -18,8 +18,14 @@ typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#endif
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+
#define SW_SHOWNORMAL 1
#define SW_SHOWMINNOACTIVE 7
+#define CSIDL_WINDOWS 0x24
+#define CSIDL_SYSTEM 0x25
typedef struct _GUID
{
@@ -125,17 +131,61 @@ typedef struct _ID_LIST_DRIVE
uint16_t unknown;
} ID_LIST_DRIVE;
+#define EXP_SPECIAL_FOLDER_SIG 0xA0000005
+typedef struct _EXP_SPECIAL_FOLDER
+{
+ uint32_t cbSize, dwSignature, idSpecialFolder, cbOffset;
+} EXP_SPECIAL_FOLDER;
+
#pragma pack(pop)
+static const struct SPECIALFOLDER {
+ unsigned char csidl;
+ const char* name;
+} g_specialfolders[] = {
+ { CSIDL_WINDOWS, "windows" },
+ { CSIDL_SYSTEM, "system" },
+ { 0, NULL}
+};
+
+static unsigned int is_path_separator(unsigned int c)
+{
+ return c == '\\' || c == '/';
+}
+
+static const struct SPECIALFOLDER* get_special_folder(const char *target)
+{
+ char buf[256];
+ strncpy(buf, target, sizeof(buf));
+ buf[sizeof("shell:") - 1] = '\0';
+ if (strcasecmp("shell:", buf))
+ return NULL;
+
+ target += sizeof("shell:") - 1;
+ for (unsigned long i = 0;; ++i)
+ {
+ unsigned long len;
+ const struct SPECIALFOLDER *special = &g_specialfolders[i];
+ if (!special->name)
+ return NULL;
+ len = strlen(special->name);
+ strncpy(buf, target, sizeof(buf));
+ buf[len] = '\0';
+ if (!strcasecmp(special->name, buf) && (is_path_separator(target[len])
|| !target[len]))
+ return &g_specialfolders[i];
+ }
+}
+
int main(int argc, const char *argv[])
{
int i;
const char *pszOutputPath = "shortcut.lnk";
const char *pszTarget = NULL;
- const char *pszDescription = "Description";
+ const char *pszDescription = NULL;
const char *pszWorkingDir = NULL;
const char *pszCmdLineArgs = NULL;
const char *pszIcon = NULL;
+ char targetpath[260];
int IconNr = 0;
GUID Guid = CLSID_MyComputer;
int bHelp = 0, bMinimized = 0;
@@ -143,6 +193,7 @@ int main(int argc, const char *argv[])
LNK_HEADER Header;
uint16_t uhTmp;
uint32_t dwTmp;
+ EXP_SPECIAL_FOLDER CsidlBlock, *pCsidlBlock = NULL;
for (i = 1; i < argc; ++i)
{
@@ -226,14 +277,26 @@ int main(int argc, const char *argv[])
ID_LIST_DRIVE IdListDrive;
unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName;
const char *pszName = pszTarget;
+ int index = 1, specialindex = -1;
+ const struct SPECIALFOLDER *special = get_special_folder(pszTarget);
// ID list
// It seems explorer does not accept links without id list. List is relative to
desktop.
- pszName = pszTarget;
+ if (special)
+ {
+ Header.Flags &= ~LINK_RELATIVE_PATH;
+ CsidlBlock.cbSize = sizeof(CsidlBlock);
+ CsidlBlock.dwSignature = EXP_SPECIAL_FOLDER_SIG;
+ CsidlBlock.idSpecialFolder = special->csidl;
+ specialindex = 3; // Skip GUID, drive and fake windows/reactos folder
+ sprintf(targetpath, "x:\\reactos\\%s", pszTarget +
sizeof("shell:") + strlen(special->name));
+ pszName = pszTarget = targetpath;
+ }
- if (pszName[0] && pszName[1] == ':')
+ if (pszName[0] && pszName[0] != ':' && pszName[1] ==
':')
{
+ ++index;
cbListSize += sizeof(IdListDrive);
pszName += 2;
while (*pszName == '\\' || *pszName == '/')
@@ -249,6 +312,12 @@ int main(int argc, const char *argv[])
if (cchName != 1 || pszName[0] != '.')
cbListSize += sizeof(IdListFile) + 2 * (cchName + 1);
+ if (++index == specialindex)
+ {
+ CsidlBlock.cbOffset = cbListSize - sizeof(uint16_t);
+ pCsidlBlock = &CsidlBlock;
+ }
+
pszName += cchName;
while (*pszName == '\\' || *pszName == '/')
++pszName;
@@ -309,7 +378,7 @@ int main(int argc, const char *argv[])
if (Header.Flags & LINK_DESCRIPTION)
{
- // Dscription
+ // Description
uhTmp = strlen(pszDescription);
fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
fputs(pszDescription, pFile);
@@ -348,6 +417,8 @@ int main(int argc, const char *argv[])
}
// Extra stuff
+ if (pCsidlBlock)
+ fwrite(pCsidlBlock, sizeof(*pCsidlBlock), 1, pFile);
dwTmp = 0;
fwrite(&dwTmp, sizeof(dwTmp), 1, pFile);