diff --git a/dll/win32/shell32/folders/CControlPanelFolder.cpp b/dll/win32/shell32/folders/CControlPanelFolder.cpp index 706be10390e..bebb5e11073 100644 --- a/dll/win32/shell32/folders/CControlPanelFolder.cpp +++ b/dll/win32/shell32/folders/CControlPanelFolder.cpp @@ -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; } /************************************************************************ diff --git a/dll/win32/shell32/folders/CDesktopFolder.cpp b/dll/win32/shell32/folders/CDesktopFolder.cpp index 370a614285e..5749c04c755 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.cpp +++ b/dll/win32/shell32/folders/CDesktopFolder.cpp @@ -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 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) diff --git a/dll/win32/shell32/folders/CDrivesFolder.cpp b/dll/win32/shell32/folders/CDrivesFolder.cpp index c4e76121a91..73d90de4a26 100644 --- a/dll/win32/shell32/folders/CDrivesFolder.cpp +++ b/dll/win32/shell32/folders/CDrivesFolder.cpp @@ -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 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 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; } /************************************************************************ diff --git a/dll/win32/shell32/folders/CFSFolder.cpp b/dll/win32/shell32/folders/CFSFolder.cpp index bc59d820902..c72441771d2 100644 --- a/dll/win32/shell32/folders/CFSFolder.cpp +++ b/dll/win32/shell32/folders/CFSFolder.cpp @@ -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; } /************************************************************************ diff --git a/dll/win32/shell32/folders/CRegFolder.cpp b/dll/win32/shell32/folders/CRegFolder.cpp index efaf4711f86..603fa47f309 100644 --- a/dll/win32/shell32/folders/CRegFolder.cpp +++ b/dll/win32/shell32/folders/CRegFolder.cpp @@ -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, diff --git a/dll/win32/shell32/shfldr.h b/dll/win32/shell32/shfldr.h index 2ab941e494c..fb04ea565ea 100644 --- a/dll/win32/shell32/shfldr.h +++ b/dll/win32/shell32/shfldr.h @@ -23,6 +23,7 @@ #ifndef _SHFLDR_H_ #define _SHFLDR_H_ +#include // 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); diff --git a/dll/win32/shell32/shlfolder.cpp b/dll/win32/shell32/shlfolder.cpp index 04dcbcc3232..d425dc9b70b 100644 --- a/dll/win32/shell32/shlfolder.cpp +++ b/dll/win32/shell32/shlfolder.cpp @@ -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; diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c index 43511ca40f1..ad86794634e 100644 --- a/dll/win32/shell32/wine/pidl.c +++ b/dll/win32/shell32/wine/pidl.c @@ -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; diff --git a/dll/win32/shell32/wine/shell32_main.h b/dll/win32/shell32/wine/shell32_main.h index a8a7f9cd72e..c983a487d84 100644 --- a/dll/win32/shell32/wine/shell32_main.h +++ b/dll/win32/shell32/wine/shell32_main.h @@ -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 diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h index 2165a6706dc..531d022ba54 100644 --- a/sdk/include/reactos/shellutils.h +++ b/sdk/include/reactos/shellutils.h @@ -474,6 +474,13 @@ template 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;