[0.4.12][SHELL32][SHLWAPI][COMDLG32][SDK] Unable to select a Zip file for sending...
authorJoachim Henze <Joachim.Henze@reactos.org>
Sat, 26 Feb 2022 22:53:39 +0000 (23:53 +0100)
committerJoachim Henze <Joachim.Henze@reactos.org>
Sat, 26 Feb 2022 22:53:39 +0000 (23:53 +0100)
It "regressed" by 0.4.9-dev-632-g da6a46c6ac52cda4191fb09955fa791f13039fb7 when zipfldr.dll got registered.
Ftr: Even without this complex fix it was possible to workaround this bug by 'regsvr32 /u zipfldr.dll'.

by porting back:
0.4.15-dev-279-g 83a9f7169086d25a9d32a2e227bb421e5c417bdf CORE-16908 [SHELL32] Allow creation of an empty CFileSysEnum
0.4.15-dev-254-g 332889b8d7b452df9bd899a5ed04d41dd22876de CORE-16908 [COMDLG32] Differentiate between real and virtual folders
0.4.15-dev-252-g f379a29606aa03c74f521de5b9028eb623ed4055 CORE-16908 [SHELL32][SDK] Properly enumerate virtual shell folders (on files) as fake folders
0.4.15-dev-251-g b1003ae909f5a76d38944852c82c5bdd863ab15d CORE-16908 [SHELL32] Update CFileSysEnum to be maintaineable
0.4.15-dev-250-g ac215455bb6a76d2431d42b8ab5d1b78dcd35709 CORE-16908 [SHLWAPI] Fix SHRegGetCLSIDKeyW
and we also need:
0.4.14-dev-73-g 5d54b65ceb2c0ae0afd9b9ca442559d72cdbc2ad CORE-16271 [SHELL32] Add support for custom View objects defined with UICLSID

dll/win32/comdlg32/filedlg.c
dll/win32/comdlg32/filedlgbrowser.c
dll/win32/shell32/folders/CFSFolder.cpp
dll/win32/shell32/folders/CFSFolder.h
dll/win32/shlwapi/reg.c
sdk/include/reactos/shlwapi_undoc.h

index e3d6c28..c059709 100644 (file)
@@ -2526,12 +2526,12 @@ int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
             PathAddBackslashW(lpwstrTemp);
         }
 
