https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8107ff86368259fd53582…
commit 8107ff86368259fd5358287d8e39c5e7180946e1
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Sun Nov 17 20:13:05 2024 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Sun Nov 17 20:13:05 2024 +0100
[SHELL32][SHELL32_APITEST] Consolidate file type description handling (#7485)
- Fixes the case where an extension exists in HKCR but has no ProgId (half of
CORE-19355)
- Fixes some cases where Wine hardcoded "File and "... file" strings
are used instead of localized strings in SHGetFileInfo.
---
dll/win32/shell32/CQueryAssociations.cpp | 50 ++++++++
dll/win32/shell32/dialogs/filetypes.cpp | 13 --
dll/win32/shell32/folders/CFSFolder.cpp | 35 +++++-
dll/win32/shell32/wine/classes.c | 51 +++++---
dll/win32/shell32/wine/pidl.c | 61 ++-------
dll/win32/shell32/wine/pidl.h | 2 +-
dll/win32/shell32/wine/shell32_main.c | 150 +++++++++++------------
dll/win32/shell32/wine/shell32_main.h | 7 ++
modules/rostests/apitests/shell32/CMakeLists.txt | 1 +
modules/rostests/apitests/shell32/ItemIDList.cpp | 6 +
modules/rostests/apitests/shell32/ShellInfo.cpp | 76 ++++++++++++
modules/rostests/apitests/shell32/testlist.c | 2 +
12 files changed, 288 insertions(+), 166 deletions(-)
diff --git a/dll/win32/shell32/CQueryAssociations.cpp
b/dll/win32/shell32/CQueryAssociations.cpp
index a21e49625f8..14a618b9611 100644
--- a/dll/win32/shell32/CQueryAssociations.cpp
+++ b/dll/win32/shell32/CQueryAssociations.cpp
@@ -22,6 +22,56 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
+EXTERN_C HRESULT SHELL32_AssocGetFSDirectoryDescription(PWSTR Buf, UINT cchBuf)
+{
+ static WCHAR cache[33] = {};
+ if (!*cache)
+ LoadStringW(shell32_hInstance, IDS_DIRECTORY, cache, _countof(cache));
+ return StringCchCopyW(Buf, cchBuf, cache);
+}
+
+static HRESULT GetExtensionDefaultDescription(PCWSTR DotExt, PWSTR Buf, UINT cchBuf)
+{
+ static WCHAR fmt[33] = {};
+ if (!*fmt)
+ LoadStringW(shell32_hInstance, IDS_ANY_FILE, fmt, _countof(fmt));
+ return StringCchPrintfW(Buf, cchBuf, fmt, DotExt);
+}
+
+static HRESULT SHELL32_AssocGetExtensionDescription(PCWSTR DotExt, PWSTR Buf, UINT
cchBuf)
+{
+ HRESULT hr;
+ if (!DotExt[0] || (!DotExt[1] && DotExt[0] == '.'))
+ {
+ if (SUCCEEDED(hr = GetExtensionDefaultDescription(L"", Buf, cchBuf)))
+ StrTrimW(Buf, L" -"); // Remove the empty %s so we are left with
"File"
+ return hr;
+ }
+ HKEY hKey;
+ if (SUCCEEDED(hr = HCR_GetProgIdKeyOfExtension(DotExt, &hKey, TRUE)))
+ {
+ DWORD err = RegLoadMUIStringW(hKey, L"FriendlyTypeName", Buf, cchBuf,
NULL, 0, NULL);
+ if (err && hr == S_OK) // ProgId default value fallback (but not if we
only have a .ext key)
+ {
+ DWORD cb = cchBuf * sizeof(*Buf);
+ err = RegGetValueW(hKey, NULL, NULL, RRF_RT_REG_SZ, NULL, Buf, &cb);
+ }
+ RegCloseKey(hKey);
+ if (!err)
+ return err;
+ }
+ // No information in the registry, default to "UPPERCASEEXT File"
+ WCHAR ext[MAX_PATH + 33];
+ if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, ++DotExt, -1, ext,
_countof(ext)))
+ DotExt = ext;
+ return GetExtensionDefaultDescription(DotExt, Buf, cchBuf);
+}
+
+EXTERN_C HRESULT SHELL32_AssocGetFileDescription(PCWSTR Name, PWSTR Buf, UINT cchBuf)
+{
+ return SHELL32_AssocGetExtensionDescription(PathFindExtensionW(Name), Buf, cchBuf);
+}
+
/**************************************************************************
* IQueryAssociations
*
diff --git a/dll/win32/shell32/dialogs/filetypes.cpp
b/dll/win32/shell32/dialogs/filetypes.cpp
index c10c62573eb..a2206ad9fe9 100644
--- a/dll/win32/shell32/dialogs/filetypes.cpp
+++ b/dll/win32/shell32/dialogs/filetypes.cpp
@@ -89,7 +89,6 @@ typedef struct _FILE_TYPE_GLOBALS
HICON hDefExtIconSmall;
HBITMAP hOpenWithImage;
HANDLE hHeap;
- WCHAR DefExtTypeNameFmt[TYPENAME_CCHMAX];
WCHAR NoneString[42];
INT8 SortCol, SortReverse;
UINT Restricted;
@@ -298,12 +297,6 @@ GetTypeName(PFILE_TYPE_ENTRY Entry, PFILE_TYPE_GLOBALS pG)
{
StringCchCopyW(Entry->FileDescription,
_countof(Entry->FileDescription), fi.szTypeName);
}
- else
- {
- // FIXME: Remove this hack when SHGetFileInfo is able to handle
extensions without a ProgId (.ASM etc)
- StringCchPrintfW(Entry->FileDescription,
_countof(Entry->FileDescription),
- pG->DefExtTypeNameFmt,
&Entry->FileExtension[1]);
- }
}
else
{
@@ -1773,12 +1766,6 @@ FileTypesDlg_Initialize(HWND hwndDlg)
pG->himlSmall = ImageList_Create(pG->IconSize, pG->IconSize, ILC_COLOR32 |
ILC_MASK, 256, 20);
pG->hHeap = GetProcessHeap();
- if (!LoadStringW(shell32_hInstance, IDS_ANY_FILE,
- pG->DefExtTypeNameFmt, _countof(pG->DefExtTypeNameFmt)))
- {
- LPCWSTR fallback = L"%s File"; // Default to English
- StringCchCopyW(pG->DefExtTypeNameFmt, _countof(pG->DefExtTypeNameFmt),
fallback);
- }
pG->NoneString[0] = UNICODE_NULL;
LoadStringW(shell32_hInstance, IDS_NONE, pG->NoneString,
_countof(pG->NoneString));
diff --git a/dll/win32/shell32/folders/CFSFolder.cpp
b/dll/win32/shell32/folders/CFSFolder.cpp
index 8ff94898d81..bb73ec85407 100644
--- a/dll/win32/shell32/folders/CFSFolder.cpp
+++ b/dll/win32/shell32/folders/CFSFolder.cpp
@@ -14,6 +14,13 @@ WINE_DEFAULT_DEBUG_CHANNEL (shell);
static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID*
pclsidFolder);
+static BOOL ItemIsFolder(PCUITEMID_CHILD pidl)
+{
+ const BYTE mask = PT_FS | PT_FS_FOLDER_FLAG | PT_FS_FILE_FLAG;
+ const BYTE type = _ILGetType(pidl);
+ return (type & mask) == (PT_FS | PT_FS_FOLDER_FLAG) || (type == PT_FS &&
ILGetNext(pidl));
+}
+
static LPCWSTR GetItemFileName(PCUITEMID_CHILD pidl, LPWSTR Buf, UINT cchMax)
{
FileStructW* pDataW = _ILGetFileStructW(pidl);
@@ -34,6 +41,23 @@ static BOOL IsRealItem(const ITEMIDLIST &idl)
return fsitem.dwFileSize | fsitem.uFileDate;
}
+static void GetItemDescription(PCUITEMID_CHILD pidl, LPWSTR Buf, UINT cchMax)
+{
+ HRESULT hr = E_FAIL;
+ if (ItemIsFolder(pidl))
+ {
+ hr = SHELL32_AssocGetFSDirectoryDescription(Buf, cchMax);
+ }
+ else
+ {
+ WCHAR temp[MAX_PATH];
+ LPCWSTR name = GetItemFileName(pidl, temp, _countof(temp));
+ hr = SHELL32_AssocGetFileDescription(name ? name : L"", Buf, cchMax);
+ }
+ if (FAILED(hr) && cchMax)
+ Buf[0] = UNICODE_NULL;
+}
+
static HKEY OpenKeyFromFileType(LPCWSTR pExtension, LPCWSTR KeyName)
{
HKEY hkey;
@@ -1640,18 +1664,23 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
{
hr = S_OK;
psd->str.uType = STRRET_WSTR;
- psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
+ if (iColumn != SHFSF_COL_NAME)
+ {
+ psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
+ if (!psd->str.pOleStr)
+ return E_OUTOFMEMORY;
+ }
/* the data from the pidl */
switch (iColumn)
{
case SHFSF_COL_NAME:
- hr = GetDisplayNameOf (pidl, SHGDN_NORMAL | SHGDN_INFOLDER,
&psd->str);
+ hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER,
&psd->str);
break;
case SHFSF_COL_SIZE:
_ILGetFileSize(pidl, psd->str.pOleStr, MAX_PATH);
break;
case SHFSF_COL_TYPE:
- _ILGetFileType(pidl, psd->str.pOleStr, MAX_PATH);
+ GetItemDescription(pidl, psd->str.pOleStr, MAX_PATH);
break;
case SHFSF_COL_MDATE:
_ILGetFileDate(pidl, psd->str.pOleStr, MAX_PATH);
diff --git a/dll/win32/shell32/wine/classes.c b/dll/win32/shell32/wine/classes.c
index 12571e14c58..6138fdac267 100644
--- a/dll/win32/shell32/wine/classes.c
+++ b/dll/win32/shell32/wine/classes.c
@@ -44,7 +44,40 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
-#define MAX_EXTENSION_LENGTH 20
+#define MAX_EXTENSION_LENGTH 20 // FIXME: The limit is 254?
+
+static LONG GetRegString(HKEY hKey, PCWSTR SubKey, PCWSTR Name, PWSTR Buffer, UINT
cchBuf)
+{
+ DWORD cb = sizeof(*Buffer) * cchBuf;
+ return RegGetValueW(hKey, SubKey, Name, RRF_RT_REG_SZ, NULL, Buffer, &cb);
+}
+
+HRESULT HCR_GetProgIdKeyOfExtension(PCWSTR szExtension, PHKEY phKey, BOOL AllowFallback)
+{
+ LONG err;
+ WCHAR ext[max(1 + MAX_EXTENSION_LENGTH + 1, MAX_PATH)];
+ WCHAR progid[MAX_PATH];
+ if (szExtension[0] != '.')
+ {
+ ext[0] = '.';
+ lstrcpynW(ext + 1, szExtension, _countof(ext) - 1);
+ szExtension = ext;
+ }
+ err = GetRegString(HKEY_CLASSES_ROOT, szExtension, NULL, progid, _countof(progid));
+ if (!err && progid[0] != UNICODE_NULL)
+ {
+ err = RegOpenKeyExW(HKEY_CLASSES_ROOT, progid, 0, KEY_READ, phKey);
+ if (!err)
+ return err; /* A real ProgId key, return S_OK */
+ }
+ if (AllowFallback)
+ {
+ err = RegOpenKeyExW(HKEY_CLASSES_ROOT, szExtension, 0, KEY_READ, phKey);
+ if (!err)
+ return S_FALSE;
+ }
+ return HRESULT_FROM_WIN32(err);
+}
BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG len, BOOL
bPrependDot)
{
@@ -67,14 +100,6 @@ BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG
len, BOOL
return FALSE;
}
-#ifdef __REACTOS__
- if (!RegLoadMUIStringW(hkey, L"FriendlyTypeName", szFileType, len,
NULL, 0, NULL))
- {
- RegCloseKey(hkey);
- return TRUE;
- }
-#endif
-
if (RegQueryValueW(hkey, NULL, szFileType, &len))
{
RegCloseKey(hkey);
@@ -109,14 +134,6 @@ BOOL HCR_MapTypeToValueA(LPCSTR szExtension, LPSTR szFileType, LONG
len, BOOL bP
return FALSE;
}
-#ifdef __REACTOS__
- if (!RegLoadMUIStringA(hkey, "FriendlyTypeName", szFileType, len, NULL,
0, NULL))
- {
- RegCloseKey(hkey);
- return TRUE;
- }
-#endif
-
if (RegQueryValueA(hkey, NULL, szFileType, &len))
{
RegCloseKey(hkey);
diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c
index f6058d04ee5..de484982b15 100644
--- a/dll/win32/shell32/wine/pidl.c
+++ b/dll/win32/shell32/wine/pidl.c
@@ -1183,6 +1183,14 @@ static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW
lpFindFile,
return ret;
}
+LPITEMIDLIST SHELL32_CreateSimpleIDListFromPath(LPCWSTR pszPath, DWORD dwAttributes)
+{
+ WIN32_FIND_DATAW data = { dwAttributes };
+ LPITEMIDLIST pidl = NULL;
+ _ILParsePathW(pszPath, &data, TRUE, &pidl, NULL);
+ return pidl;
+}
+
/*************************************************************************
* SHSimpleIDListFromPath [SHELL32.162]
*
@@ -2583,59 +2591,6 @@ BOOL _ILGetExtension(LPCITEMIDLIST pidl, LPWSTR pOut, UINT
uOutSize)
return TRUE;
}
-/*************************************************************************
- * _ILGetFileType
- *
- * Given the ItemIdList, get the file type description
- *
- * PARAMS
- * pidl [I] The ItemIDList (simple)
- * pOut [I] The buffer to save the result
- * uOutsize [I] The size of the buffer
- *
- * RETURNS
- * nothing
- *
- * NOTES
- * This function copies as much as possible into the buffer.
- */
-void _ILGetFileType(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
-{
- WCHAR sType[64], sTemp[64];
-
- if(_ILIsValue(pidl))
- {
- if(uOutSize > 0)
- pOut[0] = 0;
- if (_ILGetExtension(pidl, sType, _countof(sType)))
- {
- if (HCR_MapTypeToValueW(sType, sTemp, _countof(sTemp), TRUE))
- {
- /* retrieve description */
- if (HCR_MapTypeToValueW(sTemp, pOut, uOutSize, FALSE))
- return;
- }
-
- /* display Ext-file as description */
- CharUpperW(sType);
- /* load localized file string */
- sTemp[0] = UNICODE_NULL;
- if (LoadStringW(shell32_hInstance, IDS_ANY_FILE, sTemp, _countof(sTemp)))
- {
- sTemp[_countof(sTemp) - 1] = UNICODE_NULL;
- StringCchPrintfW(pOut, uOutSize, sTemp, sType);
- }
- }
- }
- else
- {
- pOut[0] = UNICODE_NULL;
- LoadStringW(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize);
- /* make sure its null terminated */
- pOut[uOutSize - 1] = UNICODE_NULL;
- }
-}
-
/*************************************************************************
* _ILGetFileAttributes
*
diff --git a/dll/win32/shell32/wine/pidl.h b/dll/win32/shell32/wine/pidl.h
index ef0002941f7..28fff42feb4 100644
--- a/dll/win32/shell32/wine/pidl.h
+++ b/dll/win32/shell32/wine/pidl.h
@@ -246,7 +246,6 @@ DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR pOut, UINT
uOutSize) DEC
BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
DECLSPEC_HIDDEN;
DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
DECLSPEC_HIDDEN;
BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
DECLSPEC_HIDDEN;
-void _ILGetFileType (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
DECLSPEC_HIDDEN;
DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize)
DECLSPEC_HIDDEN;
BOOL _ILGetFileDateTime (LPCITEMIDLIST pidl, FILETIME *ft) DECLSPEC_HIDDEN;
DWORD _ILGetDrive (LPCITEMIDLIST, LPWSTR, UINT) DECLSPEC_HIDDEN;
@@ -291,6 +290,7 @@ LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) DECLSPEC_HIDDEN;
LPITEMIDLIST _ILCreateDesktop (void) DECLSPEC_HIDDEN;
LPITEMIDLIST _ILCreateFromFindDataW(const WIN32_FIND_DATAW *stffile) DECLSPEC_HIDDEN;
HRESULT _ILCreateFromPathW (LPCWSTR szPath, LPITEMIDLIST* ppidl) DECLSPEC_HIDDEN;
+LPITEMIDLIST SHELL32_CreateSimpleIDListFromPath(LPCWSTR pszPath, DWORD dwAttributes);
/* Other helpers */
LPITEMIDLIST _ILCreateMyComputer (void) DECLSPEC_HIDDEN;
diff --git a/dll/win32/shell32/wine/shell32_main.c
b/dll/win32/shell32/wine/shell32_main.c
index e6dc9810c79..04967da66d1 100644
--- a/dll/win32/shell32/wine/shell32_main.c
+++ b/dll/win32/shell32/wine/shell32_main.c
@@ -310,6 +310,28 @@ LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
return argv;
}
+static HRESULT SHELL_GetDetailsOfToBuffer(IShellFolder *psf, PCUITEMID_CHILD pidl,
+ UINT col, LPWSTR Buf, UINT cchBuf)
+{
+ IShellFolder2 *psf2;
+ IShellDetails *psd;
+ SHELLDETAILS details;
+ HRESULT hr = IShellFolder_QueryInterface(psf, &IID_IShellFolder2,
(void**)&psf2);
+ if (SUCCEEDED(hr))
+ {
+ hr = IShellFolder2_GetDetailsOf(psf2, pidl, col, &details);
+ IShellFolder2_Release(psf2);
+ }
+ else if (SUCCEEDED(hr = IShellFolder_QueryInterface(psf, &IID_IShellDetails,
(void**)&psd)))
+ {
+ hr = IShellDetails_GetDetailsOf(psd, pidl, col, &details);
+ IShellDetails_Release(psd);
+ }
+ if (SUCCEEDED(hr))
+ hr = StrRetToStrNW(Buf, cchBuf, &details.str, pidl) ? S_OK : E_FAIL;
+ return hr;
+}
+
static DWORD shgfi_get_exe_type(LPCWSTR szFullPath)
{
BOOL status = FALSE;
@@ -386,17 +408,11 @@ BOOL SHELL_IsShortcut(LPCITEMIDLIST pidlLast)
BOOL ret = FALSE;
if (_ILGetExtension(pidlLast, szTemp, _countof(szTemp)) &&
- HCR_MapTypeToValueW(szTemp, szTemp, _countof(szTemp), TRUE))
+ SUCCEEDED(HCR_GetProgIdKeyOfExtension(szTemp, &keyCls, FALSE)))
{
- if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE,
&keyCls))
- {
- if (ERROR_SUCCESS == RegQueryValueExW(keyCls, L"IsShortcut", NULL,
NULL, NULL, NULL))
- ret = TRUE;
-
- RegCloseKey(keyCls);
- }
+ ret = RegQueryValueExW(keyCls, L"IsShortcut", NULL, NULL, NULL, NULL)
== ERROR_SUCCESS;
+ RegCloseKey(keyCls);
}
-
return ret;
}
@@ -420,7 +436,7 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
DWORD dwAttributes = 0;
IShellFolder * psfParent = NULL;
IExtractIconW * pei = NULL;
- LPITEMIDLIST pidlLast = NULL, pidl = NULL;
+ LPITEMIDLIST pidlLast = NULL, pidl = NULL, pidlFree = NULL;
HRESULT hr = S_OK;
BOOL IconNotYetLoaded=TRUE;
UINT uGilFlags = 0;
@@ -453,6 +469,27 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
{
lstrcpynW(szFullPath, path, MAX_PATH);
}
+
+ if ((flags & SHGFI_TYPENAME) && !PathIsRootW(szFullPath))
+ {
+ HRESULT hr2;
+ if (!(flags & SHGFI_USEFILEATTRIBUTES))
+ {
+ dwFileAttributes = GetFileAttributesW(szFullPath);
+ if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
+ dwFileAttributes = 0;
+ }
+ if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ hr2 = SHELL32_AssocGetFSDirectoryDescription(psfi->szTypeName,
_countof(psfi->szTypeName));
+ else
+ hr2 = SHELL32_AssocGetFileDescription(path, psfi->szTypeName,
_countof(psfi->szTypeName));
+ if (SUCCEEDED(hr2))
+ {
+ flags &= ~SHGFI_TYPENAME;
+ if (!(flags & ~SHGFI_USEFILEATTRIBUTES))
+ return ret; /* Bail out early if this was our only operation */
+ }
+ }
}
else
{
@@ -489,31 +526,26 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD
dwFileAttributes,
if (flags & SHGFI_PIDL)
{
- pidl = ILClone((LPCITEMIDLIST)path);
- }
- else if (!(flags & SHGFI_USEFILEATTRIBUTES))
- {
- hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes);
+ pidl = (LPITEMIDLIST)path;
+ hr = pidl ? S_OK : E_FAIL;
}
-
- if ((flags & SHGFI_PIDL) || !(flags & SHGFI_USEFILEATTRIBUTES))
+ else
{
- /* get the parent shellfolder */
- if (pidl)
+ if (flags & SHGFI_USEFILEATTRIBUTES)
{
- hr = SHBindToParent( pidl, &IID_IShellFolder, (LPVOID*)&psfParent,
- (LPCITEMIDLIST*)&pidlLast );
- if (SUCCEEDED(hr))
- pidlLast = ILClone(pidlLast);
- else
- hr = S_OK;
- ILFree(pidl);
+ pidl = SHELL32_CreateSimpleIDListFromPath(szFullPath, dwFileAttributes);
+ hr = pidl ? S_OK : E_FAIL;
}
else
{
- ERR("pidl is null!\n");
- return FALSE;
+ hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes);
}
+ pidlFree = pidl;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfParent,
(LPCITEMIDLIST*)&pidlLast);
}
/* get the attributes of the child */
@@ -523,11 +555,7 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
{
psfi->dwAttributes = 0xffffffff;
}
- if (psfParent)
- {
- IShellFolder_GetAttributesOf(psfParent, 1, (LPCITEMIDLIST*)&pidlLast,
- &(psfi->dwAttributes));
- }
+ hr = IShellFolder_GetAttributesOf(psfParent, 1, (LPCITEMIDLIST*)&pidlLast,
&psfi->dwAttributes);
}
if (flags & SHGFI_USEFILEATTRIBUTES)
@@ -541,55 +569,20 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD
dwFileAttributes,
/* get the displayname */
if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME))
{
- if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
- {
- lstrcpyW (psfi->szDisplayName, PathFindFileNameW(szFullPath));
- }
- else if (psfParent)
- {
- STRRET str;
- hr = IShellFolder_GetDisplayNameOf( psfParent, pidlLast,
- SHGDN_INFOLDER, &str);
- StrRetToStrNW (psfi->szDisplayName, MAX_PATH, &str, pidlLast);
- }
+ STRRET str;
+ psfi->szDisplayName[0] = UNICODE_NULL;
+ hr = IShellFolder_GetDisplayNameOf(psfParent, pidlLast, SHGDN_INFOLDER,
&str);
+ if (SUCCEEDED(hr))
+ StrRetToStrNW(psfi->szDisplayName, _countof(psfi->szDisplayName),
&str, pidlLast);
}
/* get the type name */
if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME))
{
- if (!(flags & SHGFI_USEFILEATTRIBUTES) || (flags & SHGFI_PIDL))
- {
- _ILGetFileType(pidlLast, psfi->szTypeName,
_countof(psfi->szTypeName));
- }
- else
- {
- if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- strcatW (psfi->szTypeName, L"Folder");
- else
- {
- WCHAR sTemp[64];
-
- lstrcpyW(sTemp,PathFindExtensionW(szFullPath));
- if (sTemp[0] == 0 || (sTemp[0] == '.' && sTemp[1] == 0))
- {
- /* "name" or "name." => "File" */
- lstrcpynW (psfi->szTypeName, L"File", 64);
- }
- else if (!( HCR_MapTypeToValueW(sTemp, sTemp, 64, TRUE) &&
- HCR_MapTypeToValueW(sTemp, psfi->szTypeName, 80, FALSE )))
- {
- if (sTemp[0])
- {
- lstrcpynW (psfi->szTypeName, sTemp, 64);
- strcatW (psfi->szTypeName, L" file");
- }
- else
- {
- lstrcpynW (psfi->szTypeName, L"File", 64);
- }
- }
- }
- }
+ /* FIXME: Use IShellFolder2::GetDetailsEx */
+ UINT col = _ILIsDrive(pidlLast) ? 1 : 2; /* SHFSF_COL_TYPE */
+ psfi->szTypeName[0] = UNICODE_NULL;
+ hr = SHELL_GetDetailsOfToBuffer(psfParent, pidlLast, col, psfi->szTypeName,
_countof(psfi->szTypeName));
}
/* ### icons ###*/
@@ -757,12 +750,11 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD
dwFileAttributes,
if (psfParent)
IShellFolder_Release(psfParent);
+ SHFree(pidlFree);
if (hr != S_OK)
ret = FALSE;
- SHFree(pidlLast);
-
TRACE ("icon=%p index=0x%08x attr=0x%08x name=%s type=%s ret=0x%08lx\n",
psfi->hIcon, psfi->iIcon, psfi->dwAttributes,
debugstr_w(psfi->szDisplayName), debugstr_w(psfi->szTypeName), ret);
diff --git a/dll/win32/shell32/wine/shell32_main.h
b/dll/win32/shell32/wine/shell32_main.h
index 73bebc71d3b..4392a50659a 100644
--- a/dll/win32/shell32/wine/shell32_main.h
+++ b/dll/win32/shell32/wine/shell32_main.h
@@ -46,6 +46,7 @@ BOOL PidlToSicIndex (IShellFolder * sh, LPCITEMIDLIST pidl, BOOL
bBigIcon, UINT
INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
DECLSPEC_HIDDEN;
/* Classes Root */
+HRESULT HCR_GetProgIdKeyOfExtension(PCWSTR szExtension, PHKEY phKey, BOOL
AllowFallback);
BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG len, BOOL
bPrependDot) DECLSPEC_HIDDEN;
BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
DECLSPEC_HIDDEN;
BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR
szDest, DWORD len ) DECLSPEC_HIDDEN;
@@ -67,6 +68,12 @@ BOOL HCR_GetClassNameA(REFIID riid, LPSTR szDest, DWORD len)
DECLSPEC_HIDDEN;
BOOL HCR_GetFolderAttributes(LPCITEMIDLIST pidlFolder, LPDWORD dwAttributes)
DECLSPEC_HIDDEN;
+/* File associations */
+#define SHELL32_AssocGetFolderDescription SHELL32_AssocGetFSDirectoryDescription
+HRESULT SHELL32_AssocGetFSDirectoryDescription(PWSTR Buf, UINT cchBuf);
+HRESULT SHELL32_AssocGetFileDescription(PCWSTR Name, PWSTR Buf, UINT cchBuf);
+
+
DWORD WINAPI ParseFieldA(LPCSTR src, DWORD nField, LPSTR dst, DWORD len)
DECLSPEC_HIDDEN;
DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len)
DECLSPEC_HIDDEN;
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt
b/modules/rostests/apitests/shell32/CMakeLists.txt
index c0a6686eecf..2a90a0e009d 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -38,6 +38,7 @@ list(APPEND SOURCE
ShellExecuteEx.cpp
ShellExecuteW.cpp
ShellHook.cpp
+ ShellInfo.cpp
ShellState.cpp
SHGetAttributesFromDataObject.cpp
SHLimitInputEdit.cpp
diff --git a/modules/rostests/apitests/shell32/ItemIDList.cpp
b/modules/rostests/apitests/shell32/ItemIDList.cpp
index 9665dede641..02c4e694bd6 100644
--- a/modules/rostests/apitests/shell32/ItemIDList.cpp
+++ b/modules/rostests/apitests/shell32/ItemIDList.cpp
@@ -148,6 +148,12 @@ START_TEST(SHSimpleIDListFromPath)
ok_long(item->mkid.abID[0] & 0x70, 0x20); // Something in My Computer
ok_char(item->mkid.abID[1] | 32, 'x' | 32); // x:
}
+
+ LPITEMIDLIST pidl;
+ ok_int((pidl = SHSimpleIDListFromPath(L"c:")) != NULL, TRUE);
+ ILFree(pidl);
+ ok_int((pidl = SHSimpleIDListFromPath(L"c:\\")) != NULL, TRUE);
+ ILFree(pidl);
}
START_TEST(ILCreateFromPath)
diff --git a/modules/rostests/apitests/shell32/ShellInfo.cpp
b/modules/rostests/apitests/shell32/ShellInfo.cpp
new file mode 100644
index 00000000000..13921611667
--- /dev/null
+++ b/modules/rostests/apitests/shell32/ShellInfo.cpp
@@ -0,0 +1,76 @@
+/*
+ * PROJECT: ReactOS API tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Test for SHGetFileInfo
+ * COPYRIGHT: Copyright 2024 Whindmar Saksit <whindsaks(a)proton.me>
+ */
+
+#include "shelltest.h"
+#include <shellutils.h>
+
+#define UNIQUEEXT L"ABC123XYZ"
+#define my_ok_all_flags(val, flags) ok_eq_hex((val) & (flags), (flags))
+
+static DWORD_PTR SHGFI(PCWSTR Path, SHFILEINFOW &Info, UINT Flags, UINT Attributes =
0)
+{
+ return SHGetFileInfoW(Path, Attributes, &Info, sizeof(Info), Flags);
+}
+
+static DWORD_PTR SHGFI(LPCITEMIDLIST Pidl, SHFILEINFOW &Info, UINT Flags, UINT
Attributes = 0)
+{
+ return SHGFI((PCWSTR)Pidl, Info, Flags | SHGFI_PIDL, Attributes);
+}
+
+START_TEST(SHGetFileInfo)
+{
+ CCoInit ComInit;
+ LPITEMIDLIST pidl;
+ SHFILEINFOW info;
+ UINT flags;
+ WCHAR buf[MAX_PATH];
+
+ ok_int(SHGFI((PCWSTR)NULL, info, 0), FALSE);
+ ok_int(SHGFI((PCWSTR)NULL, info, SHGFI_DISPLAYNAME), FALSE);
+ ok_int(SHGFI((PCWSTR)NULL, info, SHGFI_TYPENAME), FALSE);
+ ok_int(SHGFI((PCWSTR)NULL, info, SHGFI_ICONLOCATION), FALSE);
+ ok_int(SHGFI((PCWSTR)NULL, info, SHGFI_SYSICONINDEX), FALSE);
+ ok_int(SHGFI(UNIQUEEXT, info, SHGFI_USEFILEATTRIBUTES), TRUE); // Success when asking
for no info
+ ok_int(SHGetFileInfoW(UNIQUEEXT, 0, NULL, 0, SHGFI_DISPLAYNAME |
SHGFI_USEFILEATTRIBUTES), FALSE); // NULL pointer
+ ok_int(SHGFI(UNIQUEEXT, info, SHGFI_EXETYPE | SHGFI_USEFILEATTRIBUTES), TRUE); //
Invalid combination, returns TRUE!
+
+ GetModuleFileNameW(NULL, buf, _countof(buf));
+ ok_int(LOWORD(SHGFI(buf, info, SHGFI_EXETYPE)), 0x4550); // 'PE'
+
+ flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES | SHGFI_ATTRIBUTES;
+ ZeroMemory(&info, sizeof(info));
+ info.dwAttributes = ~SFGAO_VALIDATE;
+ ok_int(SHGFI(UNIQUEEXT, info, flags | SHGFI_ATTR_SPECIFIED), TRUE);
+ ok_ptr(StrStrIW(info.szTypeName, UNIQUEEXT), NULL); // A file without extension (not
"EXT File")
+ my_ok_all_flags(info.dwAttributes, SFGAO_FILESYSTEM | SFGAO_STREAM);
+
+ ZeroMemory(&info, sizeof(info));
+ info.dwAttributes = ~SFGAO_VALIDATE;
+ ok_int(SHGFI(UNIQUEEXT, info, flags | SHGFI_ATTR_SPECIFIED,
FILE_ATTRIBUTE_DIRECTORY), TRUE);
+ ok_ptr(StrStrIW(info.szTypeName, UNIQUEEXT), NULL); // A directory (not "EXT
File")
+ my_ok_all_flags(info.dwAttributes, SFGAO_FILESYSTEM | SFGAO_FOLDER);
+
+ ZeroMemory(&info, sizeof(info));
+ info.dwAttributes = ~SFGAO_VALIDATE;
+ ok_int(SHGFI(L"." UNIQUEEXT, info, flags | SHGFI_ATTR_SPECIFIED), TRUE);
+ ok_bool_true(StrStrIW(info.szTypeName, UNIQUEEXT) != NULL, ".ext is treated as
extension");
+ my_ok_all_flags(info.dwAttributes, SFGAO_FILESYSTEM | SFGAO_STREAM);
+
+ info.dwAttributes = ~SFGAO_VALIDATE;
+ ok_int(SHGFI(L"c:", info, flags | SHGFI_ATTR_SPECIFIED), TRUE); // ROS
fails this, a parsing bug in CDrivesFolder?
+ my_ok_all_flags(info.dwAttributes, SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR);
+
+ info.dwAttributes = ~SFGAO_VALIDATE;
+ ok_int(SHGFI(L"c:\\", info, flags | SHGFI_ATTR_SPECIFIED), TRUE);
+ my_ok_all_flags(info.dwAttributes, SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR);
+
+ pidl = SHSimpleIDListFromPath(L"c:\\foo");
+ info.iIcon = -1;
+ ok_int(SHGFI(pidl, info, SHGFI_SYSICONINDEX) > TRUE, TRUE);
+ ok_int(info.iIcon != -1, TRUE);
+ ILFree(pidl);
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c
b/modules/rostests/apitests/shell32/testlist.c
index 4b16a6dd4d5..ff06c5a5dc6 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -41,6 +41,7 @@ extern void func_ShellExecuteW(void);
extern void func_ShellHook(void);
extern void func_ShellState(void);
extern void func_SHGetAttributesFromDataObject(void);
+extern void func_SHGetFileInfo(void);
extern void func_SHLimitInputEdit(void);
extern void func_SHParseDisplayName(void);
extern void func_SHSimpleIDListFromPath(void);
@@ -86,6 +87,7 @@ const struct test winetest_testlist[] =
{ "ShellHook", func_ShellHook },
{ "ShellState", func_ShellState },
{ "SHGetAttributesFromDataObject", func_SHGetAttributesFromDataObject },
+ { "SHGetFileInfo", func_SHGetFileInfo },
{ "SHLimitInputEdit", func_SHLimitInputEdit },
{ "SHParseDisplayName", func_SHParseDisplayName },
{ "SHSimpleIDListFromPath", func_SHSimpleIDListFromPath },