diff --git a/dll/shellext/cabview/cabview.h b/dll/shellext/cabview/cabview.h index dbc20744dfd..bd31cfac64f 100644 --- a/dll/shellext/cabview/cabview.h +++ b/dll/shellext/cabview/cabview.h @@ -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; diff --git a/dll/shellext/cabview/folder.cpp b/dll/shellext/cabview/folder.cpp index c96e941392c..85076f7376d 100644 --- a/dll/shellext/cabview/folder.cpp +++ b/dll/shellext/cabview/folder.cpp @@ -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 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; diff --git a/dll/shellext/zipfldr/CEnumZipContents.cpp b/dll/shellext/zipfldr/CEnumZipContents.cpp index 2e9ecb8fa8d..5a30da50ec2 100644 --- a/dll/shellext/zipfldr/CEnumZipContents.cpp +++ b/dll/shellext/zipfldr/CEnumZipContents.cpp @@ -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, 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) { diff --git a/dll/shellext/zipfldr/CZipFolder.cpp b/dll/shellext/zipfldr/CZipFolder.cpp index b289a7df7cc..720f613ec65 100644 --- a/dll/shellext/zipfldr/CZipFolder.cpp +++ b/dll/shellext/zipfldr/CZipFolder.cpp @@ -7,18 +7,45 @@ */ #include "precomp.h" +#include // 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 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 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); } diff --git a/dll/shellext/zipfldr/CZipFolder.hpp b/dll/shellext/zipfldr/CZipFolder.hpp index 54cd5155ea0..fb9cce725ac 100644 --- a/dll/shellext/zipfldr/CZipFolder.hpp +++ b/dll/shellext/zipfldr/CZipFolder.hpp @@ -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, public CComObjectRootEx, @@ -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)); diff --git a/dll/shellext/zipfldr/zippidl.hpp b/dll/shellext/zipfldr/zippidl.hpp index f67f260a88b..5d3fba4c34f 100644 --- a/dll/shellext/zipfldr/zippidl.hpp +++ b/dll/shellext/zipfldr/zippidl.hpp @@ -25,6 +25,8 @@ struct ZipPidlEntry ULONG DosDate; WCHAR Name[1]; + + bool IsDirectory() const { return ZipType == ZIP_PIDL_DIRECTORY; } }; #include