[SHELL32] Implement IShellFolder2::GetDetailsEx (#7880)

This commit is contained in:
Whindmar Saksit 2025-04-21 23:21:44 +02:00 committed by GitHub
parent 4cbd5d1b44
commit d3456f5060
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 395 additions and 44 deletions

View file

@ -84,6 +84,14 @@ HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags, IEnumIDList* pRegEnu
return S_OK;
}
static const CLSID* IsRegItem(LPCITEMIDLIST pidl)
{
BYTE type = _ILGetType(pidl);
if (type == PT_CONTROLS_OLDREGITEM || type == PT_CONTROLS_NEWREGITEM)
return (CLSID*)((BYTE*)pidl + (pidl->mkid.cb - sizeof(CLSID)));
return NULL;
}
static LPITEMIDLIST _ILCreateCPanelApplet(LPCWSTR pszName, LPCWSTR pszDisplayName, LPCWSTR pszComment, int iIconIdx)
{
PIDLCPanelStruct *pCP;
@ -565,8 +573,9 @@ HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *p
HRESULT WINAPI CControlPanelFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
if (IsRegItem(pidl))
return m_regFolder->GetDetailsEx(pidl, pscid, pv);
return SH32_GetDetailsOfPKeyAsVariant(this, pidl, pscid, pv, FALSE);
}
HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
@ -605,8 +614,12 @@ HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iCol
HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
switch (column)
{
case CONTROLPANEL_COL_NAME: return MakeSCID(*pscid, FMTID_Storage, PID_STG_NAME);
case CONTROLPANEL_COL_COMMENT: return MakeSCID(*pscid, FMTID_SummaryInformation, PIDSI_COMMENTS);
}
return E_INVALIDARG;
}
/************************************************************************

View file

@ -955,14 +955,14 @@ HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *
return hr;
}
HRESULT WINAPI CDesktopFolder::GetDetailsEx(
PCUITEMID_CHILD pidl,
const SHCOLUMNID *pscid,
VARIANT *pv)
HRESULT WINAPI CDesktopFolder::GetDetailsEx(PCUITEMID_CHILD pidl,
const SHCOLUMNID *pscid, VARIANT *pv)
{
FIXME ("(%p)\n", this);
return E_NOTIMPL;
HRESULT hr;
CComPtr<IShellFolder2> psf;
if (FAILED_UNEXPECTEDLY(hr = _GetSFFromPidl(pidl, &psf)))
return hr;
return psf->GetDetailsEx(pidl, pscid, pv);
}
/*************************************************************************
@ -1002,8 +1002,14 @@ HRESULT WINAPI CDesktopFolder::GetDetailsOf(
HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
{
FIXME ("(%p)\n", this);
return E_NOTIMPL;
// Note: All these folders use the same SHFSF_COL mapping (m_regFolder only handles a subset).
if (m_DesktopFSFolder)
return m_DesktopFSFolder->MapColumnToSCID(column, pscid);
if (m_SharedDesktopFSFolder)
return m_SharedDesktopFSFolder->MapColumnToSCID(column, pscid);
if (m_regFolder)
return m_regFolder->MapColumnToSCID(column, pscid);
return E_FAIL;
}
HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)

View file

@ -26,6 +26,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
extern BOOL IsDriveFloppyA(LPCSTR pszDriveRoot);
extern BOOL IsDriveFloppyW(LPCWSTR pszDriveRoot);
/*
CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
the registry. The CRegFolder is aggregated by the CDrivesFolder.
@ -105,6 +108,13 @@ template<class T> static T* GetDrivePath(PCUITEMID_CHILD pidl, T *Path)
return Path;
}
static inline UINT _ILGetRemovableTypeId(LPCITEMIDLIST pidl)
{
WCHAR buf[8];
if (GetDrivePath(pidl, buf) && IsDriveFloppyW(buf))
return SHDID_COMPUTER_DRIVE35; // TODO: 3.5-inch vs 5.25-inch
return SHDID_COMPUTER_REMOVABLE;
}
BOOL _ILGetDriveType(LPCITEMIDLIST pidl)
{
@ -477,8 +487,6 @@ static HRESULT GetDriveLabel(PCWSTR DrivePath, LPWSTR szLabel, UINT cchMax)
return hr == S_OK ? S_OK : GetRawDriveLabel(DrivePath, szLabel, cchMax);
}
BOOL IsDriveFloppyA(LPCSTR pszDriveRoot);
HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
{
CComPtr<IDefaultExtractIconInit> initIcon;
@ -1149,10 +1157,33 @@ HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *
return S_OK;
}
HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
const CLSID *pCLSID = IsRegItem(pidl);
if (pscid->fmtid == FMTID_ShellDetails)
{
switch (pscid->pid)
{
case PID_DESCRIPTIONID:
{
if (pCLSID)
return SHELL_CreateSHDESCRIPTIONID(pv, SHDID_ROOT_REGITEM, pCLSID);
UINT id = SHDID_COMPUTER_OTHER;
switch (_ILGetDriveType(pidl))
{
case DRIVE_REMOVABLE: id = _ILGetRemovableTypeId(pidl); break;
case DRIVE_FIXED: id = SHDID_COMPUTER_FIXED; break;
case DRIVE_REMOTE: id = SHDID_COMPUTER_NETDRIVE; break;
case DRIVE_CDROM: id = SHDID_COMPUTER_CDROM; break;
case DRIVE_RAMDISK: id = SHDID_COMPUTER_RAMDISK; break;
}
return SHELL_CreateSHDESCRIPTIONID(pv, id, &CLSID_NULL);
}
}
}
if (pCLSID)
return m_regFolder->GetDetailsEx(pidl, pscid, pv);
return SH32_GetDetailsOfPKeyAsVariant(this, pidl, pscid, pv, FALSE);
}
HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
@ -1175,13 +1206,14 @@ HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, S
switch (MyComputerSFHeader[iColumn].colnameid)
{
case IDS_SHV_COLUMN_NAME:
return m_regFolder->GetDetailsOf(pidl, SHFSF_COL_NAME, psd);
case IDS_SHV_COLUMN_TYPE:
return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
return m_regFolder->GetDetailsOf(pidl, SHFSF_COL_TYPE, psd);
case IDS_SHV_COLUMN_DISK_CAPACITY:
case IDS_SHV_COLUMN_DISK_AVAILABLE:
return SHSetStrRet(&psd->str, ""); /* blank col */
return SHSetStrRetEmpty(&psd->str);
case IDS_SHV_COLUMN_COMMENTS:
return m_regFolder->GetDetailsOf(pidl, 2, psd); /* 2 = comments */
return m_regFolder->GetDetailsOf(pidl, SHFSF_COL_COMMENT, psd);
DEFAULT_UNREACHABLE;
}
}
@ -1228,10 +1260,15 @@ HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, S
return hr;
}
HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
{
FIXME("(%p)\n", this);
return E_NOTIMPL;
switch (column < _countof(MyComputerSFHeader) ? MyComputerSFHeader[column].colnameid : ~0UL)
{
case IDS_SHV_COLUMN_NAME: return MakeSCID(*pscid, FMTID_Storage, PID_STG_NAME);
case IDS_SHV_COLUMN_TYPE: return MakeSCID(*pscid, FMTID_Storage, PID_STG_STORAGETYPE);
case IDS_SHV_COLUMN_COMMENTS: return MakeSCID(*pscid, FMTID_SummaryInformation, PIDSI_COMMENTS);
}
return E_INVALIDARG;
}
/************************************************************************

View file

@ -88,9 +88,9 @@ static HKEY OpenKeyFromFileType(LPCWSTR pExtension, LPCWSTR KeyName)
return hkey;
}
static LPCWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl, LPWSTR Buf, UINT cchMax)
static LPCWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl, LPWSTR Buf, UINT cchMax, BOOL AllowFolder = FALSE)
{
if (!_ILIsValue(pidl))
if (!AllowFolder && !_ILIsValue(pidl))
{
ERR("Invalid pidl!\n");
return NULL;
@ -171,6 +171,21 @@ HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pcl
return GetCLSIDForFileTypeFromExtension(pExtension, KeyName, pclsid);
}
HRESULT GetItemCLSID(PCUIDLIST_RELATIVE pidl, CLSID *pclsid)
{
WCHAR buf[256];
LPCWSTR pExt = ExtensionFromPidl(pidl, buf, _countof(buf), TRUE);
if (!pExt)
return E_FAIL;
HRESULT hr = E_FAIL;
if (!ItemIsFolder(pidl))
hr = GetCLSIDForFileTypeFromExtension(pExt, L"CLSID", pclsid);
// TODO: Should we handle folders with desktop.ini here?
if (hr != S_OK && pExt[0] == '.' && pExt[1] == '{')
hr = CLSIDFromString(pExt + 1, pclsid);
return hr;
}
static HRESULT
getDefaultIconLocation(LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT uFlags)
{
@ -1643,12 +1658,56 @@ HRESULT WINAPI CFSFolder::GetDefaultColumnState(UINT iColumn,
return GetDefaultFSColumnState(iColumn, *pcsFlags);
}
HRESULT WINAPI CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl,
const SHCOLUMNID * pscid, VARIANT * pv)
HRESULT WINAPI CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
FIXME ("(%p)\n", this);
return E_NOTIMPL;
if (!_ILGetFSType(pidl))
return E_INVALIDARG;
HRESULT hr;
if (pscid->fmtid == FMTID_ShellDetails)
{
switch (pscid->pid)
{
case PID_DESCRIPTIONID:
{
if (FAILED(hr = SHELL_CreateVariantBuffer(pv, sizeof(SHDESCRIPTIONID))))
return hr;
SHDESCRIPTIONID *pDID = (SHDESCRIPTIONID*)V_ARRAY(pv)->pvData;
if (ItemIsFolder(pidl))
pDID->dwDescriptionId = SHDID_FS_DIRECTORY;
else if (_ILGetFSType(pidl) & PT_FS_FILE_FLAG)
pDID->dwDescriptionId = SHDID_FS_FILE;
else
pDID->dwDescriptionId = SHDID_FS_OTHER;
if (FAILED(GetItemCLSID(pidl, &pDID->clsid)))
pDID->clsid = CLSID_NULL;
return S_OK;
}
}
}
// Handle non-string fields here when possible instead of deferring to GetDetailsOf
const FileStruct &fsitem = ((PIDLDATA*)pidl->mkid.abID)->u.file;
if (pscid->fmtid == FMTID_Storage)
{
switch (pscid->pid)
{
case PID_STG_NAME: // Handled directly here for faster performance
return SHELL_GetDetailsOfAsStringVariant(this, pidl, SHFSF_COL_NAME, pv);
case PID_STG_SIZE:
V_VT(pv) = VT_UI4;
V_UI4(pv) = _ILGetFileSize(pidl, NULL, 0);
return S_OK;
case PID_STG_ATTRIBUTES:
V_VT(pv) = VT_UI4;
V_UI4(pv) = fsitem.uFileAttribs;
return S_OK;
case PID_STG_WRITETIME:
V_VT(pv) = VT_DATE;
if (DosDateTimeToVariantTime(fsitem.uFileDate, fsitem.uFileTime, &V_DATE(pv)))
return S_OK;
break;
}
}
return SH32_GetDetailsOfPKeyAsVariant(this, pidl, pscid, pv, TRUE);
}
HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
@ -1714,11 +1773,18 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
return hr;
}
HRESULT WINAPI CFSFolder::MapColumnToSCID (UINT column,
SHCOLUMNID * pscid)
HRESULT WINAPI CFSFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
{
FIXME ("(%p)\n", this);
return E_NOTIMPL;
switch (column)
{
case SHFSF_COL_NAME: return MakeSCID(*pscid, FMTID_Storage, PID_STG_NAME);
case SHFSF_COL_SIZE: return MakeSCID(*pscid, FMTID_Storage, PID_STG_SIZE);
case SHFSF_COL_TYPE: return MakeSCID(*pscid, FMTID_Storage, PID_STG_STORAGETYPE);
case SHFSF_COL_MDATE: return MakeSCID(*pscid, FMTID_Storage, PID_STG_WRITETIME);
case SHFSF_COL_FATTS: return MakeSCID(*pscid, FMTID_Storage, PID_STG_ATTRIBUTES);
case SHFSF_COL_COMMENT: return MakeSCID(*pscid, FMTID_SummaryInformation, PIDSI_COMMENTS);
}
return E_INVALIDARG;
}
/************************************************************************

View file

@ -818,7 +818,18 @@ HRESULT WINAPI CRegFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
HRESULT WINAPI CRegFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
return E_NOTIMPL;
const CLSID *pCLSID = IsRegItem(pidl);
if (!pCLSID)
return E_INVALIDARG;
if (pscid->fmtid == FMTID_ShellDetails)
{
switch (pscid->pid)
{
case PID_DESCRIPTIONID:
return SHELL_CreateSHDESCRIPTIONID(pv, SHDID_ROOT_REGITEM, pCLSID);
}
}
return SH32_GetDetailsOfPKeyAsVariant(this, pidl, pscid, pv, TRUE);
}
HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
@ -849,7 +860,7 @@ HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHEL
case COL_INFOTIP:
HKEY hKey;
if (!HCR_RegOpenClassIDKey(*clsid, &hKey))
return SHSetStrRet(&psd->str, "");
return SHSetStrRetEmpty(&psd->str);
psd->str.cStr[0] = 0x00;
psd->str.uType = STRRET_CSTR;
@ -857,17 +868,23 @@ HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHEL
RegCloseKey(hKey);
return S_OK;
default:
/* Return an empty string when we area asked for a column we don't support.
Only the regfolder is supposed to do this as it supports less columns compared to other folder
/* Return an empty string when we are asked for a column we don't support.
Only the regfolder is supposed to do this as it supports fewer columns compared to other folders
and its contents are supposed to be presented alongside items that support more columns. */
return SHSetStrRet(&psd->str, "");
return SHSetStrRetEmpty(&psd->str);
}
return E_FAIL;
}
HRESULT WINAPI CRegFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
{
return E_NOTIMPL;
switch (column)
{
case COL_NAME: return MakeSCID(*pscid, FMTID_Storage, PID_STG_NAME);
case COL_TYPE: return MakeSCID(*pscid, FMTID_Storage, PID_STG_STORAGETYPE);
case COL_INFOTIP: return MakeSCID(*pscid, FMTID_SummaryInformation, PIDSI_COMMENTS);
}
return E_INVALIDARG;
}
static HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj,

