[CABVIEW][ZIPFLDR] Implement ParseDisplayName and GetDetailsEx (#9197)

This commit is contained in:
Whindmar Saksit
2026-07-01 12:29:53 +02:00
committed by GitHub
parent c891aefdcf
commit ff2ad34155
6 changed files with 269 additions and 45 deletions
+3 -6
View File
@@ -49,7 +49,8 @@ public:
}
int FindNamedItem(PCUITEMID_CHILD pidl) const;
HRESULT Fill(LPCWSTR path, HWND hwnd = NULL, SHCONTF contf = 0);
static HRESULT Enumerate(PCIDLIST_ABSOLUTE pidl, HWND hwnd, EXTRACTCALLBACK Callback, LPVOID cookie);
HRESULT Fill(PCIDLIST_ABSOLUTE pidl, HWND hwnd = NULL, SHCONTF contf = 0);
HRESULT Append(LPCITEMIDLIST pidl)
@@ -159,11 +160,7 @@ public:
IFACEMETHODIMP MapColumnToSCID(UINT column, SHCOLUMNID *pscid) override;
IFACEMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
IFACEMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override;
IFACEMETHODIMP EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override;
+62 -9
View File
@@ -212,18 +212,18 @@ static HRESULT CALLBACK EnumFillCallback(EXTRACTCALLBACKMSG msg, const EXTRACTCA
return E_NOTIMPL;
}
HRESULT CEnumIDList::Fill(LPCWSTR path, HWND hwnd, SHCONTF contf)
HRESULT CEnumIDList::Enumerate(PCIDLIST_ABSOLUTE pidl, HWND hwnd, EXTRACTCALLBACK Callback, LPVOID cookie)
{
FILLCALLBACKDATA data = { this, contf };
return ExtractCabinet(path, NULL, EnumFillCallback, &data);
WCHAR path[MAX_PATH];
if (SHGetPathFromIDListW(pidl, path))
return ExtractCabinet(path, NULL, Callback, cookie);
return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
}
HRESULT CEnumIDList::Fill(PCIDLIST_ABSOLUTE pidl, HWND hwnd, SHCONTF contf)
{
WCHAR path[MAX_PATH];
if (SHGetPathFromIDListW(pidl, path))
return Fill(path, hwnd, contf);
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
FILLCALLBACKDATA data = { this, contf };
return Enumerate(pidl, NULL, EnumFillCallback, &data);
}
IFACEMETHODIMP CCabFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
@@ -440,6 +440,57 @@ IFACEMETHODIMP CCabFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
return E_FAIL;
}
struct PDNCALLBACKDATA
{
LPOLESTR pszName;
CABITEM *pItem;
};
static HRESULT CALLBACK ParseDisplayNameCallback(EXTRACTCALLBACKMSG msg, const EXTRACTCALLBACKDATA &ecd, LPVOID cookie)
{
PDNCALLBACKDATA &data = *(PDNCALLBACKDATA*)cookie;
switch ((UINT)msg)
{
case ECM_FILE:
{
const FDINOTIFICATION &fdin = *ecd.pfdin;
HRESULT hr = S_FALSE;
UINT datetime = MAKELONG(fdin.time, fdin.date);
CABITEM *item = CreateItem(fdin.psz1, fdin.attribs, fdin.cb, datetime);
if (!item)
return E_OUTOFMEMORY;
if (!lstrcmpiW(item->Path, data.pszName))
data.pItem = item;
else
SHFree(item);
return SUCCEEDED(hr) ? S_FALSE : hr; // Never extract
}
}
return E_NOTIMPL;
}
IFACEMETHODIMP CCabFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
{
*ppidl = NULL;
if (pchEaten)
*pchEaten = 0;
HRESULT hr;
PDNCALLBACKDATA data = { lpszDisplayName, NULL };
if (FAILED(hr = CEnumIDList::Enumerate(m_CurDir, hwndOwner, ParseDisplayNameCallback, &data)))
return hr;
if (!data.pItem)
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
*ppidl = (PIDLIST_RELATIVE)data.pItem;
if (pchEaten)
*pchEaten = lstrlenW(lpszDisplayName);
if (pdwAttributes)
GetAttributesOf(1, ppidl, (SFGAOF*)pdwAttributes);
return S_OK;
}
IFACEMETHODIMP CCabFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
{
CEnumIDList *p = CEnumIDList::CreateInstance();
@@ -449,6 +500,7 @@ IFACEMETHODIMP CCabFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLI
IFACEMETHODIMP CCabFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
{
static_assert(FLATFOLDER, "Support Bind if we display the archive as a tree");
UNIMPLEMENTED;
return E_NOTIMPL;
}
@@ -551,7 +603,8 @@ IFACEMETHODIMP CCabFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apid
return E_INVALIDARG;
}
HRESULT hr = S_OK;
const SFGAOF filemask = SFGAO_READONLY | SFGAO_HIDDEN | SFGAO_SYSTEM | SFGAO_ISSLOW;
const SFGAOF impliedmask = SFGAO_ISSLOW | SFGAO_CANCOPY;
const SFGAOF filemask = SFGAO_READONLY | SFGAO_HIDDEN | SFGAO_SYSTEM | impliedmask;
SFGAOF remain = *rgfInOut & filemask, validate = *rgfInOut & SFGAO_VALIDATE;
CComPtr<CEnumIDList> list;
for (UINT i = 0; i < cidl && (remain || validate); ++i)
@@ -569,7 +622,7 @@ IFACEMETHODIMP CCabFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apid
if (list->FindNamedItem((PCUITEMID_CHILD)item) == -1)
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
SFGAOF att = MapFSToSFAttributes(item->GetFSAttributes()) | SFGAO_ISSLOW;
SFGAOF att = MapFSToSFAttributes(item->GetFSAttributes()) | impliedmask;
remain &= att & ~(FLATFOLDER ? SFGAO_FOLDER : 0);
}
*rgfInOut = remain;
+29
View File
@@ -8,6 +8,32 @@
#include "precomp.h"
static inline bool IncludeInEnumIDList(SHCONTF contf, SFGAOF att) // Borrowed from cabview
{
const SHCONTF both = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
const SFGAOF superbits = SFGAO_HIDDEN | SFGAO_READONLY | SFGAO_SYSTEM;
const bool isfile = (att & (SFGAO_STREAM | SFGAO_FOLDER)) != SFGAO_FOLDER;
if ((contf & both) != both && !(contf & SHCONTF_STORAGE))
{
if (isfile && (contf & SHCONTF_FOLDERS))
return false;
if ((att & SFGAO_FOLDER) && (contf & SHCONTF_NONFOLDERS))
return false;
}
if ((att & SFGAO_HIDDEN) && !(contf & (SHCONTF_INCLUDEHIDDEN | SHCONTF_STORAGE)))
return false;
if ((att & superbits) > SFGAO_HIDDEN && !(contf & (SHCONTF_INCLUDESUPERHIDDEN | SHCONTF_STORAGE)))
return false;
return true;
}
static inline bool IncludeInEnumIDList(SHCONTF contf, bool dir, unz_file_info64 &zfi)
{
SFGAOF att = dir ? SFGAO_FOLDER : SFGAO_STREAM;
// TODO: SFGAO_HIDDEN,READONLY,SYSTEM from zfi.external_fa? (Use MapFSToSFAttributes)
return IncludeInEnumIDList(contf, att);
}
class CEnumZipContents :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IEnumIDList
@@ -48,6 +74,9 @@ public:
{
if (mEnumerator.NextUnique(m_Prefix, name, dir, info))
{
if (!IncludeInEnumIDList(dwFlags, dir, info))
continue;
item = _ILCreateZipItem(dir ? ZIP_PIDL_DIRECTORY : ZIP_PIDL_FILE, name, info);
if (!item)
{
+152 -10
View File
@@ -7,18 +7,45 @@
*/
#include "precomp.h"
#include <ntquery.h> // PID_STG_*
static FolderViewColumns g_ColumnDefs[] =
static const GUID FmtIdZipFolder = { 0xE88DCCE0, 0xB7B3, 0x11D1, { 0xA9,0xF0,0x00,0xAA,0x00,0x60,0xFA,0x31 } };
static const FolderViewColumn g_ColumnDefs[] =
{
{ IDS_COL_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 25, LVCFMT_LEFT },
{ IDS_COL_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 20, LVCFMT_LEFT },
{ IDS_COL_COMPRSIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT },
{ IDS_COL_PASSWORD, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT },
{ IDS_COL_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT },
{ IDS_COL_RATIO, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT },
{ IDS_COL_DATE_MOD, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, 15, LVCFMT_LEFT },
{ IDS_COL_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 25, LVCFMT_LEFT, &FMTID_Storage, PID_STG_NAME },
{ IDS_COL_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 20, LVCFMT_LEFT, &FMTID_Storage, PID_STG_STORAGETYPE },
{ IDS_COL_COMPRSIZE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT, &FmtIdZipFolder, 6 },
{ IDS_COL_PASSWORD, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT, &FmtIdZipFolder, 2 },
{ IDS_COL_SIZE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT, &FMTID_Storage, PID_STG_SIZE },
{ IDS_COL_RATIO, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT, &FmtIdZipFolder, 4 },
{ IDS_COL_DATE_MOD, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, 15, LVCFMT_LEFT, &FMTID_Storage, PID_STG_WRITETIME },
// IDS_COL_METHOD, SHCOLSTATE_TYPE_STR, ... &FmtIdZipFolder, 3 },
// IDS_COL_CRC32, SHCOLSTATE_TYPE_STR, ... &FmtIdZipFolder, 5 },
};
static int MapScidToColumn(const SHCOLUMNID &scid)
{
for (UINT i = 0; i < _countof(g_ColumnDefs); ++i)
{
if (IsEqual(scid, g_ColumnDefs[i]))
return i;
}
return -1;
}
static PIDLIST_RELATIVE FindItem(IEnumIDList &List, PCWSTR Path)
{
for (PITEMID_CHILD pidl; List.Next(1, &pidl, NULL) == S_OK;)
{
ZipPidlEntry *p = (ZipPidlEntry*)pidl;
if (!lstrcmpiW(p->Name, Path))
return pidl;
CoTaskMemFree(pidl);
}
return NULL;
}
CZipFolder::CZipFolder()
{
}
@@ -280,10 +307,69 @@ STDMETHODIMP CZipFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
{
if (!pcsFlags || iColumn >= _countof(g_ColumnDefs))
return E_INVALIDARG;
*pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
*pcsFlags = g_ColumnDefs[iColumn].ColumnFlags;
return S_OK;
}
STDMETHODIMP CZipFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
if (!pidl || !pscid || !pv)
return E_INVALIDARG;
V_VT(pv) = VT_EMPTY;
PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl);
if (curpidl->mkid.cb != 0)
{
DPRINT1("ERROR, unhandled PIDL!\n");
return E_FAIL;
}
const ZipPidlEntry* zipEntry = _ZipFromIL(pidl);
if (!zipEntry)
return E_INVALIDARG;
bool isDir = zipEntry->IsDirectory();
// Handle the non-string columns here so the caller gets the correct variant type
if (!isDir && IsEqual(*pscid, g_ColumnDefs[COL_SIZE]))
{
V_VT(pv) = VT_UI8;
V_UI8(pv) = zipEntry->UncompressedSize;
return S_OK;
}
else if (!isDir && IsEqual(*pscid, g_ColumnDefs[COL_COMPRSIZE]))
{
V_VT(pv) = VT_UI8;
V_UI8(pv) = zipEntry->CompressedSize;
return S_OK;
}
else if (!isDir && IsEqual(*pscid, g_ColumnDefs[COL_DATE_MOD]))
{
if (DosDateTimeToVariantTime(HIWORD(zipEntry->DosDate), LOWORD(zipEntry->DosDate), &V_DATE(pv)))
{
V_VT(pv) = VT_DATE;
return S_OK;
}
}
HRESULT hr = E_FAIL;
int col = MapScidToColumn(*pscid);
if (col >= 0)
{
SHELLDETAILS sd;
if (SUCCEEDED(hr = GetDetailsOf(pidl, col, &sd)))
{
CComHeapPtr<WCHAR> str;
if (SUCCEEDED(hr = StrRetToStrW(&sd.str, pidl, &str)))
{
hr = (V_BSTR(pv) = SysAllocString(str)) != NULL ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
V_VT(pv) = VT_BSTR;
}
}
}
return hr;
}
STDMETHODIMP CZipFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
{
if (iColumn >= _countof(g_ColumnDefs))
@@ -313,7 +399,7 @@ STDMETHODIMP CZipFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLD
switch (iColumn)
{
case COL_NAME:
return GetDisplayNameOf(pidl, 0, &psd->str);
return GetDisplayNameOf(pidl, SHGDN_INFOLDER, &psd->str);
case COL_TYPE:
{
SHFILEINFOW shfi;
@@ -365,6 +451,40 @@ STDMETHODIMP CZipFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLD
return E_NOTIMPL;
}
STDMETHODIMP CZipFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
{
if (column < _countof(g_ColumnDefs) && g_ColumnDefs[column].pkg)
{
pscid->fmtid = *g_ColumnDefs[column].pkg;
pscid->pid = g_ColumnDefs[column].pki;
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP CZipFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
{
if (pchEaten)
*pchEaten = 0;
DWORD dwFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN | SHCONTF_INCLUDESUPERHIDDEN;
CComPtr<IEnumIDList> pEnum;
HRESULT hr = EnumObjects(hwndOwner, dwFlags, &pEnum);
if (FAILED(hr))
return hr;
PIDLIST_RELATIVE pidl = FindItem(*pEnum, lpszDisplayName);
if (!pidl)
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
*ppidl = pidl;
if (pchEaten)
*pchEaten = lstrlenW(lpszDisplayName);
if (pdwAttributes)
GetAttributesOf(1, ppidl, (SFGAOF*)pdwAttributes);
return S_OK;
}
STDMETHODIMP CZipFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
{
if (riid == IID_IShellFolder)
@@ -624,6 +744,28 @@ STDMETHODIMP CZipFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, L
if (!zipEntry)
return E_FAIL;
if (dwFlags & SHGDN_FORPARSING)
{
if (dwFlags & SHGDN_INFOLDER)
return SHSetStrRet(strRet, zipEntry->Name);
WCHAR parent[MAX_PATH];
if (!SHGetPathFromIDListW(m_CurDir, parent))
return E_FAIL;
UINT cch = lstrlenW(parent) + 1 + lstrlenW(zipEntry->Name) + 1;
strRet->uType = STRRET_WSTR;
strRet->pOleStr = (LPWSTR)SHAlloc(cch * sizeof(WCHAR));
if (!strRet->pOleStr)
return E_OUTOFMEMORY;
lstrcpyW(strRet->pOleStr, parent);
PathAppendW(strRet->pOleStr, zipEntry->Name);
return S_OK;
}
SHFILEINFOW fi;
DWORD attr = zipEntry->IsDirectory() ? FILE_ATTRIBUTE_DIRECTORY : 0;
if (SHGetFileInfoW(zipEntry->Name, attr, &fi, sizeof(fi), SHGFI_DISPLAYNAME | SHGFI_USEFILEATTRIBUTES))
return SHSetStrRet(strRet, fi.szDisplayName);
return SHSetStrRet(strRet, zipEntry->Name);
}
+21 -20
View File
@@ -19,14 +19,26 @@ enum FOLDERCOLUMN
COL_DATE_MOD,
};
struct FolderViewColumns
struct FolderViewColumn
{
int iResource;
DWORD dwDefaultState;
int cxChar;
int fmt;
BYTE iResource;
BYTE ColumnFlags;
BYTE cxChar;
BYTE fmt;
const GUID *pkg;
BYTE pki;
};
inline bool IsEqual(const SHCOLUMNID &scid, REFGUID guid, UINT pid)
{
return scid.pid == pid && IsEqualGUID(scid.fmtid, guid);
}
inline bool IsEqual(const SHCOLUMNID &scid, const FolderViewColumn &col)
{
return col.pkg && IsEqual(scid, *col.pkg, col.pki);
}
class CZipFolder :
public CComCoClass<CZipFolder, &CLSID_ZipFolderStorageHandler>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
@@ -84,24 +96,13 @@ public:
return S_OK;
}
STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) override;
STDMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) override
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
STDMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) override;
STDMETHODIMP GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) override;
STDMETHODIMP MapColumnToSCID(UINT column, SHCOLUMNID *pscid) override
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
STDMETHODIMP MapColumnToSCID(UINT column, SHCOLUMNID *pscid) override;
// *** IShellFolder methods ***
STDMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
STDMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override;
STDMETHODIMP EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override
{
return _CEnumZipContents_CreateInstance(this, dwFlags, m_ZipDir, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
+2
View File
@@ -25,6 +25,8 @@ struct ZipPidlEntry
ULONG DosDate;
WCHAR Name[1];
bool IsDirectory() const { return ZipType == ZIP_PIDL_DIRECTORY; }
};
#include <poppack.h>