[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.
This commit is contained in:
Whindmar Saksit 2024-11-17 20:13:05 +01:00 committed by GitHub
parent 997b1797f4
commit 8107ff8636
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 288 additions and 166 deletions

View File

@ -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
*

View File

@ -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));

View File

@ -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);

View File

@ -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);

View File

@ -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
*

View File

@ -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;

View File

@ -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);
pidl = (LPITEMIDLIST)path;
hr = pidl ? S_OK : E_FAIL;
}
else if (!(flags & SHGFI_USEFILEATTRIBUTES))
else
{
hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes);
}
if ((flags & SHGFI_PIDL) || !(flags & SHGFI_USEFILEATTRIBUTES))
{
/* 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);

View File

@ -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;

View File

@ -38,6 +38,7 @@ list(APPEND SOURCE
ShellExecuteEx.cpp
ShellExecuteW.cpp
ShellHook.cpp
ShellInfo.cpp
ShellState.cpp
SHGetAttributesFromDataObject.cpp
SHLimitInputEdit.cpp

View File

@ -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)

View File

@ -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@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);
}

View File

@ -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 },