https://git.reactos.org/?p=reactos.git;a=commitdiff;h=63bb46a2fd416f539ae118b7a656f162252dadd4

commit 63bb46a2fd416f539ae118b7a656f162252dadd4
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Thu Dec 5 15:14:55 2024 +0100
Commit:     GitHub <nore...@github.com>
CommitDate: Thu Dec 5 15:14:55 2024 +0100

    [CABVIEW] Add CabView shell extension (#7494)
    
    CORE-14616
---
 dll/shellext/CMakeLists.txt            |   1 +
 dll/shellext/cabview/CMakeLists.txt    |  21 +
 dll/shellext/cabview/cabview.cpp       |  66 +++
 dll/shellext/cabview/cabview.h         | 240 +++++++++
 dll/shellext/cabview/cabview.rc        |  75 +++
 dll/shellext/cabview/cabview.spec      |   4 +
 dll/shellext/cabview/extract.cpp       | 248 ++++++++++
 dll/shellext/cabview/folder.cpp        | 857 +++++++++++++++++++++++++++++++++
 dll/shellext/cabview/lang/de-DE.rc     |  21 +
 dll/shellext/cabview/lang/en-US.rc     |  21 +
 dll/shellext/cabview/lang/et-EE.rc     |  21 +
 dll/shellext/cabview/lang/fr-FR.rc     |  21 +
 dll/shellext/cabview/lang/hi-IN.rc     |  21 +
 dll/shellext/cabview/lang/it-IT.rc     |  21 +
 dll/shellext/cabview/lang/ja-JP.rc     |  21 +
 dll/shellext/cabview/lang/pl-PL.rc     |  22 +
 dll/shellext/cabview/lang/pt-PT.rc     |  21 +
 dll/shellext/cabview/lang/ro-RO.rc     |  22 +
 dll/shellext/cabview/lang/ru-RU.rc     |  21 +
 dll/shellext/cabview/lang/sv-SE.rc     |  21 +
 dll/shellext/cabview/lang/tr-TR.rc     |  21 +
 dll/shellext/cabview/lang/zh-CN.rc     |  22 +
 dll/shellext/cabview/lang/zh-HK.rc     |  22 +
 dll/shellext/cabview/lang/zh-TW.rc     |  23 +
 dll/shellext/cabview/precomp.h         |  34 ++
 dll/shellext/cabview/res/cabview.rgs   |  47 ++
 dll/shellext/cabview/res/folder.ico    | Bin 0 -> 26070 bytes
 dll/shellext/cabview/resource.h        |  25 +
 dll/shellext/cabview/util.h            | 156 ++++++
 dll/win32/browseui/CProgressDialog.cpp |   1 +
 media/inf/syssetup.inf                 |   1 +
 31 files changed, 2118 insertions(+)

diff --git a/dll/shellext/CMakeLists.txt b/dll/shellext/CMakeLists.txt
index 8d005319c4c..a9c8fe256ef 100644
--- a/dll/shellext/CMakeLists.txt
+++ b/dll/shellext/CMakeLists.txt
@@ -1,5 +1,6 @@
 
 add_subdirectory(acppage)
+add_subdirectory(cabview)
 add_subdirectory(cryptext)
 add_subdirectory(deskadp)
 add_subdirectory(deskmon)
diff --git a/dll/shellext/cabview/CMakeLists.txt 
b/dll/shellext/cabview/CMakeLists.txt
new file mode 100644
index 00000000000..3a574a8933f
--- /dev/null
+++ b/dll/shellext/cabview/CMakeLists.txt
@@ -0,0 +1,21 @@
+
+spec2def(cabview.dll cabview.spec)
+
+list(APPEND SOURCE
+    cabview.cpp
+    extract.cpp
+    folder.cpp
+    resource.h)
+
+add_library(cabview MODULE
+    ${SOURCE}
+    cabview.spec
+    cabview.rc
+    ${CMAKE_CURRENT_BINARY_DIR}/cabview.def)
+
+set_module_type(cabview win32dll UNICODE)
+target_link_libraries(cabview uuid cpprt atl_classes)
+set_target_cpp_properties(cabview WITH_EXCEPTIONS)
+add_importlibs(cabview cabinet oleaut32 ole32 shlwapi comctl32 shell32 user32 
advapi32 msvcrt kernel32 ntdll)
+add_pch(cabview precomp.h SOURCE)
+add_cd_file(TARGET cabview DESTINATION reactos/system32 FOR all)
diff --git a/dll/shellext/cabview/cabview.cpp b/dll/shellext/cabview/cabview.cpp
new file mode 100644
index 00000000000..fc6d2d7302e
--- /dev/null
+++ b/dll/shellext/cabview/cabview.cpp
@@ -0,0 +1,66 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     DLL entry point
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#include "cabview.h"
+
+#include <initguid.h>
+DEFINE_GUID(CLSID_CabFolder, 
0x0CD7A5C0,0x9F37,0x11CE,0xAE,0x65,0x08,0x00,0x2B,0x2E,0x12,0x62);
+
+CComModule g_Module;
+
+BEGIN_OBJECT_MAP(ObjectMap)
+    OBJECT_ENTRY(CLSID_CabFolder, CCabFolder)
+END_OBJECT_MAP()
+
+EXTERN_C BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID 
lpReserved)
+{
+    switch (dwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hInstance);
+            g_Module.Init(ObjectMap, hInstance, NULL);
+            break;
+    }
+
+    return TRUE;
+}
+
+STDAPI DllCanUnloadNow()
+{
+    return g_Module.DllCanUnloadNow();
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+    return g_Module.DllGetClassObject(rclsid, riid, ppv);
+}
+
+STDAPI DllRegisterServer()
+{
+    HRESULT hr;
+
+    hr = g_Module.DllRegisterServer(FALSE);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    hr = g_Module.UpdateRegistryFromResource(IDR_FOLDER, TRUE, NULL);
+    if (FAILED(hr))
+        return hr;
+
+    return S_OK;
+}
+
+STDAPI DllUnregisterServer()
+{
+    HRESULT hr1 = g_Module.DllUnregisterServer(FALSE);
+    HRESULT hr2 = g_Module.UpdateRegistryFromResource(IDR_FOLDER, FALSE, NULL);
+    if (FAILED_UNEXPECTEDLY(hr1))
+        return hr1;
+    if (FAILED_UNEXPECTEDLY(hr2))
+        return hr2;
+    return S_OK;
+}
diff --git a/dll/shellext/cabview/cabview.h b/dll/shellext/cabview/cabview.h
new file mode 100644
index 00000000000..dbc20744dfd
--- /dev/null
+++ b/dll/shellext/cabview/cabview.h
@@ -0,0 +1,240 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Main header file
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#pragma once
+#include "precomp.h"
+#include "resource.h"
+
+#define FLATFOLDER TRUE
+
+EXTERN_C const GUID CLSID_CabFolder;
+
+enum EXTRACTCALLBACKMSG { ECM_BEGIN, ECM_FILE, ECM_PREPAREPATH, ECM_ERROR };
+struct EXTRACTCALLBACKDATA
+{
+    LPCWSTR Path;
+    const FDINOTIFICATION *pfdin;
+    HRESULT hr;
+};
+typedef HRESULT (CALLBACK*EXTRACTCALLBACK)(EXTRACTCALLBACKMSG msg, const 
EXTRACTCALLBACKDATA &data, LPVOID cookie);
+HRESULT ExtractCabinet(LPCWSTR cab, LPCWSTR destination, EXTRACTCALLBACK 
callback, LPVOID cookie);
+
+class CEnumIDList :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IEnumIDList
+{
+protected:
+    HDPA m_Items;
+    ULONG m_Pos;
+
+public:
+    static int CALLBACK DPADestroyCallback(void *pidl, void *pData)
+    {
+        SHFree(pidl);
+        return TRUE;
+    }
+
+    CEnumIDList() : m_Pos(0)
+    {
+        m_Items = DPA_Create(0);
+    }
+
+    virtual ~CEnumIDList()
+    {
+        DPA_DestroyCallback(m_Items, DPADestroyCallback, NULL);
+    }
+
+    int FindNamedItem(PCUITEMID_CHILD pidl) const;
+    HRESULT Fill(LPCWSTR path, HWND hwnd = NULL, SHCONTF contf = 0);
+    HRESULT Fill(PCIDLIST_ABSOLUTE pidl, HWND hwnd = NULL, SHCONTF contf = 0);
+
+    HRESULT Append(LPCITEMIDLIST pidl)
+    {
+        return DPA_AppendPtr(m_Items, (void*)pidl) != DPA_ERR ? S_OK : 
E_OUTOFMEMORY;
+    }
+
+    UINT GetCount() const { return m_Items ? DPA_GetPtrCount(m_Items) : 0; }
+
+    // IEnumIDList
+    IFACEMETHODIMP Next(ULONG celt, PITEMID_CHILD *rgelt, ULONG *pceltFetched)
+    {
+        if (!rgelt)
+            return E_INVALIDARG;
+        HRESULT hr = S_FALSE;
+        UINT count = GetCount(), fetched = 0;
+        if (m_Pos < count && fetched < celt)
+        {
+            if (SUCCEEDED(hr = SHILClone(DPA_FastGetPtr(m_Items, m_Pos), 
&rgelt[fetched])))
+                fetched++;
+        }
+        if (pceltFetched)
+            *pceltFetched = fetched;
+        m_Pos += fetched;
+        return FAILED(hr) ? hr : (celt == fetched && fetched) ? S_OK : S_FALSE;
+    }
+
+    IFACEMETHODIMP Reset()
+    {
+        m_Pos = 0;
+        return S_OK;
+    }
+
+    IFACEMETHODIMP Skip(ULONG celt)
+    {
+        UINT count = GetCount(), newpos = m_Pos + celt;
+        if (celt > count || newpos >= count)
+            return E_INVALIDARG;
+        m_Pos = newpos;
+        return S_OK;
+    }
+
+    IFACEMETHODIMP Clone(IEnumIDList **ppenum)
+    {
+        UNIMPLEMENTED;
+        *ppenum = NULL;
+        return E_NOTIMPL;
+    }
+
+    static CEnumIDList* CreateInstance()
+    {
+        CComPtr<CEnumIDList> obj;
+        return SUCCEEDED(ShellObjectCreator(obj)) ? obj.Detach() : NULL;
+    }
+
+    DECLARE_NO_REGISTRY()
+    DECLARE_NOT_AGGREGATABLE(CEnumIDList)
+
+    BEGIN_COM_MAP(CEnumIDList)
+        COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+    END_COM_MAP()
+};
+
+class CCabFolder :
+    public CComCoClass<CCabFolder, &CLSID_CabFolder>,
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IShellFolder2,
+    public IPersistFolder2,
+    public IShellFolderViewCB,
+    public IShellIcon
+{
+protected:
+    CComHeapPtr<ITEMIDLIST> m_CurDir;
+    HWND m_ShellViewWindow = NULL;
+
+public:
+    HRESULT ExtractFilesUI(HWND hWnd, IDataObject *pDO);
+    HRESULT GetItemDetails(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS 
*psd, VARIANT *pv);
+    int MapSCIDToColumn(const SHCOLUMNID &scid);
+    HRESULT CompareID(LPARAM lParam, PCUITEMID_CHILD pidl1, PCUITEMID_CHILD 
pidl2);
+
+    HRESULT CreateEnum(CEnumIDList **List)
+    {
+        CEnumIDList *pEIDL = CEnumIDList::CreateInstance();
+        *List = pEIDL;
+        return pEIDL ? pEIDL->Fill(m_CurDir) : E_OUTOFMEMORY;
+    }
+
+    // IShellFolder2
+    IFACEMETHODIMP GetDefaultSearchGUID(GUID *pguid) override
+    {
+        return E_NOTIMPL;
+    }
+
+    IFACEMETHODIMP EnumSearches(IEnumExtraSearch **ppenum) override
+    {
+        return E_NOTIMPL;
+    }
+
+    IFACEMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG 
*pDisplay) override;
+
+    IFACEMETHODIMP GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags) 
override;
+
+    IFACEMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, 
VARIANT *pv) override;
+
+    IFACEMETHODIMP GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, 
SHELLDETAILS *psd) override;
+
+    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 EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST 
*ppEnumIDList) override;
+
+    IFACEMETHODIMP BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, 
REFIID riid, LPVOID *ppvOut) override;
+    
+    IFACEMETHODIMP BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, 
REFIID riid, LPVOID *ppvOut) override
+    {
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    IFACEMETHODIMP CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, 
PCUIDLIST_RELATIVE pidl2) override;
+    
+    IFACEMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID 
*ppvOut) override;
+    
+    IFACEMETHODIMP GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 
SFGAOF *rgfInOut) override;
+    
+    IFACEMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, 
PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *prgfInOut, LPVOID *ppvOut) 
override;
+    
+    IFACEMETHODIMP GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, 
LPSTRRET pName) override;
+    
+    IFACEMETHODIMP SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR 
lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) override
+    {
+        return E_NOTIMPL;
+    }
+
+    // IPersistFolder2
+    IFACEMETHODIMP GetCurFolder(PIDLIST_ABSOLUTE *pidl) override
+    {
+        LPITEMIDLIST curdir = (LPITEMIDLIST)m_CurDir;
+        return curdir ? SHILClone(curdir, pidl) : E_UNEXPECTED;
+    }
+
+    IFACEMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidl) override
+    {
+        WCHAR path[MAX_PATH];
+        if (SHGetPathFromIDListW(pidl, path))
+        {
+            PIDLIST_ABSOLUTE curdir = ILClone(pidl);
+            if (curdir)
+            {
+                m_CurDir.Attach(curdir);
+                return S_OK;
+            }
+            return E_OUTOFMEMORY;
+        }
+        return E_INVALIDARG;
+    }
+
+    IFACEMETHODIMP GetClassID(CLSID *lpClassId) override
+    {
+        *lpClassId = CLSID_CabFolder;
+        return S_OK;
+    }
+
+    // IShellFolderViewCB
+    IFACEMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) 
override;
+
+    // IShellIcon
+    IFACEMETHODIMP GetIconOf(PCUITEMID_CHILD pidl, UINT flags, int 
*pIconIndex) override;
+
+    DECLARE_NO_REGISTRY()
+    DECLARE_NOT_AGGREGATABLE(CCabFolder)
+
+    BEGIN_COM_MAP(CCabFolder)
+        COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
+        COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
+        COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
+        COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
+        COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
+        COM_INTERFACE_ENTRY_IID(IID_IShellIcon, IShellIcon)
+    END_COM_MAP()
+};
diff --git a/dll/shellext/cabview/cabview.rc b/dll/shellext/cabview/cabview.rc
new file mode 100644
index 00000000000..526888b7b69
--- /dev/null
+++ b/dll/shellext/cabview/cabview.rc
@@ -0,0 +1,75 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Main resource file
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#include <windef.h>
+#include <winuser.h>
+
+#include "resource.h"
+
+IDI_FOLDER ICON "res/folder.ico"
+
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION  "ReactOS Cabinet Shell Extension"
+#define REACTOS_STR_INTERNAL_NAME     "cabview"
+#define REACTOS_STR_ORIGINAL_FILENAME "cabview.dll"
+#include <reactos/version.rc>
+
+#include <reactos/manifest_dll.rc>
+
+IDR_FOLDER REGISTRY "res/cabview.rgs"
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+#ifdef LANGUAGE_DE_DE
+    #include "lang/de-DE.rc"
+#endif
+#ifdef LANGUAGE_EN_US
+    #include "lang/en-US.rc"
+#endif
+#ifdef LANGUAGE_ET_EE
+    #include "lang/et-EE.rc"
+#endif
+#ifdef LANGUAGE_FR_FR
+    #include "lang/fr-FR.rc"
+#endif
+#ifdef LANGUAGE_HI_IN
+    #include "lang/hi-IN.rc"
+#endif
+#ifdef LANGUAGE_IT_IT
+    #include "lang/it-IT.rc"
+#endif
+#ifdef LANGUAGE_JA_JP
+    #include "lang/ja-JP.rc"
+#endif
+#ifdef LANGUAGE_PL_PL
+    #include "lang/pl-PL.rc"
+#endif
+#ifdef LANGUAGE_PT_PT
+    #include "lang/pt-PT.rc"
+#endif
+#ifdef LANGUAGE_RO_RO
+    #include "lang/ro-RO.rc"
+#endif
+#ifdef LANGUAGE_RU_RU
+    #include "lang/ru-RU.rc"
+#endif
+#ifdef LANGUAGE_SV_SE
+    #include "lang/sv-SE.rc"
+#endif
+#ifdef LANGUAGE_TR_TR
+    #include "lang/tr-TR.rc"
+#endif
+#ifdef LANGUAGE_ZH_CN
+    #include "lang/zh-CN.rc"
+#endif
+#ifdef LANGUAGE_ZH_HK
+    #include "lang/zh-HK.rc"
+#endif
+#ifdef LANGUAGE_ZH_TW
+    #include "lang/zh-TW.rc"
+#endif
diff --git a/dll/shellext/cabview/cabview.spec 
b/dll/shellext/cabview/cabview.spec
new file mode 100644
index 00000000000..b16365d0c9f
--- /dev/null
+++ b/dll/shellext/cabview/cabview.spec
@@ -0,0 +1,4 @@
+@ stdcall -private DllCanUnloadNow()
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
diff --git a/dll/shellext/cabview/extract.cpp b/dll/shellext/cabview/extract.cpp
new file mode 100644
index 00000000000..cdb1ff19d79
--- /dev/null
+++ b/dll/shellext/cabview/extract.cpp
@@ -0,0 +1,248 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     FDI API wrapper
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#include "precomp.h"
+#include "cabview.h"
+#include "util.h"
+#include <fcntl.h>
+
+struct EXTRACTCABINETINTERNALDATA
+{
+    LPCWSTR destination;
+    EXTRACTCALLBACK callback;
+    LPVOID cookie;
+};
+
+static LPWSTR BuildPath(LPCWSTR Dir, LPCSTR File, UINT Attr)
+{
+    UINT cp = Attr & _A_NAME_IS_UTF ? CP_UTF8 : CP_ACP;
+    UINT cchfile = MultiByteToWideChar(cp, 0, File, -1, 0, 0);
+    SIZE_T lendir = lstrlenW(Dir), cch = lendir + 1 + cchfile;
+    LPWSTR path = (LPWSTR)SHAlloc(cch * sizeof(*path));
+    if (path)
+    {
+        lstrcpyW(path, Dir);
+        if (lendir && !IsPathSep(path[lendir - 1]))
+            path[lendir++] = '\\';
+
+        LPWSTR dst = &path[lendir];
+        MultiByteToWideChar(cp, 0, File + IsPathSep(*File), -1, dst, cchfile);
+        for (SIZE_T i = 0; dst[i]; ++i)
+        {
+            if (dst[i] == L':' && lendir) // Don't allow absolute paths
+                dst[i] = L'_';
+            if (dst[i] == L'/') // Normalize
+                dst[i] = L'\\';
+        }
+    }
+    return path;
+}
+
+static HRESULT HResultFrom(const ERF &erf)
+{
+    switch (erf.fError ? erf.erfOper : FDIERROR_NONE)
+    {
+        case FDIERROR_NONE:
+            return erf.fError ? HRESULT_FROM_WIN32(erf.erfType) : S_OK;
+        case FDIERROR_CABINET_NOT_FOUND:
+            return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+        case FDIERROR_ALLOC_FAIL:
+            return E_OUTOFMEMORY;
+        case FDIERROR_USER_ABORT:
+            return S_FALSE;
+        default:
+            return erf.erfType ? HRESULT_FROM_WIN32(erf.erfType) : E_FAIL;
+    }
+}
+
+FNFREE(CabMemFree)
+{
+    SHFree(pv);
+}
+
+FNALLOC(CabMemAlloc)
+{
+    return SHAlloc(cb);
+}
+
+FNCLOSE(CabClose)
+{
+    return CloseHandle((HANDLE)hf) ? 0 : -1;
+}
+
+static INT_PTR CabOpenEx(LPCWSTR path, UINT access, UINT share, UINT disp, 
UINT attr)
+{
+    return (INT_PTR)CreateFileW(path, access, share, NULL, disp, attr, NULL);
+}
+
+FNOPEN(CabOpen)
+{
+    UINT disp = (oflag & _O_CREAT) ? CREATE_ALWAYS : OPEN_EXISTING;
+    UINT access = GENERIC_READ;
+    if (oflag & _O_RDWR)
+        access = GENERIC_READ | GENERIC_WRITE;
+    else if (oflag & _O_WRONLY)
+        access = GENERIC_WRITE;
+    UNREFERENCED_PARAMETER(pmode);
+    WCHAR buf[MAX_PATH * 2];
+    MultiByteToWideChar(CP_UTF8, 0, pszFile, -1, buf, _countof(buf));
+    return CabOpenEx(buf, access, FILE_SHARE_READ, disp, 
FILE_ATTRIBUTE_NORMAL);
+}
+
+FNREAD(CabRead)
+{
+    DWORD dwBytesRead;
+    return ReadFile((HANDLE)hf, pv, cb, &dwBytesRead, NULL) ? dwBytesRead : -1;
+}
+
+FNWRITE(CabWrite)
+{
+    DWORD dwBytesWritten;
+    return WriteFile((HANDLE)hf, pv, cb, &dwBytesWritten, NULL) ? 
dwBytesWritten : -1;
+}
+
+FNSEEK(CabSeek)
+{
+    return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
+}
+
+static HRESULT Init(HFDI &hfdi, ERF &erf)
+{
+    const int cpu = cpuUNKNOWN;
+    hfdi = FDICreate(CabMemAlloc, CabMemFree, CabOpen, CabRead, CabWrite, 
CabClose, CabSeek, cpu, &erf);
+    return hfdi ? S_OK : HResultFrom(erf);
+}
+
+FNFDINOTIFY(ExtractCabinetCallback)
+{
+    const UINT attrmask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | 
FILE_ATTRIBUTE_ARCHIVE;
+    EXTRACTCABINETINTERNALDATA &ecd = *(EXTRACTCABINETINTERNALDATA*)pfdin->pv;
+    EXTRACTCALLBACKDATA noti;
+    HRESULT hr;
+    FILETIME ft;
+
+    noti.pfdin = pfdin;
+    switch (fdint)
+    {
+        case fdintCOPY_FILE:
+            hr = ecd.callback(ECM_FILE, noti, ecd.cookie);
+            if (hr == S_OK)
+            {
+                hr = E_OUTOFMEMORY;
+                LPWSTR path = BuildPath(ecd.destination, pfdin->psz1, 
pfdin->attribs);
+                if (path)
+                {
+                    // Callee is using SHPPFW_IGNOREFILENAME so we don't need 
to remove the name.
+                    /*LPWSTR file = PathFindFileNameW(path);
+                    if (file > path)
+                    {
+                        file[-1] = L'\0';*/
+                        noti.Path = path;
+                        ecd.callback(ECM_PREPAREPATH, noti, ecd.cookie);
+                    /*  file[-1] = L'\\';
+                    }*/
+                    UINT attr = pfdin->attribs & attrmask;
+                    UINT access = GENERIC_READ | GENERIC_WRITE, share = 
FILE_SHARE_DELETE;
+                    INT_PTR handle = CabOpenEx(path, access, share, 
CREATE_NEW, attr | FILE_FLAG_SEQUENTIAL_SCAN);
+                    noti.hr = HResultFromWin32(GetLastError());
+                    SHFree(path);
+                    if (handle != (INT_PTR)-1)
+                        return handle;
+                    if (ecd.callback(ECM_ERROR, noti, ecd.cookie) != E_NOTIMPL)
+                        hr = noti.hr;
+                }
+            }
+            return hr == S_FALSE ? 0 : -1;
+
+        case fdintCLOSE_FILE_INFO:
+            if (DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
+                SetFileTime((HANDLE)(pfdin->hf), NULL, NULL, &ft);
+            return !CabClose(pfdin->hf);
+
+        case fdintNEXT_CABINET:
+            if (pfdin->fdie && pfdin->fdie != FDIERROR_USER_ABORT)
+            {
+                if (pfdin->fdie == FDIERROR_CABINET_NOT_FOUND)
+                    noti.hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+                else
+                    noti.hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+                ecd.callback(ECM_ERROR, noti, ecd.cookie);
+            }
+            return pfdin->fdie ? -1 : 0;
+
+        case fdintPARTIAL_FILE:
+            return 0;
+
+        case fdintCABINET_INFO:
+            return 0;
+
+        case fdintENUMERATE:
+            return 0;
+    }
+    return -1;
+}
+
+HRESULT ExtractCabinet(LPCWSTR cab, LPCWSTR destination, EXTRACTCALLBACK 
callback, LPVOID cookie)
+{
+    BOOL quick = !destination;
+    if (!destination)
+        destination = L"?:"; // Dummy path for callers that enumerate without 
extracting
+    EXTRACTCABINETINTERNALDATA data = { destination, callback, cookie };
+    EXTRACTCALLBACKDATA noti;
+    ERF erf = { };
+    HFDI hfdi;
+    UINT total = 0, files = 0;
+    HRESULT hr = Init(hfdi, erf);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    UINT share = FILE_SHARE_READ | FILE_SHARE_DELETE;
+    INT_PTR hf = quick ? -1 : CabOpenEx(cab, GENERIC_READ, share, 
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL);
+    if (hf != -1)
+    {
+        FDICABINETINFO ci;
+        if (FDIIsCabinet(hfdi, hf, &ci))
+        {
+            total = ci.cbCabinet;
+            files = ci.cFiles;
+        }
+        CabClose(hf);
+    }
+
+    hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+    char buf[MAX_PATH * 2], *name = 0;
+    if (!WideCharToMultiByte(CP_UTF8, 0, cab, -1, buf, _countof(buf), NULL, 
NULL))
+    {
+        *buf = '\0';
+        hr = E_INVALIDARG;
+    }
+    for (UINT i = 0; buf[i]; ++i)
+    {
+        if (buf[i] == '\\' || buf[i] == '/')
+            name = &buf[i + 1];
+    }
+    if (name > buf && *name)
+    {
+        // Format the name the way FDI likes it
+        name[-1] = ANSI_NULL;
+        char namebuf[MAX_PATH];
+        namebuf[0] = '\\';
+        lstrcpyA(namebuf + 1, name);
+        name = namebuf;
+
+        FDINOTIFICATION fdin;
+        fdin.cb = total;
+        fdin.hf = files;
+        noti.Path = cab;
+        noti.pfdin = &fdin;
+        callback(ECM_BEGIN, noti, cookie);
+
+        hr = FDICopy(hfdi, name, buf, 0, ExtractCabinetCallback, NULL, &data) 
? S_OK : HResultFrom(erf);
+    }
+    FDIDestroy(hfdi);
+    return hr;
+}
diff --git a/dll/shellext/cabview/folder.cpp b/dll/shellext/cabview/folder.cpp
new file mode 100644
index 00000000000..c96e941392c
--- /dev/null
+++ b/dll/shellext/cabview/folder.cpp
@@ -0,0 +1,857 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Shell folder implementation
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#include "cabview.h"
+#include "util.h"
+
+enum FOLDERCOLUMNS
+{
+    COL_NAME,   // PKEY_ItemNameDisplay
+    COL_SIZE,   // PKEY_Size
+    COL_TYPE,   // PKEY_ItemTypeText
+    COL_MDATE,  // PKEY_DateModified
+    COL_PATH,   // PKEY_?: Archive-relative path
+    COL_ATT,    // PKEY_FileAttributes
+    COLCOUNT
+};
+
+static const struct FOLDERCOLUMN
+{
+    BYTE TextId;
+    BYTE LvcFmt;
+    BYTE LvcChars;
+    BYTE ColFlags;
+    const GUID *pkg;
+    BYTE pki;
+} g_Columns[] =
+{
+    { IDS_COL_NAME, LVCFMT_LEFT, 20, SHCOLSTATE_TYPE_STR | 
SHCOLSTATE_ONBYDEFAULT, &FMTID_Storage, PID_STG_NAME },
+    { IDS_COL_SIZE, LVCFMT_RIGHT, 16, SHCOLSTATE_TYPE_INT | 
SHCOLSTATE_ONBYDEFAULT, &FMTID_Storage, PID_STG_SIZE },
+    { IDS_COL_TYPE, LVCFMT_LEFT, 20, SHCOLSTATE_TYPE_STR | 
SHCOLSTATE_ONBYDEFAULT, &FMTID_Storage, PID_STG_STORAGETYPE },
+    { IDS_COL_MDATE, LVCFMT_LEFT, 20, SHCOLSTATE_TYPE_DATE | 
SHCOLSTATE_ONBYDEFAULT, &FMTID_Storage, PID_STG_WRITETIME },
+    { IDS_COL_PATH, LVCFMT_LEFT, 30, SHCOLSTATE_TYPE_STR | 
SHCOLSTATE_ONBYDEFAULT, &CLSID_CabFolder, 0 },
+    { IDS_COL_ATT, LVCFMT_RIGHT, 10, SHCOLSTATE_TYPE_STR, &FMTID_Storage, 
PID_STG_ATTRIBUTES },
+};
+
+#include <pshpack1.h>
+struct CABITEM
+{
+    WORD cb;
+    WORD Unknown; // Not sure what Windows uses this for, we always store 0
+    UINT Size;
+    WORD Date, Time; // DOS
+    WORD Attrib;
+    WORD NameOffset;
+    WCHAR Path[ANYSIZE_ARRAY];
+
+#if FLATFOLDER
+    inline bool IsFolder() const { return false; }
+#else
+    inline BOOL IsFolder() const { return Attrib & FILE_ATTRIBUTE_DIRECTORY; }
+#endif
+    enum { FSATTS = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | 
FILE_ATTRIBUTE_SYSTEM |
+                    FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY };
+    WORD GetFSAttributes() const { return Attrib & FSATTS; }
+    LPCWSTR GetName() const { return Path + NameOffset; }
+
+    template<class PIDL> static CABITEM* Validate(PIDL pidl)
+    {
+        CABITEM *p = (CABITEM*)pidl;
+        return p && p->cb > FIELD_OFFSET(CABITEM, Path[1]) && p->Unknown == 0 
? p : NULL;
+    }
+};
+#include <poppack.h>
+
+static CABITEM* CreateItem(LPCWSTR Path, UINT Attrib, UINT Size, UINT DateTime)
+{
+    const SIZE_T len = lstrlenW(Path), cb = FIELD_OFFSET(CABITEM, Path[len + 
1]);
+    if (cb > 0xffff)
+        return NULL;
+    CABITEM *p = (CABITEM*)SHAlloc(cb + sizeof(USHORT));
+    if (p)
+    {
+        p->cb = (USHORT)cb;
+        p->Unknown = 0;
+        p->Size = Size;
+        p->Attrib = Attrib;
+        p->Date = HIWORD(DateTime);
+        p->Time = LOWORD(DateTime);
+        p->NameOffset = 0;
+        for (UINT i = 0;; ++i)
+        {
+            WCHAR c = Path[i];
+            if (c == L':') // Don't allow absolute paths
+                c = L'_';
+            if (c == L'/') // Normalize
+                c = L'\\';
+            if (c == '\\')
+                p->NameOffset = i + 1;
+            p->Path[i] = c;
+            if (!c)
+                break;
+        }
+        ((SHITEMID*)((BYTE*)p + cb))->cb = 0;
+    }
+    return p;
+}
+
+static CABITEM* CreateItem(LPCSTR Path, UINT Attrib, UINT Size = 0, UINT 
DateTime = 0)
+{
+    WCHAR buf[MAX_PATH * 2];
+    UINT codepage = (Attrib & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP;
+    if (MultiByteToWideChar(codepage, 0, Path, -1, buf, _countof(buf)))
+        return CreateItem(buf, Attrib, Size, DateTime);
+    return NULL;
+}
+
+static HRESULT CALLBACK ItemMenuCallback(IShellFolder *psf, HWND hwnd, 
IDataObject *pdtobj,
+                                         UINT uMsg, WPARAM wParam, LPARAM 
lParam)
+{
+    enum { IDC_EXTRACT, IDC_EXTRACTALL };
+    HRESULT hr = E_NOTIMPL;
+    const BOOL Background = !pdtobj;
+
+    switch (uMsg)
+    {
+        case DFM_MODIFYQCMFLAGS:
+        {
+            *((UINT*)lParam) = wParam | CMF_NOVERBS | (Background ? 0 : 
CMF_VERBSONLY);
+            return S_OK;
+        }
+
+        case DFM_MERGECONTEXTMENU:
+        {
+            QCMINFO &qcmi = *(QCMINFO*)lParam;
+            UINT pos = qcmi.indexMenu, id = 0;
+            if (Background || SUCCEEDED(hr = InsertMenuItem(qcmi, pos, id, 
IDC_EXTRACT, IDS_EXTRACT, MFS_DEFAULT)))
+            {
+                hr = InsertMenuItem(qcmi, pos, id, IDC_EXTRACTALL, 
IDS_EXTRACTALL);
+                if (SUCCEEDED(hr) && !Background)
+                {
+                    --pos;
+                    InsertMenuItem(qcmi, pos, id, 0, -1); // Separator
+                }
+            }
+            if (SUCCEEDED(hr))
+            {
+                qcmi.idCmdFirst = id + 1;
+                hr = S_FALSE; // Don't add verbs
+            }
+            break;
+        }
+
+        case DFM_INVOKECOMMAND:
+        {
+            hr = S_FALSE;
+            CCabFolder *pCabFolder = static_cast<CCabFolder*>(psf);
+            switch (wParam)
+            {
+                case IDC_EXTRACT:
+                case IDC_EXTRACTALL:
+                    hr = pCabFolder->ExtractFilesUI(hwnd, wParam == 
IDC_EXTRACT ? pdtobj : NULL);
+                    break;
+            }
+            break;
+        }
+    }
+    return hr;
+}
+
+static HRESULT CALLBACK FolderBackgroundMenuCallback(IShellFolder *psf, HWND 
hwnd,
+                                                     IDataObject *pdtobj, UINT 
uMsg,
+                                                     WPARAM wParam, LPARAM 
lParam)
+{
+    return ItemMenuCallback(psf, hwnd, NULL, uMsg, wParam, lParam);
+}
+
+int CEnumIDList::FindNamedItem(PCUITEMID_CHILD pidl) const
+{
+    CABITEM *needle = (CABITEM*)pidl;
+    for (ULONG i = 0, c = GetCount(); i < c; ++i)
+    {
+        CABITEM *item = (CABITEM*)DPA_FastGetPtr(m_Items, i);
+        if (!lstrcmpiW(needle->Path, item->Path))
+            return i;
+    }
+    return -1;
+}
+
+struct FILLCALLBACKDATA
+{
+    CEnumIDList *pEIDL;
+    SHCONTF ContF;
+};
+
+static HRESULT CALLBACK EnumFillCallback(EXTRACTCALLBACKMSG msg, const 
EXTRACTCALLBACKDATA &ecd, LPVOID cookie)
+{
+    FILLCALLBACKDATA &data = *(FILLCALLBACKDATA*)cookie;
+
+    switch ((UINT)msg)
+    {
+        case ECM_FILE:
+        {
+            const FDINOTIFICATION &fdin = *ecd.pfdin;
+            HRESULT hr = S_FALSE;
+            SFGAOF attr = MapFSToSFAttributes(fdin.attribs & CABITEM::FSATTS);
+            if (IncludeInEnumIDList(data.ContF, attr))
+            {
+                UINT datetime = MAKELONG(fdin.time, fdin.date);
+                CABITEM *item = CreateItem(fdin.psz1, fdin.attribs, fdin.cb, 
datetime);
+                if (!item)
+                    return E_OUTOFMEMORY;
+                if (FAILED(hr = data.pEIDL->Append((LPCITEMIDLIST)item)))
+                    SHFree(item);
+            }
+            return SUCCEEDED(hr) ? S_FALSE : hr; // Never extract
+        }
+    }
+    return E_NOTIMPL;
+}
+
+HRESULT CEnumIDList::Fill(LPCWSTR path, HWND hwnd, SHCONTF contf)
+{
+    FILLCALLBACKDATA data = { this, contf };
+    return ExtractCabinet(path, NULL, EnumFillCallback, &data);
+}
+
+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);
+}
+
+IFACEMETHODIMP CCabFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG 
*pDisplay)
+{
+    if (pSort)
+        *pSort = COL_NAME;
+    if (pDisplay)
+        *pDisplay = COL_NAME;
+    return S_OK;
+}
+
+IFACEMETHODIMP CCabFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF 
*pcsFlags)
+{
+    if (!pcsFlags || iColumn >= _countof(g_Columns))
+        return E_INVALIDARG;
+    *pcsFlags = g_Columns[iColumn].ColFlags;
+    return S_OK;
+}
+
+IFACEMETHODIMP CCabFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD 
dwFlags, LPSTRRET pName)
+{
+    CABITEM *item = CABITEM::Validate(pidl);
+    if (!item || !pName)
+        return E_INVALIDARG;
+
+    if (dwFlags & SHGDN_FORPARSING)
+    {
+        if (dwFlags & SHGDN_INFOLDER)
+            return StrTo(FLATFOLDER ? item->Path : item->GetName(), *pName);
+
+        WCHAR parent[MAX_PATH];
+        if (!SHGetPathFromIDListW(m_CurDir, parent))
+            return E_FAIL;
+        UINT cch = lstrlenW(parent) + 1 + lstrlenW(item->Path) + 1;
+        pName->uType = STRRET_WSTR;
+        pName->pOleStr = (LPWSTR)SHAlloc(cch * sizeof(WCHAR));
+        if (!pName->pOleStr)
+            return E_OUTOFMEMORY;
+        lstrcpyW(pName->pOleStr, parent);
+        PathAppendW(pName->pOleStr, item->Path);
+        return S_OK;
+    }
+
+    SHFILEINFO fi;
+    DWORD attr = item->IsFolder() ? FILE_ATTRIBUTE_DIRECTORY : 0;
+    UINT flags = SHGFI_DISPLAYNAME | SHGFI_USEFILEATTRIBUTES;
+    if (SHGetFileInfo(item->GetName(), attr, &fi, sizeof(fi), flags))
+        return StrTo(fi.szDisplayName, *pName);
+    return StrTo(item->GetName(), *pName);
+}
+
+HRESULT CCabFolder::GetItemDetails(PCUITEMID_CHILD pidl, UINT iColumn, 
SHELLDETAILS *psd, VARIANT *pv)
+{
+    HRESULT hr = E_FAIL;
+    STRRET *psr = &psd->str, srvar;
+    CABITEM *item = CABITEM::Validate(pidl);
+    if (!item)
+        return E_INVALIDARG;
+
+    switch (iColumn)
+    {
+        case COL_NAME:
+        {
+            hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, pv ? 
&srvar : psr);
+            return SUCCEEDED(hr) && pv ? StrRetToVariantBSTR(&srvar, *pv) : hr;
+        }
+
+        case COL_SIZE:
+        {
+            UINT data = item->Size;
+            if (pv)
+            {
+                V_VT(pv) = VT_UI4;
+                V_UI4(pv) = data;
+            }
+            else
+            {
+                psr->uType = STRRET_CSTR;
+                StrFormatByteSizeA(data, psr->cStr, _countof(psr->cStr));
+            }
+            return S_OK;
+        }
+
+        case COL_TYPE:
+        {
+            SHFILEINFO fi;
+            LPCWSTR data = fi.szTypeName;
+            DWORD attr = item->GetFSAttributes();
+            UINT flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES;
+            if (SHGetFileInfo(item->GetName(), attr, &fi, sizeof(fi), flags))
+                return pv ? StrTo(data, *pv) : StrTo(data, *psr);
+            break;
+        }
+
+        case COL_MDATE:
+        {
+            if (pv)
+            {
+                if (DosDateTimeToVariantTime(item->Date, item->Time, 
&V_DATE(pv)))
+                {
+                    V_VT(pv) = VT_DATE;
+                    return S_OK;
+                }
+            }
+            else
+            {
+                FILETIME utc, loc;
+                if (DosDateTimeToFileTime(item->Date, item->Time, &utc) && 
FileTimeToLocalFileTime(&utc, &loc))
+                {
+                    psr->uType = STRRET_CSTR;
+                    if (SHFormatDateTimeA(&loc, NULL, psr->cStr, 
_countof(psr->cStr)))
+                    {
+                        return S_OK;
+                    }
+                }
+            }
+            break;
+        }
+
+        case COL_PATH:
+        {
+            UINT len = item->NameOffset ? item->NameOffset - 1 : 0;
+            return pv ? StrTo(item->Path, len, *pv) : StrTo(item->Path, len, 
*psr);
+        }
+
+        case COL_ATT:
+        {
+            UINT data = item->GetFSAttributes();
+            if (pv)
+            {
+                V_VT(pv) = VT_UI4;
+                V_UI4(pv) = data;
+            }
+            else
+            {
+                UINT i = 0;
+                psr->uType = STRRET_CSTR;
+                if (data & FILE_ATTRIBUTE_READONLY) psr->cStr[i++] = 'R';
+                if (data & FILE_ATTRIBUTE_HIDDEN) psr->cStr[i++] = 'H';
+                if (data & FILE_ATTRIBUTE_SYSTEM) psr->cStr[i++] = 'S';
+                if (data & FILE_ATTRIBUTE_ARCHIVE) psr->cStr[i++] = 'A';
+                psr->cStr[i++] = '\0';
+            }
+            return S_OK;
+        }
+    }
+    return hr;
+}
+
+IFACEMETHODIMP CCabFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID 
*pscid, VARIANT *pv)
+{
+    if (!pscid || !pv)
+        return E_INVALIDARG;
+
+    CABITEM *item;
+    int col = MapSCIDToColumn(*pscid);
+    if (col >= 0)
+    {
+        return GetItemDetails(pidl, col, NULL, pv);
+    }
+    else if ((item = CABITEM::Validate(pidl)) == NULL)
+    {
+        return E_INVALIDARG;
+    }
+    else if (IsEqual(*pscid, FMTID_ShellDetails, PID_FINDDATA))
+    {
+        WIN32_FIND_DATA wfd;
+        ZeroMemory(&wfd, sizeof(wfd));
+        wfd.dwFileAttributes = item->GetFSAttributes();
+        wfd.nFileSizeLow = item->Size;
+        DosDateTimeToFileTime(item->Date, item->Time, &wfd.ftLastWriteTime);
+        lstrcpyn(wfd.cFileName, item->GetName(), MAX_PATH);
+        return InitVariantFromBuffer(&wfd, sizeof(wfd), pv);
+    }
+    return E_FAIL;
+}
+
+IFACEMETHODIMP CCabFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, 
SHELLDETAILS *psd)
+{
+    if (!psd || iColumn >= _countof(g_Columns))
+    {
+        return E_INVALIDARG;
+    }
+    else if (!pidl)
+    {
+        psd->fmt = g_Columns[iColumn].LvcFmt;
+        psd->cxChar = g_Columns[iColumn].LvcChars;
+        WCHAR buf[MAX_PATH];
+        if (LoadStringW(_AtlBaseModule.GetResourceInstance(), 
g_Columns[iColumn].TextId, buf, _countof(buf)))
+            return StrTo(buf, psd->str);
+        return E_FAIL;
+    }
+    return GetItemDetails(pidl, iColumn, psd, NULL);
+}
+
+int CCabFolder::MapSCIDToColumn(const SHCOLUMNID &scid)
+{
+    for (UINT i = 0; i < _countof(g_Columns); ++i)
+    {
+        if (g_Columns[i].pkg && IsEqual(scid, *g_Columns[i].pkg, 
g_Columns[i].pki))
+            return i;
+    }
+    return -1;
+}
+
+IFACEMETHODIMP CCabFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+    if (column < _countof(g_Columns) && g_Columns[column].pkg)
+    {
+        pscid->fmtid = *g_Columns[column].pkg;
+        pscid->pid = g_Columns[column].pki;
+        return S_OK;
+    }
+    return E_FAIL;
+}
+
+IFACEMETHODIMP CCabFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, 
LPENUMIDLIST *ppEnumIDList)
+{
+    CEnumIDList *p = CEnumIDList::CreateInstance();
+    *ppEnumIDList = static_cast<LPENUMIDLIST>(p);
+    return p ? p->Fill(m_CurDir, hwndOwner, dwFlags) : E_OUTOFMEMORY;
+}
+
+IFACEMETHODIMP CCabFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC 
pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+    UNIMPLEMENTED;
+    return E_NOTIMPL;
+}
+
+HRESULT CCabFolder::CompareID(LPARAM lParam, PCUITEMID_CHILD pidl1, 
PCUITEMID_CHILD pidl2)
+{
+    CABITEM *p1 = (CABITEM*)pidl1, *p2 = (CABITEM*)pidl2;
+    HRESULT hr = S_OK;
+    int ret = 0;
+
+    if (lParam & (SHCIDS_ALLFIELDS | SHCIDS_CANONICALONLY))
+    {
+        ret = lstrcmpiW(p1->Path, p2->Path);
+        if (ret && (lParam & SHCIDS_ALLFIELDS))
+        {
+            for (UINT i = 0; ret && SUCCEEDED(hr) && i < COLCOUNT; ++i)
+            {
+                hr = (i == COL_NAME) ? 0 : CompareID(i, pidl1, pidl2);
+                ret = (short)HRESULT_CODE(hr);
+            }
+        }
+    }
+    else
+    {
+        UINT col = lParam & SHCIDS_COLUMNMASK;
+        switch (col)
+        {
+            case COL_NAME:
+                ret = StrCmpLogicalW(p1->GetName(), p2->GetName());
+                break;
+
+            case COL_SIZE:
+                ret = p1->Size - p2->Size;
+                break;
+
+            case COL_MDATE:
+                ret = MAKELONG(p1->Time, p1->Date) - MAKELONG(p2->Time, 
p2->Date);
+                break;
+
+            default:
+            {
+                if (col < COLCOUNT)
+                {
+                    PWSTR str1, str2;
+                    if (SUCCEEDED(hr = ::GetDetailsOf(*this, pidl1, col, 
str1)))
+                    {
+                        if (SUCCEEDED(hr = ::GetDetailsOf(*this, pidl2, col, 
str2)))
+                        {
+                            ret = StrCmpLogicalW(str1, str2);
+                            SHFree(str2);
+                        }
+                        SHFree(str1);
+                    }
+                }
+                else
+                {
+                    hr = E_INVALIDARG;
+                }
+            }
+        }
+    }
+    return SUCCEEDED(hr) ? MAKE_COMPARE_HRESULT(ret) : hr;
+}
+
+IFACEMETHODIMP CCabFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, 
PCUIDLIST_RELATIVE pidl2)
+{
+    C_ASSERT(FLATFOLDER);
+    if (!pidl1 || !ILIsSingle(pidl1) || !pidl2 || !ILIsSingle(pidl2))
+        return E_UNEXPECTED;
+
+    return CompareID(lParam, pidl1, pidl2);
+}
+
+IFACEMETHODIMP CCabFolder::CreateViewObject(HWND hwndOwner, REFIID riid, 
LPVOID *ppv)
+{
+    if (riid == IID_IShellView)
+    {
+        SFV_CREATE sfvc = { sizeof(SFV_CREATE), 
static_cast<IShellFolder*>(this) };
+        return SHCreateShellFolderView(&sfvc, (IShellView**)ppv);
+    }
+    if (riid == IID_IContextMenu)
+    {
+        LPFNDFMCALLBACK func = FolderBackgroundMenuCallback;
+        IContextMenu **ppCM = (IContextMenu**)ppv;
+        return CDefFolderMenu_Create2(m_CurDir, hwndOwner, 0, NULL, this, 
func, 0, NULL, ppCM);
+    }
+    return E_NOINTERFACE;
+}
+
+IFACEMETHODIMP CCabFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY 
apidl, SFGAOF *rgfInOut)
+{
+    if (!cidl)
+    {
+        const SFGAOF ThisFolder = (SFGAO_FOLDER | SFGAO_BROWSABLE | 
SFGAO_CANLINK);
+        *rgfInOut = *rgfInOut & ThisFolder;
+        return S_OK;
+    }
+    else if (!apidl)
+    {
+        return E_INVALIDARG;
+    }
+    HRESULT hr = S_OK;
+    const SFGAOF filemask = SFGAO_READONLY | SFGAO_HIDDEN | SFGAO_SYSTEM | 
SFGAO_ISSLOW;
+    SFGAOF remain = *rgfInOut & filemask, validate = *rgfInOut & 
SFGAO_VALIDATE;
+    CComPtr<CEnumIDList> list;
+    for (UINT i = 0; i < cidl && (remain || validate); ++i)
+    {
+        CABITEM *item = CABITEM::Validate(apidl[i]);
+        if (!item)
+        {
+            hr = E_INVALIDARG;
+            break;
+        }
+        else if (validate)
+        {
+            if (!list && FAILED_UNEXPECTEDLY(hr = CreateEnum(&list)))
+                return hr;
+            if (list->FindNamedItem((PCUITEMID_CHILD)item) == -1)
+                return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+        }
+        SFGAOF att = MapFSToSFAttributes(item->GetFSAttributes()) | 
SFGAO_ISSLOW;
+        remain &= att & ~(FLATFOLDER ? SFGAO_FOLDER : 0);
+    }
+    *rgfInOut = remain;
+    return hr;
+}
+
+IFACEMETHODIMP CCabFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, 
PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
+{
+    HRESULT hr = E_NOINTERFACE;
+    if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
+    {
+        if (cidl != 1)
+            return E_INVALIDARG;
+        CABITEM *item = CABITEM::Validate(apidl[0]);
+        if (!item)
+            return E_INVALIDARG;
+
+        DWORD attr = item->GetFSAttributes();
+        return SHCreateFileExtractIconW(item->GetName(), attr, riid, ppvOut);
+    }
+    else if (riid == IID_IContextMenu && cidl)
+    {
+        LPFNDFMCALLBACK func = ItemMenuCallback;
+        IContextMenu **ppCM = (IContextMenu**)ppvOut;
+        return CDefFolderMenu_Create2(NULL, hwndOwner, cidl, apidl, this, 
func, 0, NULL, ppCM);
+    }
+    else if (riid == IID_IDataObject && cidl)
+    {
+        // Note: This IDataObject is only compatible with IContextMenu, it 
cannot handle drag&drop of virtual items!
+        return CIDLData_CreateFromIDArray(m_CurDir, cidl, apidl, 
(IDataObject**)ppvOut);
+    }
+    return hr;
+}
+
+IFACEMETHODIMP CCabFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM 
lParam)
+{
+    switch (uMsg)
+    {
+        case SFVM_WINDOWCREATED:
+            m_ShellViewWindow = (HWND)wParam;
+            return S_OK;
+        case SFVM_WINDOWCLOSING:
+            m_ShellViewWindow = NULL;
+            return S_OK;
+    }
+    return E_NOTIMPL;
+}
+
+IFACEMETHODIMP CCabFolder::GetIconOf(PCUITEMID_CHILD pidl, UINT flags, int 
*pIconIndex)
+{
+    if (CABITEM *item = CABITEM::Validate(pidl))
+    {
+        int index = MapPIDLToSystemImageListIndex(this, pidl, flags);
+        if (index == -1 && item->IsFolder())
+            index = (flags & GIL_OPENICON) ? SIID_FOLDEROPEN : SIID_FOLDER;
+        if (index != -1)
+        {
+            *pIconIndex = index;
+            return S_OK;
+        }
+    }
+    return S_FALSE;
+}
+
+static HRESULT GetFsPathFromIDList(PCIDLIST_ABSOLUTE pidl, PWSTR pszPath)
+{
+    BOOL ret = SHGetPathFromIDListW(pidl, pszPath);
+    if (!ret && ILIsEmpty(pidl))
+        ret = SHGetSpecialFolderPathW(NULL, pszPath, CSIDL_DESKTOPDIRECTORY, 
TRUE);
+    return ret ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+}
+
+static int CALLBACK FolderBrowseCallback(HWND hwnd, UINT uMsg, LPARAM lParam, 
LPARAM lpData)
+{
+    WCHAR buf[MAX_PATH];
+    switch (uMsg)
+    {
+        case BFFM_INITIALIZED:
+        {
+            if (LoadStringW(_AtlBaseModule.GetResourceInstance(), IDS_EXTRACT, 
buf, _countof(buf)))
+            {
+                // Remove leading and trailing dots
+                WCHAR *s = buf, *e = s + lstrlenW(s);
+                while (*s == '.') ++s;
+                while (e > s && e[-1] == '.') *--e = UNICODE_NULL;
+                SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)s);
+                SendMessageW(GetDlgItem(hwnd, IDOK), WM_SETTEXT, 0, (LPARAM)s);
+            }
+            if (lpData)
+            {
+                SendMessageW(hwnd, BFFM_SETEXPANDED, FALSE, lpData);
+                SendMessageW(hwnd, BFFM_SETSELECTION, FALSE, lpData);
+            }
+            break;
+        }
+
+        case BFFM_SELCHANGED:
+        {
+            SFGAOF wanted = SFGAO_FILESYSTEM | SFGAO_FOLDER, query = wanted | 
SFGAO_STREAM;
+            PCIDLIST_ABSOLUTE pidl = (PCIDLIST_ABSOLUTE)lParam;
+            BOOL enable = ILIsEmpty(pidl); // Allow the desktop
+            PCUITEMID_CHILD child;
+            IShellFolder *pSF;
+            if (SUCCEEDED(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, 
&pSF), &child)))
+            {
+                SFGAOF attrib = query;
+                if (SUCCEEDED(pSF->GetAttributesOf(1, &child, &attrib)))
+                    enable = (attrib & query) == wanted;
+                pSF->Release();
+            }
+            if (enable)
+            {
+                // We don't trust .zip folders, check the file-system to make 
sure
+                UINT attrib = SUCCEEDED(GetFsPathFromIDList(pidl, buf)) ? 
GetFileAttributesW(buf) : 0;
+                enable = (attrib & FILE_ATTRIBUTE_DIRECTORY) && attrib != 
INVALID_FILE_ATTRIBUTES;
+            }
+            PostMessageW(hwnd, BFFM_ENABLEOK, 0, enable);
+            break;
+        }
+    }
+    return 0;
+}
+
+struct EXTRACTFILESDATA
+{
+    CCabFolder *pLifetimeCF;
+    HWND hWndOwner;
+    CIDA *pCIDA;
+    STGMEDIUM cidamedium;
+    IDataObject *pDO;
+    IStream *pMarshalDO;
+    IProgressDialog *pPD;
+    UINT cabfiles, completed;
+    WCHAR path[MAX_PATH], cab[MAX_PATH];
+};
+
+static HWND GetUiOwner(const EXTRACTFILESDATA &data)
+{
+    HWND hWnd;
+    if (SUCCEEDED(IUnknown_GetWindow(data.pPD, &hWnd)) && 
IsWindowVisible(hWnd))
+        return hWnd;
+    return IsWindowVisible(data.hWndOwner) ? data.hWndOwner : NULL;
+}
+
+static HRESULT CALLBACK ExtractFilesCallback(EXTRACTCALLBACKMSG msg, const 
EXTRACTCALLBACKDATA &ecd, LPVOID cookie)
+{
+    EXTRACTFILESDATA &data = *(EXTRACTFILESDATA*)cookie;
+    switch ((UINT)msg)
+    {
+        case ECM_BEGIN:
+        {
+            data.cabfiles = (UINT)(SIZE_T)ecd.pfdin->hf;
+            return S_OK;
+        }
+
+        case ECM_FILE:
+        {
+            if (data.pPD && data.pPD->HasUserCancelled())
+                return HRESULT_FROM_WIN32(ERROR_CANCELLED);
+            HRESULT hr = data.pCIDA ? S_FALSE : S_OK; // Filtering or all 
items?
+            if (hr != S_OK)
+            {
+                CABITEM *needle = CreateItem(ecd.pfdin->psz1, 
ecd.pfdin->attribs);
+                if (!needle)
+                    return E_OUTOFMEMORY;
+                for (UINT i = 0; i < data.pCIDA->cidl && hr == S_FALSE; ++i)
+                {
+                    C_ASSERT(FLATFOLDER);
+                    LPCITEMIDLIST pidlChild = 
ILFindLastID(HIDA_GetPIDLItem(data.pCIDA, i));
+                    CABITEM *haystack = CABITEM::Validate(pidlChild);
+                    if (!haystack && FAILED_UNEXPECTEDLY(hr = E_FAIL))
+                        break;
+                    if (!lstrcmpiW(needle->Path, haystack->Path))
+                    {
+                        if (data.pPD)
+                            data.pPD->SetLine(1, needle->Path, TRUE, NULL);
+                        hr = S_OK; // Found it in the list of files to extract
+                    }
+                }
+                SHFree(needle);
+            }
+            if (data.pPD)
+                data.pPD->SetProgress(data.completed++, data.cabfiles);
+            return hr;
+        }
+
+        case ECM_PREPAREPATH:
+        {
+            UINT flags = SHPPFW_DIRCREATE | SHPPFW_IGNOREFILENAME;
+            return SHPathPrepareForWriteW(GetUiOwner(data), NULL, ecd.Path, 
flags);
+        }
+
+        case ECM_ERROR:
+        {
+            return ErrorBox(GetUiOwner(data), ecd.hr);
+        }
+    }
+    return E_NOTIMPL;
+}
+
+static void Free(EXTRACTFILESDATA &data)
+{
+    if (data.pPD)
+    {
+        data.pPD->StopProgressDialog();
+        data.pPD->Release();
+    }
+    CDataObjectHIDA::DestroyCIDA(data.pCIDA, data.cidamedium);
+    IUnknown_Set((IUnknown**)&data.pDO, NULL);
+    IUnknown_Set((IUnknown**)&data.pMarshalDO, NULL);
+    IUnknown_Set((IUnknown**)&data.pLifetimeCF, NULL);
+    SHFree(&data);
+}
+
+static DWORD CALLBACK ExtractFilesThread(LPVOID pParam)
+{
+    EXTRACTFILESDATA &data = *(EXTRACTFILESDATA*)pParam;
+    HRESULT hr = S_OK;
+    if (SUCCEEDED(SHCoCreateInstance(NULL, &CLSID_ProgressDialog, NULL, 
IID_PPV_ARG(IProgressDialog, &data.pPD))))
+    {
+        // TODO: IActionProgress SPACTION_COPYING
+        if (SUCCEEDED(data.pPD->StartProgressDialog(data.hWndOwner, NULL, 
PROGDLG_NOTIME, NULL)))
+        {
+            data.pPD->SetTitle(data.cab);
+            data.pPD->SetLine(2, data.path, TRUE, NULL);
+            data.pPD->SetAnimation(GetModuleHandleW(L"SHELL32"), 161);
+            data.pPD->SetProgress(0, 0);
+        }
+    }
+    if (data.pMarshalDO)
+    {
+        hr = CoGetInterfaceAndReleaseStream(data.pMarshalDO, 
IID_PPV_ARG(IDataObject, &data.pDO));
+        data.pMarshalDO = NULL;
+        if (SUCCEEDED(hr))
+            hr = CDataObjectHIDA::CreateCIDA(data.pDO, &data.pCIDA, 
data.cidamedium);
+    }
+    if (SUCCEEDED(hr))
+    {
+        ExtractCabinet(data.cab, data.path, ExtractFilesCallback, &data);
+    }
+    Free(data);
+    return 0;
+}
+
+HRESULT CCabFolder::ExtractFilesUI(HWND hWnd, IDataObject *pDO)
+{
+    if (!IsWindowVisible(hWnd) && IsWindowVisible(m_ShellViewWindow))
+        hWnd = m_ShellViewWindow;
+
+    EXTRACTFILESDATA *pData = (EXTRACTFILESDATA*)SHAlloc(sizeof(*pData));
+    if (!pData)
+        return E_OUTOFMEMORY;
+    ZeroMemory(pData, sizeof(*pData));
+    pData->hWndOwner = hWnd;
+    pData->pLifetimeCF = this;
+    pData->pLifetimeCF->AddRef();
+
+    HRESULT hr = GetFsPathFromIDList(m_CurDir, pData->cab);
+    if (SUCCEEDED(hr) && pDO)
+    {
+        hr = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDO, 
&pData->pMarshalDO);
+    }
+    if (SUCCEEDED(hr))
+    {
+        hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
+        LPITEMIDLIST pidlInitial = ILClone(m_CurDir);
+        ILRemoveLastID(pidlInitial); // Remove the "name.cab" part (we can't 
extract into ourselves)
+        UINT bif = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
+        BROWSEINFO bi = { hWnd, NULL, NULL, pData->cab, bif, 
FolderBrowseCallback, (LPARAM)pidlInitial };
+        if (PIDLIST_ABSOLUTE folder = SHBrowseForFolderW(&bi))
+        {
+            hr = GetFsPathFromIDList(folder, pData->path);
+            ILFree(folder);
+            if (SUCCEEDED(hr))
+            {
+                UINT ctf = CTF_COINIT | CTF_PROCESS_REF | CTF_THREAD_REF | 
CTF_FREELIBANDEXIT;
+                hr = SHCreateThread(ExtractFilesThread, pData, ctf, NULL) ? 
S_OK : E_OUTOFMEMORY;
+            }
+        }
+        ILFree(pidlInitial);
+    }
+    if (hr != S_OK)
+        Free(*pData);
+    return hr == HRESULT_FROM_WIN32(ERROR_CANCELLED) ? S_OK : hr;
+}
diff --git a/dll/shellext/cabview/lang/de-DE.rc 
b/dll/shellext/cabview/lang/de-DE.rc
new file mode 100644
index 00000000000..3951491271b
--- /dev/null
+++ b/dll/shellext/cabview/lang/de-DE.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     German (Germany) resource file
+ * TRANSLATOR:  Copyright 2018 Robert Naumann <gonzo...@gmail.com>
+ */
+
+LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Name"
+    IDS_COL_TYPE    "Dateityp"
+    IDS_COL_SIZE    "Größe"
+    IDS_COL_MDATE   "Änderungsdatum"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/en-US.rc 
b/dll/shellext/cabview/lang/en-US.rc
new file mode 100644
index 00000000000..4205c4912dc
--- /dev/null
+++ b/dll/shellext/cabview/lang/en-US.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     English (United States) resource file
+ * TRANSLATOR:  Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Name"
+    IDS_COL_SIZE    "Size"
+    IDS_COL_TYPE    "Type"
+    IDS_COL_MDATE   "Date modified"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/et-EE.rc 
b/dll/shellext/cabview/lang/et-EE.rc
new file mode 100644
index 00000000000..bd1cd3029d9
--- /dev/null
+++ b/dll/shellext/cabview/lang/et-EE.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Estonian resource file
+ * TRANSLATOR:  Copyright 2018 Joann Mõndresku <joann.mondre...@gmail.com>
+ */
+
+LANGUAGE LANG_ESTONIAN, SUBLANG_DEFAULT
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Nimi"
+    IDS_COL_TYPE    "Tüüp"
+    IDS_COL_SIZE    "Suurus"
+    IDS_COL_MDATE   "Kuupäeval muudetud"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/fr-FR.rc 
b/dll/shellext/cabview/lang/fr-FR.rc
new file mode 100644
index 00000000000..5c848d20827
--- /dev/null
+++ b/dll/shellext/cabview/lang/fr-FR.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     French (France) resource file
+ * TRANSLATOR:  Copyright 2018 Pierre Schweitzer <pie...@reactos.org>
+ */
+
+LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Nom"
+    IDS_COL_TYPE    "Type"
+    IDS_COL_SIZE    "Taille"
+    IDS_COL_MDATE   "Date de modification"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/hi-IN.rc 
b/dll/shellext/cabview/lang/hi-IN.rc
new file mode 100644
index 00000000000..943076df123
--- /dev/null
+++ b/dll/shellext/cabview/lang/hi-IN.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Hindi (India) resource file
+ * TRANSLATOR:  Copyright 2019 Arnav Bhatt <arnavbhatt2...@gmail.com>
+*/
+
+LANGUAGE LANG_HINDI, SUBLANG_HINDI_INDIA
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "नाम"
+    IDS_COL_TYPE    "प्रकार"
+    IDS_COL_SIZE    "साइज़"
+    IDS_COL_MDATE   "तिथि संशोधित"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/it-IT.rc 
b/dll/shellext/cabview/lang/it-IT.rc
new file mode 100644
index 00000000000..912949f98df
--- /dev/null
+++ b/dll/shellext/cabview/lang/it-IT.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Italian resource file
+ * TRANSLATOR:  Copyright 2018 George Bișoc <george.bi...@reactos.org>
+ */
+
+LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Nome"
+    IDS_COL_TYPE    "Tipo"
+    IDS_COL_SIZE    "Dimensione"
+    IDS_COL_MDATE   "Data modificata"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/ja-JP.rc 
b/dll/shellext/cabview/lang/ja-JP.rc
new file mode 100644
index 00000000000..fcc6dc8d90e
--- /dev/null
+++ b/dll/shellext/cabview/lang/ja-JP.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Japanese resource file
+ * TRANSLATOR:  Copyright 2018 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
+ */
+
+LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "名前"
+    IDS_COL_TYPE    "種類"
+    IDS_COL_SIZE    "サイズ"
+    IDS_COL_MDATE   "変更日"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/pl-PL.rc 
b/dll/shellext/cabview/lang/pl-PL.rc
new file mode 100644
index 00000000000..0d6fb1ba41a
--- /dev/null
+++ b/dll/shellext/cabview/lang/pl-PL.rc
@@ -0,0 +1,22 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Polish resource file
+ * TRANSLATORS: Copyright 2018-2019 Adam Słaboń <asaillen456...@gmail.com>
+ *              Copyright 2020 Piotr Hetnarowicz <piotr...@gmail.com>
+ */
+
+LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Nazwa"
+    IDS_COL_TYPE    "Typ"
+    IDS_COL_SIZE    "Rozmiar oryginalny"
+    IDS_COL_MDATE   "Data modyfikacji"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/pt-PT.rc 
b/dll/shellext/cabview/lang/pt-PT.rc
new file mode 100644
index 00000000000..9671f14a3bf
--- /dev/null
+++ b/dll/shellext/cabview/lang/pt-PT.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Portuguese (Portugal) resource file
+ * TRANSLATOR:  Copyright 2020 Jose Carlos Jesus <zecarlos1...@hotmail.com>
+ */
+
+LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Nome"
+    IDS_COL_TYPE    "Tipo"
+    IDS_COL_SIZE    "Tamanho"
+    IDS_COL_MDATE   "Data da modificação"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/ro-RO.rc 
b/dll/shellext/cabview/lang/ro-RO.rc
new file mode 100644
index 00000000000..9e9c0684fd3
--- /dev/null
+++ b/dll/shellext/cabview/lang/ro-RO.rc
@@ -0,0 +1,22 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Romanian resource file
+ * TRANSLATORS: Copyright 2018 George Bișoc <george.bi...@reactos.org>
+ *              Copyright 2022-2024 Andrei Miloiu <miloiuand...@gmail.com>
+ */
+
+LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Nume"
+    IDS_COL_TYPE    "Tip"
+    IDS_COL_SIZE    "Dimensiune"
+    IDS_COL_MDATE   "Data modificată"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/ru-RU.rc 
b/dll/shellext/cabview/lang/ru-RU.rc
new file mode 100644
index 00000000000..e377821fcb3
--- /dev/null
+++ b/dll/shellext/cabview/lang/ru-RU.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Russian resource translation
+ * TRANSLATOR:  Copyright 2018-2020 Stanislav Motylkov <x86co...@gmail.com>
+ */
+
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Название"
+    IDS_COL_TYPE    "Тип"
+    IDS_COL_SIZE    "Размер"
+    IDS_COL_MDATE   "Дата изменения"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/sv-SE.rc 
b/dll/shellext/cabview/lang/sv-SE.rc
new file mode 100644
index 00000000000..f65e8352d64
--- /dev/null
+++ b/dll/shellext/cabview/lang/sv-SE.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Swedish resource file
+ * TRANSLATOR:  Copyright 2018 Andreas Bjerkeholt 
<andreas.bjerkeh...@reactos.org>
+ */
+
+LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "Namn"
+    IDS_COL_TYPE    "Typ"
+    IDS_COL_SIZE    "Storlek"
+    IDS_COL_MDATE   "Ändrad den"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extrahera..."
+    IDS_EXTRACTALL  "Extrahera &alla..."
+END
diff --git a/dll/shellext/cabview/lang/tr-TR.rc 
b/dll/shellext/cabview/lang/tr-TR.rc
new file mode 100644
index 00000000000..e0d5a7a81bf
--- /dev/null
+++ b/dll/shellext/cabview/lang/tr-TR.rc
@@ -0,0 +1,21 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Turkish resource file
+ * TRANSLATOR:  Copyright 2021 Süleyman Poyraz <zaryob....@gmail.com>
+ */
+
+LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "İsim"
+    IDS_COL_TYPE    "Tür"
+    IDS_COL_SIZE    "Boyut"
+    IDS_COL_MDATE   "Değiştirilme Tarihi"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/zh-CN.rc 
b/dll/shellext/cabview/lang/zh-CN.rc
new file mode 100644
index 00000000000..3437d81d1b3
--- /dev/null
+++ b/dll/shellext/cabview/lang/zh-CN.rc
@@ -0,0 +1,22 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Chinese (Simplified) resource file
+ * TRANSLATORS: Copyright 2018 Li Keqing <auroracloud4...@gmail.com>
+ *              Copyright 2021 Wu Haotian <rigolig...@gmail.com>
+ */
+
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "名称"
+    IDS_COL_TYPE    "类型"
+    IDS_COL_SIZE    "大小"
+    IDS_COL_MDATE   "修改日期"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/zh-HK.rc 
b/dll/shellext/cabview/lang/zh-HK.rc
new file mode 100644
index 00000000000..a5969223b8d
--- /dev/null
+++ b/dll/shellext/cabview/lang/zh-HK.rc
@@ -0,0 +1,22 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Chinese (Hong Kong) resources file
+ * TRANSLATOR:  Copyright 2021 Chan Chilung <eason...@gmail.com>
+ * REFERENCES:  Chinese (Simplified) resource file
+ */
+
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_HONGKONG
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "名稱"
+    IDS_COL_TYPE    "類型"
+    IDS_COL_SIZE    "大小"
+    IDS_COL_MDATE   "修改日期"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/lang/zh-TW.rc 
b/dll/shellext/cabview/lang/zh-TW.rc
new file mode 100644
index 00000000000..bbe5accd92f
--- /dev/null
+++ b/dll/shellext/cabview/lang/zh-TW.rc
@@ -0,0 +1,23 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Chinese (Traditional) resource file
+ * TRANSLATOR:  Copyright 2020-2021 Chan Chilung <eason...@gmail.com>
+ * REFERENCES:  Chinese (Simplified) resource translation
+ *              Copyright 2018 Li Keqing <auroracloud4...@gmail.com>
+ */
+
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
+
+STRINGTABLE
+BEGIN
+    IDS_COL_NAME    "名稱"
+    IDS_COL_TYPE    "類型"
+    IDS_COL_SIZE    "大小"
+    IDS_COL_MDATE   "修改日期"
+    IDS_COL_PATH    "Path"
+    IDS_COL_ATT     "Attributes"
+
+    IDS_EXTRACT     "Extract..."
+    IDS_EXTRACTALL  "Extract &All..."
+END
diff --git a/dll/shellext/cabview/precomp.h b/dll/shellext/cabview/precomp.h
new file mode 100644
index 00000000000..d69f972a2e6
--- /dev/null
+++ b/dll/shellext/cabview/precomp.h
@@ -0,0 +1,34 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Precompiled header file
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#pragma once
+#define NTOS_MODE_USER
+#include <windows.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <strsafe.h>
+#include <shlobj.h>
+#include <shobjidl.h>
+#include <shlwapi.h>
+#include <shellapi.h>
+#include <shlguid_undoc.h>
+#define NTSTATUS LONG // for debug.h
+#include <reactos/debug.h>
+#include <shellutils.h>
+#include <ntquery.h>
+#include <fdi.h>
+
+#ifndef SFGAO_SYSTEM
+#define SFGAO_SYSTEM 0x00001000
+#endif
+
+#ifndef SHGSI_ICONLOCATION
+#define SIID_FOLDER 3
+#define SIID_FOLDEROPEN 4
+#endif
+
+EXTERN_C INT WINAPI SHFormatDateTimeA(const FILETIME UNALIGNED *fileTime, 
DWORD *flags, LPSTR buf, UINT size);
diff --git a/dll/shellext/cabview/res/cabview.rgs 
b/dll/shellext/cabview/res/cabview.rgs
new file mode 100644
index 00000000000..f9316200962
--- /dev/null
+++ b/dll/shellext/cabview/res/cabview.rgs
@@ -0,0 +1,47 @@
+HKCR
+{
+    NoRemove CLSID
+    {
+        '{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}' = s 'Cabinet Shell Folder'
+        {
+            InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' 
}
+            ShellFolder
+            {
+                val Attributes = d '0x680001a0'
+            }
+            'Implemented Categories'
+            {
+                '{00021490-0000-0000-C000-000000000046}'
+                {
+                }
+            }
+        }
+    }
+
+    NoRemove CABFolder
+    {
+        CLSID = s '{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}'
+        DefaultIcon = s '%MODULE%'
+
+        NoRemove Shell
+        {
+            NoRemove Open
+            {
+                val BrowserFlags = d '0x10'
+                val ExplorerFlags = d '0x20'
+                command = s '"explorer.exe" "%%L"'
+            }
+        }
+    }
+    NoRemove '.cab' = s 'CABFolder'
+    {
+    }
+
+    NoRemove SystemFileAssociations
+    {
+        '.cab'
+        {
+            CLSID = s '{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}'
+        }
+    }
+}
diff --git a/dll/shellext/cabview/res/folder.ico 
b/dll/shellext/cabview/res/folder.ico
new file mode 100644
index 00000000000..04f98dcb2fd
Binary files /dev/null and b/dll/shellext/cabview/res/folder.ico differ
diff --git a/dll/shellext/cabview/resource.h b/dll/shellext/cabview/resource.h
new file mode 100644
index 00000000000..b964a8c2c10
--- /dev/null
+++ b/dll/shellext/cabview/resource.h
@@ -0,0 +1,25 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Resource header file
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#pragma once
+
+/* Icons */
+#define IDI_FOLDER          1
+
+/* Registry */
+#define IDR_FOLDER          8000
+
+/* Strings */
+#define IDS_COL_NAME        1
+#define IDS_COL_SIZE        2
+#define IDS_COL_TYPE        3
+#define IDS_COL_MDATE       4
+#define IDS_COL_PATH        5
+#define IDS_COL_ATT         6
+
+#define IDS_EXTRACT         72
+#define IDS_EXTRACTALL      82
diff --git a/dll/shellext/cabview/util.h b/dll/shellext/cabview/util.h
new file mode 100644
index 00000000000..5f3d5e38196
--- /dev/null
+++ b/dll/shellext/cabview/util.h
@@ -0,0 +1,156 @@
+/*
+ * PROJECT:     ReactOS CabView Shell Extension
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Utility header file
+ * COPYRIGHT:   Copyright 2024 Whindmar Saksit <whinds...@proton.me>
+ */
+
+#pragma once
+
+template<class H> static int ErrorBox(H hWnd, int Error)
+{
+    SHELL_ErrorBox(hWnd, Error);
+    return Error;
+}
+
+template<class T> static inline bool IsPathSep(T c)
+{
+    return c == '\\' || c == '/';
+}
+
+inline bool IsEqual(const SHCOLUMNID &scid, REFGUID guid, UINT pid)
+{
+    return scid.pid == pid && IsEqualGUID(scid.fmtid, guid);
+}
+
+inline HRESULT InitVariantFromBuffer(const void *buffer, UINT cb, VARIANT *pv)
+{
+    SAFEARRAY *pa = SafeArrayCreateVector(VT_UI1, 0, cb);
+    if (pa)
+    {
+        CopyMemory(pa->pvData, buffer, cb);
+        V_VT(pv) = VT_UI1 | VT_ARRAY;
+        V_UNION(pv, parray) = pa;
+        return S_OK;
+    }
+    V_VT(pv) = VT_EMPTY;
+    return E_OUTOFMEMORY;
+}
+
+inline void FreeStrRet(STRRET &str)
+{
+    if (str.uType == STRRET_WSTR)
+    {
+        SHFree(str.pOleStr);
+        str.uType = STRRET_CSTR;
+    }
+}
+
+inline HRESULT StrTo(LPCWSTR str, UINT len, STRRET &sr)
+{
+    LPWSTR data = (LPWSTR)SHAlloc(++len * sizeof(WCHAR));
+    if (!data)
+        return E_OUTOFMEMORY;
+    lstrcpynW(data, str, len);
+    sr.uType = STRRET_WSTR;
+    sr.pOleStr = data;
+    return S_OK;
+}
+
+inline HRESULT StrTo(LPCWSTR str, STRRET &sr)
+{
+    return StrTo(str, lstrlenW(str), sr);
+}
+
+inline HRESULT StrTo(LPCWSTR str, UINT len, VARIANT &v)
+{
+    BSTR data = SysAllocStringLen(str, len);
+    if (!data)
+        return E_OUTOFMEMORY;
+    V_VT(&v) = VT_BSTR;
+    V_BSTR(&v) = data;
+    return S_OK;
+}
+
+inline HRESULT StrTo(LPCWSTR str, VARIANT &v)
+{
+    return StrTo(str, lstrlenW(str), v);
+}
+
+inline HRESULT StrRetToVariantBSTR(STRRET *psr, VARIANT &v)
+{
+    HRESULT hr = StrRetToBSTR(psr, NULL, &V_BSTR(&v));
+    if (SUCCEEDED(hr))
+        V_VT(&v) = VT_BSTR;
+    return hr;
+}
+
+inline HRESULT GetDetailsOf(IShellFolder2 &Folder, PCUITEMID_CHILD pidl, UINT 
Column, PWSTR &String)
+{
+    SHELLDETAILS details;
+    HRESULT hr = Folder.GetDetailsOf(pidl, Column, &details);
+    if (SUCCEEDED(hr))
+        hr = StrRetToStrW(&details.str, pidl, &String);
+    return hr;
+}
+
+inline HRESULT InsertMenuItem(QCMINFO &qcmi, UINT &Pos, UINT &TrackId, UINT 
Id, UINT ResId, int State = 0)
+{
+    UINT flags = 0;
+    WCHAR string[MAX_PATH];
+    string[0] = UNICODE_NULL;
+    if ((Id += qcmi.idCmdFirst) > qcmi.idCmdLast)
+        return E_FAIL;
+    else if (ResId == (UINT)-1)
+        flags |= MF_SEPARATOR;
+    else if (!LoadStringW(_AtlBaseModule.GetResourceInstance(), ResId, string, 
_countof(string)))
+        return E_FAIL;
+
+    MENUITEMINFOW mii;
+    mii.cbSize = FIELD_OFFSET(MENUITEMINFOW, hbmpItem); // USER32 version 
agnostic
+    mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_STATE;
+    mii.fType = flags;
+    mii.wID = Id;
+    mii.dwTypeData = string;
+    mii.cch = 0;
+    mii.fState = State;
+    if (!InsertMenuItemW(qcmi.hmenu, Pos, TRUE, &mii))
+        return E_FAIL;
+    Pos++;
+    TrackId = max(TrackId, Id);
+    return S_OK;
+}
+
+inline SFGAOF MapFSToSFAttributes(UINT att)
+{
+    return ((att & FILE_ATTRIBUTE_READONLY) ? SFGAO_READONLY : 0) |
+           ((att & FILE_ATTRIBUTE_HIDDEN) ? SFGAO_HIDDEN : 0) |
+           ((att & FILE_ATTRIBUTE_SYSTEM) ? SFGAO_SYSTEM : 0);
+}
+
+inline bool IncludeInEnumIDList(SHCONTF contf, SFGAOF att)
+{
+    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;
+}
+
+inline int MapPIDLToSystemImageListIndex(IShellFolder *pSF, PCUITEMID_CHILD 
pidl, UINT GilFlags = 0)
+{
+    int normal, open;
+    BOOL qopen = GilFlags & GIL_OPENICON;
+    normal = SHMapPIDLToSystemImageListIndex(pSF, pidl, qopen ? &open : NULL);
+    return qopen && open != -1 ? open : normal;
+}
diff --git a/dll/win32/browseui/CProgressDialog.cpp 
b/dll/win32/browseui/CProgressDialog.cpp
index 6d32d01ecb2..4f748b12057 100644
--- a/dll/win32/browseui/CProgressDialog.cpp
+++ b/dll/win32/browseui/CProgressDialog.cpp
@@ -44,6 +44,7 @@
 
 CProgressDialog::CProgressDialog()
 {
+    this->hwnd = NULL;
     this->lines[0]  = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, BUFFER_SIZE);
     this->lines[1]  = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, BUFFER_SIZE);
     this->lines[2]  = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, BUFFER_SIZE);
diff --git a/media/inf/syssetup.inf b/media/inf/syssetup.inf
index 14700f060e1..1ef4a04bc3d 100644
--- a/media/inf/syssetup.inf
+++ b/media/inf/syssetup.inf
@@ -52,6 +52,7 @@ AddReg=Classes
 11,,amstream.dll,1
 11,,avifil32.dll,1
 11,,browseui.dll,1
+11,,cabview.dll,1
 11,,comcat.dll,1
 11,,cryptdlg.dll,1
 11,,cryptnet.dll,1

Reply via email to