View file

@ -23,6 +23,7 @@
#ifndef _SHFLDR_H_
#define _SHFLDR_H_
#include <ntquery.h> // For PID_STG_*
#define CHARS_IN_GUID 39
@ -94,6 +95,23 @@ SHELL_GetDefaultFolderEnumSHCONTF();
BOOL
SHELL_IncludeItemInFolderEnum(IShellFolder *pSF, PCUITEMID_CHILD pidl, SFGAOF Query, SHCONTF Flags);
static inline HRESULT
MakeSCID(SHCOLUMNID &scid, REFCLSID fmtid, UINT pid)
{
scid.fmtid = fmtid;
scid.pid = pid;
return S_OK;
}
HRESULT
SHELL_MapSCIDToColumn(IShellFolder2 *pSF, const SHCOLUMNID *pscid);
HRESULT
SHELL_GetDetailsOfAsStringVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar);
HRESULT
SHELL_GetDetailsOfColumnAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARTYPE vt, VARIANT *pVar);
HRESULT
SH32_GetDetailsOfPKeyAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pVar, BOOL UseFsColMap);
HRESULT
SHELL_CreateAbsolutePidl(IShellFolder *pSF, PCUIDLIST_RELATIVE pidlChild, PIDLIST_ABSOLUTE *ppPidl);

