https://git.reactos.org/?p=reactos.git;a=commitdiff;h=962ff6e2fa96dd9f6f5fe…
commit 962ff6e2fa96dd9f6f5fee0e04551d4a54c076ec
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sun Dec 1 21:20:53 2019 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sun Dec 1 21:20:53 2019 +0900
[SHELLEXT][ZIPFLDR] Implement ZIP creation (#2114)
This PR will implement *.ZFSendToTarget file type that will realize SendTo ZIP folder
in future.
CORE-16495, CORE-12562
---
dll/shellext/zipfldr/CMakeLists.txt | 2 +
dll/shellext/zipfldr/CSendToZip.cpp | 90 +++++++++
dll/shellext/zipfldr/CSendToZip.hpp | 79 ++++++++
dll/shellext/zipfldr/CZipCreater.cpp | 358 +++++++++++++++++++++++++++++++++++
dll/shellext/zipfldr/CZipCreater.hpp | 32 ++++
dll/shellext/zipfldr/lang/de-DE.rc | 5 +
dll/shellext/zipfldr/lang/en-US.rc | 5 +
dll/shellext/zipfldr/lang/et-EE.rc | 5 +
dll/shellext/zipfldr/lang/fr-FR.rc | 5 +
dll/shellext/zipfldr/lang/hi-IN.rc | 5 +
dll/shellext/zipfldr/lang/it-IT.rc | 5 +
dll/shellext/zipfldr/lang/ja-JP.rc | 5 +
dll/shellext/zipfldr/lang/pl-PL.rc | 5 +
dll/shellext/zipfldr/lang/ro-RO.rc | 5 +
dll/shellext/zipfldr/lang/ru-RU.rc | 5 +
dll/shellext/zipfldr/lang/sv-SE.rc | 5 +
dll/shellext/zipfldr/lang/zh-CN.rc | 5 +
dll/shellext/zipfldr/precomp.h | 2 +
dll/shellext/zipfldr/res/zipfldr.rgs | 32 +++-
dll/shellext/zipfldr/resource.h | 6 +-
dll/shellext/zipfldr/zipfldr.cpp | 1 +
21 files changed, 658 insertions(+), 4 deletions(-)
diff --git a/dll/shellext/zipfldr/CMakeLists.txt b/dll/shellext/zipfldr/CMakeLists.txt
index 3c39dc45c3e..a0244d642aa 100644
--- a/dll/shellext/zipfldr/CMakeLists.txt
+++ b/dll/shellext/zipfldr/CMakeLists.txt
@@ -28,6 +28,8 @@ list(APPEND SOURCE
CExplorerCommand.cpp
CEnumZipContents.cpp
CFolderViewCB.cpp
+ CSendToZip.cpp
+ CZipCreater.cpp
CZipEnumerator.hpp
CZipExtract.cpp
CZipFolder.hpp
diff --git a/dll/shellext/zipfldr/CSendToZip.cpp b/dll/shellext/zipfldr/CSendToZip.cpp
new file mode 100644
index 00000000000..9ec9bd5dc7a
--- /dev/null
+++ b/dll/shellext/zipfldr/CSendToZip.cpp
@@ -0,0 +1,90 @@
+/*
+ * PROJECT: ReactOS Zip Shell Extension
+ * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: SendTo handler
+ * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen(a)reactos.org)
+ * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#include "precomp.h"
+
+STDMETHODIMP
+CSendToZip::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt,
+ DWORD *pdwEffect)
+{
+ m_pDataObject = pDataObj;
+
+ FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ m_fCanDragDrop = SUCCEEDED(pDataObj->QueryGetData(&etc));
+
+ if (m_fCanDragDrop)
+ *pdwEffect &= DROPEFFECT_COPY;
+ else
+ *pdwEffect = DROPEFFECT_NONE;
+
+ return S_OK;
+}
+
+STDMETHODIMP CSendToZip::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ if (m_fCanDragDrop)
+ *pdwEffect &= DROPEFFECT_COPY;
+ else
+ *pdwEffect = DROPEFFECT_NONE;
+
+ return S_OK;
+}
+
+STDMETHODIMP CSendToZip::DragLeave()
+{
+ m_fCanDragDrop = FALSE;
+ m_pDataObject.Release();
+ return S_OK;
+}
+
+STDMETHODIMP
+CSendToZip::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt,
+ DWORD *pdwEffect)
+{
+ m_pDataObject = pDataObj;
+ *pdwEffect &= DROPEFFECT_COPY;
+
+ if (!pDataObj || !m_fCanDragDrop || !*pdwEffect)
+ {
+ DPRINT1("Drop failed: %d %d %d\n",
+ !pDataObj, !m_fCanDragDrop, !*pdwEffect);
+ *pdwEffect = 0;
+ DragLeave();
+ return E_FAIL;
+ }
+
+ STGMEDIUM stg;
+ FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ HRESULT hr = pDataObj->GetData(&etc, &stg);
+ if (FAILED_UNEXPECTEDLY(hr))
+ {
+ *pdwEffect = 0;
+ DragLeave();
+ return E_FAIL;
+ }
+
+ HDROP hDrop = reinterpret_cast<HDROP>(stg.hGlobal);
+ UINT cItems = ::DragQueryFileW(hDrop, -1, NULL, 0);
+
+ CZipCreator *pCreater = CZipCreator::DoCreate();
+
+ for (UINT iItem = 0; iItem < cItems; ++iItem)
+ {
+ WCHAR szPath[MAX_PATH];
+ DragQueryFileW(hDrop, iItem, szPath, _countof(szPath));
+
+ pCreater->DoAddItem(szPath);
+ }
+
+ ::ReleaseStgMedium(&stg);
+
+ CZipCreator::runThread(pCreater); // pCreater is deleted in runThread
+
+ DragLeave();
+ return hr;
+}
diff --git a/dll/shellext/zipfldr/CSendToZip.hpp b/dll/shellext/zipfldr/CSendToZip.hpp
new file mode 100644
index 00000000000..1f3eb248a13
--- /dev/null
+++ b/dll/shellext/zipfldr/CSendToZip.hpp
@@ -0,0 +1,79 @@
+/*
+ * PROJECT: ReactOS Zip Shell Extension
+ * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: SendTo handler
+ * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen(a)reactos.org)
+ * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#ifndef CSENDTOZIP_HPP_
+#define CSENDTOZIP_HPP_
+
+class CSendToZip :
+ public CComCoClass<CSendToZip, &CLSID_ZipFolderSendTo>,
+ public CComObjectRootEx<CComMultiThreadModelNoCS>,
+ public IDropTarget,
+ public IPersistFile
+{
+ CComPtr<IDataObject> m_pDataObject;
+ BOOL m_fCanDragDrop;
+
+public:
+ CSendToZip() : m_fCanDragDrop(FALSE)
+ {
+ InterlockedIncrement(&g_ModuleRefCnt);
+ }
+
+ virtual ~CSendToZip()
+ {
+ InterlockedDecrement(&g_ModuleRefCnt);
+ }
+
+ // *** IShellFolder2 methods ***
+ STDMETHODIMP DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD
*pdwEffect);
+ STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+ STDMETHODIMP DragLeave();
+ STDMETHODIMP Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD
*pdwEffect);
+
+ // *** IPersistFile methods ***
+ STDMETHODIMP IsDirty()
+ {
+ return S_FALSE;
+ }
+ STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode)
+ {
+ return S_OK;
+ }
+ STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember)
+ {
+ return E_FAIL;
+ }
+ STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName)
+ {
+ return E_FAIL;
+ }
+ STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName)
+ {
+ return E_FAIL;
+ }
+
+ // *** IPersist methods ***
+ STDMETHODIMP GetClassID(CLSID *pclsid)
+ {
+ return E_FAIL;
+ }
+
+public:
+ DECLARE_NO_REGISTRY() // Handled manually
+ DECLARE_NOT_AGGREGATABLE(CSendToZip)
+
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+ BEGIN_COM_MAP(CSendToZip)
+ COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
+ COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile)
+ COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+ END_COM_MAP()
+};
+
+#endif
diff --git a/dll/shellext/zipfldr/CZipCreater.cpp b/dll/shellext/zipfldr/CZipCreater.cpp
new file mode 100644
index 00000000000..694128b6bcb
--- /dev/null
+++ b/dll/shellext/zipfldr/CZipCreater.cpp
@@ -0,0 +1,358 @@
+/*
+ * PROJECT: ReactOS Zip Shell Extension
+ * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: Create a zip file
+ * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen(a)reactos.org)
+ * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#include "precomp.h"
+#include "atlsimpcoll.h"
+#include "minizip/zip.h"
+#include "minizip/iowin32.h"
+#include <process.h>
+
+static CStringW DoGetZipName(LPCWSTR filename)
+{
+ WCHAR szPath[MAX_PATH];
+ StringCbCopyW(szPath, sizeof(szPath), filename);
+ PathRemoveExtensionW(szPath);
+
+ CStringW ret = szPath;
+ ret += L".zip";
+
+ UINT i = 2;
+ while (PathFileExistsW(ret))
+ {
+ CStringW str;
+ str.Format(L" (%u).zip", i++);
+
+ ret = szPath;
+ ret += str;
+ }
+
+ return ret;
+}
+
+static CStringA DoGetAnsiName(LPCWSTR filename)
+{
+ CHAR buf[MAX_PATH];
+ WideCharToMultiByte(CP_ACP, 0, filename, -1, buf, _countof(buf), NULL, NULL);
+ return buf;
+}
+
+static CStringW DoGetBaseName(LPCWSTR filename)
+{
+ WCHAR szBaseName[MAX_PATH];
+ StringCbCopyW(szBaseName, sizeof(szBaseName), filename);
+ PathRemoveFileSpecW(szBaseName);
+ PathAddBackslashW(szBaseName);
+ return szBaseName;
+}
+
+static CStringA
+DoGetNameInZip(const CStringW& basename, const CStringW& filename)
+{
+ CStringW basenameI = basename, filenameI = filename;
+ basenameI.MakeUpper();
+ filenameI.MakeUpper();
+
+ CStringW ret;
+ if (filenameI.Find(basenameI) == 0)
+ ret = filename.Mid(basename.GetLength());
+ else
+ ret = filename;
+
+ ret.Replace(L'\\', L'/');
+
+ return DoGetAnsiName(ret);
+}
+
+static BOOL
+DoReadAllOfFile(LPCWSTR filename, CSimpleArray<BYTE>& contents,
+ zip_fileinfo *pzi)
+{
+ contents.RemoveAll();
+
+ HANDLE hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ DPRINT1("%S: cannot open\n", filename);
+ return FALSE;
+ }
+
+ FILETIME ft, ftLocal;
+ ZeroMemory(pzi, sizeof(*pzi));
+ if (GetFileTime(hFile, NULL, NULL, &ft))
+ {
+ SYSTEMTIME st;
+ FileTimeToLocalFileTime(&ft, &ftLocal);
+ FileTimeToSystemTime(&ftLocal, &st);
+ pzi->tmz_date.tm_sec = st.wSecond;
+ pzi->tmz_date.tm_min = st.wMinute;
+ pzi->tmz_date.tm_hour = st.wHour;
+ pzi->tmz_date.tm_mday = st.wDay;
+ pzi->tmz_date.tm_mon = st.wMonth - 1;
+ pzi->tmz_date.tm_year = st.wYear;
+ }
+
+ const DWORD cbBuff = 0x7FFF;
+ LPBYTE pbBuff = reinterpret_cast<LPBYTE>(CoTaskMemAlloc(cbBuff));
+ if (!pbBuff)
+ {
+ DPRINT1("Out of memory\n");
+ CloseHandle(hFile);
+ return FALSE;
+ }
+
+ for (;;)
+ {
+ DWORD cbRead;
+ if (!ReadFile(hFile, pbBuff, cbBuff, &cbRead, NULL) || !cbRead)
+ break;
+
+ for (DWORD i = 0; i < cbRead; ++i)
+ contents.Add(pbBuff[i]);
+ }
+
+ CoTaskMemFree(pbBuff);
+ CloseHandle(hFile);
+
+ return TRUE;
+}
+
+static void
+DoAddFilesFromItem(CSimpleArray<CStringW>& files, LPCWSTR item)
+{
+ if (!PathIsDirectoryW(item))
+ {
+ files.Add(item);
+ return;
+ }
+
+ WCHAR szPath[MAX_PATH];
+ StringCbCopyW(szPath, sizeof(szPath), item);
+ PathAppendW(szPath, L"*");
+
+ WIN32_FIND_DATAW find;
+ HANDLE hFind = FindFirstFileW(szPath, &find);
+ if (hFind == INVALID_HANDLE_VALUE)
+ return;
+
+ do
+ {
+ if (wcscmp(find.cFileName, L".") == 0 ||
+ wcscmp(find.cFileName, L"..") == 0)
+ {
+ continue;
+ }
+
+ StringCbCopyW(szPath, sizeof(szPath), item);
+ PathAppendW(szPath, find.cFileName);
+
+ if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ DoAddFilesFromItem(files, szPath);
+ else
+ files.Add(szPath);
+ } while (FindNextFileW(hFind, &find));
+
+ FindClose(hFind);
+}
+
+struct CZipCreatorImpl
+{
+ CSimpleArray<CStringW> m_items;
+
+ unsigned JustDoIt();
+};
+
+CZipCreator::CZipCreator() : m_pimpl(new CZipCreatorImpl)
+{
+ InterlockedIncrement(&g_ModuleRefCnt);
+}
+
+CZipCreator::~CZipCreator()
+{
+ InterlockedDecrement(&g_ModuleRefCnt);
+ delete m_pimpl;
+}
+
+static unsigned __stdcall
+create_zip_function(void *arg)
+{
+ CZipCreator *pCreater = reinterpret_cast<CZipCreator *>(arg);
+ return pCreater->m_pimpl->JustDoIt();
+}
+
+BOOL CZipCreator::runThread(CZipCreator *pCreater)
+{
+ unsigned tid = 0;
+ HANDLE hThread = reinterpret_cast<HANDLE>(
+ _beginthreadex(NULL, 0, create_zip_function, pCreater, 0, &tid));
+
+ if (hThread)
+ {
+ CloseHandle(hThread);
+ return TRUE;
+ }
+
+ DPRINT1("hThread == NULL\n");
+
+ CStringW strTitle(MAKEINTRESOURCEW(IDS_ERRORTITLE));
+ CStringW strText(MAKEINTRESOURCEW(IDS_CANTSTARTTHREAD));
+ MessageBoxW(NULL, strText, strTitle, MB_ICONERROR);
+
+ delete pCreater;
+ return FALSE;
+}
+
+void CZipCreator::DoAddItem(LPCWSTR pszFile)
+{
+ // canonicalize path
+ WCHAR szPath[MAX_PATH];
+ GetFullPathNameW(pszFile, _countof(szPath), szPath, NULL);
+
+ m_pimpl->m_items.Add(szPath);
+}
+
+enum CZC_ERROR
+{
+ CZCERR_ZEROITEMS = 1,
+ CZCERR_NOFILES,
+ CZCERR_CREATE,
+ CZCERR_READ
+};
+
+unsigned CZipCreatorImpl::JustDoIt()
+{
+ // TODO: Show progress.
+
+ if (m_items.GetSize() <= 0)
+ {
+ DPRINT1("GetSize() <= 0\n");
+ return CZCERR_ZEROITEMS;
+ }
+
+ CSimpleArray<CStringW> files;
+ for (INT iItem = 0; iItem < m_items.GetSize(); ++iItem)
+ {
+ DoAddFilesFromItem(files, m_items[iItem]);
+ }
+
+ if (files.GetSize() <= 0)
+ {
+ DPRINT1("files.GetSize() <= 0\n");
+
+ CStringW strTitle(MAKEINTRESOURCEW(IDS_ERRORTITLE));
+ CStringW strText;
+ strText.Format(IDS_NOFILES, static_cast<LPCWSTR>(m_items[0]));
+ MessageBoxW(NULL, strText, strTitle, MB_ICONERROR);
+
+ return CZCERR_NOFILES;
+ }
+
+ zlib_filefunc64_def ffunc;
+ fill_win32_filefunc64W(&ffunc);
+
+ CStringW strZipName = DoGetZipName(m_items[0]);
+ zipFile zf = zipOpen2_64(strZipName, APPEND_STATUS_CREATE, NULL, &ffunc);
+ if (zf == 0)
+ {
+ DPRINT1("zf == 0\n");
+
+ int err = CZCERR_CREATE;
+
+ CStringW strTitle(MAKEINTRESOURCEW(IDS_ERRORTITLE));
+ CStringW strText;
+ strText.Format(IDS_CANTCREATEZIP, static_cast<LPCWSTR>(strZipName), err);
+ MessageBoxW(NULL, strText, strTitle, MB_ICONERROR);
+
+ return err;
+ }
+
+ // TODO: password
+ const char *password = NULL;
+ int zip64 = 1; // always zip64
+ zip_fileinfo zi;
+
+ int err = 0;
+ CStringW strTarget, strBaseName = DoGetBaseName(m_items[0]);
+ for (INT iFile = 0; iFile < files.GetSize(); ++iFile)
+ {
+ const CStringW& strFile = files[iFile];
+
+ CSimpleArray<BYTE> contents;
+ if (!DoReadAllOfFile(strFile, contents, &zi))
+ {
+ DPRINT1("DoReadAllOfFile failed\n");
+ err = CZCERR_READ;
+ strTarget = strFile;
+ break;
+ }
+
+ unsigned long crc = 0;
+ if (password)
+ {
+ // TODO: crc = ...;
+ }
+
+ CStringA strNameInZip = DoGetNameInZip(strBaseName, strFile);
+ err = zipOpenNewFileInZip3_64(zf,
+ strNameInZip,
+ &zi,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ password,
+ crc,
+ zip64);
+ if (err)
+ {
+ DPRINT1("zipOpenNewFileInZip3_64\n");
+ break;
+ }
+
+ err = zipWriteInFileInZip(zf, contents.GetData(), contents.GetSize());
+ if (err)
+ {
+ DPRINT1("zipWriteInFileInZip\n");
+ break;
+ }
+
+ err = zipCloseFileInZip(zf);
+ if (err)
+ {
+ DPRINT1("zipCloseFileInZip\n");
+ break;
+ }
+ }
+
+ zipClose(zf, NULL);
+
+ if (err)
+ {
+ DeleteFileW(strZipName);
+
+ CStringW strTitle(MAKEINTRESOURCEW(IDS_ERRORTITLE));
+
+ CStringW strText;
+ if (err < 0)
+ strText.Format(IDS_CANTCREATEZIP, static_cast<LPCWSTR>(strZipName),
err);
+ else
+ strText.Format(IDS_CANTREADFILE, static_cast<LPCWSTR>(strTarget));
+
+ MessageBoxW(NULL, strText, strTitle, MB_ICONERROR);
+ }
+
+ return err;
+}
diff --git a/dll/shellext/zipfldr/CZipCreater.hpp b/dll/shellext/zipfldr/CZipCreater.hpp
new file mode 100644
index 00000000000..52fb14f9ead
--- /dev/null
+++ b/dll/shellext/zipfldr/CZipCreater.hpp
@@ -0,0 +1,32 @@
+/*
+ * PROJECT: ReactOS Zip Shell Extension
+ * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: Create a zip file
+ * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen(a)reactos.org)
+ * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+#ifndef CZIPCREATER_HPP_
+#define CZIPCREATER_HPP_
+
+struct CZipCreatorImpl;
+
+class CZipCreator
+{
+public:
+ struct CZipCreatorImpl *m_pimpl;
+
+ virtual ~CZipCreator();
+
+ static CZipCreator* DoCreate()
+ {
+ return new CZipCreator();
+ }
+
+ virtual void DoAddItem(LPCWSTR pszFile);
+ static BOOL runThread(CZipCreator* pCreater);
+
+protected:
+ CZipCreator();
+};
+
+#endif
diff --git a/dll/shellext/zipfldr/lang/de-DE.rc b/dll/shellext/zipfldr/lang/de-DE.rc
index 5925822e051..6f50cb7d0d0 100644
--- a/dll/shellext/zipfldr/lang/de-DE.rc
+++ b/dll/shellext/zipfldr/lang/de-DE.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Änderungsdatum"
IDS_YES "Ja"
IDS_NO "Nein"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Extrahier-Assistent"
IDS_WIZ_DEST_TITLE "Ziel auswählen"
diff --git a/dll/shellext/zipfldr/lang/en-US.rc b/dll/shellext/zipfldr/lang/en-US.rc
index bba5be5c870..a73ad541688 100644
--- a/dll/shellext/zipfldr/lang/en-US.rc
+++ b/dll/shellext/zipfldr/lang/en-US.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Date modified"
IDS_YES "Yes"
IDS_NO "No"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Extraction Wizard"
IDS_WIZ_DEST_TITLE "Select a Destination"
diff --git a/dll/shellext/zipfldr/lang/et-EE.rc b/dll/shellext/zipfldr/lang/et-EE.rc
index c9a7cc0f982..eb2b0280afb 100644
--- a/dll/shellext/zipfldr/lang/et-EE.rc
+++ b/dll/shellext/zipfldr/lang/et-EE.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Kuupäeval muudetud"
IDS_YES "Jah"
IDS_NO "Ei"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Ekstraktimise visard"
IDS_WIZ_DEST_TITLE "Vali sihtkoht"
diff --git a/dll/shellext/zipfldr/lang/fr-FR.rc b/dll/shellext/zipfldr/lang/fr-FR.rc
index 19d4520a605..24decc1fa3c 100644
--- a/dll/shellext/zipfldr/lang/fr-FR.rc
+++ b/dll/shellext/zipfldr/lang/fr-FR.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Date de modification"
IDS_YES "Oui"
IDS_NO "Non"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Assistant d'extraction"
IDS_WIZ_DEST_TITLE "Choisir une destination"
diff --git a/dll/shellext/zipfldr/lang/hi-IN.rc b/dll/shellext/zipfldr/lang/hi-IN.rc
index 7794f630cb3..cf31cce8e32 100644
--- a/dll/shellext/zipfldr/lang/hi-IN.rc
+++ b/dll/shellext/zipfldr/lang/hi-IN.rc
@@ -55,6 +55,11 @@ BEGIN
IDS_COL_DATE_MOD "तिथि संशोधित"
IDS_YES "हाँ"
IDS_NO "नहीं"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "निष्कर्षण विज़ार्ड"
IDS_WIZ_DEST_TITLE "एक गंतव्य चुनें"
diff --git a/dll/shellext/zipfldr/lang/it-IT.rc b/dll/shellext/zipfldr/lang/it-IT.rc
index 9f8864383f7..d3572fa0101 100644
--- a/dll/shellext/zipfldr/lang/it-IT.rc
+++ b/dll/shellext/zipfldr/lang/it-IT.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Data modificata"
IDS_YES "Sì"
IDS_NO "No"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Estrazione Guidata"
IDS_WIZ_DEST_TITLE "Seleziona una Destinazione"
diff --git a/dll/shellext/zipfldr/lang/ja-JP.rc b/dll/shellext/zipfldr/lang/ja-JP.rc
index 63564b7200d..157e6717dac 100644
--- a/dll/shellext/zipfldr/lang/ja-JP.rc
+++ b/dll/shellext/zipfldr/lang/ja-JP.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "変更日"
IDS_YES "はい"
IDS_NO "いいえ"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "展開ウィザード"
IDS_WIZ_DEST_TITLE "展開先を選んで下さい"
diff --git a/dll/shellext/zipfldr/lang/pl-PL.rc b/dll/shellext/zipfldr/lang/pl-PL.rc
index c4130cb6db2..fcdb0436d22 100644
--- a/dll/shellext/zipfldr/lang/pl-PL.rc
+++ b/dll/shellext/zipfldr/lang/pl-PL.rc
@@ -67,6 +67,11 @@ BEGIN
IDS_COL_DATE_MOD "Data modyfikacji"
IDS_YES "Tak"
IDS_NO "Nie"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Kreator wyodrębniania"
IDS_WIZ_DEST_TITLE "Wybierz miejsce docelowe"
diff --git a/dll/shellext/zipfldr/lang/ro-RO.rc b/dll/shellext/zipfldr/lang/ro-RO.rc
index 31642b0f48a..cb15956e6cb 100644
--- a/dll/shellext/zipfldr/lang/ro-RO.rc
+++ b/dll/shellext/zipfldr/lang/ro-RO.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Data modificată"
IDS_YES "Da"
IDS_NO "Nu"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Asistent de extracție"
IDS_WIZ_DEST_TITLE "Selectați o Destinație"
diff --git a/dll/shellext/zipfldr/lang/ru-RU.rc b/dll/shellext/zipfldr/lang/ru-RU.rc
index 89096a34401..1791169c937 100644
--- a/dll/shellext/zipfldr/lang/ru-RU.rc
+++ b/dll/shellext/zipfldr/lang/ru-RU.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Дата изменения"
IDS_YES "Да"
IDS_NO "Нет"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Мастер извлечения архивов"
IDS_WIZ_DEST_TITLE "Укажите путь"
diff --git a/dll/shellext/zipfldr/lang/sv-SE.rc b/dll/shellext/zipfldr/lang/sv-SE.rc
index a2f1c90c73c..886dddfe8bf 100644
--- a/dll/shellext/zipfldr/lang/sv-SE.rc
+++ b/dll/shellext/zipfldr/lang/sv-SE.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "Ändrad den"
IDS_YES "Ja"
IDS_NO "Nej"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "Extraheringsguiden"
IDS_WIZ_DEST_TITLE "Välj ett mål"
diff --git a/dll/shellext/zipfldr/lang/zh-CN.rc b/dll/shellext/zipfldr/lang/zh-CN.rc
index 27066adfdf9..6d69c012991 100644
--- a/dll/shellext/zipfldr/lang/zh-CN.rc
+++ b/dll/shellext/zipfldr/lang/zh-CN.rc
@@ -68,6 +68,11 @@ BEGIN
IDS_COL_DATE_MOD "修改日期"
IDS_YES "是"
IDS_NO "否"
+ IDS_ERRORTITLE "Compressed (zipped) Folders Error"
+ IDS_CANTSTARTTHREAD "Cannot start thread to compress files."
+ IDS_NOFILES "The specified directory '%s' is empty, so Compressed
(zipped) Folders cannot add it to the archive."
+ IDS_CANTCREATEZIP "Failed to create a compressed folder '%s' (Error
Code: %d)."
+ IDS_CANTREADFILE "Cannot read file '%s'."
IDS_WIZ_TITLE "解压向导"
IDS_WIZ_DEST_TITLE "选择一个目标文件夹"
diff --git a/dll/shellext/zipfldr/precomp.h b/dll/shellext/zipfldr/precomp.h
index e25e2f19024..ed61dc75dcc 100644
--- a/dll/shellext/zipfldr/precomp.h
+++ b/dll/shellext/zipfldr/precomp.h
@@ -78,5 +78,7 @@ eZipConfirmResponse _CZipAskReplace(HWND hDlg, const char* FullPath);
#include "CZipEnumerator.hpp"
#include "CZipFolder.hpp"
+#include "CZipCreater.hpp"
+#include "CSendToZip.hpp"
#endif /* ZIPFLDR_PRECOMP_H */
diff --git a/dll/shellext/zipfldr/res/zipfldr.rgs b/dll/shellext/zipfldr/res/zipfldr.rgs
index 82cfc8dfaeb..c57aeae4815 100644
--- a/dll/shellext/zipfldr/res/zipfldr.rgs
+++ b/dll/shellext/zipfldr/res/zipfldr.rgs
@@ -12,10 +12,26 @@ HKCR
val UseDropHandler = s ''
}
}
- '{b8cdcb65-b1bf-4b42-9428-1dfdb7ee92af}' = s 'Compressed (zipped)
Folder Menu'
+ '{B8CDCB65-B1BF-4B42-9428-1DFDB7EE92AF}' = s 'Compressed (zipped)
Folder Menu'
{
InprocServer32 = s '%MODULE%' { val ThreadingModel = s
'Apartment' }
}
+ '{888DCA60-FC0A-11CF-8F0F-00C04FD7D062}' = s 'Compressed (zipped)
Folder SendTo Target'
+ {
+ val EditFlags = d '0x01'
+ val FriendlyTypeName = s '%MODULE%,-10226'
+ val NeverShowExt = s ''
+ val NoOpen = s 'Drag Files onto this icon to compress them.'
+ DefaultIcon = s '%MODULE%' { }
+ InprocServer32 = s '%MODULE%'
+ {
+ val ThreadingModel = s 'Apartment'
+ }
+ ShellEx
+ {
+ DropHandler = s '{888DCA60-FC0A-11CF-8F0F-00C04FD7D062}' { }
+ }
+ }
}
NoRemove Applications
{
@@ -24,7 +40,7 @@ HKCR
NoRemove CompressedFolder
{
FriendlyTypeName = s '%MODULE%,-10195'
- CLSID = s '{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}'
+ CLSID = s '{E88DCCE0-B7B3-11D1-A9F0-00AA0060FA31}'
DefaultIcon = s '%MODULE%'
NoRemove Shell
@@ -41,7 +57,7 @@ HKCR
{
NoRemove ContextMenuHandlers
{
- ForceRemove '{b8cdcb65-b1bf-4b42-9428-1dfdb7ee92af}' = s
'Compressed (zipped) Folder Menu'
+ ForceRemove '{B8CDCB65-B1BF-4B42-9428-1DFDB7EE92AF}' = s
'Compressed (zipped) Folder Menu'
{
}
}
@@ -52,3 +68,13 @@ HKCR
val 'Content Type' = s 'application/x-zip-compressed'
}
}
+HKLM
+{
+ NoRemove Software
+ {
+ NoRemove Classes
+ {
+ '.ZFSendToTarget' = s
'CLSID\{888DCA60-FC0A-11CF-8F0F-00C04FD7D062}'
+ }
+ }
+}
diff --git a/dll/shellext/zipfldr/resource.h b/dll/shellext/zipfldr/resource.h
index b14faeb7d28..b294e823b77 100644
--- a/dll/shellext/zipfldr/resource.h
+++ b/dll/shellext/zipfldr/resource.h
@@ -35,7 +35,11 @@
#define IDS_COL_DATE_MOD 106
#define IDS_YES 107
#define IDS_NO 108
-
+#define IDS_ERRORTITLE 109
+#define IDS_CANTSTARTTHREAD 110
+#define IDS_NOFILES 111
+#define IDS_CANTCREATEZIP 112
+#define IDS_CANTREADFILE 113
/* Wizard titles */
#define IDS_WIZ_TITLE 8000
diff --git a/dll/shellext/zipfldr/zipfldr.cpp b/dll/shellext/zipfldr/zipfldr.cpp
index 2b9e5b63801..eecb1ac02de 100644
--- a/dll/shellext/zipfldr/zipfldr.cpp
+++ b/dll/shellext/zipfldr/zipfldr.cpp
@@ -31,6 +31,7 @@ public:
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_ZipFolderStorageHandler, CZipFolder)
OBJECT_ENTRY(CLSID_ZipFolderContextMenu, CZipFolder)
+ OBJECT_ENTRY(CLSID_ZipFolderSendTo, CSendToZip)
END_OBJECT_MAP()
CZipFldrModule gModule;