mirror of
https://github.com/reactos/reactos.git
synced 2025-02-28 19:32:59 +00:00
parent
3bd9ddca94
commit
63bb46a2fd
31 changed files with 2118 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
|||
|
||||
add_subdirectory(acppage)
|
||||
add_subdirectory(cabview)
|
||||
add_subdirectory(cryptext)
|
||||
add_subdirectory(deskadp)
|
||||
add_subdirectory(deskmon)
|
||||
|
|
21
dll/shellext/cabview/CMakeLists.txt
Normal file
21
dll/shellext/cabview/CMakeLists.txt
Normal file
|
@ -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
dll/shellext/cabview/cabview.cpp
Normal file
66
dll/shellext/cabview/cabview.cpp
Normal file
|
@ -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 <whindsaks@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;
|
||||
}
|
240
dll/shellext/cabview/cabview.h
Normal file
240
dll/shellext/cabview/cabview.h
Normal file
|
@ -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 <whindsaks@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()
|
||||
};
|
75
dll/shellext/cabview/cabview.rc
Normal file
75
dll/shellext/cabview/cabview.rc
Normal file
|
@ -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 <whindsaks@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
|
4
dll/shellext/cabview/cabview.spec
Normal file
4
dll/shellext/cabview/cabview.spec
Normal file
|
@ -0,0 +1,4 @@
|
|||
@ stdcall -private DllCanUnloadNow()
|
||||
@ stdcall -private DllGetClassObject(ptr ptr ptr)
|
||||
@ stdcall -private DllRegisterServer()
|
||||
@ stdcall -private DllUnregisterServer()
|
248
dll/shellext/cabview/extract.cpp
Normal file
248
dll/shellext/cabview/extract.cpp
Normal file
|
@ -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 <whindsaks@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;
|
||||
}
|
857
dll/shellext/cabview/folder.cpp
Normal file
857
dll/shellext/cabview/folder.cpp
Normal file
|
@ -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 <whindsaks@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;
|
||||
}
|
21
dll/shellext/cabview/lang/de-DE.rc
Normal file
21
dll/shellext/cabview/lang/de-DE.rc
Normal file
|
@ -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 <gonzomdx@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
|
21
dll/shellext/cabview/lang/en-US.rc
Normal file
21
dll/shellext/cabview/lang/en-US.rc
Normal file
|
@ -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 <whindsaks@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
|
21
dll/shellext/cabview/lang/et-EE.rc
Normal file
21
dll/shellext/cabview/lang/et-EE.rc
Normal file
|
@ -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.mondresku@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
|
21
dll/shellext/cabview/lang/fr-FR.rc
Normal file
21
dll/shellext/cabview/lang/fr-FR.rc
Normal file
|
@ -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 <pierre@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
|
21
dll/shellext/cabview/lang/hi-IN.rc
Normal file
21
dll/shellext/cabview/lang/hi-IN.rc
Normal file
|
@ -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 <arnavbhatt2004@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
|
21
dll/shellext/cabview/lang/it-IT.rc
Normal file
21
dll/shellext/cabview/lang/it-IT.rc
Normal file
|
@ -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.bisoc@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
|
21
dll/shellext/cabview/lang/ja-JP.rc
Normal file
21
dll/shellext/cabview/lang/ja-JP.rc
Normal file
|
@ -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.mz@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
|
22
dll/shellext/cabview/lang/pl-PL.rc
Normal file
22
dll/shellext/cabview/lang/pl-PL.rc
Normal file
|
@ -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ń <asaillen456esx@gmail.com>
|
||||
* Copyright 2020 Piotr Hetnarowicz <piotrhwz@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
|
21
dll/shellext/cabview/lang/pt-PT.rc
Normal file
21
dll/shellext/cabview/lang/pt-PT.rc
Normal file
|
@ -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 <zecarlos1957@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
|
22
dll/shellext/cabview/lang/ro-RO.rc
Normal file
22
dll/shellext/cabview/lang/ro-RO.rc
Normal file
|
@ -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.bisoc@reactos.org>
|
||||
* Copyright 2022-2024 Andrei Miloiu <miloiuandrei@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
|
21
dll/shellext/cabview/lang/ru-RU.rc
Normal file
21
dll/shellext/cabview/lang/ru-RU.rc
Normal file
|
@ -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 <x86corez@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
|
21
dll/shellext/cabview/lang/sv-SE.rc
Normal file
21
dll/shellext/cabview/lang/sv-SE.rc
Normal file
|
@ -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.bjerkeholt@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
|
21
dll/shellext/cabview/lang/tr-TR.rc
Normal file
21
dll/shellext/cabview/lang/tr-TR.rc
Normal file
|
@ -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.dev@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
|
22
dll/shellext/cabview/lang/zh-CN.rc
Normal file
22
dll/shellext/cabview/lang/zh-CN.rc
Normal file
|
@ -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 <auroracloud4096@gmail.com>
|
||||
* Copyright 2021 Wu Haotian <rigoligo03@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
|
22
dll/shellext/cabview/lang/zh-HK.rc
Normal file
22
dll/shellext/cabview/lang/zh-HK.rc
Normal file
|
@ -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 <eason066@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
|
23
dll/shellext/cabview/lang/zh-TW.rc
Normal file
23
dll/shellext/cabview/lang/zh-TW.rc
Normal file
|
@ -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 <eason066@gmail.com>
|
||||
* REFERENCES: Chinese (Simplified) resource translation
|
||||
* Copyright 2018 Li Keqing <auroracloud4096@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
|
34
dll/shellext/cabview/precomp.h
Normal file
34
dll/shellext/cabview/precomp.h
Normal file
|
@ -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 <whindsaks@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);
|
47
dll/shellext/cabview/res/cabview.rgs
Normal file
47
dll/shellext/cabview/res/cabview.rgs
Normal file
|
@ -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}'
|
||||
}
|
||||
}
|
||||
}
|
BIN
dll/shellext/cabview/res/folder.ico
Normal file
BIN
dll/shellext/cabview/res/folder.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
25
dll/shellext/cabview/resource.h
Normal file
25
dll/shellext/cabview/resource.h
Normal file
|
@ -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 <whindsaks@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
|
156
dll/shellext/cabview/util.h
Normal file
156
dll/shellext/cabview/util.h
Normal file
|
@ -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 <whindsaks@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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue