https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7b081be46de966e3fe6c2aa47a5a26deb7541e8a

commit 7b081be46de966e3fe6c2aa47a5a26deb7541e8a
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Sat Sep 14 13:10:49 2024 +0200
Commit:     GitHub <nore...@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);
 

Reply via email to