Skip to content

Commit 63bb46a

Browse files
authored
[CABVIEW] Add CabView shell extension (reactos#7494)
CORE-14616
1 parent 3bd9ddc commit 63bb46a

31 files changed

+2118
-0
lines changed

dll/shellext/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
add_subdirectory(acppage)
3+
add_subdirectory(cabview)
34
add_subdirectory(cryptext)
45
add_subdirectory(deskadp)
56
add_subdirectory(deskmon)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
spec2def(cabview.dll cabview.spec)
3+
4+
list(APPEND SOURCE
5+
cabview.cpp
6+
extract.cpp
7+
folder.cpp
8+
resource.h)
9+
10+
add_library(cabview MODULE
11+
${SOURCE}
12+
cabview.spec
13+
cabview.rc
14+
${CMAKE_CURRENT_BINARY_DIR}/cabview.def)
15+
16+
set_module_type(cabview win32dll UNICODE)
17+
target_link_libraries(cabview uuid cpprt atl_classes)
18+
set_target_cpp_properties(cabview WITH_EXCEPTIONS)
19+
add_importlibs(cabview cabinet oleaut32 ole32 shlwapi comctl32 shell32 user32 advapi32 msvcrt kernel32 ntdll)
20+
add_pch(cabview precomp.h SOURCE)
21+
add_cd_file(TARGET cabview DESTINATION reactos/system32 FOR all)

dll/shellext/cabview/cabview.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* PROJECT: ReactOS CabView Shell Extension
3+
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4+
* PURPOSE: DLL entry point
5+
* COPYRIGHT: Copyright 2024 Whindmar Saksit <[email protected]>
6+
*/
7+
8+
#include "cabview.h"
9+
10+
#include <initguid.h>
11+
DEFINE_GUID(CLSID_CabFolder, 0x0CD7A5C0,0x9F37,0x11CE,0xAE,0x65,0x08,0x00,0x2B,0x2E,0x12,0x62);
12+
13+
CComModule g_Module;
14+
15+
BEGIN_OBJECT_MAP(ObjectMap)
16+
OBJECT_ENTRY(CLSID_CabFolder, CCabFolder)
17+
END_OBJECT_MAP()
18+
19+
EXTERN_C BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
20+
{
21+
switch (dwReason)
22+
{
23+
case DLL_PROCESS_ATTACH:
24+
DisableThreadLibraryCalls(hInstance);
25+
g_Module.Init(ObjectMap, hInstance, NULL);
26+
break;
27+
}
28+
29+
return TRUE;
30+
}
31+
32+
STDAPI DllCanUnloadNow()
33+
{
34+
return g_Module.DllCanUnloadNow();
35+
}
36+
37+
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
38+
{
39+
return g_Module.DllGetClassObject(rclsid, riid, ppv);
40+
}
41+
42+
STDAPI DllRegisterServer()
43+
{
44+
HRESULT hr;
45+
46+
hr = g_Module.DllRegisterServer(FALSE);
47+
if (FAILED_UNEXPECTEDLY(hr))
48+
return hr;
49+
50+
hr = g_Module.UpdateRegistryFromResource(IDR_FOLDER, TRUE, NULL);
51+
if (FAILED(hr))
52+
return hr;
53+
54+
return S_OK;
55+
}
56+
57+
STDAPI DllUnregisterServer()
58+
{
59+
HRESULT hr1 = g_Module.DllUnregisterServer(FALSE);
60+
HRESULT hr2 = g_Module.UpdateRegistryFromResource(IDR_FOLDER, FALSE, NULL);
61+
if (FAILED_UNEXPECTEDLY(hr1))
62+
return hr1;
63+
if (FAILED_UNEXPECTEDLY(hr2))
64+
return hr2;
65+
return S_OK;
66+
}

dll/shellext/cabview/cabview.h

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/*
2+
* PROJECT: ReactOS CabView Shell Extension
3+
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4+
* PURPOSE: Main header file
5+
* COPYRIGHT: Copyright 2024 Whindmar Saksit <[email protected]>
6+
*/
7+
8+
#pragma once
9+
#include "precomp.h"
10+
#include "resource.h"
11+
12+
#define FLATFOLDER TRUE
13+
14+
EXTERN_C const GUID CLSID_CabFolder;
15+
16+
enum EXTRACTCALLBACKMSG { ECM_BEGIN, ECM_FILE, ECM_PREPAREPATH, ECM_ERROR };
17+
struct EXTRACTCALLBACKDATA
18+
{
19+
LPCWSTR Path;
20+
const FDINOTIFICATION *pfdin;
21+
HRESULT hr;
22+
};
23+
typedef HRESULT (CALLBACK*EXTRACTCALLBACK)(EXTRACTCALLBACKMSG msg, const EXTRACTCALLBACKDATA &data, LPVOID cookie);
24+
HRESULT ExtractCabinet(LPCWSTR cab, LPCWSTR destination, EXTRACTCALLBACK callback, LPVOID cookie);
25+
26+
class CEnumIDList :
27+
public CComObjectRootEx<CComMultiThreadModelNoCS>,
28+
public IEnumIDList
29+
{
30+
protected:
31+
HDPA m_Items;
32+
ULONG m_Pos;
33+
34+
public:
35+
static int CALLBACK DPADestroyCallback(void *pidl, void *pData)
36+
{
37+
SHFree(pidl);
38+
return TRUE;
39+
}
40+
41+
CEnumIDList() : m_Pos(0)
42+
{
43+
m_Items = DPA_Create(0);
44+
}
45+
46+
virtual ~CEnumIDList()
47+
{
48+
DPA_DestroyCallback(m_Items, DPADestroyCallback, NULL);
49+
}
50+
51+
int FindNamedItem(PCUITEMID_CHILD pidl) const;
52+
HRESULT Fill(LPCWSTR path, HWND hwnd = NULL, SHCONTF contf = 0);
53+
HRESULT Fill(PCIDLIST_ABSOLUTE pidl, HWND hwnd = NULL, SHCONTF contf = 0);
54+
55+
HRESULT Append(LPCITEMIDLIST pidl)
56+
{
57+
return DPA_AppendPtr(m_Items, (void*)pidl) != DPA_ERR ? S_OK : E_OUTOFMEMORY;
58+
}
59+
60+
UINT GetCount() const { return m_Items ? DPA_GetPtrCount(m_Items) : 0; }
61+
62+
// IEnumIDList
63+
IFACEMETHODIMP Next(ULONG celt, PITEMID_CHILD *rgelt, ULONG *pceltFetched)
64+
{
65+
if (!rgelt)
66+
return E_INVALIDARG;
67+
HRESULT hr = S_FALSE;
68+
UINT count = GetCount(), fetched = 0;
69+
if (m_Pos < count && fetched < celt)
70+
{
71+
if (SUCCEEDED(hr = SHILClone(DPA_FastGetPtr(m_Items, m_Pos), &rgelt[fetched])))
72+
fetched++;
73+
}
74+
if (pceltFetched)
75+
*pceltFetched = fetched;
76+
m_Pos += fetched;
77+
return FAILED(hr) ? hr : (celt == fetched && fetched) ? S_OK : S_FALSE;
78+
}
79+
80+
IFACEMETHODIMP Reset()
81+
{
82+
m_Pos = 0;
83+
return S_OK;
84+
}
85+
86+
IFACEMETHODIMP Skip(ULONG celt)
87+
{
88+
UINT count = GetCount(), newpos = m_Pos + celt;
89+
if (celt > count || newpos >= count)
90+
return E_INVALIDARG;
91+
m_Pos = newpos;
92+
return S_OK;
93+
}
94+
95+
IFACEMETHODIMP Clone(IEnumIDList **ppenum)
96+
{
97+
UNIMPLEMENTED;
98+
*ppenum = NULL;
99+
return E_NOTIMPL;
100+
}
101+
102+
static CEnumIDList* CreateInstance()
103+
{
104+
CComPtr<CEnumIDList> obj;
105+
return SUCCEEDED(ShellObjectCreator(obj)) ? obj.Detach() : NULL;
106+
}
107+
108+
DECLARE_NO_REGISTRY()
109+
DECLARE_NOT_AGGREGATABLE(CEnumIDList)
110+
111+
BEGIN_COM_MAP(CEnumIDList)
112+
COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
113+
END_COM_MAP()
114+
};
115+
116+
class CCabFolder :
117+
public CComCoClass<CCabFolder, &CLSID_CabFolder>,
118+
public CComObjectRootEx<CComMultiThreadModelNoCS>,
119+
public IShellFolder2,
120+
public IPersistFolder2,
121+
public IShellFolderViewCB,
122+
public IShellIcon
123+
{
124+
protected:
125+
CComHeapPtr<ITEMIDLIST> m_CurDir;
126+
HWND m_ShellViewWindow = NULL;
127+
128+
public:
129+
HRESULT ExtractFilesUI(HWND hWnd, IDataObject *pDO);
130+
HRESULT GetItemDetails(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd, VARIANT *pv);
131+
int MapSCIDToColumn(const SHCOLUMNID &scid);
132+
HRESULT CompareID(LPARAM lParam, PCUITEMID_CHILD pidl1, PCUITEMID_CHILD pidl2);
133+
134+
HRESULT CreateEnum(CEnumIDList **List)
135+
{
136+
CEnumIDList *pEIDL = CEnumIDList::CreateInstance();
137+
*List = pEIDL;
138+
return pEIDL ? pEIDL->Fill(m_CurDir) : E_OUTOFMEMORY;
139+
}
140+
141+
// IShellFolder2
142+
IFACEMETHODIMP GetDefaultSearchGUID(GUID *pguid) override
143+
{
144+
return E_NOTIMPL;
145+
}
146+
147+
IFACEMETHODIMP EnumSearches(IEnumExtraSearch **ppenum) override
148+
{
149+
return E_NOTIMPL;
150+
}
151+
152+
IFACEMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) override;
153+
154+
IFACEMETHODIMP GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags) override;
155+
156+
IFACEMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) override;
157+
158+
IFACEMETHODIMP GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) override;
159+
160+
IFACEMETHODIMP MapColumnToSCID(UINT column, SHCOLUMNID *pscid) override;
161+
162+
IFACEMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override
163+
{
164+
UNIMPLEMENTED;
165+
return E_NOTIMPL;
166+
}
167+
168+
IFACEMETHODIMP EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override;
169+
170+
IFACEMETHODIMP BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override;
171+
172+
IFACEMETHODIMP BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override
173+
{
174+
UNIMPLEMENTED;
175+
return E_NOTIMPL;
176+
}
177+
178+
IFACEMETHODIMP CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) override;
179+
180+
IFACEMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) override;
181+
182+
IFACEMETHODIMP GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, SFGAOF *rgfInOut) override;
183+
184+
IFACEMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *prgfInOut, LPVOID *ppvOut) override;
185+
186+
IFACEMETHODIMP GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET pName) override;
187+
188+
IFACEMETHODIMP SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) override
189+
{
190+
return E_NOTIMPL;
191+
}
192+
193+
// IPersistFolder2
194+
IFACEMETHODIMP GetCurFolder(PIDLIST_ABSOLUTE *pidl) override
195+
{
196+
LPITEMIDLIST curdir = (LPITEMIDLIST)m_CurDir;
197+
return curdir ? SHILClone(curdir, pidl) : E_UNEXPECTED;
198+
}
199+
200+
IFACEMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidl) override
201+
{
202+
WCHAR path[MAX_PATH];
203+
if (SHGetPathFromIDListW(pidl, path))
204+
{
205+
PIDLIST_ABSOLUTE curdir = ILClone(pidl);
206+
if (curdir)
207+
{
208+
m_CurDir.Attach(curdir);
209+
return S_OK;
210+
}
211+
return E_OUTOFMEMORY;
212+
}
213+
return E_INVALIDARG;
214+
}
215+
216+
IFACEMETHODIMP GetClassID(CLSID *lpClassId) override
217+
{
218+
*lpClassId = CLSID_CabFolder;
219+
return S_OK;
220+
}
221+
222+
// IShellFolderViewCB
223+
IFACEMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
224+
225+
// IShellIcon
226+
IFACEMETHODIMP GetIconOf(PCUITEMID_CHILD pidl, UINT flags, int *pIconIndex) override;
227+
228+
DECLARE_NO_REGISTRY()
229+
DECLARE_NOT_AGGREGATABLE(CCabFolder)
230+
231+
BEGIN_COM_MAP(CCabFolder)
232+
COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
233+
COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
234+
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
235+
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
236+
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
237+
COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
238+
COM_INTERFACE_ENTRY_IID(IID_IShellIcon, IShellIcon)
239+
END_COM_MAP()
240+
};

0 commit comments

Comments
 (0)