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 <whindsaks@proton.me> 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 }; 241