Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions BuildAllTargets.proj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project
<Project
DefaultTargets="RefreshVersion;Restore;Build;Packaging"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="NanaZip.Project\NanaZip.Project.props" />
Expand Down Expand Up @@ -30,10 +30,13 @@
<Target Name="Restore">
<ItemGroup>
<RestoreProjectReference Include="$(MSBuildThisFileDirectory)NanaZip.sln">
<AdditionalProperties>Configuration=Debug;Platform=x64</AdditionalProperties>
<AdditionalProperties>Configuration=Debug;Platform=x64</AdditionalProperties>
</RestoreProjectReference>
<RestoreProjectReference Include="$(MSBuildThisFileDirectory)NanaZip.sln">
<AdditionalProperties>Configuration=Release;Platform=x64</AdditionalProperties>
<AdditionalProperties>Configuration=Release;Platform=x64</AdditionalProperties>
</RestoreProjectReference>
<RestoreProjectReference Include="$(MSBuildThisFileDirectory)NanaZip.ExtensionPackage\NanaZip.Extension.vcxproj">
<AdditionalProperties>Configuration=Release</AdditionalProperties>
</RestoreProjectReference>
<RestoreProjectReference Include="$(MSBuildThisFileDirectory)NanaZip.ExtensionPackage\NanaZip.ExtensionPackage.Installer.proj">
<AdditionalProperties>Configuration=Release</AdditionalProperties>
Expand All @@ -58,6 +61,18 @@
BuildInParallel="True"
StopOnFirstFailure="True"
Properties="PreferredToolArchitecture=x64;Configuration=Release;Platform=x64" />
<MSBuild
Projects="$(MSBuildThisFileDirectory)NanaZip.ExtensionPackage\NanaZip.Extension.vcxproj"
Targets="Build"
BuildInParallel="True"
StopOnFirstFailure="True"
Properties="Configuration=Release;Platform=ARM64" />
<MSBuild
Projects="$(MSBuildThisFileDirectory)NanaZip.ExtensionPackage\NanaZip.Extension.vcxproj"
Targets="Build"
BuildInParallel="True"
StopOnFirstFailure="True"
Properties="Configuration=Release;Platform=x64" />
<MSBuild
Projects="$(MSBuildThisFileDirectory)NanaZip.ExtensionPackage\NanaZip.ExtensionPackage.Installer.proj"
Targets="Build"
Expand Down Expand Up @@ -92,10 +107,14 @@
<Copy SourceFiles="$(InputBinariesPath)NanaZipPackage\x64\NanaZip.Modern.FileManager.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />
<Copy SourceFiles="$(InputBinariesPath)NanaZipPackage\x64\NanaZip.ShellExtension.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />
<Copy SourceFiles="$(InputBinariesPath)NanaZipPackage\x64\NanaZip.Windows.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />

<Copy SourceFiles="$(InputBinariesPath)arm64\NanaZip.Extension.pdb" DestinationFolder="$(OutputSymbolsPath)arm64" />
<Copy SourceFiles="$(InputBinariesPath)x64\NanaZip.Extension.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />

<Copy SourceFiles="$(InputBinariesPath)x64\NanaZip.Core.Console.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />
<Copy SourceFiles="$(InputBinariesPath)x64\NanaZip.Core.Sfx.Shared.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />
<Copy SourceFiles="$(InputBinariesPath)x64\NanaZip.Core.Windows.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />
<Copy SourceFiles="$(InputBinariesPath)x64\NanaZip.Core.Windows.pdb" DestinationFolder="$(OutputSymbolsPath)x64" />

<Exec Command="7z a -r .\Output\$(OutputFileNamePrefix)_DebugSymbols.zip .\Output\Binaries\Root\Symbols\*.*" WorkingDirectory="$(MSBuildThisFileDirectory)"/>
</Target>
</Project>
</Project>
84 changes: 84 additions & 0 deletions NanaZip.ExtensionPackage/CNanaZipCopyHook.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* PROJECT: NanaZip
* FILE: CNanaZipCopyHook.cpp
* PURPOSE: Copy hook implementation
*
* LICENSE: The MIT License
*
* DEVELOPER: dinhngtu ([email protected])
*/

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <exception>
#include <filesystem>
#include <Unknwn.h>
#include <olectl.h>
#include <shellapi.h>
#include <strsafe.h>

#include "CopyHook.h"
#include "CNanaZipCopyHook.hpp"

