From 1a2031b169495c627de76a3b3f0d1c81eb23c448 Mon Sep 17 00:00:00 2001 From: Joachim Henze Date: Sat, 26 Feb 2022 23:55:30 +0100 Subject: [PATCH] [0.4.10][SHELL32][SHLWAPI][COMDLG32][SDK] Unable to select a Zip file for sending with Common Open Dialog CORE-16908 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 | 8 +- dll/win32/comdlg32/filedlgbrowser.c | 4 +- dll/win32/shell32/folders/CFSFolder.cpp | 469 ++++++++++++++++-------- dll/win32/shell32/folders/CFSFolder.h | 36 +- dll/win32/shlwapi/reg.c | 17 + sdk/include/reactos/shlwapi_undoc.h | 1 + 6 files changed, 357 insertions(+), 178 deletions(-) diff --git a/dll/win32/comdlg32/filedlg.c b/dll/win32/comdlg32/filedlg.c index cd856471f80..1dd6b2ff898 100644 --- a/dll/win32/comdlg32/filedlg.c +++ b/dll/win32/comdlg32/filedlg.c @@ -2522,12 +2522,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))) { @@ -4108,7 +4108,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); @@ -4117,7 +4117,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); } /*********************************************************************** diff --git a/dll/win32/comdlg32/filedlgbrowser.c b/dll/win32/comdlg32/filedlgbrowser.c index 5b5323f4d22..83d5f5e9e09 100644 --- a/dll/win32/comdlg32/filedlgbrowser.c +++ b/dll/win32/comdlg32/filedlgbrowser.c @@ -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) diff --git a/dll/win32/shell32/folders/CFSFolder.cpp b/dll/win32/shell32/folders/CFSFolder.cpp index ad205c47e10..799622f4d0b 100644 --- a/dll/win32/shell32/folders/CFSFolder.cpp +++ b/dll/win32/shell32/folders/CFSFolder.cpp @@ -1,53 +1,24 @@ - /* - * file system folder - * - * Copyright 1997 Marcus Meissner - * Copyright 1998, 1999, 2002 Juergen Schmied - * - * 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 WINE_DEFAULT_DEBUG_CHANNEL (shell); -HKEY OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName) +static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID* pclsidFolder); + + +HKEY OpenKeyFromFileType(LPWSTR pExtension, LPCWSTR KeyName) { HKEY hkey; - 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; - } - WCHAR FullName[MAX_PATH]; DWORD dwSize = sizeof(FullName); wsprintf(FullName, L"%s\\%s", pExtension, KeyName); @@ -59,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; } @@ -74,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); @@ -129,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) { @@ -292,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"); @@ -334,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); - - BEGIN_COM_MAP(CFileSysEnum) - COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) - END_COM_MAP() -}; - -CFileSysEnum::CFileSysEnum() -{ -} - -CFileSysEnum::~CFileSysEnum() -{ -} - -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 }; - - TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath), dwFlags); - - if(!lpszPath || !lpszPath[0]) return FALSE; - - wcscpy(szPath, lpszPath); - PathAddBackslashW(szPath); - wcscat(szPath,stars); - - hFile = FindFirstFileW(szPath,&stffile); - if ( hFile != INVALID_HANDLE_VALUE ) +private: + HRESULT _AddFindResult(LPWSTR sParentDir, const WIN32_FIND_DATAW& FindData, DWORD dwFlags) { - BOOL findFinished = FALSE; + // 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; + } + + BOOL bDirectory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + + HRESULT hr; + if (bDirectory) + { + // Skip the current and parent directory nodes + if (!strcmpW(FindData.cFileName, L".") || !strcmpW(FindData.cFileName, L"..")) + return S_OK; + + // Does this directory need special handling? + if ((FindData.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0) + { + WCHAR Tmp[MAX_PATH]; + CLSID clsidFolder; + + PathCombineW(Tmp, sParentDir, FindData.cFileName); + + 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); + } + } + } + } + + 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); + } + } + + if (pidl && !AddToEnumList(pidl)) + { + FAILED_UNEXPECTEDLY(E_FAIL); + return E_FAIL; + } + + return S_OK; + } + +public: + CFileSysEnum() + { + + } + + ~CFileSysEnum() + { + } + + 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() { @@ -489,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) @@ -524,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; @@ -741,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 { @@ -856,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)) - { - HKEY hKeys[16]; - UINT cKeys = 0; - AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys); + BOOL bIsDropTarget = IsEqualIID (riid, IID_IDropTarget); + BOOL bIsShellView = !bIsDropTarget && IsEqualIID (riid, IID_IShellView); - 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 (IsEqualIID (riid, IID_IShellView)) + if (bIsDropTarget || bIsShellView) { - SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; - hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); + DWORD dwDirAttributes = _ILGetFileAttributes(ILFindLastID(pidlRoot), NULL, 0); + + if ((dwDirAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0) + { + CLSID clsidFolder; + hr = SHELL32_GetCLSIDForDirectory(sPathTarget, L"UICLSID", &clsidFolder); + if (SUCCEEDED(hr)) + { + CComPtr 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; + } + } + } + + if (!SUCCEEDED(hr)) + { + // 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}; + hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); + } + else + { + hr = E_INVALIDARG; + } } } TRACE("-- (%p)->(interface=%p)\n", this, ppvOut); diff --git a/dll/win32/shell32/folders/CFSFolder.h b/dll/win32/shell32/folders/CFSFolder.h index 73f5400fd74..01cab234e12 100644 --- a/dll/win32/shell32/folders/CFSFolder.h +++ b/dll/win32/shell32/folders/CFSFolder.h @@ -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_ @@ -84,19 +72,19 @@ class CFSFolder : // IContextMenuCB virtual HRESULT WINAPI CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, 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) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder3, IPersistFolder3) COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) - END_COM_MAP() + END_COM_MAP() }; #endif /* _CFSFOLDER_H_ */ diff --git a/dll/win32/shlwapi/reg.c b/dll/win32/shlwapi/reg.c index a72f4c24e46..5f9c218a545 100644 --- a/dll/win32/shlwapi/reg.c +++ b/dll/win32/shlwapi/reg.c @@ -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; diff --git a/sdk/include/reactos/shlwapi_undoc.h b/sdk/include/reactos/shlwapi_undoc.h index 27000e3bdd6..bbf3e3b8df7 100644 --- a/sdk/include/reactos/shlwapi_undoc.h +++ b/sdk/include/reactos/shlwapi_undoc.h @@ -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);