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
32 changes: 32 additions & 0 deletions FastCopy.sln
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RobocopyInjection", "RobocopyInjection\RobocopyInjection.vcxproj", "{3CFC5459-E40B-4049-A227-81BD5675F3D7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FastCopyKeyboardHook", "FastCopyKeyboardHook\FastCopyKeyboardHook.vcxproj", "{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -210,6 +212,36 @@ Global
{3CFC5459-E40B-4049-A227-81BD5675F3D7}.Release|x64.Build.0 = Release|x64
{3CFC5459-E40B-4049-A227-81BD5675F3D7}.Release|x86.ActiveCfg = Release|Win32
{3CFC5459-E40B-4049-A227-81BD5675F3D7}.Release|x86.Build.0 = Release|Win32
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|Any CPU.ActiveCfg = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|Any CPU.Build.0 = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|ARM.ActiveCfg = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|ARM.Build.0 = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|arm64.ActiveCfg = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|arm64.Build.0 = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|x64.ActiveCfg = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|x64.Build.0 = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|x86.ActiveCfg = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Debug|x86.Build.0 = Debug|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|Any CPU.ActiveCfg = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|Any CPU.Build.0 = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|ARM.ActiveCfg = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|ARM.Build.0 = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|arm64.ActiveCfg = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|arm64.Build.0 = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|x64.ActiveCfg = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|x64.Build.0 = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|x86.ActiveCfg = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Package|x86.Build.0 = Package|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|Any CPU.ActiveCfg = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|Any CPU.Build.0 = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|ARM.ActiveCfg = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|ARM.Build.0 = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|arm64.ActiveCfg = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|arm64.Build.0 = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|x64.ActiveCfg = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|x64.Build.0 = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|x86.ActiveCfg = Release|x64
{83E7518D-7BA4-4A13-B2C9-4AB98DA778DE}.Release|x86.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 2 additions & 0 deletions FastCopy/App.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "RobocopyViewModel.h"
#include "CommandLineHandler.h"
#include "Settings.h"
#include "KeyboardHookController.h"


namespace winrt::FastCopy::implementation
Expand Down Expand Up @@ -61,6 +62,7 @@ namespace winrt::FastCopy::implementation
{
try
{
KeyboardHookController::Start();
CommandLineHandler::AppLaunchMode == AppLaunchMode::LaunchSettings ? launchSettings() : normalLaunch();
}
catch (winrt::hresult_error const& e)
Expand Down
15 changes: 14 additions & 1 deletion FastCopy/FastCopy.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ xcopy "$(SolutionDir)$(Platform)\$(Configuration)\FastCopy\RobocopyInjection.dll
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Public\PackageConfig.h" />
<ClInclude Include="..\Public\KeyboardHookSettings.h" />
<ClInclude Include="..\Public\ModulePath.h" />
<ClInclude Include="..\Public\PropertyDescription.h" />
<ClInclude Include="..\Public\ShellItem2.h" />
<ClInclude Include="AcrylicHelper.h" />
Expand Down Expand Up @@ -285,6 +287,7 @@ xcopy "$(SolutionDir)$(Platform)\$(Configuration)\FastCopy\RobocopyInjection.dll
<ClInclude Include="Global.h" />
<ClInclude Include="ImageUtils.h" />
<ClInclude Include="JobObject.h" />
<ClInclude Include="KeyboardHookController.h" />
<ClInclude Include="KnownFolderPath.h" />
<ClInclude Include="MutexWrapper.h" />
<ClInclude Include="NewFile.h" />
Expand Down Expand Up @@ -397,6 +400,9 @@ xcopy "$(SolutionDir)$(Platform)\$(Configuration)\FastCopy\RobocopyInjection.dll
</Page>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Public\ModulePath.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\Public\PropertyDescription.cpp" />
<ClCompile Include="..\Public\ShellItem2.cpp" />
<ClCompile Include="AcrylicHelper.cpp" />
Expand Down Expand Up @@ -430,6 +436,7 @@ xcopy "$(SolutionDir)$(Platform)\$(Configuration)\FastCopy\RobocopyInjection.dll
<ClCompile Include="EmptyFolder.cpp" />
<ClCompile Include="Fallback.cpp" />
<ClCompile Include="FastcopySettingsSingleInstanceLock.cpp" />
<ClCompile Include="KeyboardHookController.cpp" />
<ClCompile Include="FileCompareViewModel.cpp">
<DependentUpon>FileCompareViewModel.idl</DependentUpon>
<SubType>Code</SubType>
Expand Down Expand Up @@ -693,6 +700,9 @@ xcopy "$(SolutionDir)$(Platform)\$(Configuration)\FastCopy\RobocopyInjection.dll
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Package|Win32'">true</DeploymentContent>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Package|x64'">true</DeploymentContent>
</None>
<None Include="..\x64\Package\FastCopy\FastCopyKeyboardHook.exe">
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Package|x64'">true</DeploymentContent>
</None>
<None Include="..\x64\Package\FastCopy\RobocopyInjection.dll">
<DeploymentContent>true</DeploymentContent>
</None>
Expand All @@ -703,6 +713,9 @@ xcopy "$(SolutionDir)$(Platform)\$(Configuration)\FastCopy\RobocopyInjection.dll
<ProjectReference Include="..\FastCopyShellExtension\FastCopyShellExtension.vcxproj">
<Project>{17f52e4d-1e98-4288-9aa1-20a384171876}</Project>
</ProjectReference>
<ProjectReference Include="..\FastCopyKeyboardHook\FastCopyKeyboardHook.vcxproj">
<Project>{83e7518d-7ba4-4a13-b2c9-4ab98da778de}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PRIResource Include="Strings\en-US\Resources.resw" />
Expand Down Expand Up @@ -811,4 +824,4 @@ xcopy "$(SolutionDir)$(Platform)\$(Configuration)\FastCopy\RobocopyInjection.dll
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.8.250916003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.8.250916003\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\packages\WinUIEssential.WinUI3.1.3.29\build\native\WinUIEssential.WinUI3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WinUIEssential.WinUI3.1.3.29\build\native\WinUIEssential.WinUI3.targets'))" />
</Target>
</Project>
</Project>
58 changes: 58 additions & 0 deletions FastCopy/KeyboardHookController.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "pch.h"
#include "KeyboardHookController.h"
#include "../Public/KeyboardHookSettings.h"
#include "../Public/ModulePath.h"

#include <wil/resource.h>
#include <wil/result_macros.h>

#include <filesystem>

bool KeyboardHookController::IsEnabled()
{
return KeyboardHookSettings::IsEnabled();
}

void KeyboardHookController::SetEnabled(bool enabled)
{
if (!KeyboardHookSettings::SetEnabled(enabled))
{
return;
}

enabled ? Start() : Stop();
}

void KeyboardHookController::Start()
{
if (!IsEnabled())
{
return;
}

auto const hookPath = std::filesystem::path{ ModulePath() }.parent_path() / L"FastCopyKeyboardHook.exe";
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), !std::filesystem::exists(hookPath));

STARTUPINFOW startupInfo{ sizeof(startupInfo) };
wil::unique_process_information processInfo;
THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(
hookPath.c_str(),
nullptr,
nullptr,
nullptr,
FALSE,
CREATE_NO_WINDOW,
nullptr,
hookPath.parent_path().c_str(),
&startupInfo,
processInfo.addressof()));
}