IFACEMETHODIMP_(UINT)
CNanaZipCopyHook::CopyCallback(
_In_opt_ HWND hwnd,
UINT wFunc,
UINT wFlags,
_In_ PCWSTR pszSrcFile,
DWORD dwSrcAttribs,
_In_opt_ PCWSTR pszDestFile,
DWORD dwDestAttribs) {

UNREFERENCED_PARAMETER(wFlags);
UNREFERENCED_PARAMETER(dwSrcAttribs);
UNREFERENCED_PARAMETER(dwDestAttribs);

try {
if (wFunc != FO_COPY && wFunc != FO_MOVE)
return IDYES;

std::filesystem::path SourcePath(pszSrcFile);
std::filesystem::path DestinationPath(pszDestFile);
if (SourcePath.stem() != COPY_HOOK_PREFIX)
return IDYES;

auto HwndString = SourcePath.extension().wstring();
if (!HwndString.length())
return IDYES;

auto DestinationHwnd = reinterpret_cast<HWND>(std::stoull(
HwndString.substr(1)));
auto DestinationDir = DestinationPath.parent_path();
COPY_HOOK_DATA CopyHookData = {};
if (FAILED(::StringCchCopyW(
&CopyHookData.FileName[0],
ARRAYSIZE(CopyHookData.FileName),
DestinationDir.c_str())))
return IDYES;

COPYDATASTRUCT CopyMessageData;
DWORD_PTR MessageResult;

CopyMessageData.dwData = COPY_HOOK_COMMAND_COPY;
CopyMessageData.cbData = sizeof(COPY_HOOK_DATA);
CopyMessageData.lpData = &CopyHookData;

// we can't use PostMessage since the copydata message needs to stay
// alive during the send
::SendMessageTimeoutW(
DestinationHwnd,
WM_COPYDATA,
reinterpret_cast<WPARAM>(hwnd),
reinterpret_cast<LPARAM>(&CopyMessageData),
SMTO_ABORTIFHUNG,
100,
&MessageResult);
// but it doesn't matter if the caller returns or not
return IDNO;
} catch (std::exception const& ex) {
::OutputDebugStringA(ex.what());
return IDYES;
}
}
28 changes: 28 additions & 0 deletions NanaZip.ExtensionPackage/CNanaZipCopyHook.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* PROJECT: NanaZip
* FILE: CNanaZipCopyHook.cpp
* PURPOSE: Copy hook implementation
*
* LICENSE: The MIT License
*
* DEVELOPER: dinhngtu ([email protected])
*/

#pragma once

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winrt/windows.foundation.h>
#include <ShlObj.h>

struct CNanaZipCopyHook : winrt::implements<CNanaZipCopyHook, ICopyHookW> {
STDMETHOD_(UINT, CopyCallback)(
_In_opt_ HWND hwnd,
UINT wFunc,
UINT wFlags,
_In_ PCWSTR pszSrcFile,
DWORD dwSrcAttribs,
_In_opt_ PCWSTR pszDestFile,
DWORD dwDestAttribs);
};
13 changes: 13 additions & 0 deletions NanaZip.ExtensionPackage/CopyHook.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef COPY_HOOK_H
#define COPY_HOOK_H

#include <Windows.h>

#define COPY_HOOK_PREFIX "{7F4FD2EA-8CC8-43C4-8440-CD76805B4E95}"
#define COPY_HOOK_COMMAND_COPY 0x7F4FD2EA

typedef struct _COPY_HOOK_DATA {
wchar_t FileName[MAX_PATH];
} COPY_HOOK_DATA, *PCOPY_HOOK_DATA;

#endif
204 changes: 204 additions & 0 deletions NanaZip.ExtensionPackage/DllMain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/*
* PROJECT: NanaZip
* FILE: NanaZip.ModernExperience.Com.cpp
* PURPOSE: Entry point and self registration code
*
* LICENSE: The MIT License
*
* DEVELOPER: dinhngtu ([email protected])
*/

#define WIN32_LEAN_AND_MEAN

#include <string>
#include <windows.h>
#include <unknwn.h>

#include "CNanaZipCopyHook.hpp"

static constexpr size_t GUID_STRING_LENGTH =
ARRAYSIZE(L"{12345678-90AB-CDEF-1234-567890ABCDEF}");