View file

@ -54,6 +54,91 @@ BOOL SHELL_IncludeItemInFolderEnum(IShellFolder *pSF, PCUITEMID_CHILD pidl, SFGA
return TRUE;
}
static HRESULT
MapSCIDToShell32FsColumn(const SHCOLUMNID *pscid, VARTYPE &vt)
{
if (pscid->fmtid == FMTID_Storage)
{
switch (pscid->pid)
{
case PID_STG_NAME: vt = VT_BSTR; return SHFSF_COL_NAME;
case PID_STG_SIZE: vt = VT_UI8; return SHFSF_COL_SIZE;
case PID_STG_STORAGETYPE: vt = VT_BSTR; return SHFSF_COL_TYPE;
case PID_STG_ATTRIBUTES: vt = VT_BSTR; return SHFSF_COL_FATTS;
case PID_STG_WRITETIME: vt = VT_DATE; return SHFSF_COL_MDATE;
}
}
if (pscid->fmtid == FMTID_SummaryInformation && pscid->pid == PIDSI_COMMENTS)
{
vt = VT_BSTR;
return SHFSF_COL_COMMENT;
}
return E_INVALIDARG;
}
HRESULT
SHELL_MapSCIDToColumn(IShellFolder2 *pSF, const SHCOLUMNID *pscid)
{
for (UINT i = 0; i <= SHCIDS_COLUMNMASK; ++i)
{
SHCOLUMNID scid;
HRESULT hr = pSF->MapColumnToSCID(i, &scid);
if (FAILED(hr))
break;
if (IsEqualPropertyKey(scid, *pscid))
return i;
}
return E_FAIL;
}
HRESULT
SHELL_GetDetailsOfAsStringVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar)
{
V_VT(pVar) = VT_EMPTY;
SHELLDETAILS sd;
sd.str.uType = STRRET_CSTR;
HRESULT hr = pSF->GetDetailsOf(pidl, Column, &sd);
if (FAILED(hr))
return hr;
if (FAILED(hr = StrRetToBSTR(&sd.str, pidl, &V_BSTR(pVar))))
return hr;
V_VT(pVar) = VT_BSTR;
return hr;
}
HRESULT
SHELL_GetDetailsOfColumnAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARTYPE vt, VARIANT *pVar)
{
HRESULT hr = SHELL_GetDetailsOfAsStringVariant(pSF, pidl, Column, pVar);
if (FAILED(hr))
return hr;
if (vt == VT_EMPTY)
{
SHCOLSTATEF state;
if (FAILED(pSF->GetDefaultColumnState(Column, &state)))
state = SHCOLSTATE_TYPE_STR;
if ((state & SHCOLSTATE_TYPEMASK) == SHCOLSTATE_TYPE_INT)
vt = VT_I8;
else if ((state & SHCOLSTATE_TYPEMASK) == SHCOLSTATE_TYPE_DATE)
vt = VT_DATE;
else
vt = VT_BSTR;
}
if (vt != VT_BSTR)
VariantChangeType(pVar, pVar, 0, vt);
return hr;
}
HRESULT
SH32_GetDetailsOfPKeyAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pVar, BOOL UseFsColMap)
{
// CFSFolder and CRegFolder uses the SHFSF_COL columns and can use the faster and better version,
// everyone else must ask the folder to map the SCID to a column.
VARTYPE vt = VT_EMPTY;
HRESULT hr = UseFsColMap ? MapSCIDToShell32FsColumn(pscid, vt) : SHELL_MapSCIDToColumn(pSF, pscid);
return SUCCEEDED(hr) ? SHELL_GetDetailsOfColumnAsVariant(pSF, pidl, hr, vt, pVar) : hr;
}
HRESULT SHELL_CreateAbsolutePidl(IShellFolder *pSF, PCUIDLIST_RELATIVE pidlChild, PIDLIST_ABSOLUTE *ppPidl)
{
PIDLIST_ABSOLUTE pidlFolder;

View file

@ -1254,6 +1254,33 @@ LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath)
return SHSimpleIDListFromPathA (lpszPath);
}
static HRESULT GetShellFolder2ItemDetailsExToBuffer(IShellFolder2 *psf2, LPCITEMIDLIST pidl,
const SHCOLUMNID *pscid, void*buf, UINT cb)
{
VARIANT var;
V_VT(&var) = VT_EMPTY;
HRESULT hr = IShellFolder2_GetDetailsEx(psf2, pidl, pscid, &var);
if (SUCCEEDED(hr))
{
hr = SHELL_VariantToBuffer(&var, buf, cb);
VariantClear(&var);
}
return hr;
}
static HRESULT GetShellFolder1ItemDetailsExToBuffer(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
const SHCOLUMNID *pscid, void*buf, UINT cb)
{
IShellFolder2 *psf2;
HRESULT hr = IShellFolder_QueryInterface(psf, &IID_IShellFolder2, (void**)&psf2);
if (SUCCEEDED(hr))
{
hr = GetShellFolder2ItemDetailsExToBuffer(psf2, pidl, pscid, buf, cb);
IShellFolder2_Release(psf2);
}
return hr;
}
/*************************************************************************
* SHGetDataFromIDListA [SHELL32.247]
*
@ -1303,8 +1330,10 @@ HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
pfd->cAlternateFileName[0] = '\0';
return S_OK;
case SHGDFIL_NETRESOURCE:
case SHGDFIL_DESCRIPTIONID:
return SHGetDataFromIDListW(psf, pidl, nFormat, dest, len);
case SHGDFIL_NETRESOURCE:
FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
break;
@ -1334,7 +1363,7 @@ HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
switch (nFormat)
{
case SHGDFIL_FINDDATA:
case SHGDFIL_FINDDATA: /* FIXME: Ask the folder for PID_FINDDATA */
pfd = dest;
if (_ILIsDrive(pidl))
@ -1362,8 +1391,14 @@ HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
pfd->cAlternateFileName[13] = 0;
return S_OK;
case SHGDFIL_NETRESOURCE:
case SHGDFIL_DESCRIPTIONID:
{
/* TODO: Use PKEY_DescriptionID when the propsys headers are ready */
SHCOLUMNID scid = { FMTID_ShellDetails, PID_DESCRIPTIONID };
return GetShellFolder1ItemDetailsExToBuffer(psf, pidl, &scid, dest, len);
}
case SHGDFIL_NETRESOURCE:
FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
break;

