Skip to content

Commit

Permalink
[CABVIEW] Add CabView shell extension (reactos#7494)
Browse files Browse the repository at this point in the history
CORE-14616
  • Loading branch information
whindsaks authored Dec 5, 2024
1 parent 3bd9ddc commit 63bb46a
Show file tree
Hide file tree
Showing 31 changed files with 2,118 additions and 0 deletions.
1 change: 1 addition & 0 deletions dll/shellext/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

add_subdirectory(acppage)
add_subdirectory(cabview)
add_subdirectory(cryptext)
add_subdirectory(deskadp)
add_subdirectory(deskmon)
Expand Down
21 changes: 21 additions & 0 deletions dll/shellext/cabview/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
66 changes: 66 additions & 0 deletions dll/shellext/cabview/cabview.cpp
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
*/

#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;
}
240 changes: 240 additions & 0 deletions dll/shellext/cabview/cabview.h
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
*/

#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()
};
Loading

0 comments on commit 63bb46a

Please sign in to comment.