void KeyboardHookController::Stop()
{
auto const window = FindWindowW(KeyboardHookSettings::WindowClassName, nullptr);
if (window)
{
PostMessageW(window, WM_CLOSE, 0, 0);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stop cannot find hook window

High Severity

Stop uses FindWindowW to locate the hook HWND, but PasteWindow is created as an HWND_MESSAGE window. FindWindowW never searches message-only windows, so disable always fails to post WM_CLOSE. The registry flag flips off while the helper keeps intercepting Ctrl+V until reboot. The existing SettingsChangeListener already uses FindWindowEx(HWND_MESSAGE, ...) for this case.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 247b2c1. Configure here.

9 changes: 9 additions & 0 deletions FastCopy/KeyboardHookController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

namespace KeyboardHookController
{
[[nodiscard]] bool IsEnabled();
void SetEnabled(bool enabled);
void Start();
void Stop();
}
12 changes: 11 additions & 1 deletion FastCopy/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,17 @@
<uap:DisplayName>FastCopy</uap:DisplayName>
</uap:Protocol>
</uap:Extension>


<desktop:Extension
Category="windows.startupTask"
Executable="FastCopyKeyboardHook.exe"
EntryPoint="Windows.FullTrustApplication">
<desktop:StartupTask
TaskId="RoboCopyExKeyboardHook"
Enabled="true"
DisplayName="RoboCopyEx keyboard integration" />
</desktop:Extension>

<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>

Expand Down
42 changes: 42 additions & 0 deletions FastCopy/SettingsViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@
#include "Global.h"
#include "SettingsChangeListener.h"
#include "RenameUtils.h"
#include "KeyboardHookController.h"

#include <wil/result_macros.h>

#include <string>

namespace
{
void ShowError(char const* message)
{
if (!message)
{
message = "Unknown error";
}
auto const length = MultiByteToWideChar(CP_UTF8, 0, message, -1, nullptr, 0);
std::wstring wide(length > 0 ? length - 1 : 0, L'\0');
if (length > 0)
{
MultiByteToWideChar(CP_UTF8, 0, message, -1, wide.data(), length);
}
MessageBoxW(nullptr, wide.c_str(), L"RoboCopyEx", MB_OK | MB_ICONERROR);
}
}

namespace winrt::FastCopy::implementation
{
Expand All @@ -17,6 +40,25 @@ namespace winrt::FastCopy::implementation
{
m_model.Set(Settings::Notify, value);
}
bool SettingsViewModel::KeyboardIntegration()
{
return KeyboardHookController::IsEnabled();
}
void SettingsViewModel::KeyboardIntegration(bool value)
{
try
{
KeyboardHookController::SetEnabled(value);
}
catch (wil::ResultException const& e)
{
ShowError(e.what());
}
catch (std::exception const& e)
{
ShowError(e.what());
}
}
int SettingsViewModel::RenameBehavior()
{
return m_model.Get<int>(Settings::RenameBehavior, 1);
Expand Down
3 changes: 3 additions & 0 deletions FastCopy/SettingsViewModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ namespace winrt::FastCopy::implementation
bool Notify();
void Notify(bool value);

bool KeyboardIntegration();
void KeyboardIntegration(bool value);

int RenameBehavior();
void RenameBehavior(int value);

Expand Down
1 change: 1 addition & 0 deletions FastCopy/SettingsViewModel.idl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
SettingsViewModel();

Boolean Notify;
Boolean KeyboardIntegration;
Int32 RenameBehavior;
String RenameSuffix;
Int32 MultipleWindowBehavior;
Expand Down
10 changes: 10 additions & 0 deletions FastCopy/SettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,16 @@
Style="{StaticResource ToggleSwitchLeftLabelStyle}" />
</essential:SettingsCard>

<essential:SettingsCard x:Uid="KeyboardIntegrationSettingItem">
<essential:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE765;" />
</essential:SettingsCard.HeaderIcon>
<ToggleSwitch
Margin="0,0,-80,0"
IsOn="{x:Bind ViewModel.KeyboardIntegration, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchLeftLabelStyle}" />
</essential:SettingsCard>

<essential:SettingsCard x:Uid="UniqueNameSettingItem">
<essential:SettingsCard.HeaderIcon>
<PathIcon
Expand Down
6 changes: 6 additions & 0 deletions FastCopy/Strings/de-DE/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@
<data name="NotificationSettingItem.Title" xml:space="preserve">
<value>Bei Fertigstellung benachrichtigen</value>
</data>
<data name="KeyboardIntegrationSettingItem.Header" xml:space="preserve">
<value>Explorer-Tastaturintegration</value>
</data>
<data name="KeyboardIntegrationSettingItem.Description" xml:space="preserve">
<value>RoboCopyEx beim Einfügen von Dateien mit Strg+V im Datei-Explorer verwenden</value>
</data>
<data name="SettingWindowTitle.Text" xml:space="preserve">
<value>FastCopy-Einstellungen</value>
</data>
Expand Down
6 changes: 6 additions & 0 deletions FastCopy/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@
<data name="NotificationSettingItem.Header" xml:space="preserve">
<value>Notify upon finish</value>
</data>
<data name="KeyboardIntegrationSettingItem.Header" xml:space="preserve">
<value>Explorer keyboard integration</value>
</data>
<data name="KeyboardIntegrationSettingItem.Description" xml:space="preserve">
<value>Use RoboCopyEx when pasting files with Ctrl+V in File Explorer</value>
</data>
<data name="RobocopyNotWorkingTextBlock.Text" xml:space="preserve">
<value>This software will not work properly. Please re-install Windows!</value>
</data>
Expand Down
6 changes: 6 additions & 0 deletions FastCopy/Strings/es-ES/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@
<data name="NotificationSettingItem.Title" xml:space="preserve">
<value>Notificar al acabar</value>
</data>
<data name="KeyboardIntegrationSettingItem.Header" xml:space="preserve">
<value>Integración de teclado del Explorador</value>
</data>
<data name="KeyboardIntegrationSettingItem.Description" xml:space="preserve">
<value>Usar RoboCopyEx al pegar archivos con Ctrl+V en el Explorador de archivos</value>
</data>
<data name="SettingWindowTitle.Text" xml:space="preserve">
<value>Ajustes de FastCopy</value>
</data>
Expand Down
6 changes: 6 additions & 0 deletions FastCopy/Strings/zh-CN/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@
<data name="NotificationSettingItem.Header" xml:space="preserve">
<value>复制完成后通知</value>
</data>
<data name="KeyboardIntegrationSettingItem.Header" xml:space="preserve">
<value>资源管理器快捷键集成</value>
</data>
<data name="KeyboardIntegrationSettingItem.Description" xml:space="preserve">
<value>在文件资源管理器中按 Ctrl+V 时使用 RoboCopyEx</value>
</data>
<data name="RobocopyNotWorkingTextBlock.Text" xml:space="preserve">
<value>软件无法正常工作,请重新安装Windows!</value>
</data>
Expand Down
Loading