View file

@ -216,6 +216,73 @@ LPWSTR SH_FormatFileSizeWithBytes(PULARGE_INTEGER lpQwSize, LPWSTR pszBuf, UINT
HRESULT WINAPI DoRegisterServer(void);
HRESULT WINAPI DoUnregisterServer(void);
/* Property system */
static inline HRESULT
SHELL_CreateVariantBufferEx(VARIANT *pVar, UINT cb, VARTYPE vt)
{
SAFEARRAY *pSA = SafeArrayCreateVector(vt, 0, cb);
if (pSA)
{
V_VT(pVar) = VT_ARRAY | vt;
V_ARRAY(pVar) = pSA;
return S_OK;
}
return E_OUTOFMEMORY;
}
static inline HRESULT
SHELL_CreateVariantBuffer(VARIANT *pVar, UINT cb)
{
return SHELL_CreateVariantBufferEx(pVar, cb, VT_UI1);
}
static inline HRESULT
SHELL_InitVariantFromBuffer(VARIANT *pVar, const void *pData, UINT cb)
{
HRESULT hr = SHELL_CreateVariantBuffer(pVar, cb);
if (SUCCEEDED(hr))
CopyMemory(V_ARRAY(pVar)->pvData, pData, cb);
return hr;
}
static inline void*
SHELL_GetSafeArrayDataPtr(const SAFEARRAY *pSA, SIZE_T *pcb)
{
if (pSA->cDims != 1)
return NULL;
LONG lob, upb;
SafeArrayGetLBound((SAFEARRAY*)pSA, 1, &lob);
SafeArrayGetUBound((SAFEARRAY*)pSA, 1, &upb);
*pcb = (SIZE_T)(upb - lob) + 1;
return pSA->pvData;
}
static inline HRESULT
SHELL_VariantToBuffer(VARIANT *pVar, void *pData, SIZE_T cb)
{
if (V_VT(pVar) != (VT_ARRAY | VT_UI1))
return E_INVALIDARG;
SIZE_T cbArr;
void *pArrData = SHELL_GetSafeArrayDataPtr(V_ARRAY(pVar), &cbArr);
if (!pArrData || cbArr < cb)
return E_FAIL;
CopyMemory(pData, pArrData, cb);
return (cbArr > cb) ? S_FALSE : S_OK;
}
static inline HRESULT
SHELL_CreateSHDESCRIPTIONID(VARIANT *pVar, DWORD Id, const CLSID *pCLSID)
{
HRESULT hr = SHELL_CreateVariantBuffer(pVar, sizeof(SHDESCRIPTIONID));
if (SUCCEEDED(hr))
{
SHDESCRIPTIONID *pDID = (SHDESCRIPTIONID*)V_ARRAY(pVar)->pvData;
pDID->dwDescriptionId = Id;
pDID->clsid = *pCLSID;
}
return hr;
}
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -474,6 +474,13 @@ template<class B, class R> static HRESULT SHILCombine(B base, PCUIDLIST_RELATIVE
static inline bool StrIsNullOrEmpty(LPCSTR str) { return !str || !*str; }
static inline bool StrIsNullOrEmpty(LPCWSTR str) { return !str || !*str; }
HRESULT inline SHSetStrRetEmpty(LPSTRRET pStrRet)
{
pStrRet->uType = STRRET_CSTR;
pStrRet->cStr[0] = '\0';
return S_OK;
}
HRESULT inline SHSetStrRet(LPSTRRET pStrRet, LPCSTR pstrValue)
{
pStrRet->uType = STRRET_CSTR;