static const std::wstring CLSID_REGISTRY_PATH =
L"Software\\Classes\\CLSID\\";
static const std::wstring COPY_HOOK_REGISTRY_PATH =
L"Software\\Classes\\Directory\\shellex\\CopyHookHandlers\\";

static HINSTANCE g_hInstance = NULL;

BOOL WINAPI DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(lpReserved);

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInstance = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

struct DECLSPEC_UUID("{542CE69A-6EA7-4D77-9B8F-8F56CEA2BF16}")
CNanaZipCopyHookFactory : winrt::implements<
CNanaZipCopyHookFactory,
IClassFactory>
{
IFACEMETHODIMP CreateInstance(
IUnknown * pUnkOuter,
REFIID riid,
void** ppvObject) WIN_NOEXCEPT
{
if (pUnkOuter)
{
return CLASS_E_NOAGGREGATION;
}

try
{
return winrt::make<CNanaZipCopyHook>()
->QueryInterface(riid, ppvObject);
}
catch (...)
{
return winrt::to_hresult();
}
}

IFACEMETHODIMP LockServer(BOOL fLock) WIN_NOEXCEPT
{
if (fLock)
{
++winrt::get_module_lock();
}
else
{
--winrt::get_module_lock();
}
return S_OK;
}
};

STDAPI DllCanUnloadNow()
{
if (winrt::get_module_lock())
{
return S_FALSE;
}
winrt::clear_factory_cache();
return S_OK;
}

STDAPI DllGetClassObject(
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Outptr_ LPVOID* ppv)
{
try
{
*ppv = NULL;
if (rclsid == __uuidof(CNanaZipCopyHookFactory))
{
return winrt::make<CNanaZipCopyHookFactory>()
->QueryInterface(riid, ppv);
}
return E_INVALIDARG;
}
catch (...)
{
return winrt::to_hresult();
}
}

STDAPI DllRegisterServer()
{
try
{
wchar_t clsid[GUID_STRING_LENGTH];

auto clsidLen = ::StringFromGUID2(
__uuidof(CNanaZipCopyHookFactory),
clsid,
ARRAYSIZE(clsid));
if (!clsidLen)
{
winrt::throw_hresult(E_OUTOFMEMORY);
}

auto serverKeyName = CLSID_REGISTRY_PATH + clsid + L"\\InprocServer32";

wchar_t dllPath[MAX_PATH];
::SetLastError(ERROR_SUCCESS);
auto dllPathLen = ::GetModuleFileNameW(
g_hInstance,
dllPath,
ARRAYSIZE(dllPath));
winrt::check_win32(::GetLastError());

winrt::check_win32(::RegSetKeyValueW(
HKEY_CURRENT_USER,
serverKeyName.c_str(),
NULL,
REG_SZ,
dllPath,
sizeof(wchar_t) * (dllPathLen + 1)));
winrt::check_win32(::RegSetKeyValueW(
HKEY_CURRENT_USER,
serverKeyName.c_str(),
L"ThreadingModel",
REG_SZ,
L"Apartment",
sizeof(L"Apartment")));

auto handlerKeyName = COPY_HOOK_REGISTRY_PATH + clsid;
winrt::check_win32(::RegSetKeyValueW(
HKEY_CURRENT_USER,
handlerKeyName.c_str(),
NULL,
REG_SZ,
clsid,
sizeof(wchar_t) * (clsidLen + 1)));

return S_OK;
}
catch (...)
{
return winrt::to_hresult();
}
}

STDAPI DllUnregisterServer()
{
try
{
wchar_t clsid[GUID_STRING_LENGTH];

if (!::StringFromGUID2(
__uuidof(CNanaZipCopyHookFactory),
clsid,
ARRAYSIZE(clsid)))
winrt::throw_hresult(E_OUTOFMEMORY);

auto handlerKeyName = COPY_HOOK_REGISTRY_PATH + clsid;
::RegDeleteKeyExW(HKEY_CURRENT_USER, handlerKeyName.c_str(), 0, 0);

auto serverKeyName = CLSID_REGISTRY_PATH + clsid + L"\\InprocServer32";
::RegDeleteKeyExW(HKEY_CURRENT_USER, serverKeyName.c_str(), 0, 0);

auto clsidKeyName = CLSID_REGISTRY_PATH + clsid;
::RegDeleteKeyExW(HKEY_CURRENT_USER, clsidKeyName.c_str(), 0, 0);

return S_OK;
}
catch (...)
{
return winrt::to_hresult();
}
}
Loading
Loading