mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[ZIPFLDR] Initial implementation.
Icon by Jared Smudde CORE-7684
This commit is contained in:
parent
5100859e06
commit
c7e6a9d04b
19 changed files with 2105 additions and 0 deletions
|
@ -8,3 +8,4 @@ add_subdirectory(netshell)
|
||||||
add_subdirectory(ntobjshex)
|
add_subdirectory(ntobjshex)
|
||||||
add_subdirectory(shellbtrfs)
|
add_subdirectory(shellbtrfs)
|
||||||
add_subdirectory(stobject)
|
add_subdirectory(stobject)
|
||||||
|
add_subdirectory(zipfldr)
|
||||||
|
|
95
dll/shellext/zipfldr/CEnumZipContents.cpp
Normal file
95
dll/shellext/zipfldr/CEnumZipContents.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: CEnumZipContents
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
class CEnumZipContents :
|
||||||
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
|
public IEnumIDList
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CZipEnumerator mEnumerator;
|
||||||
|
DWORD dwFlags;
|
||||||
|
CStringA m_Prefix;
|
||||||
|
public:
|
||||||
|
CEnumZipContents()
|
||||||
|
:dwFlags(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP Initialize(IZip* zip, DWORD flags, const char* prefix)
|
||||||
|
{
|
||||||
|
dwFlags = flags;
|
||||||
|
m_Prefix = prefix;
|
||||||
|
if (mEnumerator.initialize(zip))
|
||||||
|
return S_OK;
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IEnumIDList methods ***
|
||||||
|
STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
|
||||||
|
{
|
||||||
|
if (!pceltFetched || !rgelt)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*pceltFetched = 0;
|
||||||
|
|
||||||
|
if (celt != 1)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
CStringA name;
|
||||||
|
bool dir;
|
||||||
|
unz_file_info64 info;
|
||||||
|
if (mEnumerator.next_unique(m_Prefix, name, dir, info))
|
||||||
|
{
|
||||||
|
*pceltFetched = 1;
|
||||||
|
*rgelt = _ILCreate(dir ? ZIP_PIDL_DIRECTORY : ZIP_PIDL_FILE, name, info);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
STDMETHODIMP Skip(ULONG celt)
|
||||||
|
{
|
||||||
|
CStringA name;
|
||||||
|
bool dir;
|
||||||
|
unz_file_info64 info;
|
||||||
|
while (celt--)
|
||||||
|
{
|
||||||
|
if (!mEnumerator.next_unique(m_Prefix, name, dir, info))
|
||||||
|
return E_FAIL;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
STDMETHODIMP Reset()
|
||||||
|
{
|
||||||
|
if (mEnumerator.reset())
|
||||||
|
return S_OK;
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP Clone(IEnumIDList **ppenum)
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_NOT_AGGREGATABLE(CEnumZipContents)
|
||||||
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||||
|
|
||||||
|
BEGIN_COM_MAP(CEnumZipContents)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
|
||||||
|
END_COM_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT _CEnumZipContents_CreateInstance(IZip* zip, DWORD flags, const char* prefix, REFIID riid, LPVOID * ppvOut)
|
||||||
|
{
|
||||||
|
return ShellObjectCreatorInit<CEnumZipContents>(zip, flags, prefix, riid, ppvOut);
|
||||||
|
}
|
||||||
|
|
189
dll/shellext/zipfldr/CExplorerCommand.cpp
Normal file
189
dll/shellext/zipfldr/CExplorerCommand.cpp
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: IExplorerCommand implementation
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
class CExplorerCommand :
|
||||||
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
|
public IExplorerCommand
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CComPtr<IContextMenu> m_pZipObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
STDMETHODIMP Initialize(IContextMenu* zipObject)
|
||||||
|
{
|
||||||
|
m_pZipObject = zipObject;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IExplorerCommand methods ***
|
||||||
|
STDMETHODIMP GetTitle(IShellItemArray *psiItemArray, LPWSTR *ppszName)
|
||||||
|
{
|
||||||
|
CStringW Title(MAKEINTRESOURCEW(IDS_MENUITEM));
|
||||||
|
return SHStrDup(Title, ppszName);
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetIcon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
|
||||||
|
{
|
||||||
|
CStringW IconName = L"zipfldr.dll,-1";
|
||||||
|
return SHStrDup(IconName, ppszIcon);
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetToolTip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
|
||||||
|
{
|
||||||
|
CStringW HelpText(MAKEINTRESOURCEW(IDS_HELPTEXT));
|
||||||
|
return SHStrDup(HelpText, ppszInfotip);
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetCanonicalName(GUID *pguidCommandName)
|
||||||
|
{
|
||||||
|
*pguidCommandName = CLSID_ZipFolderExtractAllCommand;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetState(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState)
|
||||||
|
{
|
||||||
|
*pCmdState = ECS_ENABLED;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc)
|
||||||
|
{
|
||||||
|
CMINVOKECOMMANDINFO cm = { sizeof(cm), 0 };
|
||||||
|
cm.lpVerb = EXTRACT_VERBA;
|
||||||
|
cm.nShow = SW_SHOW;
|
||||||
|
return m_pZipObject->InvokeCommand(&cm);
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetFlags(EXPCMDFLAGS *pFlags)
|
||||||
|
{
|
||||||
|
*pFlags = ECF_DEFAULT;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
STDMETHODIMP EnumSubCommands(IEnumExplorerCommand **ppEnum)
|
||||||
|
{
|
||||||
|
DbgPrint("%s\n", __FUNCTION__);
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_NOT_AGGREGATABLE(CExplorerCommand)
|
||||||
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||||
|
|
||||||
|
BEGIN_COM_MAP(CExplorerCommand)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IExplorerCommand, IExplorerCommand)
|
||||||
|
END_COM_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CEnumExplorerCommand :
|
||||||
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
|
public IEnumExplorerCommand
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool m_bFirst;
|
||||||
|
CComPtr<IContextMenu> m_pZipObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CEnumExplorerCommand()
|
||||||
|
:m_bFirst(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP Initialize(IContextMenu* zipObject)
|
||||||
|
{
|
||||||
|
m_pZipObject = zipObject;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IEnumExplorerCommand methods ***
|
||||||
|
STDMETHODIMP Next(ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched)
|
||||||
|
{
|
||||||
|
if (!pUICommand)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
if (pceltFetched)
|
||||||
|
*pceltFetched = 0;
|
||||||
|
if (m_bFirst && celt)
|
||||||
|
{
|
||||||
|
m_bFirst = false;
|
||||||
|
celt--;
|
||||||
|
HRESULT hr = ShellObjectCreatorInit<CExplorerCommand>(m_pZipObject, IID_PPV_ARG(IExplorerCommand, pUICommand));
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (pceltFetched)
|
||||||
|
*pceltFetched = 1;
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
STDMETHODIMP Skip(ULONG celt)
|
||||||
|
{
|
||||||
|
if (m_bFirst)
|
||||||
|
{
|
||||||
|
m_bFirst = false;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
STDMETHODIMP Reset()
|
||||||
|
{
|
||||||
|
m_bFirst = true;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
STDMETHODIMP Clone(IEnumExplorerCommand **ppenum)
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_NOT_AGGREGATABLE(CEnumExplorerCommand)
|
||||||
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||||
|
|
||||||
|
BEGIN_COM_MAP(CEnumExplorerCommand)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IEnumExplorerCommand, IEnumExplorerCommand)
|
||||||
|
END_COM_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
class CExplorerCommandProvider :
|
||||||
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
|
public IExplorerCommandProvider
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CComPtr<IContextMenu> m_pZipObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
STDMETHODIMP Initialize(IContextMenu* zipObject)
|
||||||
|
{
|
||||||
|
m_pZipObject = zipObject;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IExplorerCommandProvider methods ***
|
||||||
|
STDMETHODIMP GetCommands(IUnknown *punkSite, REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
return ShellObjectCreatorInit<CEnumExplorerCommand>(m_pZipObject, riid, ppv);
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetCommand(REFGUID rguidCommandId, REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
*ppv = NULL;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_NOT_AGGREGATABLE(CExplorerCommandProvider)
|
||||||
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||||
|
|
||||||
|
BEGIN_COM_MAP(CExplorerCommandProvider)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IExplorerCommandProvider, IExplorerCommandProvider)
|
||||||
|
END_COM_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT _CExplorerCommandProvider_CreateInstance(IContextMenu* zipObject, REFIID riid, LPVOID * ppvOut)
|
||||||
|
{
|
||||||
|
return ShellObjectCreatorInit<CExplorerCommandProvider>(zipObject, riid, ppvOut);
|
||||||
|
}
|
54
dll/shellext/zipfldr/CFolderViewCB.cpp
Normal file
54
dll/shellext/zipfldr/CFolderViewCB.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: IShellFolderViewCB implementation
|
||||||
|
* COPYRIGHT: Copyright 2017 David Quintana (gigaherz@gmail.com)
|
||||||
|
* Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
class CFolderViewCB :
|
||||||
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
|
public IShellFolderViewCB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~CFolderViewCB()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IShellFolderViewCB methods ***
|
||||||
|
STDMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
/* TODO: Handle SFVM_GET_WEBVIEW_CONTENT to add tasks */
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case SFVM_DEFVIEWMODE:
|
||||||
|
{
|
||||||
|
FOLDERVIEWMODE* pViewMode = (FOLDERVIEWMODE*)lParam;
|
||||||
|
*pViewMode = FVM_DETAILS;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
case SFVM_COLUMNCLICK:
|
||||||
|
return S_FALSE;
|
||||||
|
case SFVM_BACKGROUNDENUM:
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_NOT_AGGREGATABLE(CFolderViewCB)
|
||||||
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||||
|
|
||||||
|
BEGIN_COM_MAP(CFolderViewCB)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
|
||||||
|
END_COM_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT _CFolderViewCB_CreateInstance(REFIID riid, LPVOID * ppvOut)
|
||||||
|
{
|
||||||
|
return ShellObjectCreator<CFolderViewCB>(riid, ppvOut);
|
||||||
|
}
|
50
dll/shellext/zipfldr/CMakeLists.txt
Normal file
50
dll/shellext/zipfldr/CMakeLists.txt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
set_cpp(WITH_RUNTIME WITH_EXCEPTIONS)
|
||||||
|
if(NOT MSVC)
|
||||||
|
# HACK: this should be enabled globally!
|
||||||
|
add_compile_flags_language("-std=c++11" "CXX")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
remove_definitions(-D_WIN32_WINNT=0x502)
|
||||||
|
add_definitions(-D_WIN32_WINNT=0x600)
|
||||||
|
|
||||||
|
add_definitions(
|
||||||
|
-D_ATL_NO_EXCEPTIONS)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib
|
||||||
|
${REACTOS_SOURCE_DIR}/sdk/lib/atl
|
||||||
|
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/contrib)
|
||||||
|
|
||||||
|
spec2def(zipfldr.dll zipfldr.spec ADD_IMPORTLIB)
|
||||||
|
|
||||||
|
|
||||||
|
list(APPEND SOURCE
|
||||||
|
zipfldr.cpp
|
||||||
|
zippidl.cpp
|
||||||
|
zippidl.hpp
|
||||||
|
IZip.hpp
|
||||||
|
CExplorerCommand.cpp
|
||||||
|
CEnumZipContents.cpp
|
||||||
|
CFolderViewCB.cpp
|
||||||
|
CZipEnumerator.hpp
|
||||||
|
CZipExtract.cpp
|
||||||
|
CZipFolder.hpp
|
||||||
|
Debug.cpp
|
||||||
|
zipfldr.spec
|
||||||
|
precomp.h
|
||||||
|
resource.h)
|
||||||
|
|
||||||
|
add_library(zipfldr SHARED
|
||||||
|
${SOURCE}
|
||||||
|
${ZLIB_SOURCE}
|
||||||
|
zipfldr.rc
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/zipfldr.def)
|
||||||
|
|
||||||
|
|
||||||
|
set_module_type(zipfldr win32dll UNICODE)
|
||||||
|
target_link_libraries(zipfldr minizip zlib atlnew uuid)
|
||||||
|
add_importlibs(zipfldr oleaut32 ole32 shlwapi comctl32 shell32 user32 advapi32 msvcrt kernel32 ntdll)
|
||||||
|
add_pch(zipfldr precomp.h SOURCE)
|
||||||
|
add_cd_file(TARGET zipfldr DESTINATION reactos/system32 FOR all)
|
||||||
|
|
94
dll/shellext/zipfldr/CZipEnumerator.hpp
Normal file
94
dll/shellext/zipfldr/CZipEnumerator.hpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: CZipEnumerator
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct CZipEnumerator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CComPtr<IZip> m_Zip;
|
||||||
|
bool m_First;
|
||||||
|
CAtlList<CStringA> m_Returned;
|
||||||
|
public:
|
||||||
|
CZipEnumerator()
|
||||||
|
:m_First(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initialize(IZip* zip)
|
||||||
|
{
|
||||||
|
m_Zip = zip;
|
||||||
|
return reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reset()
|
||||||
|
{
|
||||||
|
unzFile uf = m_Zip->getZip();
|
||||||
|
m_First = true;
|
||||||
|
if (unzGoToFirstFile(uf) != UNZ_OK)
|
||||||
|
return false;
|
||||||
|
m_Returned.RemoveAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next_unique(const char* prefix, CStringA& name, bool& folder, unz_file_info64& info)
|
||||||
|
{
|
||||||
|
size_t len = strlen(prefix);
|
||||||
|
CStringA tmp;
|
||||||
|
while (next(tmp, info))
|
||||||
|
{
|
||||||
|
if (!_strnicmp(tmp, prefix, len))
|
||||||
|
{
|
||||||
|
int pos = tmp.Find('/', len);
|
||||||
|
if (pos < 0)
|
||||||
|
{
|
||||||
|
name = tmp.Mid(len);
|
||||||
|
folder = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = tmp.Mid(len, pos - len);
|
||||||
|
folder = true;
|
||||||
|
}
|
||||||
|
tmp = name.MakeLower();
|
||||||
|
|
||||||
|
POSITION it = m_Returned.Find(tmp);
|
||||||
|
if (!name.IsEmpty() && !it)
|
||||||
|
{
|
||||||
|
m_Returned.AddTail(tmp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next(CStringA& name, unz_file_info64& info)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
unzFile uf = m_Zip->getZip();
|
||||||
|
if (!m_First)
|
||||||
|
{
|
||||||
|
err = unzGoToNextFile(uf);
|
||||||
|
if (err == UNZ_END_OF_LIST_OF_FILE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_First = false;
|
||||||
|
|
||||||
|
err = unzGetCurrentFileInfo64(uf, &info, NULL, 0, NULL, 0, NULL, 0);
|
||||||
|
if (err == UNZ_OK)
|
||||||
|
{
|
||||||
|
PSTR buf = name.GetBuffer(info.size_filename);
|
||||||
|
err = unzGetCurrentFileInfo64(uf, NULL, buf, name.GetAllocLength(), NULL, 0, NULL, 0);
|
||||||
|
name.ReleaseBuffer(info.size_filename);
|
||||||
|
name.Replace('\\', '/');
|
||||||
|
}
|
||||||
|
return err == UNZ_OK;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
481
dll/shellext/zipfldr/CZipExtract.cpp
Normal file
481
dll/shellext/zipfldr/CZipExtract.cpp
Normal file
|
@ -0,0 +1,481 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: Zip extraction
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
class CZipExtract :
|
||||||
|
public IZip
|
||||||
|
{
|
||||||
|
CStringW m_Filename;
|
||||||
|
CStringW m_Directory;
|
||||||
|
unzFile uf;
|
||||||
|
public:
|
||||||
|
CZipExtract(PCWSTR Filename)
|
||||||
|
:uf(NULL)
|
||||||
|
{
|
||||||
|
m_Filename = Filename;
|
||||||
|
m_Directory = m_Filename;
|
||||||
|
PWSTR Dir = m_Directory.GetBuffer();
|
||||||
|
PathRemoveExtensionW(Dir);
|
||||||
|
m_Directory.ReleaseBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
~CZipExtract()
|
||||||
|
{
|
||||||
|
if (uf)
|
||||||
|
{
|
||||||
|
DPRINT1("WARNING: uf not closed!\n");
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close()
|
||||||
|
{
|
||||||
|
if (uf)
|
||||||
|
unzClose(uf);
|
||||||
|
uf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IZip methods ***
|
||||||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
|
||||||
|
{
|
||||||
|
if (riid == IID_IUnknown)
|
||||||
|
{
|
||||||
|
*ppvObject = this;
|
||||||
|
AddRef();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(ULONG) AddRef(void)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(ULONG) Release(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(unzFile) getZip()
|
||||||
|
{
|
||||||
|
return uf;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CConfirmReplace : public CDialogImpl<CConfirmReplace>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CStringA m_Filename;
|
||||||
|
public:
|
||||||
|
enum DialogResult
|
||||||
|
{
|
||||||
|
Yes,
|
||||||
|
YesToAll,
|
||||||
|
No,
|
||||||
|
Cancel
|
||||||
|
};
|
||||||
|
|
||||||
|
static DialogResult ShowDlg(HWND hDlg, PCSTR FullPath)
|
||||||
|
{
|
||||||
|
PCSTR Filename = PathFindFileNameA(FullPath);
|
||||||
|
CConfirmReplace confirm(Filename);
|
||||||
|
INT_PTR Result = confirm.DoModal(hDlg);
|
||||||
|
switch (Result)
|
||||||
|
{
|
||||||
|
case IDYES: return Yes;
|
||||||
|
case IDYESALL: return YesToAll;
|
||||||
|
default:
|
||||||
|
case IDNO: return No;
|
||||||
|
case IDCANCEL: return Cancel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CConfirmReplace(const char* filename)
|
||||||
|
{
|
||||||
|
m_Filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT OnInitDialog(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||||
|
{
|
||||||
|
CenterWindow(GetParent());
|
||||||
|
|
||||||
|
HICON hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
|
||||||
|
SendDlgItemMessage(IDC_EXCLAMATION_ICON, STM_SETICON, (WPARAM)hIcon);
|
||||||
|
|
||||||
|
/* Our CString does not support FormatMessage yet */
|
||||||
|
CStringA message(MAKEINTRESOURCE(IDS_OVERWRITEFILE_TEXT));
|
||||||
|
CHeapPtr<CHAR, CLocalAllocator> formatted;
|
||||||
|
|
||||||
|
DWORD_PTR args[2] =
|
||||||
|
{
|
||||||
|
(DWORD_PTR)m_Filename.GetString(),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
::FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||||
|
message, 0, 0, (LPSTR)&formatted, 0, (va_list*)args);
|
||||||
|
|
||||||
|
::SetDlgItemTextA(m_hWnd, IDC_MESSAGE, formatted);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT OnButton(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
||||||
|
{
|
||||||
|
EndDialog(wID);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { IDD = IDD_CONFIRM_FILE_REPLACE };
|
||||||
|
|
||||||
|
BEGIN_MSG_MAP(CConfirmReplace)
|
||||||
|
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
|
||||||
|
COMMAND_ID_HANDLER(IDYES, OnButton)
|
||||||
|
COMMAND_ID_HANDLER(IDYESALL, OnButton)
|
||||||
|
COMMAND_ID_HANDLER(IDNO, OnButton)
|
||||||
|
COMMAND_ID_HANDLER(IDCANCEL, OnButton)
|
||||||
|
END_MSG_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CExtractSettingsPage : public CPropertyPageImpl<CExtractSettingsPage>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CZipExtract* m_pExtract;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CExtractSettingsPage(CZipExtract* extract)
|
||||||
|
:CPropertyPageImpl<CExtractSettingsPage>(MAKEINTRESOURCE(IDS_WIZ_TITLE))
|
||||||
|
,m_pExtract(extract)
|
||||||
|
{
|
||||||
|
m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_WIZ_DEST_TITLE);
|
||||||
|
m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_WIZ_DEST_SUBTITLE);
|
||||||
|
m_psp.dwFlags |= PSP_USETITLE | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OnSetActive()
|
||||||
|
{
|
||||||
|
SetDlgItemTextW(IDC_DIRECTORY, m_pExtract->m_Directory);
|
||||||
|
::EnableWindow(GetDlgItem(IDC_PASSWORD), FALSE); /* Not supported for now */
|
||||||
|
GetParent().CenterWindow(::GetDesktopWindow());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OnWizardNext()
|
||||||
|
{
|
||||||
|
::EnableWindow(GetDlgItem(IDC_BROWSE), FALSE);
|
||||||
|
::EnableWindow(GetDlgItem(IDC_DIRECTORY), FALSE);
|
||||||
|
::EnableWindow(GetDlgItem(IDC_PASSWORD), FALSE);
|
||||||
|
|
||||||
|
if (!m_pExtract->Extract(m_hWnd, GetDlgItem(IDC_PROGRESS)))
|
||||||
|
{
|
||||||
|
/* Extraction failed, do not go to the next page */
|
||||||
|
SetWindowLongPtr(DWLP_MSGRESULT, -1);
|
||||||
|
|
||||||
|
::EnableWindow(GetDlgItem(IDC_BROWSE), TRUE);
|
||||||
|
::EnableWindow(GetDlgItem(IDC_DIRECTORY), TRUE);
|
||||||
|
::EnableWindow(GetDlgItem(IDC_PASSWORD), FALSE); /* Not supported for now */
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct browse_info
|
||||||
|
{
|
||||||
|
HWND hWnd;
|
||||||
|
LPCWSTR Directory;
|
||||||
|
};
|
||||||
|
|
||||||
|
static INT CALLBACK s_BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lp, LPARAM pData)
|
||||||
|
{
|
||||||
|
if (uMsg == BFFM_INITIALIZED)
|
||||||
|
{
|
||||||
|
browse_info* info = (browse_info*)pData;
|
||||||
|
CWindow dlg(hWnd);
|
||||||
|
dlg.SendMessage(BFFM_SETSELECTION, TRUE, (LPARAM)info->Directory);
|
||||||
|
dlg.CenterWindow(info->hWnd);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT OnBrowse(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
||||||
|
{
|
||||||
|
BROWSEINFOW bi = { m_hWnd };
|
||||||
|
WCHAR path[MAX_PATH];
|
||||||
|
bi.pszDisplayName = path;
|
||||||
|
bi.lpfn = s_BrowseCallbackProc;
|
||||||
|
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
|
||||||
|
CStringW title(MAKEINTRESOURCEW(IDS_WIZ_BROWSE_TITLE));
|
||||||
|
bi.lpszTitle = title;
|
||||||
|
|
||||||
|
browse_info info = { m_hWnd, m_pExtract->m_Directory.GetString() };
|
||||||
|
bi.lParam = (LPARAM)&info;
|
||||||
|
|
||||||
|
CComHeapPtr<ITEMIDLIST> pidl;
|
||||||
|
pidl.Attach(SHBrowseForFolderW(&bi));
|
||||||
|
|
||||||
|
WCHAR tmpPath[MAX_PATH];
|
||||||
|
if (pidl && SHGetPathFromIDListW(pidl, tmpPath))
|
||||||
|
{
|
||||||
|
m_pExtract->m_Directory = tmpPath;
|
||||||
|
SetDlgItemTextW(IDC_DIRECTORY, m_pExtract->m_Directory);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT OnPassword(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { IDD = IDD_PROPPAGEDESTIONATION };
|
||||||
|
|
||||||
|
BEGIN_MSG_MAP(CCompleteSettingsPage)
|
||||||
|
COMMAND_ID_HANDLER(IDC_BROWSE, OnBrowse)
|
||||||
|
COMMAND_ID_HANDLER(IDC_PASSWORD, OnPassword)
|
||||||
|
CHAIN_MSG_MAP(CPropertyPageImpl<CExtractSettingsPage>)
|
||||||
|
END_MSG_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CCompleteSettingsPage : public CPropertyPageImpl<CCompleteSettingsPage>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CZipExtract* m_pExtract;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CCompleteSettingsPage(CZipExtract* extract)
|
||||||
|
:CPropertyPageImpl<CCompleteSettingsPage>(MAKEINTRESOURCE(IDS_WIZ_TITLE))
|
||||||
|
, m_pExtract(extract)
|
||||||
|
{
|
||||||
|
m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_WIZ_COMPL_TITLE);
|
||||||
|
m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_WIZ_COMPL_SUBTITLE);
|
||||||
|
m_psp.dwFlags |= PSP_USETITLE | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int OnSetActive()
|
||||||
|
{
|
||||||
|
SetWizardButtons(PSWIZB_FINISH);
|
||||||
|
CStringW Path = m_pExtract->m_Directory;
|
||||||
|
PWSTR Ptr = Path.GetBuffer();
|
||||||
|
RECT rc;
|
||||||
|
::GetWindowRect(GetDlgItem(IDC_DESTDIR), &rc);
|
||||||
|
HDC dc = GetDC();
|
||||||
|
PathCompactPathW(dc, Ptr, rc.right - rc.left);
|
||||||
|
ReleaseDC(dc);
|
||||||
|
Path.ReleaseBuffer();
|
||||||
|
SetDlgItemTextW(IDC_DESTDIR, Path);
|
||||||
|
CheckDlgButton(IDC_SHOW_EXTRACTED, BST_CHECKED);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BOOL OnWizardFinish()
|
||||||
|
{
|
||||||
|
if (IsDlgButtonChecked(IDC_SHOW_EXTRACTED) == BST_CHECKED)
|
||||||
|
{
|
||||||
|
ShellExecuteW(NULL, L"explore", m_pExtract->m_Directory, NULL, NULL, SW_SHOW);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { IDD = IDD_PROPPAGECOMPLETE };
|
||||||
|
|
||||||
|
BEGIN_MSG_MAP(CCompleteSettingsPage)
|
||||||
|
CHAIN_MSG_MAP(CPropertyPageImpl<CCompleteSettingsPage>)
|
||||||
|
END_MSG_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void runWizard()
|
||||||
|
{
|
||||||
|
PROPSHEETHEADERW psh = { sizeof(psh), 0 };
|
||||||
|
psh.dwFlags = PSH_WIZARD97 | PSH_HEADER;
|
||||||
|
psh.hInstance = _AtlBaseModule.GetResourceInstance();
|
||||||
|
|
||||||
|
CExtractSettingsPage extractPage(this);
|
||||||
|
CCompleteSettingsPage completePage(this);
|
||||||
|
HPROPSHEETPAGE hpsp[] =
|
||||||
|
{
|
||||||
|
extractPage.Create(),
|
||||||
|
completePage.Create()
|
||||||
|
};
|
||||||
|
|
||||||
|
psh.phpage = hpsp;
|
||||||
|
psh.nPages = _countof(hpsp);
|
||||||
|
|
||||||
|
PropertySheetW(&psh);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Extract(HWND hDlg, HWND hProgress)
|
||||||
|
{
|
||||||
|
unz_global_info64 gi;
|
||||||
|
uf = unzOpen2_64(m_Filename.GetString(), &g_FFunc);
|
||||||
|
int err = unzGetGlobalInfo64(uf, &gi);
|
||||||
|
if (err != UNZ_OK)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, unzGetGlobalInfo64: 0x%x\n", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CZipEnumerator zipEnum;
|
||||||
|
if (!zipEnum.initialize(this))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, zipEnum.initialize\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWindow Progress(hProgress);
|
||||||
|
Progress.SendMessage(PBM_SETRANGE32, 0, gi.number_entry);
|
||||||
|
Progress.SendMessage(PBM_SETPOS, 0, 0);
|
||||||
|
|
||||||
|
BYTE Buffer[2048];
|
||||||
|
CStringA BaseDirectory = m_Directory;
|
||||||
|
CStringA Name;
|
||||||
|
unz_file_info64 Info;
|
||||||
|
int CurrentFile = 0;
|
||||||
|
bool bOverwriteAll = false;
|
||||||
|
while (zipEnum.next(Name, Info))
|
||||||
|
{
|
||||||
|
bool is_dir = Name.GetLength() > 0 && Name[Name.GetLength()-1] == '/';
|
||||||
|
|
||||||
|
char CombinedPath[MAX_PATH * 2] = { 0 };
|
||||||
|
PathCombineA(CombinedPath, BaseDirectory, Name);
|
||||||
|
CStringA FullPath = CombinedPath;
|
||||||
|
FullPath.Replace('/', '\\'); /* SHPathPrepareForWriteA does not handle '/' */
|
||||||
|
DWORD dwFlags = SHPPFW_DIRCREATE | (is_dir ? SHPPFW_NONE : SHPPFW_IGNOREFILENAME);
|
||||||
|
HRESULT hr = SHPathPrepareForWriteA(hDlg, NULL, FullPath, dwFlags);
|
||||||
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CurrentFile++;
|
||||||
|
if (is_dir)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char* password = NULL;
|
||||||
|
/* FIXME: Process password, if required and not specified, prompt the user */
|
||||||
|
err = unzOpenCurrentFilePassword(uf, password);
|
||||||
|
if (err != UNZ_OK)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, unzOpenCurrentFilePassword: 0x%x\n", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE hFile = CreateFileA(FullPath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
DWORD dwErr = GetLastError();
|
||||||
|
if (dwErr == ERROR_FILE_EXISTS)
|
||||||
|
{
|
||||||
|
bool bOverwrite = bOverwriteAll;
|
||||||
|
if (!bOverwriteAll)
|
||||||
|
{
|
||||||
|
CConfirmReplace::DialogResult Result = CConfirmReplace::ShowDlg(hDlg, FullPath);
|
||||||
|
switch (Result)
|
||||||
|
{
|
||||||
|
case CConfirmReplace::YesToAll:
|
||||||
|
bOverwriteAll = true;
|
||||||
|
case CConfirmReplace::Yes:
|
||||||
|
bOverwrite = true;
|
||||||
|
break;
|
||||||
|
case CConfirmReplace::No:
|
||||||
|
break;
|
||||||
|
case CConfirmReplace::Cancel:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bOverwrite)
|
||||||
|
{
|
||||||
|
hFile = CreateFileA(FullPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
dwErr = GetLastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unzCloseCurrentFile(uf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
unzCloseCurrentFile(uf);
|
||||||
|
DPRINT1("ERROR, CreateFileA: 0x%x (%s)\n", dwErr, bOverwriteAll ? "Y" : "N");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
err = unzReadCurrentFile(uf, Buffer, sizeof(Buffer));
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, unzReadCurrentFile: 0x%x\n", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (err > 0)
|
||||||
|
{
|
||||||
|
DWORD dwWritten;
|
||||||
|
if (!WriteFile(hFile, Buffer, err, &dwWritten, NULL))
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, WriteFile: 0x%x\n", GetLastError());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dwWritten != (DWORD)err)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, WriteFile: dwWritten:%d err:%d\n", dwWritten, err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (err > 0);
|
||||||
|
|
||||||
|
/* Update Filetime */
|
||||||
|
FILETIME LastAccessTime;
|
||||||
|
GetFileTime(hFile, NULL, &LastAccessTime, NULL);
|
||||||
|
FILETIME LocalFileTime;
|
||||||
|
DosDateTimeToFileTime((WORD)(Info.dosDate >> 16), (WORD)Info.dosDate, &LocalFileTime);
|
||||||
|
FILETIME FileTime;
|
||||||
|
LocalFileTimeToFileTime(&LocalFileTime, &FileTime);
|
||||||
|
SetFileTime(hFile, &FileTime, &LastAccessTime, &FileTime);
|
||||||
|
|
||||||
|
/* Done.. */
|
||||||
|
CloseHandle(hFile);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
unzCloseCurrentFile(uf);
|
||||||
|
DPRINT1("ERROR, unzReadCurrentFile2: 0x%x\n", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = unzCloseCurrentFile(uf);
|
||||||
|
if (err != UNZ_OK)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR(non-fatal), unzCloseCurrentFile: 0x%x\n", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Progress.SendMessage(PBM_SETPOS, CurrentFile, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void _CZipExtract_runWizard(PCWSTR Filename)
|
||||||
|
{
|
||||||
|
CZipExtract extractor(Filename);
|
||||||
|
extractor.runWizard();
|
||||||
|
}
|
||||||
|
|
625
dll/shellext/zipfldr/CZipFolder.hpp
Normal file
625
dll/shellext/zipfldr/CZipFolder.hpp
Normal file
|
@ -0,0 +1,625 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: Main class
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
EXTERN_C HRESULT WINAPI SHCreateFileExtractIconW(LPCWSTR pszPath, DWORD dwFileAttributes, REFIID riid, void **ppv);
|
||||||
|
|
||||||
|
|
||||||
|
struct FolderViewColumns
|
||||||
|
{
|
||||||
|
int iResource;
|
||||||
|
DWORD dwDefaultState;
|
||||||
|
int cxChar;
|
||||||
|
int fmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static FolderViewColumns g_ColumnDefs[] =
|
||||||
|
{
|
||||||
|
{ IDS_COL_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 25, LVCFMT_LEFT },
|
||||||
|
{ IDS_COL_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 20, LVCFMT_LEFT },
|
||||||
|
{ IDS_COL_COMPRSIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT },
|
||||||
|
{ IDS_COL_PASSWORD, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT },
|
||||||
|
{ IDS_COL_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT },
|
||||||
|
{ IDS_COL_RATIO, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT },
|
||||||
|
{ IDS_COL_DATE_MOD, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, 15, LVCFMT_LEFT },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CZipFolder :
|
||||||
|
public CComCoClass<CZipFolder, &CLSID_ZipFolderStorageHandler>,
|
||||||
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
|
public IShellFolder2,
|
||||||
|
//public IStorage,
|
||||||
|
public IContextMenu,
|
||||||
|
public IShellExtInit,
|
||||||
|
//public IPersistFile,
|
||||||
|
public IPersistFolder2,
|
||||||
|
public IZip
|
||||||
|
{
|
||||||
|
CStringW m_ZipFile;
|
||||||
|
CStringA m_ZipDir;
|
||||||
|
CComHeapPtr<ITEMIDLIST> m_CurDir;
|
||||||
|
unzFile m_UnzipFile;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CZipFolder()
|
||||||
|
:m_UnzipFile(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~CZipFolder()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close()
|
||||||
|
{
|
||||||
|
if (m_UnzipFile)
|
||||||
|
unzClose(m_UnzipFile);
|
||||||
|
m_UnzipFile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IZip methods ***
|
||||||
|
STDMETHODIMP_(unzFile) getZip()
|
||||||
|
{
|
||||||
|
if (!m_UnzipFile)
|
||||||
|
{
|
||||||
|
m_UnzipFile = unzOpen2_64(m_ZipFile, &g_FFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_UnzipFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IShellFolder2 methods ***
|
||||||
|
STDMETHODIMP GetDefaultSearchGUID(GUID *pguid)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
|
||||||
|
{
|
||||||
|
if (!pcsFlags || iColumn >= _countof(g_ColumnDefs))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
*pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
// Adapted from CFileDefExt::GetFileTimeString
|
||||||
|
BOOL _GetFileTimeString(LPFILETIME lpFileTime, LPWSTR pwszResult, UINT cchResult)
|
||||||
|
{
|
||||||
|
SYSTEMTIME st;
|
||||||
|
|
||||||
|
if (!FileTimeToSystemTime(lpFileTime, &st))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
size_t cchRemaining = cchResult;
|
||||||
|
LPWSTR pwszEnd = pwszResult;
|
||||||
|
int cchWritten = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pwszEnd, cchRemaining);
|
||||||
|
if (cchWritten)
|
||||||
|
--cchWritten; // GetDateFormatW returns count with terminating zero
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
cchRemaining -= cchWritten;
|
||||||
|
pwszEnd += cchWritten;
|
||||||
|
|
||||||
|
StringCchCopyExW(pwszEnd, cchRemaining, L" ", &pwszEnd, &cchRemaining, 0);
|
||||||
|
|
||||||
|
cchWritten = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, pwszEnd, cchRemaining);
|
||||||
|
if (cchWritten)
|
||||||
|
--cchWritten; // GetTimeFormatW returns count with terminating zero
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
|
||||||
|
{
|
||||||
|
if (iColumn >= _countof(g_ColumnDefs))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
psd->cxChar = g_ColumnDefs[iColumn].cxChar;
|
||||||
|
psd->fmt = g_ColumnDefs[iColumn].fmt;
|
||||||
|
|
||||||
|
if (pidl == NULL)
|
||||||
|
{
|
||||||
|
return SHSetStrRet(&psd->str, _AtlBaseModule.GetResourceInstance(), g_ColumnDefs[iColumn].iResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl);
|
||||||
|
if (curpidl->mkid.cb != 0)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, unhandled PIDL!\n");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZipPidlEntry* zipEntry = _ZipFromIL(pidl);
|
||||||
|
if (!zipEntry)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
WCHAR Buffer[100];
|
||||||
|
bool isDir = zipEntry->ZipType == ZIP_PIDL_DIRECTORY;
|
||||||
|
switch (iColumn)
|
||||||
|
{
|
||||||
|
case 0: /* Name, ReactOS specific? */
|
||||||
|
return GetDisplayNameOf(pidl, 0, &psd->str);
|
||||||
|
case 1: /* Type */
|
||||||
|
{
|
||||||
|
SHFILEINFOA shfi;
|
||||||
|
DWORD dwAttributes = isDir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
|
||||||
|
ULONG_PTR firet = SHGetFileInfoA(zipEntry->Name, dwAttributes, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME);
|
||||||
|
if (!firet)
|
||||||
|
return E_FAIL;
|
||||||
|
return SHSetStrRet(&psd->str, shfi.szTypeName);
|
||||||
|
}
|
||||||
|
case 2: /* Compressed size */
|
||||||
|
case 4: /* Size */
|
||||||
|
{
|
||||||
|
ULONG64 Size = iColumn == 2 ? zipEntry->CompressedSize : zipEntry->UncompressedSize;
|
||||||
|
if (!StrFormatByteSizeW(Size, Buffer, _countof(Buffer)))
|
||||||
|
return E_FAIL;
|
||||||
|
return SHSetStrRet(&psd->str, Buffer);
|
||||||
|
}
|
||||||
|
case 3: /* Password */
|
||||||
|
if (isDir)
|
||||||
|
return SHSetStrRet(&psd->str, L"");
|
||||||
|
return SHSetStrRet(&psd->str, _AtlBaseModule.GetResourceInstance(), zipEntry->Password ? IDS_YES : IDS_NO);
|
||||||
|
case 5: /* Ratio */
|
||||||
|
{
|
||||||
|
int ratio = 0;
|
||||||
|
if (zipEntry->UncompressedSize && !isDir)
|
||||||
|
ratio = 100 - (int)((zipEntry->CompressedSize*100)/zipEntry->UncompressedSize);
|
||||||
|
StringCchPrintfW(Buffer, _countof(Buffer), L"%d%%", ratio);
|
||||||
|
return SHSetStrRet(&psd->str, Buffer);
|
||||||
|
}
|
||||||
|
case 6: /* Date */
|
||||||
|
{
|
||||||
|
if (isDir)
|
||||||
|
return SHSetStrRet(&psd->str, L"");
|
||||||
|
FILETIME ftLocal;
|
||||||
|
DosDateTimeToFileTime((WORD)(zipEntry->DosDate>>16), (WORD)zipEntry->DosDate, &ftLocal);
|
||||||
|
if (!_GetFileTimeString(&ftLocal, Buffer, _countof(Buffer)))
|
||||||
|
return E_FAIL;
|
||||||
|
return SHSetStrRet(&psd->str, Buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IShellFolder methods ***
|
||||||
|
STDMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
|
||||||
|
{
|
||||||
|
return _CEnumZipContents_CreateInstance(this, dwFlags, m_ZipDir, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
|
||||||
|
}
|
||||||
|
STDMETHODIMP BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
|
||||||
|
{
|
||||||
|
if (riid == IID_IShellFolder)
|
||||||
|
{
|
||||||
|
CStringA newZipDir = m_ZipDir;
|
||||||
|
PCUIDLIST_RELATIVE curpidl = pidl;
|
||||||
|
while (curpidl->mkid.cb)
|
||||||
|
{
|
||||||
|
const ZipPidlEntry* zipEntry = _ZipFromIL(curpidl);
|
||||||
|
if (!zipEntry)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
newZipDir += zipEntry->Name;
|
||||||
|
newZipDir += '/';
|
||||||
|
|
||||||
|
curpidl = ILGetNext(curpidl);
|
||||||
|
}
|
||||||
|
return ShellObjectCreatorInit<CZipFolder>(m_ZipFile, newZipDir, m_CurDir, pidl, riid, ppvOut);
|
||||||
|
}
|
||||||
|
DbgPrint("%s(%S) UNHANDLED\n", __FUNCTION__, guid2string(riid));
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
|
||||||
|
{
|
||||||
|
const ZipPidlEntry* zipEntry1 = _ZipFromIL(pidl1);
|
||||||
|
const ZipPidlEntry* zipEntry2 = _ZipFromIL(pidl2);
|
||||||
|
|
||||||
|
if (!zipEntry1 || !zipEntry2)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
if (zipEntry1->ZipType != zipEntry2->ZipType)
|
||||||
|
result = zipEntry1->ZipType - zipEntry2->ZipType;
|
||||||
|
else
|
||||||
|
result = stricmp(zipEntry1->Name, zipEntry2->Name);
|
||||||
|
|
||||||
|
if (!result && zipEntry1->ZipType == ZIP_PIDL_DIRECTORY)
|
||||||
|
{
|
||||||
|
PCUIDLIST_RELATIVE child1 = ILGetNext(pidl1);
|
||||||
|
PCUIDLIST_RELATIVE child2 = ILGetNext(pidl2);
|
||||||
|
|
||||||
|
if (child1->mkid.cb && child2->mkid.cb)
|
||||||
|
return CompareIDs(lParam, child1, child2);
|
||||||
|
else if (child1->mkid.cb)
|
||||||
|
result = 1;
|
||||||
|
else if (child2->mkid.cb)
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MAKE_COMPARE_HRESULT(result);
|
||||||
|
}
|
||||||
|
STDMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
|
||||||
|
{
|
||||||
|
static const GUID UnknownIID = // {93F81976-6A0D-42C3-94DD-AA258A155470}
|
||||||
|
{0x93F81976, 0x6A0D, 0x42C3, {0x94, 0xDD, 0xAA, 0x25, 0x8A, 0x15, 0x54, 0x70}};
|
||||||
|
if (riid == IID_IShellView)
|
||||||
|
{
|
||||||
|
SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
|
||||||
|
CComPtr<IShellFolderViewCB> pcb;
|
||||||
|
|
||||||
|
HRESULT hr = _CFolderViewCB_CreateInstance(IID_PPV_ARG(IShellFolderViewCB, &pcb));
|
||||||
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
sfvparams.psfvcb = pcb;
|
||||||
|
hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
if (riid == IID_IExplorerCommandProvider)
|
||||||
|
{
|
||||||
|
return _CExplorerCommandProvider_CreateInstance(this, riid, ppvOut);
|
||||||
|
}
|
||||||
|
if (UnknownIID != riid)
|
||||||
|
DbgPrint("%s(%S) UNHANDLED\n", __FUNCTION__, guid2string(riid));
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
|
||||||
|
{
|
||||||
|
if (!rgfInOut || !cidl || !apidl)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
*rgfInOut = 0;
|
||||||
|
|
||||||
|
//static DWORD dwFileAttrs = SFGAO_STREAM | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | SFGAO_CANCOPY | SFGAO_CANMOVE;
|
||||||
|
//static DWORD dwFolderAttrs = SFGAO_FOLDER | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | SFGAO_STORAGE | SFGAO_CANCOPY | SFGAO_CANMOVE;
|
||||||
|
static DWORD dwFileAttrs = SFGAO_STREAM;
|
||||||
|
static DWORD dwFolderAttrs = SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
|
||||||
|
|
||||||
|
|
||||||
|
while (cidl > 0 && *apidl)
|
||||||
|
{
|
||||||
|
const ZipPidlEntry* zipEntry = _ZipFromIL(*apidl);
|
||||||
|
|
||||||
|
if (zipEntry)
|
||||||
|
{
|
||||||
|
if (zipEntry->ZipType == ZIP_PIDL_FILE)
|
||||||
|
*rgfInOut |= dwFileAttrs;
|
||||||
|
else
|
||||||
|
*rgfInOut |= dwFolderAttrs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*rgfInOut = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
apidl++;
|
||||||
|
cidl--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*rgfInOut &= ~SFGAO_VALIDATE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
static HRESULT CALLBACK ZipFolderMenuCallback(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj,
|
||||||
|
UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case DFM_MERGECONTEXTMENU:
|
||||||
|
DPRINT1("FIXME: Add menu items for DFM_MERGECONTEXTMENU\n");
|
||||||
|
return S_OK;
|
||||||
|
case DFM_INVOKECOMMAND:
|
||||||
|
case DFM_INVOKECOMMANDEX:
|
||||||
|
case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
|
||||||
|
{
|
||||||
|
if ((riid == IID_IExtractIconA || riid == IID_IExtractIconW) && cidl == 1)
|
||||||
|
{
|
||||||
|
const ZipPidlEntry* zipEntry = _ZipFromIL(*apidl);
|
||||||
|
if (zipEntry)
|
||||||
|
{
|
||||||
|
CComHeapPtr<WCHAR> pathW;
|
||||||
|
|
||||||
|
int len = MultiByteToWideChar(CP_ACP, 0, zipEntry->Name, -1, NULL, 0);
|
||||||
|
pathW.Allocate(len);
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, zipEntry->Name, -1, pathW, len);
|
||||||
|
|
||||||
|
DWORD dwAttributes = (zipEntry->ZipType == ZIP_PIDL_DIRECTORY) ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
|
||||||
|
return SHCreateFileExtractIconW(pathW, dwAttributes, riid, ppvOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (riid == IID_IContextMenu && cidl >= 0)
|
||||||
|
{
|
||||||
|
const ZipPidlEntry* zipEntry = _ZipFromIL(*apidl);
|
||||||
|
if (zipEntry)
|
||||||
|
{
|
||||||
|
HKEY keys[1] = {0};
|
||||||
|
int nkeys = 0;
|
||||||
|
if (zipEntry->ZipType == ZIP_PIDL_DIRECTORY)
|
||||||
|
{
|
||||||
|
LSTATUS res = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ | KEY_QUERY_VALUE, keys);
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
return E_FAIL;
|
||||||
|
nkeys++;
|
||||||
|
}
|
||||||
|
return CDefFolderMenu_Create2(NULL, hwndOwner, cidl, apidl, this, ZipFolderMenuCallback, nkeys, keys, (IContextMenu**)ppvOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (riid == IID_IDataObject && cidl >= 1)
|
||||||
|
{
|
||||||
|
return CIDLData_CreateFromIDArray(m_CurDir, cidl, apidl, (IDataObject**)ppvOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
DbgPrint("%s(%S) UNHANDLED\n", __FUNCTION__ , guid2string(riid));
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
STDMETHODIMP GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
|
||||||
|
{
|
||||||
|
if (!pidl)
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl);
|
||||||
|
if (curpidl->mkid.cb != 0)
|
||||||
|
{
|
||||||
|
DPRINT1("ERROR, unhandled PIDL!\n");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZipPidlEntry* zipEntry = _ZipFromIL(pidl);
|
||||||
|
if (!zipEntry)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
return SHSetStrRet(strRet, (LPCSTR)zipEntry->Name);
|
||||||
|
}
|
||||||
|
STDMETHODIMP SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
//// IStorage
|
||||||
|
//STDMETHODIMP CreateStream(LPCOLESTR pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm);
|
||||||
|
//STDMETHODIMP OpenStream(LPCOLESTR pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
|
||||||
|
//STDMETHODIMP CreateStorage(LPCOLESTR pwcsName, DWORD grfMode, DWORD dwStgFmt, DWORD reserved2, IStorage **ppstg);
|
||||||
|
//STDMETHODIMP OpenStorage(LPCOLESTR pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
|
||||||
|
//STDMETHODIMP CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest);
|
||||||
|
//STDMETHODIMP MoveElementTo(LPCOLESTR pwcsName, IStorage *pstgDest, LPCOLESTR pwcsNewName, DWORD grfFlags);
|
||||||
|
//STDMETHODIMP Commit(DWORD grfCommitFlags);
|
||||||
|
//STDMETHODIMP Revert();
|
||||||
|
//STDMETHODIMP EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum);
|
||||||
|
//STDMETHODIMP DestroyElement(LPCOLESTR pwcsName);
|
||||||
|
//STDMETHODIMP RenameElement(LPCOLESTR pwcsOldName, LPCOLESTR pwcsNewName);
|
||||||
|
//STDMETHODIMP SetElementTimes(LPCOLESTR pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime);
|
||||||
|
//STDMETHODIMP SetClass(REFCLSID clsid);
|
||||||
|
//STDMETHODIMP SetStateBits(DWORD grfStateBits, DWORD grfMask);
|
||||||
|
//STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag);
|
||||||
|
|
||||||
|
// *** IContextMenu methods ***
|
||||||
|
STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||||
|
{
|
||||||
|
if (idCmd != 0)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
switch (uFlags)
|
||||||
|
{
|
||||||
|
case GCS_VERBA:
|
||||||
|
return StringCchCopyA(pszName, cchMax, EXTRACT_VERBA);
|
||||||
|
case GCS_VERBW:
|
||||||
|
return StringCchCopyW((LPWSTR)pszName, cchMax, EXTRACT_VERBW);
|
||||||
|
case GCS_HELPTEXTA:
|
||||||
|
{
|
||||||
|
CStringA helpText(MAKEINTRESOURCEA(IDS_HELPTEXT));
|
||||||
|
return StringCchCopyA(pszName, cchMax, helpText);
|
||||||
|
}
|
||||||
|
case GCS_HELPTEXTW:
|
||||||
|
{
|
||||||
|
CStringW helpText(MAKEINTRESOURCEA(IDS_HELPTEXT));
|
||||||
|
return StringCchCopyW((LPWSTR)pszName, cchMax, helpText);
|
||||||
|
}
|
||||||
|
case GCS_VALIDATEA:
|
||||||
|
case GCS_VALIDATEW:
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||||||
|
{
|
||||||
|
if (!pici || pici->cbSize != sizeof(*pici))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (pici->lpVerb == MAKEINTRESOURCEA(0) || (HIWORD(pici->lpVerb) && !strcmp(pici->lpVerb, EXTRACT_VERBA)))
|
||||||
|
{
|
||||||
|
BSTR ZipFile = m_ZipFile.AllocSysString();
|
||||||
|
InterlockedIncrement(&g_ModuleRefCnt);
|
||||||
|
|
||||||
|
DWORD tid;
|
||||||
|
HANDLE hThread = CreateThread(NULL, 0, s_ExtractProc, ZipFile, NULL, &tid);
|
||||||
|
if (hThread)
|
||||||
|
{
|
||||||
|
CloseHandle(hThread);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||||
|
{
|
||||||
|
int Entries = 0;
|
||||||
|
|
||||||
|
CStringW menuText(MAKEINTRESOURCEW(IDS_MENUITEM));
|
||||||
|
|
||||||
|
InsertMenuW(hmenu, indexMenu++, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
|
||||||
|
Entries++;
|
||||||
|
InsertMenuW(hmenu, indexMenu++, MF_BYPOSITION | MF_STRING, idCmdFirst++, menuText);
|
||||||
|
Entries++;
|
||||||
|
|
||||||
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IShellExtInit methods ***
|
||||||
|
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hkeyProgID)
|
||||||
|
{
|
||||||
|
FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||||
|
STGMEDIUM stg;
|
||||||
|
|
||||||
|
HRESULT hr = pDataObj->GetData(&etc, &stg);
|
||||||
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
{
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
hr = E_FAIL;
|
||||||
|
HDROP hdrop = (HDROP)GlobalLock(stg.hGlobal);
|
||||||
|
if (hdrop)
|
||||||
|
{
|
||||||
|
UINT uNumFiles = DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0);
|
||||||
|
if (uNumFiles == 1)
|
||||||
|
{
|
||||||
|
WCHAR szFile[MAX_PATH * 2];
|
||||||
|
if (DragQueryFileW(hdrop, 0, szFile, _countof(szFile)))
|
||||||
|
{
|
||||||
|
CComHeapPtr<ITEMIDLIST> pidl;
|
||||||
|
hr = SHParseDisplayName(szFile, NULL, &pidl, 0, NULL);
|
||||||
|
if (!FAILED_UNEXPECTEDLY(hr))
|
||||||
|
{
|
||||||
|
hr = Initialize(pidl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DbgPrint("Failed to query the file.\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DbgPrint("Invalid number of files: %d\r\n", uNumFiles);
|
||||||
|
}
|
||||||
|
GlobalUnlock(stg.hGlobal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DbgPrint("Could not lock stg.hGlobal\r\n");
|
||||||
|
}
|
||||||
|
ReleaseStgMedium(&stg);
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//// IPersistFile
|
||||||
|
////STDMETHODIMP GetClassID(CLSID *pclsid);
|
||||||
|
//STDMETHODIMP IsDirty();
|
||||||
|
//STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode);
|
||||||
|
//STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember);
|
||||||
|
//STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName);
|
||||||
|
//STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName);
|
||||||
|
|
||||||
|
//// *** IPersistFolder2 methods ***
|
||||||
|
STDMETHODIMP GetCurFolder(LPITEMIDLIST * pidl)
|
||||||
|
{
|
||||||
|
*pidl = ILClone(m_CurDir);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IPersistFolder methods ***
|
||||||
|
STDMETHODIMP Initialize(LPCITEMIDLIST pidl)
|
||||||
|
{
|
||||||
|
WCHAR tmpPath[MAX_PATH];
|
||||||
|
|
||||||
|
if (SHGetPathFromIDListW(pidl, tmpPath))
|
||||||
|
{
|
||||||
|
m_ZipFile = tmpPath;
|
||||||
|
m_CurDir.Attach(ILClone(pidl));
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
DbgPrint("%s() => Unable to parse pidl\n", __FUNCTION__);
|
||||||
|
return E_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** IPersist methods ***
|
||||||
|
STDMETHODIMP GetClassID(CLSID *lpClassId)
|
||||||
|
{
|
||||||
|
DbgPrint("%s\n", __FUNCTION__);
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STDMETHODIMP Initialize(PCWSTR zipFile, PCSTR zipDir, PCUIDLIST_ABSOLUTE curDir, PCUIDLIST_RELATIVE pidl)
|
||||||
|
{
|
||||||
|
m_ZipFile = zipFile;
|
||||||
|
m_ZipDir = zipDir;
|
||||||
|
|
||||||
|
m_CurDir.Attach(ILCombine(curDir, pidl));
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
static DWORD WINAPI s_ExtractProc(LPVOID arg)
|
||||||
|
{
|
||||||
|
CComBSTR ZipFile;
|
||||||
|
ZipFile.Attach((BSTR)arg);
|
||||||
|
|
||||||
|
_CZipExtract_runWizard(ZipFile);
|
||||||
|
|
||||||
|
InterlockedDecrement(&g_ModuleRefCnt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_NO_REGISTRY() // Handled manually because this object is exposed via multiple clsid's
|
||||||
|
DECLARE_NOT_AGGREGATABLE(CZipFolder)
|
||||||
|
|
||||||
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||||||
|
|
||||||
|
BEGIN_COM_MAP(CZipFolder)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
|
||||||
|
// COM_INTERFACE_ENTRY_IID(IID_IStorage, IStorage)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
|
||||||
|
//COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
|
||||||
|
END_COM_MAP()
|
||||||
|
};
|
||||||
|
|
44
dll/shellext/zipfldr/Debug.cpp
Normal file
44
dll/shellext/zipfldr/Debug.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: Zip extraction
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
static bool GetInterfaceName(const WCHAR* InterfaceString, WCHAR* buf, size_t size)
|
||||||
|
{
|
||||||
|
WCHAR LocalBuf[100];
|
||||||
|
DWORD dwType = 0, dwDataSize = size * sizeof(WCHAR);
|
||||||
|
|
||||||
|
if (!SUCCEEDED(StringCchPrintfW(LocalBuf, _countof(LocalBuf), L"Interface\\%s", InterfaceString)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return SHRegGetValueW(HKEY_CLASSES_ROOT, LocalBuf, NULL, RRF_RT_REG_SZ, &dwType, buf, &dwDataSize) == ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR* guid2string(REFCLSID iid)
|
||||||
|
{
|
||||||
|
static WCHAR buf[2][300];
|
||||||
|
static int idx = 0;
|
||||||
|
|
||||||
|
idx ^= 1;
|
||||||
|
|
||||||
|
LPOLESTR tmp;
|
||||||
|
HRESULT hr = ProgIDFromCLSID(iid, &tmp);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
wcscpy(buf[idx], tmp);
|
||||||
|
CoTaskMemFree(tmp);
|
||||||
|
return buf[idx];
|
||||||
|
}
|
||||||
|
StringFromGUID2(iid, buf[idx], _countof(buf[idx]));
|
||||||
|
if (GetInterfaceName(buf[idx], buf[idx], _countof(buf[idx])))
|
||||||
|
{
|
||||||
|
return buf[idx];
|
||||||
|
}
|
||||||
|
StringFromGUID2(iid, buf[idx], _countof(buf[idx]));
|
||||||
|
|
||||||
|
return buf[idx];
|
||||||
|
}
|
12
dll/shellext/zipfldr/IZip.hpp
Normal file
12
dll/shellext/zipfldr/IZip.hpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: IZip
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct IZip : public IUnknown
|
||||||
|
{
|
||||||
|
virtual STDMETHODIMP_(unzFile) getZip() PURE;
|
||||||
|
};
|
||||||
|
|
62
dll/shellext/zipfldr/precomp.h
Normal file
62
dll/shellext/zipfldr/precomp.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef ZIPFLDR_PRECOMP_H
|
||||||
|
#define ZIPFLDR_PRECOMP_H
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
#define COM_NO_WINDOWS_H
|
||||||
|
#define NTOS_MODE_USER
|
||||||
|
|
||||||
|
#include <windef.h>
|
||||||
|
#include <winbase.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <atlbase.h>
|
||||||
|
#include <atlcom.h>
|
||||||
|
#include <atlcoll.h>
|
||||||
|
#include <atlstr.h>
|
||||||
|
#include <rosdlgs.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
// debug.h needs this:
|
||||||
|
#define NTSTATUS LONG
|
||||||
|
#include <reactos/debug.h>
|
||||||
|
#include <shellutils.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define EXTRACT_VERBA "extract"
|
||||||
|
#define EXTRACT_VERBW L"extract"
|
||||||
|
|
||||||
|
EXTERN_C const GUID CLSID_ZipFolderStorageHandler;
|
||||||
|
EXTERN_C const GUID CLSID_ZipFolderSendTo;
|
||||||
|
EXTERN_C const GUID CLSID_ZipFolderContextMenu;
|
||||||
|
EXTERN_C const GUID CLSID_ZipFolderRightDragHandler;
|
||||||
|
EXTERN_C const GUID CLSID_ZipFolderDropHandler;
|
||||||
|
|
||||||
|
EXTERN_C const GUID CLSID_ZipFolderExtractAllCommand;
|
||||||
|
|
||||||
|
extern LONG g_ModuleRefCnt;
|
||||||
|
|
||||||
|
|
||||||
|
#define Win32DbgPrint(file, line, warn, func) DbgPrint("(%s:%d) " warn, file, line, func)
|
||||||
|
WCHAR* guid2string(REFCLSID iid);
|
||||||
|
|
||||||
|
|
||||||
|
#include "minizip/unzip.h"
|
||||||
|
#include "minizip/ioapi.h"
|
||||||
|
|
||||||
|
extern zlib_filefunc64_def g_FFunc;
|
||||||
|
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
#include "zippidl.hpp"
|
||||||
|
#include "IZip.hpp"
|
||||||
|
|
||||||
|
HRESULT _CEnumZipContents_CreateInstance(IZip* zip, DWORD flags, const char* prefix, REFIID riid, LPVOID * ppvOut);
|
||||||
|
HRESULT _CExplorerCommandProvider_CreateInstance(IContextMenu* zipObject, REFIID riid, LPVOID * ppvOut);
|
||||||
|
HRESULT _CFolderViewCB_CreateInstance(REFIID riid, LPVOID * ppvOut);
|
||||||
|
void _CZipExtract_runWizard(PCWSTR Filename);
|
||||||
|
|
||||||
|
#include "CZipEnumerator.hpp"
|
||||||
|
#include "CZipFolder.hpp"
|
||||||
|
|
||||||
|
#endif /* ZIPFLDR_PRECOMP_H */
|
BIN
dll/shellext/zipfldr/res/zipfldr.ico
Normal file
BIN
dll/shellext/zipfldr/res/zipfldr.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
54
dll/shellext/zipfldr/res/zipfldr.rgs
Normal file
54
dll/shellext/zipfldr/res/zipfldr.rgs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
HKCR
|
||||||
|
{
|
||||||
|
NoRemove CLSID
|
||||||
|
{
|
||||||
|
'{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}' = s 'CompressedFolder'
|
||||||
|
{
|
||||||
|
InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' }
|
||||||
|
ProgId = s 'CompressedFolder'
|
||||||
|
ShellFolder
|
||||||
|
{
|
||||||
|
val Attributes = d '0x200001a0'
|
||||||
|
val UseDropHandler = s ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'{b8cdcb65-b1bf-4b42-9428-1dfdb7ee92af}' = s 'Compressed (zipped) Folder Menu'
|
||||||
|
{
|
||||||
|
InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NoRemove Applications
|
||||||
|
{
|
||||||
|
'zipfldr.dll' { val NoOpenWith = s '' }
|
||||||
|
}
|
||||||
|
NoRemove CompressedFolder
|
||||||
|
{
|
||||||
|
FriendlyTypeName = s '%MODULE%,-10195'
|
||||||
|
CLSID = s '{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}'
|
||||||
|
DefaultIcon = s '%MODULE%'
|
||||||
|
|
||||||
|
NoRemove Shell
|
||||||
|
{
|
||||||
|
NoRemove Open
|
||||||
|
{
|
||||||
|
command = s 'rundll32.exe zipfldr.dll,RouteTheCall %%L'
|
||||||
|
val BrowserFlags = d '0x10'
|
||||||
|
val ExplorerFlags = d '0x10'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NoRemove shellex
|
||||||
|
{
|
||||||
|
NoRemove ContextMenuHandlers
|
||||||
|
{
|
||||||
|
ForceRemove '{b8cdcb65-b1bf-4b42-9428-1dfdb7ee92af}' = s 'Compressed (zipped) Folder Menu'
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NoRemove '.zip' = s 'CompressedFolder'
|
||||||
|
{
|
||||||
|
val 'Content Type' = s 'application/x-zip-compressed'
|
||||||
|
}
|
||||||
|
}
|
58
dll/shellext/zipfldr/resource.h
Normal file
58
dll/shellext/zipfldr/resource.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* registry stuff */
|
||||||
|
#define IDR_ZIPFLDR 8000
|
||||||
|
|
||||||
|
|
||||||
|
/* Dialogs */
|
||||||
|
|
||||||
|
#define IDD_PROPPAGEDESTIONATION 1000
|
||||||
|
#define IDC_DIRECTORY 1001
|
||||||
|
#define IDC_BROWSE 1002
|
||||||
|
#define IDC_PASSWORD 1003
|
||||||
|
#define IDC_PROGRESS 1004
|
||||||
|
|
||||||
|
#define IDD_PROPPAGECOMPLETE 1100
|
||||||
|
#define IDC_DESTDIR 1101
|
||||||
|
#define IDC_SHOW_EXTRACTED 1102
|
||||||
|
|
||||||
|
#define IDD_CONFIRM_FILE_REPLACE 1200
|
||||||
|
#define IDYESALL 1202
|
||||||
|
#define IDC_EXCLAMATION_ICON 1205
|
||||||
|
#define IDC_MESSAGE 1206
|
||||||
|
|
||||||
|
|
||||||
|
/* Strings */
|
||||||
|
#define IDS_COL_NAME 100
|
||||||
|
#define IDS_COL_TYPE 101
|
||||||
|
#define IDS_COL_COMPRSIZE 102
|
||||||
|
#define IDS_COL_PASSWORD 103
|
||||||
|
#define IDS_COL_SIZE 104
|
||||||
|
#define IDS_COL_RATIO 105
|
||||||
|
#define IDS_COL_DATE_MOD 106
|
||||||
|
#define IDS_YES 107
|
||||||
|
#define IDS_NO 108
|
||||||
|
|
||||||
|
|
||||||
|
/* Wizard titles */
|
||||||
|
#define IDS_WIZ_TITLE 8000
|
||||||
|
#define IDS_WIZ_DEST_TITLE 8001
|
||||||
|
#define IDS_WIZ_DEST_SUBTITLE 8002
|
||||||
|
#define IDS_WIZ_COMPL_TITLE 8003
|
||||||
|
#define IDS_WIZ_COMPL_SUBTITLE 8004
|
||||||
|
|
||||||
|
#define IDS_WIZ_BROWSE_TITLE 8010
|
||||||
|
|
||||||
|
/* Questions */
|
||||||
|
#define IDS_OVERWRITEFILE_TEXT 9000
|
||||||
|
|
||||||
|
|
||||||
|
/* Context menu / ExplorerCommand strings */
|
||||||
|
#define IDS_MENUITEM 10039
|
||||||
|
#define IDS_HELPTEXT 10041
|
||||||
|
#define IDS_FRIENDLYNAME 10195
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef IDC_STATIC
|
||||||
|
#define IDC_STATIC -1
|
||||||
|
#endif
|
117
dll/shellext/zipfldr/zipfldr.cpp
Normal file
117
dll/shellext/zipfldr/zipfldr.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: zipfldr entrypoint
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
HMODULE g_hModule = NULL;
|
||||||
|
LONG g_ModuleRefCnt = 0;
|
||||||
|
|
||||||
|
#include <initguid.h>
|
||||||
|
|
||||||
|
DEFINE_GUID(CLSID_ZipFolderStorageHandler, 0xe88dcce0, 0xb7b3, 0x11d1, 0xa9, 0xf0, 0x00, 0xaa, 0x00, 0x60, 0xfa, 0x31);
|
||||||
|
DEFINE_GUID(CLSID_ZipFolderSendTo, 0x888dca60, 0xfc0a, 0x11cf, 0x8f, 0x0f, 0x00, 0xc0, 0x4f, 0xd7, 0xd0, 0x62);
|
||||||
|
DEFINE_GUID(CLSID_ZipFolderContextMenu, 0xb8cdcb65, 0xb1bf, 0x4b42, 0x94, 0x28, 0x1d, 0xfd, 0xb7, 0xee, 0x92, 0xaf);
|
||||||
|
DEFINE_GUID(CLSID_ZipFolderRightDragHandler,0xbd472f60, 0x27fa, 0x11cf, 0xb8, 0xb4, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
|
||||||
|
DEFINE_GUID(CLSID_ZipFolderDropHandler, 0xed9d80b9, 0xd157, 0x457b, 0x91, 0x92, 0x0e, 0x72, 0x80, 0x31, 0x3b, 0xf0);
|
||||||
|
|
||||||
|
/* IExplorerCommand: Extract All */
|
||||||
|
DEFINE_GUID(CLSID_ZipFolderExtractAllCommand, 0xc3d9647b, 0x8fd9, 0x4ee6, 0x8b, 0xc7, 0x82, 0x7, 0x80, 0x9, 0x10, 0x5a);
|
||||||
|
|
||||||
|
|
||||||
|
class CZipFldrModule : public CComModule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_OBJECT_MAP(ObjectMap)
|
||||||
|
OBJECT_ENTRY(CLSID_ZipFolderStorageHandler, CZipFolder)
|
||||||
|
OBJECT_ENTRY(CLSID_ZipFolderContextMenu, CZipFolder)
|
||||||
|
END_OBJECT_MAP()
|
||||||
|
|
||||||
|
CZipFldrModule gModule;
|
||||||
|
|
||||||
|
|
||||||
|
#include "minizip/ioapi.h"
|
||||||
|
#include "minizip/iowin32.h"
|
||||||
|
|
||||||
|
zlib_filefunc64_def g_FFunc;
|
||||||
|
|
||||||
|
static void init_zlib()
|
||||||
|
{
|
||||||
|
fill_win32_filefunc64W(&g_FFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERN_C
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
switch (dwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
DisableThreadLibraryCalls(hInstance);
|
||||||
|
g_hModule = hInstance;
|
||||||
|
gModule.Init(ObjectMap, hInstance, NULL);
|
||||||
|
init_zlib();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDAPI DllCanUnloadNow()
|
||||||
|
{
|
||||||
|
if (g_ModuleRefCnt)
|
||||||
|
return S_FALSE;
|
||||||
|
return gModule.DllCanUnloadNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
|
||||||
|
{
|
||||||
|
return gModule.DllGetClassObject(rclsid, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
STDAPI DllRegisterServer()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = gModule.DllRegisterServer(FALSE);
|
||||||
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = gModule.UpdateRegistryFromResource(IDR_ZIPFLDR, TRUE, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDAPI DllUnregisterServer()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = gModule.DllUnregisterServer(FALSE);
|
||||||
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = gModule.UpdateRegistryFromResource(IDR_ZIPFLDR, FALSE, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERN_C
|
||||||
|
BOOL WINAPI
|
||||||
|
RouteTheCall(
|
||||||
|
IN HWND hWndOwner,
|
||||||
|
IN HINSTANCE hInstance,
|
||||||
|
IN LPWSTR lpNamedPipeName,
|
||||||
|
IN INT Show)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return FALSE;
|
||||||
|
}
|
88
dll/shellext/zipfldr/zipfldr.rc
Normal file
88
dll/shellext/zipfldr/zipfldr.rc
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#include <windef.h>
|
||||||
|
#include <winuser.h>
|
||||||
|
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
|
|
||||||
|
1 ICON "res/zipfldr.ico"
|
||||||
|
|
||||||
|
#define REACTOS_VERSION_DLL
|
||||||
|
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Zip Shell Extension"
|
||||||
|
#define REACTOS_STR_INTERNAL_NAME "zipfldr"
|
||||||
|
#define REACTOS_STR_ORIGINAL_FILENAME "zipfldr.dll"
|
||||||
|
#include <reactos/version.rc>
|
||||||
|
|
||||||
|
#include <reactos/manifest_dll.rc>
|
||||||
|
|
||||||
|
IDR_ZIPFLDR REGISTRY "res/zipfldr.rgs"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IDD_PROPPAGEDESTIONATION DIALOGEX 0, 0, 235, 156
|
||||||
|
STYLE DS_SHELLFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
|
||||||
|
CAPTION "Select a Destination"
|
||||||
|
FONT 8, "MS Shell Dlg", 400, 0, 0x0
|
||||||
|
BEGIN
|
||||||
|
LTEXT "Select the destionation directory",IDC_STATIC,6,12,174,8
|
||||||
|
EDITTEXT IDC_DIRECTORY,6,24,222,12,ES_AUTOHSCROLL
|
||||||
|
PUSHBUTTON "Browse...",IDC_BROWSE,174,42,54,14
|
||||||
|
PUSHBUTTON "Password",IDC_PASSWORD,174,66,54,14
|
||||||
|
LTEXT "Extracting...",IDC_STATIC,6,114,42,8
|
||||||
|
CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,6,126,222,6
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
IDD_PROPPAGECOMPLETE DIALOGEX 0, 0, 235, 156
|
||||||
|
STYLE DS_SHELLFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
|
||||||
|
CAPTION "Extraction Complete"
|
||||||
|
FONT 8, "MS Shell Dlg", 400, 0, 0x0
|
||||||
|
BEGIN
|
||||||
|
LTEXT "The files have been extracted to the following directory:",IDC_STATIC,6,12,222,18
|
||||||
|
LTEXT "Target dir",IDC_DESTDIR,6,36,222,8
|
||||||
|
CONTROL "Show extracted files",IDC_SHOW_EXTRACTED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,66,81,10
|
||||||
|
LTEXT "Press finish to continue.",IDC_STATIC,6,84,174,8
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
IDD_CONFIRM_FILE_REPLACE DIALOGEX 0, 0, 273, 56
|
||||||
|
STYLE DS_MODALFRAME | DS_SHELLFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
|
CAPTION "Confirm File Replace"
|
||||||
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
|
BEGIN
|
||||||
|
DEFPUSHBUTTON "&Yes",IDYES,6,36,62,14
|
||||||
|
PUSHBUTTON "Cancel",IDCANCEL,204,36,62,14
|
||||||
|
PUSHBUTTON "Yes &To All",IDYESALL,72,36,62,14
|
||||||
|
PUSHBUTTON "&No",IDNO,138,36,62,14
|
||||||
|
ICON "",IDC_EXCLAMATION_ICON,6,6,24,22
|
||||||
|
LTEXT "",IDC_MESSAGE,36,6,228,24
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
STRINGTABLE
|
||||||
|
BEGIN
|
||||||
|
IDS_COL_NAME "Name"
|
||||||
|
IDS_COL_TYPE "Type"
|
||||||
|
IDS_COL_COMPRSIZE "Compressed size"
|
||||||
|
IDS_COL_PASSWORD "Password"
|
||||||
|
IDS_COL_SIZE "Size"
|
||||||
|
IDS_COL_RATIO "Ratio"
|
||||||
|
IDS_COL_DATE_MOD "Date modified"
|
||||||
|
IDS_YES "Yes"
|
||||||
|
IDS_NO "No"
|
||||||
|
|
||||||
|
IDS_WIZ_TITLE "Extraction Wizard"
|
||||||
|
IDS_WIZ_DEST_TITLE "Select a Destination"
|
||||||
|
IDS_WIZ_DEST_SUBTITLE "The files from the zip archive will be extracted to the location specified."
|
||||||
|
IDS_WIZ_COMPL_TITLE "Extraction Complete"
|
||||||
|
IDS_WIZ_COMPL_SUBTITLE "The files from the zip archive have been extracted."
|
||||||
|
IDS_WIZ_BROWSE_TITLE "Select the place where you want to extract the selected items."
|
||||||
|
|
||||||
|
IDS_OVERWRITEFILE_TEXT "This folder already contains a file called '%1'.\nDo you want to replace it?"
|
||||||
|
|
||||||
|
IDS_MENUITEM "Extract &All..."
|
||||||
|
IDS_HELPTEXT "Extracts folder contents"
|
||||||
|
IDS_FRIENDLYNAME "Compressed (zipped) Folder"
|
||||||
|
|
||||||
|
END
|
5
dll/shellext/zipfldr/zipfldr.spec
Normal file
5
dll/shellext/zipfldr/zipfldr.spec
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
@ stdcall -private DllCanUnloadNow()
|
||||||
|
@ stdcall -private DllGetClassObject(ptr ptr ptr)
|
||||||
|
@ stdcall -private DllRegisterServer()
|
||||||
|
@ stdcall -private DllUnregisterServer()
|
||||||
|
@ stdcall RouteTheCall(ptr ptr wstr long)
|
42
dll/shellext/zipfldr/zippidl.cpp
Normal file
42
dll/shellext/zipfldr/zippidl.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: zip pidl handling
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
LPITEMIDLIST _ILCreate(ZipPidlType Type, LPCSTR lpString, unz_file_info64& info)
|
||||||
|
{
|
||||||
|
int cbData = sizeof(ZipPidlEntry) + strlen(lpString);
|
||||||
|
ZipPidlEntry* pidl = (ZipPidlEntry*)SHAlloc(cbData + sizeof(WORD));
|
||||||
|
if (!pidl)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pidl->cb = cbData;
|
||||||
|
pidl->MagicType = 'z';
|
||||||
|
pidl->ZipType = Type;
|
||||||
|
|
||||||
|
if (Type != ZIP_PIDL_DIRECTORY)
|
||||||
|
{
|
||||||
|
pidl->CompressedSize = info.compressed_size;
|
||||||
|
pidl->UncompressedSize = info.uncompressed_size;
|
||||||
|
pidl->DosDate = info.dosDate;
|
||||||
|
pidl->Password = info.flag & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(pidl->Name, lpString);
|
||||||
|
*(WORD*)((char*)pidl + cbData) = 0;
|
||||||
|
|
||||||
|
return (LPITEMIDLIST)pidl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ZipPidlEntry* _ZipFromIL(LPCITEMIDLIST pidl)
|
||||||
|
{
|
||||||
|
const ZipPidlEntry* zipPidl = (const ZipPidlEntry*)pidl;
|
||||||
|
if (zipPidl->MagicType == 'z')
|
||||||
|
return zipPidl;
|
||||||
|
return NULL;
|
||||||
|
}
|
34
dll/shellext/zipfldr/zippidl.hpp
Normal file
34
dll/shellext/zipfldr/zippidl.hpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Zip Shell Extension
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: zip pidl handling
|
||||||
|
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
enum ZipPidlType
|
||||||
|
{
|
||||||
|
ZIP_PIDL_DIRECTORY,
|
||||||
|
ZIP_PIDL_FILE
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <pshpack1.h>
|
||||||
|
struct ZipPidlEntry
|
||||||
|
{
|
||||||
|
WORD cb;
|
||||||
|
BYTE MagicType;
|
||||||
|
ZipPidlType ZipType;
|
||||||
|
|
||||||
|
ULONG64 CompressedSize;
|
||||||
|
ULONG64 UncompressedSize;
|
||||||
|
ULONG DosDate;
|
||||||
|
BYTE Password;
|
||||||
|
|
||||||
|
char Name[1];
|
||||||
|
};
|
||||||
|
#include <poppack.h>
|
||||||
|
|
||||||
|
|
||||||
|
LPITEMIDLIST _ILCreate(ZipPidlType Type, LPCSTR lpString, unz_file_info64& info);
|
||||||
|
const ZipPidlEntry* _ZipFromIL(LPCITEMIDLIST pidl);
|
||||||
|
|
Loading…
Reference in a new issue