-        dwAttributes = SFGAO_FOLDER;
+        dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSANCESTOR;
         if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
         {
             /* the path component is valid, we have a pidl of the next path component */
             TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
-            if(dwAttributes & SFGAO_FOLDER)
+            if((dwAttributes & (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR)) == (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR))
             {
                 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
                 {
@@ -4112,7 +4112,7 @@ static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
 */
 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
 {
-       ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
+       ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR;
        HRESULT ret;
 
        TRACE("%p, %p\n", psf, pidl);
@@ -4121,7 +4121,7 @@ static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
 
        TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
        /* see documentation shell 4.1*/
-        return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
+        return (uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER)) && (uAttr & SFGAO_FILESYSANCESTOR);
 }
 
 /***********************************************************************
index 5b5323f..83d5f5e 100644 (file)
@@ -774,9 +774,9 @@ static HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand(ICommDl
     {
         HRESULT hRes;
 
-        ULONG  ulAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
+        ULONG  ulAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR;
         IShellFolder_GetAttributesOf(fodInfos->Shell.FOIShellFolder, 1, (LPCITEMIDLIST *)&pidl, &ulAttr);
-       if (ulAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER) )
+       if ((ulAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER)) && (ulAttr & SFGAO_FILESYSANCESTOR))
        {
             hRes = IShellBrowser_BrowseObject(&This->IShellBrowser_iface,pidl,SBSP_RELATIVE);
             if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
index 4ce2a2b..625dc4f 100644 (file)
@@ -1,53 +1,23 @@
-
 /*
- * file system folder
- *
- * Copyright 1997             Marcus Meissner
- * Copyright 1998, 1999, 2002 Juergen Schmied
- * Copyright 2019             Katayama Hirofumi MZ
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     file system folder
+ * COPYRIGHT:   Copyright 1997 Marcus Meissner
+ *              Copyright 1998, 1999, 2002 Juergen Schmied
+ *              Copyright 2019 Katayama Hirofumi MZ
+ *              Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
  */
 
 #include <precomp.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL (shell);
 
-HKEY OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName)
-{
-    HKEY hkey;
+static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID* pclsidFolder);
 
-    if (!_ILIsValue(pidl))
-    {
-        ERR("Invalid pidl!\n");
-        return NULL;
-    }
 
-    FileStructW* pDataW = _ILGetFileStructW(pidl);
-    if (!pDataW)
-    {
-        ERR("Invalid pidl!\n");
-        return NULL;
-    }
-
-    LPWSTR pExtension = PathFindExtensionW(pDataW->wszName);
-    if (!pExtension || *pExtension == NULL)
-    {
-        WARN("No extension for %S!\n", pDataW->wszName);
-        return NULL;
-    }
+HKEY OpenKeyFromFileType(LPWSTR pExtension, LPCWSTR KeyName)
+{
+    HKEY hkey;
 
     WCHAR FullName[MAX_PATH];
     DWORD dwSize = sizeof(FullName);
@@ -60,7 +30,7 @@ HKEY OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName)
     res = RegGetValueW(HKEY_CLASSES_ROOT, pExtension, NULL, RRF_RT_REG_SZ, NULL, FullName, &dwSize);
     if (res)
     {
-        WARN("Failed to get progid for file %S, extension %S (%x), address %x, pidl: %x, error %d\n", pDataW->wszName, pExtension, pExtension, &dwSize, pidl, res);
+        WARN("Failed to get progid for extension %S (%x), error %d\n", pExtension, pExtension, res);
         return NULL;
     }
 
@@ -75,9 +45,33 @@ HKEY OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName)
     return hkey;
 }
 
-HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid)
+LPWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl)
 {
-    HKEY hkeyProgId = OpenKeyFromFileType(pidl, KeyName);
+    if (!_ILIsValue(pidl))
+    {
+        ERR("Invalid pidl!\n");
+        return NULL;
+    }
+
+    FileStructW* pDataW = _ILGetFileStructW(pidl);
+    if (!pDataW)
+    {
+        ERR("Invalid pidl!\n");
+        return NULL;
+    }
+
+    LPWSTR pExtension = PathFindExtensionW(pDataW->wszName);
+    if (!pExtension || *pExtension == UNICODE_NULL)
+    {
+        WARN("No extension for %S!\n", pDataW->wszName);
+        return NULL;
+    }
+    return pExtension;
+}
+
+HRESULT GetCLSIDForFileTypeFromExtension(LPWSTR pExtension, LPCWSTR KeyName, CLSID* pclsid)
+{
+    HKEY hkeyProgId = OpenKeyFromFileType(pExtension, KeyName);
     if (!hkeyProgId)
     {
         WARN("OpenKeyFromFileType failed for key %S\n", KeyName);
@@ -130,6 +124,15 @@ HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pcl
     return S_OK;
 }
 
+HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid)
+{
+    LPWSTR pExtension = ExtensionFromPidl(pidl);
+    if (!pExtension)
+        return S_FALSE;
+
+    return GetCLSIDForFileTypeFromExtension(pExtension, KeyName, pclsid);
+}
+
 static HRESULT
 getDefaultIconLocation(LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT uFlags)
 {
@@ -293,7 +296,8 @@ HRESULT CFSExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, RE
     }
     else
     {
-        HKEY hkey = OpenKeyFromFileType(pidl, L"DefaultIcon");
+        LPWSTR pExtension = ExtensionFromPidl(pidl);
+        HKEY hkey = pExtension ? OpenKeyFromFileType(pExtension, L"DefaultIcon") : NULL;
         if (!hkey)
             WARN("Could not open DefaultIcon key!\n");
 
@@ -335,92 +339,166 @@ including formatting a drive, reconnecting a network share drive, and requesting
 be inserted in a removable drive.
 */
 
-/***********************************************************************
-*   IShellFolder implementation
-*/
 
 class CFileSysEnum :
     public CEnumIDListBase
 {
-    private:
-    public:
-        CFileSysEnum();
-        ~CFileSysEnum();
-        HRESULT WINAPI Initialize(LPWSTR sPathTarget, DWORD dwFlags);
+private:
+    HRESULT _AddFindResult(LPWSTR sParentDir, const WIN32_FIND_DATAW& FindData, DWORD dwFlags)
+    {
+        // Does it need special handling because it is hidden?
+        if (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
+        {
+            // Is it hidden, but are we not asked to include hidden?
+            if (!(dwFlags & SHCONTF_INCLUDEHIDDEN))
+                return S_OK;
+        }
 
-        BEGIN_COM_MAP(CFileSysEnum)
-        COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
-        END_COM_MAP()
-};
+        BOOL bDirectory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 
-CFileSysEnum::CFileSysEnum()
-{
-}
+        HRESULT hr;
+        if (bDirectory)
+        {
+            // Skip the current and parent directory nodes
+            if (!strcmpW(FindData.cFileName, L".") || !strcmpW(FindData.cFileName, L".."))
+                return S_OK;
 
-CFileSysEnum::~CFileSysEnum()
-{
-}
+            // Does this directory need special handling?
+            if ((FindData.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0)
+            {
+                WCHAR Tmp[MAX_PATH];
+                CLSID clsidFolder;
 
-HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR lpszPath, DWORD dwFlags)
-{
-    WIN32_FIND_DATAW stffile;
-    HANDLE hFile;
-    WCHAR  szPath[MAX_PATH];
-    BOOL succeeded = TRUE;
-    static const WCHAR stars[] = { '*','.','*',0 };
-    static const WCHAR dot[] = { '.',0 };
-    static const WCHAR dotdot[] = { '.','.',0 };
+                PathCombineW(Tmp, sParentDir, FindData.cFileName);
 
-    TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath), dwFlags);
+                hr = SHELL32_GetCLSIDForDirectory(Tmp, L"CLSID", &clsidFolder);
+                if (SUCCEEDED(hr))
+                {
+                    ERR("SHOULD DO SOMETHING WITH CLSID?\n");
+                }
+            }
+        }
+        else
+        {
+            CLSID clsidFile;
+            LPWSTR pExtension = PathFindExtensionW(FindData.cFileName);
+            if (pExtension)
+            {
+                // FIXME: Cache this?
+                hr = GetCLSIDForFileTypeFromExtension(pExtension, L"CLSID", &clsidFile);
+                if (hr == S_OK)
+                {
+                    HKEY hkey;
+                    hr = SHRegGetCLSIDKeyW(clsidFile, L"ShellFolder", FALSE, FALSE, &hkey);
+                    if (SUCCEEDED(hr))
+                    {
+                        ::RegCloseKey(hkey);
+
+                        // This should be presented as directory!
+                        bDirectory = TRUE;
+                        TRACE("Treating '%S' as directory!\n", FindData.cFileName);
+                    }
+                }
+            }
+        }
 
-    if(!lpszPath || !lpszPath[0]) return FALSE;
+        LPITEMIDLIST pidl = NULL;
+        if (bDirectory)
+        {
+            if (dwFlags & SHCONTF_FOLDERS)
+            {
+                TRACE("(%p)->  (folder=%s)\n", this, debugstr_w(FindData.cFileName));
+                pidl = _ILCreateFromFindDataW(&FindData);
+            }
+        }
+        else
+        {
+            if (dwFlags & SHCONTF_NONFOLDERS)
+            {
+                TRACE("(%p)->  (file  =%s)\n", this, debugstr_w(FindData.cFileName));
+                pidl = _ILCreateFromFindDataW(&FindData);
+            }
+        }
 
-    wcscpy(szPath, lpszPath);
-    PathAddBackslashW(szPath);
-    wcscat(szPath,stars);
+        if (pidl && !AddToEnumList(pidl))
+        {
+            FAILED_UNEXPECTEDLY(E_FAIL);
+            return E_FAIL;
+        }
 
-    hFile = FindFirstFileW(szPath,&stffile);
-    if ( hFile != INVALID_HANDLE_VALUE )
+        return S_OK;
+    }
+
+public:
+    CFileSysEnum()
+    {
+
+    }
+
+    ~CFileSysEnum()
     {
-        BOOL findFinished = FALSE;
+    }
+
+    HRESULT WINAPI Initialize(LPWSTR sPathTarget, DWORD dwFlags)
+    {
+        TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(sPathTarget), dwFlags);
+
+        if (!sPathTarget || !sPathTarget[0])
+        {
+            WARN("No path for CFileSysEnum, empty result!\n");
+            return S_FALSE;
+        }
+
+        WCHAR szFindPattern[MAX_PATH];
+        HRESULT hr = StringCchCopyW(szFindPattern, _countof(szFindPattern), sPathTarget);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        /* FIXME: UNSAFE CRAP */
+        PathAddBackslashW(szFindPattern);
+
+        hr = StringCchCatW(szFindPattern, _countof(szFindPattern), L"*.*");
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+
+        WIN32_FIND_DATAW FindData;
+        HANDLE hFind = FindFirstFileW(szFindPattern, &FindData);
+        if (hFind == INVALID_HANDLE_VALUE)
+            return HRESULT_FROM_WIN32(GetLastError());
 
         do
         {
-            if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
-             || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
-            {
-                LPITEMIDLIST pidl = NULL;
+            hr = _AddFindResult(sPathTarget, FindData, dwFlags);
 
-                if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
-                 dwFlags & SHCONTF_FOLDERS &&
-                 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
-                {
-                    pidl = _ILCreateFromFindDataW(&stffile);
-                    succeeded = succeeded && AddToEnumList(pidl);
-                }
-                else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-                 && dwFlags & SHCONTF_NONFOLDERS)
-                {
-                    pidl = _ILCreateFromFindDataW(&stffile);
-                    succeeded = succeeded && AddToEnumList(pidl);
-                }
-            }
-            if (succeeded)
+            if (FAILED_UNEXPECTEDLY(hr))
+                break;
+
+        } while(FindNextFileW(hFind, &FindData));
+
+        if (SUCCEEDED(hr))
+        {
+            DWORD dwError = GetLastError();
+            if (dwError != ERROR_NO_MORE_FILES)
             {
-                if (!FindNextFileW(hFile, &stffile))
-                {
-                    if (GetLastError() == ERROR_NO_MORE_FILES)
-                        findFinished = TRUE;
-                    else
-                        succeeded = FALSE;
-                }
+                hr = HRESULT_FROM_WIN32(dwError);
+                FAILED_UNEXPECTEDLY(hr);
             }
-        } while (succeeded && !findFinished);
-        FindClose(hFile);
+        }
+        TRACE("(%p)->(hr=0x%08x)\n", this, hr);
+        FindClose(hFind);
+        return hr;
     }
 
-    return succeeded;
-}
+    BEGIN_COM_MAP(CFileSysEnum)
+        COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+    END_COM_MAP()
+};
+
+
+/***********************************************************************
+ *   IShellFolder implementation
+ */
 
 CFSFolder::CFSFolder()
 {
@@ -490,22 +568,23 @@ LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
     return pidl;
 }
 
-void SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, CLSID* pclsidFolder)
+static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID* pclsidFolder)
 {
     WCHAR wszCLSIDValue[CHARS_IN_GUID];
     WCHAR wszDesktopIni[MAX_PATH];
     StringCchCopyW(wszDesktopIni, MAX_PATH, pwszDir);
     StringCchCatW(wszDesktopIni, MAX_PATH, L"\\desktop.ini");
 
-    if (GetPrivateProfileStringW(L".ShellClassInfo", 
-                                 L"CLSID", 
+    if (GetPrivateProfileStringW(L".ShellClassInfo",
+                                 KeyName,
                                  L"",
-                                 wszCLSIDValue, 
-                                 CHARS_IN_GUID, 
+                                 wszCLSIDValue,
+                                 CHARS_IN_GUID,
                                  wszDesktopIni))
     {
-        CLSIDFromString (wszCLSIDValue, pclsidFolder);
+        return CLSIDFromString(wszCLSIDValue, pclsidFolder);
     }
+    return E_FAIL;
 }
 
 HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
@@ -525,10 +604,60 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW
     dwShellAttributes = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK | SFGAO_CANRENAME | SFGAO_CANDELETE |
                         SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSTEM;
 
-    if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-        dwShellAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STORAGE);
+    BOOL bDirectory = (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+
+    if (!bDirectory)
+    {
+        // https://git.reactos.org/?p=reactos.git;a=blob;f=dll/shellext/zipfldr/res/zipfldr.rgs;hb=032b5aacd233cd7b83ab6282aad638c161fdc400#l9
+        WCHAR szFileName[MAX_PATH];
+        LPWSTR pExtension;
+
+        if (_ILSimpleGetTextW(pidl, szFileName, _countof(szFileName)) && (pExtension = PathFindExtensionW(szFileName)))
+        {
+            CLSID clsidFile;
+            // FIXME: Cache this?
+            HRESULT hr = GetCLSIDForFileTypeFromExtension(pExtension, L"CLSID", &clsidFile);
+            if (hr == S_OK)
+            {
+                HKEY hkey;
+                hr = SHRegGetCLSIDKeyW(clsidFile, L"ShellFolder", FALSE, FALSE, &hkey);
+                if (SUCCEEDED(hr))
+                {
+                    DWORD dwAttributes = 0;
+                    DWORD dwSize = sizeof(dwAttributes);
+                    LSTATUS Status;
+
+                    Status = SHRegGetValueW(hkey, NULL, L"Attributes", RRF_RT_REG_DWORD, NULL, &dwAttributes, &dwSize);
+                    if (Status == STATUS_SUCCESS)
+                    {
+                        TRACE("Augmenting '%S' with dwAttributes=0x%x\n", szFileName, dwAttributes);
+                        dwShellAttributes |= dwAttributes;
+                    }
+                    ::RegCloseKey(hkey);
+
+                    // This should be presented as directory!
+                    bDirectory = TRUE;
+                    TRACE("Treating '%S' as directory!\n", szFileName);
+                }
+            }
+        }
+    }
+
+    // This is a directory
+    if (bDirectory)
+    {
+        dwShellAttributes |= (SFGAO_FOLDER | /*SFGAO_HASSUBFOLDER |*/ SFGAO_STORAGE);
+
+        // Is this a real directory?
+        if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        {
+            dwShellAttributes |= (SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR);
+        }
+    }
     else
+    {
         dwShellAttributes |= SFGAO_STREAM;
+    }
 
     if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
         dwShellAttributes |=  SFGAO_HIDDEN;
@@ -742,7 +871,7 @@ HRESULT WINAPI CFSFolder::BindToObject(
         clsidFolder = CLSID_ShellFSFolder;
 
         if ((pData->uFileAttribs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0)
-            SHELL32_GetCLSIDForDirectory(pfti.szTargetParsingName, &clsidFolder);
+            SHELL32_GetCLSIDForDirectory(pfti.szTargetParsingName, L"CLSID", &clsidFolder);
     }
     else
     {
@@ -857,30 +986,73 @@ HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner,
     {
         *ppvOut = NULL;
 
-        if (IsEqualIID (riid, IID_IDropTarget))
-            hr = CFSDropTarget_CreateInstance(sPathTarget, riid, ppvOut);
-        else if (IsEqualIID (riid, IID_IContextMenu))
+        BOOL bIsDropTarget = IsEqualIID (riid, IID_IDropTarget);
+        BOOL bIsShellView = !bIsDropTarget && IsEqualIID (riid, IID_IShellView);
+
+        if (bIsDropTarget || bIsShellView)
         {
-            HKEY hKeys[16];
-            UINT cKeys = 0;
-            AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
+            DWORD dwDirAttributes = _ILGetFileAttributes(ILFindLastID(pidlRoot), NULL, 0);
 
-            DEFCONTEXTMENU dcm;
-            dcm.hwnd = hwndOwner;
-            dcm.pcmcb = this;
-            dcm.pidlFolder = pidlRoot;
-            dcm.psf = this;
-            dcm.cidl = 0;
-            dcm.apidl = NULL;
-            dcm.cKeys = cKeys;
-            dcm.aKeys = hKeys;
-            dcm.punkAssociationInfo = NULL;
-            hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
+            if ((dwDirAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0)
+            {
+                CLSID clsidFolder;
+                hr = SHELL32_GetCLSIDForDirectory(sPathTarget, L"UICLSID", &clsidFolder);
+                if (SUCCEEDED(hr))
+                {
+                    CComPtr<IPersistFolder> spFolder;
+                    hr = SHCoCreateInstance(NULL, &clsidFolder, NULL, IID_PPV_ARG(IPersistFolder, &spFolder));
+                    if (!FAILED_UNEXPECTEDLY(hr))
+                    {
+                        hr = spFolder->Initialize(pidlRoot);
+
+                        if (!FAILED_UNEXPECTEDLY(hr))
+                        {
+                            hr = spFolder->QueryInterface(riid, ppvOut);
+                        }
+                    }
+                }
+                else
+                {
+                    // No desktop.ini, or no UICLSID present, continue as if nothing happened
+                    hr = E_INVALIDARG;
+                }
+            }
         }
-        else if (IsEqualIID (riid, IID_IShellView))
+
+        if (!SUCCEEDED(hr))
         {
-            SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this, NULL, this};
-            hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
+            // No UICLSID handler found, continue to the default handlers
+            if (bIsDropTarget)
+            {
+                hr = CFSDropTarget_CreateInstance(sPathTarget, riid, ppvOut);
+            }
+            else if (IsEqualIID (riid, IID_IContextMenu))
+            {
+                HKEY hKeys[16];
+                UINT cKeys = 0;
+                AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
+
+                DEFCONTEXTMENU dcm;
+                dcm.hwnd = hwndOwner;
+                dcm.pcmcb = this;
+                dcm.pidlFolder = pidlRoot;
+                dcm.psf = this;
+                dcm.cidl = 0;
+                dcm.apidl = NULL;
+                dcm.cKeys = cKeys;
+                dcm.aKeys = hKeys;
+                dcm.punkAssociationInfo = NULL;
+                hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
+            }
+            else if (bIsShellView)
+            {
+                SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this, NULL, this};
+                hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
+            }
+            else
+            {
+                hr = E_INVALIDARG;
+            }
         }
     }
     TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
index 947ec92..6ffaba9 100644 (file)
@@ -1,23 +1,11 @@
 /*
- * file system folder
- *
- * Copyright 1997             Marcus Meissner
- * Copyright 1998, 1999, 2002 Juergen Schmied
- * Copyright 2009             Andrew Hill
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     file system folder
+ * COPYRIGHT:   Copyright 1997 Marcus Meissner
+ *              Copyright 1998, 1999, 2002 Juergen Schmied
+ *              Copyright 2009 Andrew Hill
+ *              Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
  */
 
 #ifndef _CFSFOLDER_H_
@@ -88,12 +76,12 @@ class CFSFolder :
         // IShellFolderViewCB
         virtual HRESULT WINAPI MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
 
-        DECLARE_REGISTRY_RESOURCEID(IDR_SHELLFSFOLDER)
-        DECLARE_NOT_AGGREGATABLE(CFSFolder)
+    DECLARE_REGISTRY_RESOURCEID(IDR_SHELLFSFOLDER)
+    DECLARE_NOT_AGGREGATABLE(CFSFolder)
 
-        DECLARE_PROTECT_FINAL_CONSTRUCT()
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
 
-        BEGIN_COM_MAP(CFSFolder)
+    BEGIN_COM_MAP(CFSFolder)
         COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
         COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
         COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
@@ -101,7 +89,7 @@ class CFSFolder :
         COM_INTERFACE_ENTRY_IID(IID_IPersistFolder3, IPersistFolder3)
         COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
         COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
-        END_COM_MAP()
+    END_COM_MAP()
 
     protected:
         HRESULT WINAPI GetCustomViewInfo(ULONG unknown, SFVM_CUSTOMVIEWINFO_DATA *data);
index a72f4c2..5f9c218 100644 (file)
@@ -2422,16 +2422,32 @@ HRESULT WINAPI SHRegGetCLSIDKeyA(REFGUID guid, LPCSTR lpszValue, BOOL bUseHKCU,
 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU,
                            BOOL bCreate, PHKEY phKey)
 {
+#ifndef __REACTOS__
   static const WCHAR szClassIdKey[] = { 'S','o','f','t','w','a','r','e','\\',
     'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
     'E','x','p','l','o','r','e','r','\\','C','L','S','I','D','\\' };
+#endif
 #define szClassIdKeyLen (sizeof(szClassIdKey)/sizeof(WCHAR))
   WCHAR szKey[MAX_PATH];
   DWORD dwRet;
   HKEY hkey;
 
   /* Create the key string */
+#ifdef __REACTOS__
+  // https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/reg/reggetclsidkey.htm
+  WCHAR* ptr;
+
+  wcscpy(szKey, bUseHKCU ? L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\" : L"CLSID\\");
+  ptr = szKey + wcslen(szKey);
+  SHStringFromGUIDW(guid, ptr, 39); /* Append guid */
+  if (lpszValue)
+  {
+      ptr = szKey + wcslen(szKey);
+      wcscat(ptr, L"\\");
+      wcscat(++ptr, lpszValue);
+  }
+#else
   memcpy(szKey, szClassIdKey, sizeof(szClassIdKey));
   SHStringFromGUIDW(guid, szKey + szClassIdKeyLen, 39); /* Append guid */
 
@@ -2440,6 +2456,7 @@ HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU,
     szKey[szClassIdKeyLen + 39] = '\\';
     strcpyW(szKey + szClassIdKeyLen + 40, lpszValue); /* Append value name */
   }
+#endif
 
   hkey = bUseHKCU ? HKEY_CURRENT_USER : HKEY_CLASSES_ROOT;
 
index 27000e3..bbf3e3b 100644 (file)
@@ -53,6 +53,7 @@ HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds);
 BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild);
 HRESULT WINAPI SHForwardContextMenuMsg(IUnknown* pUnk, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult, BOOL useIContextMenu2);
 
+HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU, BOOL bCreate, PHKEY phKey);
 
 BOOL WINAPI SHAddDataBlock(LPDBLIST* lppList, const DATABLOCK_HEADER *lpNewItem);
 BOOL WINAPI SHRemoveDataBlock(LPDBLIST* lppList, DWORD dwSignature);