Merge branch 'microsoft/main' into dev/seraphima/tests/29246-fancyzones-tests-initial-step

This commit is contained in:
seraphima
2024-01-09 14:52:40 +01:00
608 changed files with 9236 additions and 4107 deletions

View File

@@ -3,12 +3,12 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RootNamespace>EnvironmentVariables</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<RuntimeIdentifiers>win10-x64;win10-arm64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
@@ -34,10 +34,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->

View File

@@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using EnvironmentVariables.Helpers;
using EnvironmentVariables.Helpers.Win32;
using EnvironmentVariables.ViewModels;
using ManagedCommon;
using Microsoft.UI.Dispatching;
using WinUIEx;
@@ -30,19 +31,20 @@ namespace EnvironmentVariables
Title = title;
AppTitleTextBlock.Text = title;
RegisterWindow();
var handle = this.GetWindowHandle();
RegisterWindow(handle);
WindowHelpers.BringToForeground(handle);
}
private static readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
private static NativeMethods.WinProc newWndProc;
private static IntPtr oldWndProc = IntPtr.Zero;
private void RegisterWindow()
private void RegisterWindow(IntPtr handle)
{
newWndProc = new NativeMethods.WinProc(WndProc);
var handle = this.GetWindowHandle();
oldWndProc = NativeMethods.SetWindowLongPtr(handle, NativeMethods.WindowLongIndexFlags.GWL_WNDPROC, newWndProc);
}

View File

@@ -209,7 +209,7 @@
<StackPanel Orientation="Horizontal" Spacing="12">
<ToggleSwitch
x:Uid="ToggleSwitch"
IsOn="{x:Bind Mode=TwoWay, Path=IsEnabled}"
IsOn="{x:Bind IsEnabled, Mode=TwoWay}"
Style="{StaticResource RightAlignedCompactToggleSwitchStyle}" />
<Button Content="{ui:FontIcon Glyph=&#xE712;}" Style="{StaticResource SubtleButtonStyle}">
<Button.Flyout>
@@ -465,14 +465,13 @@
TextChanged="EditVariableDialogValueTxtBox_TextChanged"
TextWrapping="Wrap" />
<MenuFlyoutSeparator Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}" />
<ListView
<ItemsControl
x:Name="EditVariableValuesList"
Margin="-16,-8,0,12"
Margin="0,-8,0,12"
HorizontalAlignment="Stretch"
ItemsSource="{Binding ValuesList, Mode=TwoWay}"
SelectionMode="None"
Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}">
<ListView.ItemTemplate>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
@@ -523,8 +522,8 @@
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</ContentDialog>
@@ -583,15 +582,14 @@
HorizontalAlignment="Right"
Visibility="Collapsed" />
<ListView
<ItemsControl
x:Name="NewProfileVariablesListView"
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="-16,-8,0,12"
Margin="0,-8,0,12"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Variables, Mode=TwoWay}"
SelectionMode="None">
<ListView.ItemTemplate>
ItemsSource="{Binding Variables, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:Variable">
<Grid Height="48" ColumnSpacing="8">
<Grid.ColumnDefinitions>
@@ -617,8 +615,8 @@
Visibility="Collapsed" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>

View File

@@ -31,7 +31,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{c604b37e-9d0e-4484-8778-e8b31b0e1b3a}</ProjectGuid>
<RootNamespace>FileLocksmithLibInterop</RootNamespace>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
<TargetName>PowerToys.FileLocksmithLib.Interop</TargetName>
</PropertyGroup>

View File

@@ -5,14 +5,14 @@
<AssemblyTitle>PowerToys.FileLocksmith</AssemblyTitle>
<AssemblyDescription>PowerToys File Locksmith</AssemblyDescription>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
<RootNamespace>PowerToys.FileLocksmithUI</RootNamespace>
<AssemblyName>PowerToys.FileLocksmithUI</AssemblyName>
<ApplicationManifest>app.manifest</ApplicationManifest>
<RuntimeIdentifiers>win10-x64;win10-arm64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -35,10 +35,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup>

View File

@@ -5,11 +5,11 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<PublishDir>$(PowerToysRoot)\$(Platform)\$(Configuration)\WinUI3Apps</PublishDir>
<RuntimeIdentifier>win10-$(Platform)</RuntimeIdentifier>
<RuntimeIdentifier>win-$(Platform)</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun>False</PublishReadyToRun>

View File

@@ -2,10 +2,10 @@
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RuntimeIdentifiers>win10-x64;win10-arm64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<IsPackable>false</IsPackable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>

View File

@@ -3,12 +3,12 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RootNamespace>Hosts</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<RuntimeIdentifiers>win10-x64;win10-arm64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<WindowsPackageType>None</WindowsPackageType>
@@ -34,10 +34,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->

View File

@@ -17,7 +17,7 @@ namespace Hosts.Settings
private const string HostsModuleName = "Hosts";
private const int MaxNumberOfRetry = 5;
private readonly ISettingsUtils _settingsUtils;
private readonly SettingsUtils _settingsUtils;
private readonly IFileSystemWatcher _watcher;
private readonly object _loadingSettingsLock = new object();

View File

@@ -289,7 +289,7 @@ namespace Hosts.ViewModels
Entries.RefreshFilter();
}
// Ping and duplicate should't trigger a file save
// Ping and duplicate should not trigger a file save
if (e.PropertyName == nameof(Entry.Ping)
|| e.PropertyName == nameof(Entry.Pinging)
|| e.PropertyName == nameof(Entry.Duplicate))

View File

@@ -51,9 +51,9 @@ private:
HANDLE m_hProcess = nullptr;
HANDLE m_hShowEvent;
HANDLE m_hShowEvent{};
HANDLE m_hShowAdminEvent;
HANDLE m_hShowAdminEvent{};
bool is_process_running()
{

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
@@ -146,8 +146,8 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
@@ -156,9 +156,9 @@
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220914.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.755\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.230913002\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.4.231115000\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
</Target>
</Project>

View File

@@ -2,6 +2,6 @@
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220914.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.755" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.4.230913002" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.756" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.4.231115000" targetFramework="native" />
</packages>

View File

@@ -5,14 +5,14 @@
<AssemblyTitle>PowerToys.MeasureTool</AssemblyTitle>
<AssemblyDescription>PowerToys MeasureTool</AssemblyDescription>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
<RootNamespace>PowerToys.MeasureToolUI</RootNamespace>
<AssemblyName>PowerToys.MeasureToolUI</AssemblyName>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -35,10 +35,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->

View File

@@ -2,7 +2,7 @@
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<ProjectGuid>{D9C5DE64-6849-4278-91AD-9660AECF2876}</ProjectGuid>

View File

@@ -16,10 +16,7 @@ internal static class LayoutHelper
public static LayoutInfo CalculateLayoutInfo(
LayoutConfig layoutConfig)
{
if (layoutConfig is null)
{
throw new ArgumentNullException(nameof(layoutConfig));
}
ArgumentNullException.ThrowIfNull(layoutConfig);
var builder = new LayoutInfo.Builder
{

View File

@@ -17,10 +17,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup>
@@ -32,7 +32,7 @@
<OutputType>WinExe</OutputType>
<RootNamespace>MouseJumpUI</RootNamespace>
<AssemblyName>PowerToys.MouseJumpUI</AssemblyName>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

View File

@@ -45,6 +45,10 @@ namespace MouseWithoutBorders
private static string lastDragDropFile;
private static long clipboardCopiedTime;
internal static readonly char[] Comma = new char[] { ',' };
internal static readonly char[] Star = new char[] { '*' };
internal static readonly char[] NullSeparator = new char[] { '\0' };
internal static ID LastIDWithClipboardData { get; set; }
internal static string LastDragDropFile
@@ -406,7 +410,7 @@ namespace MouseWithoutBorders
try
{
remoteMachine = postAct.Contains("mspaint,") ? postAct.Split(new char[] { ',' })[1] : Common.LastMachineWithClipboardData;
remoteMachine = postAct.Contains("mspaint,") ? postAct.Split(Comma)[1] : Common.LastMachineWithClipboardData;
remoteMachine = remoteMachine.Trim();
@@ -518,7 +522,7 @@ namespace MouseWithoutBorders
fileName = Common.GetStringU(header).Replace("\0", string.Empty);
Common.LogDebug("Header: " + fileName);
string[] headers = fileName.Split(new char[] { '*' });
string[] headers = fileName.Split(Star);
if (headers.Length < 2 || !long.TryParse(headers[0], out long dataSize))
{
@@ -973,7 +977,7 @@ namespace MouseWithoutBorders
foreach (string txt in texts)
{
if (string.IsNullOrEmpty(txt.Trim(new char[] { '\0' })))
if (string.IsNullOrEmpty(txt.Trim(NullSeparator)))
{
continue;
}

View File

@@ -22,7 +22,9 @@ namespace MouseWithoutBorders
{
internal partial class Common
{
private static SymmetricAlgorithm symAl;
#pragma warning disable SYSLIB0021
private static AesCryptoServiceProvider symAl;
#pragma warning restore SYSLIB0021
private static string myKey;
private static uint magicNumber;
private static Random ran = new(); // Used for non encryption related functionality.
@@ -115,7 +117,7 @@ namespace MouseWithoutBorders
byte[] rv;
string myKey = Common.MyKey;
if (!LegalKeyDictionary.ContainsKey(myKey))
if (!LegalKeyDictionary.TryGetValue(myKey, out byte[] value))
{
Rfc2898DeriveBytes key = new(
myKey,
@@ -127,7 +129,7 @@ namespace MouseWithoutBorders
}
else
{
rv = LegalKeyDictionary[myKey];
rv = value;
}
return rv;

View File

@@ -313,7 +313,8 @@ namespace MouseWithoutBorders
HasSwitchedMachineSinceLastCopy = true;
// Common.CreateLowIntegrityProcess("\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", string.Empty, 0, false, 0);
if (Process.GetProcessesByName(HelperProcessName)?.Any() != true)
var processes = Process.GetProcessesByName(HelperProcessName);
if (processes?.Length == 0)
{
Log("Unable to start helper process.");
Common.ShowToolTip("Error starting Mouse Without Borders Helper, clipboard sharing will not work!", 5000, ToolTipIcon.Error);
@@ -325,7 +326,8 @@ namespace MouseWithoutBorders
}
else
{
if (Process.GetProcessesByName(HelperProcessName)?.Any() == true)
var processes = Process.GetProcessesByName(HelperProcessName);
if (processes?.Length > 0)
{
Log("Helper process found running.");
}
@@ -432,7 +434,7 @@ namespace MouseWithoutBorders
{
if (string.IsNullOrEmpty(Setting.Values.Username) && !Common.RunOnLogonDesktop)
{
if (Program.User.ToLower(CultureInfo.CurrentCulture).Contains("system"))
if (Program.User.Contains("system", StringComparison.CurrentCultureIgnoreCase))
{
_ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
{

View File

@@ -84,12 +84,11 @@ namespace MouseWithoutBorders
}
}
[SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower", Justification = "Dotnet port with style preservation")]
internal static int CreateProcessInInputDesktopSession(string commandLine, string arg, string desktop, short wShowWindow, bool lowIntegrity = false)
// As user who runs explorer.exe
{
if (!Program.User.ToLower(CultureInfo.InvariantCulture).Contains("system"))
if (!Program.User.Contains("system", StringComparison.InvariantCultureIgnoreCase))
{
ProcessStartInfo s = new(commandLine, arg);
s.WindowStyle = wShowWindow != 0 ? ProcessWindowStyle.Normal : ProcessWindowStyle.Hidden;

View File

@@ -45,7 +45,7 @@ namespace MouseWithoutBorders
{
Process[] ps = Process.GetProcessesByName("MouseWithoutBordersSvc");
if (ps.Any())
if (ps.Length != 0)
{
if (DateTime.UtcNow - lastStartServiceTime < TimeSpan.FromSeconds(5))
{

View File

@@ -353,6 +353,7 @@ namespace MouseWithoutBorders.Class
private static bool ctrlDown;
private static bool altDown;
private static bool shiftDown;
internal static readonly string[] Args = new string[] { "CAD" };
private static void ResetModifiersState(HotkeySettings matchingHotkey)
{
@@ -456,7 +457,7 @@ namespace MouseWithoutBorders.Class
if (ctrlDown && altDown)
{
ctrlDown = altDown = false;
new ServiceController("MouseWithoutBordersSvc").Start(new string[] { "CAD" });
new ServiceController("MouseWithoutBordersSvc").Start(Args);
}
break;

View File

@@ -156,7 +156,7 @@ namespace MouseWithoutBorders.Class
}
else if (list.Count >= 4)
{
throw new ArgumentException("machineNames.Length > Common.MAX_MACHINE");
throw new ArgumentException($"The number of machines exceeded the maximum allowed limit of {Common.MAX_MACHINE}. Actual count: {list.Count}.");
}
_ = LearnMachine(name);
@@ -178,7 +178,7 @@ namespace MouseWithoutBorders.Class
}
else if (list.Count >= 4)
{
throw new ArgumentException("infos.Length > Common.MAX_MACHINE");
throw new ArgumentException($"The number of machines exceeded the maximum allowed limit of {Common.MAX_MACHINE}. Actual count: {list.Count}.");
}
_ = LearnMachine(inf.Name);

View File

@@ -8,6 +8,9 @@ namespace MouseWithoutBorders.Class
{
internal static class MachinePoolHelpers
{
internal static readonly char[] Comma = new char[] { ',' };
internal static readonly char[] Colon = new char[] { ':' };
internal static MachineInf[] LoadMachineInfoFromMachinePoolStringSetting(string s)
{
if (s == null)
@@ -15,7 +18,7 @@ namespace MouseWithoutBorders.Class
throw new ArgumentNullException(s);
}
string[] st = s.Split(new char[] { ',' });
string[] st = s.Split(Comma);
if (st.Length < Common.MAX_MACHINE)
{
@@ -25,7 +28,7 @@ namespace MouseWithoutBorders.Class
MachineInf[] rv = new MachineInf[Common.MAX_MACHINE];
for (int i = 0; i < Common.MAX_MACHINE; i++)
{
string[] mc = st[i].Split(new char[] { ':' });
string[] mc = st[i].Split(Colon);
if (mc.Length == 2)
{
rv[i].Name = mc[0];

View File

@@ -38,7 +38,7 @@ namespace MouseWithoutBorders.Class
{
internal bool Changed;
private readonly ISettingsUtils _settingsUtils;
private readonly SettingsUtils _settingsUtils;
private readonly object _loadingSettingsLock = new object();
private readonly IFileSystemWatcher _watcher;

View File

@@ -887,14 +887,14 @@ namespace MouseWithoutBorders.Class
if (!string.IsNullOrEmpty(Setting.Values.Name2IP))
{
string[] name2ip = Setting.Values.Name2IP.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
string[] name2ip = Setting.Values.Name2IP.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
string[] nameNip;
if (name2ip != null)
{
foreach (string st in name2ip)
{
nameNip = st.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
nameNip = st.Split(BlankSeparator, StringSplitOptions.RemoveEmptyEntries);
if (nameNip != null && nameNip.Length >= 2 && nameNip[0].Trim().Equals(machineName, StringComparison.OrdinalIgnoreCase)
&& IPAddress.TryParse(nameNip[1].Trim(), out IPAddress ip) && !validAddressesSt.Contains("[" + ip.ToString() + "]")
@@ -1063,7 +1063,7 @@ namespace MouseWithoutBorders.Class
List<IPAddress> localIPv4Addresses = GetMyIPv4Addresses().ToList();
if (!localIPv4Addresses.Any())
if (localIPv4Addresses.Count == 0)
{
Common.Log($"No IPv4 resolved from the local machine: {Common.MachineName}");
return true;
@@ -1234,6 +1234,8 @@ namespace MouseWithoutBorders.Class
}
private long lastRemoteMachineID;
internal static readonly string[] Separator = new string[] { "\r\n" };
internal static readonly char[] BlankSeparator = new char[] { ' ' };
private void MainTCPRoutine(TcpSk tcp, string machineName, bool isClient)
{

View File

@@ -104,6 +104,7 @@ namespace MouseWithoutBorders.Class
}
private static bool logged;
internal static readonly string[] Separator = new[] { " " };
private void LogError(string log)
{
@@ -146,7 +147,7 @@ namespace MouseWithoutBorders.Class
try
{
// Assuming the format of netstat's output is fixed.
pid = int.Parse(portLogLine.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).Last(), CultureInfo.CurrentCulture);
pid = int.Parse(portLogLine.Split(Separator, StringSplitOptions.RemoveEmptyEntries).Last(), CultureInfo.CurrentCulture);
process = Process.GetProcessById(pid);
}
catch (Exception)

View File

@@ -123,13 +123,14 @@ namespace MouseWithoutBorders
}
private string lastMessage = string.Empty;
private static readonly string[] Separator = new string[] { "\r\n" };
internal void ShowTip(ToolTipIcon icon, string msg, int durationInMilliseconds)
{
int x = 0;
string text = msg + $"\r\n {(lastMessage.Equals(msg, StringComparison.OrdinalIgnoreCase) ? string.Empty : $"\r\nPrevious message/error: {lastMessage}")} ";
lastMessage = msg;
int y = (-text.Split(new string[] { "\r\n" }, StringSplitOptions.None).Length * 15) - 30;
int y = (-text.Split(Separator, StringSplitOptions.None).Length * 15) - 30;
toolTipManual.Hide(this);

View File

@@ -742,11 +742,13 @@ namespace MouseWithoutBorders
LoadMachines();
}
internal static readonly string[] Separator = new string[] { "\r\n" };
internal void ShowTip(ToolTipIcon icon, string text, int duration)
{
int x = 0;
text += "\r\n ";
int y = (-text.Split(new string[] { "\r\n" }, StringSplitOptions.None).Length * 15) - 30;
int y = (-text.Split(Separator, StringSplitOptions.None).Length * 15) - 30;
toolTipManual.Hide(this);

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<OutputType>WinExe</OutputType>
@@ -19,10 +19,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<OutputType>WinExe</OutputType>
@@ -19,10 +19,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<ImplicitUsings>true</ImplicitUsings>
@@ -20,10 +20,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DefineConstants>TRACE;DEBUG;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN</DefineConstants>

View File

@@ -148,6 +148,8 @@ internal sealed class ImageMethods
return resultText.Trim();
}
internal static readonly char[] Separator = new char[] { '\n', '\r' };
public static async Task<string> ExtractText(Bitmap bmp, Language? preferredLanguage, System.Windows.Point? singlePoint = null)
{
Language? selectedLanguage = preferredLanguage ?? GetOCRLanguage();
@@ -211,7 +213,7 @@ internal sealed class ImageMethods
if (culture.TextInfo.IsRightToLeft)
{
string[] textListLines = text.ToString().Split(new char[] { '\n', '\r' });
string[] textListLines = text.ToString().Split(Separator);
_ = text.Clear();
foreach (string textLine in textListLines)

View File

@@ -220,9 +220,6 @@ public class WrappingStream : Stream
private void ThrowIfDisposed()
{
// throws an ObjectDisposedException if this object has been disposed
if (_streamBase == null)
{
throw new ObjectDisposedException(GetType().Name);
}
ObjectDisposedException.ThrowIf(_streamBase == null, this);
}
}

View File

@@ -239,7 +239,7 @@ public class ResultTable
return rowAreas;
}
private static void CheckIntersectionsWithWordBorders(int hitGridSpacing, ICollection<WordBorder> wordBorders, ICollection<int> rowAreas, int i, Rect horizontalLineRect)
private static void CheckIntersectionsWithWordBorders(int hitGridSpacing, ICollection<WordBorder> wordBorders, List<int> rowAreas, int i, Rect horizontalLineRect)
{
foreach (WordBorder wb in wordBorders)
{

View File

@@ -49,7 +49,9 @@ public partial class OCROverlay : Window
Top = screenRectangle.Top >= 0 ? screenRectangle.Top : screenRectangle.Top + (screenRectangle.Height / 2);
InitializeComponent();
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, Wpf.Ui.Controls.WindowBackdropType.None);
PopulateLanguageMenu();
}

View File

@@ -15,10 +15,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup>
@@ -28,7 +28,7 @@
<PackageIcon>PowerOCRLogo.png</PackageIcon>
<RootNamespace>PowerOCR</RootNamespace>
<AssemblyName>PowerToys.PowerOCR</AssemblyName>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<ProjectTypeGuids>{2150E333-8FDC-42A3-9474-1A3956D46DE8}</ProjectTypeGuids>

View File

@@ -16,7 +16,7 @@ namespace PowerOCR.Settings
[Export(typeof(IUserSettings))]
public class UserSettings : IUserSettings
{
private readonly ISettingsUtils _settingsUtils;
private readonly SettingsUtils _settingsUtils;
private const string PowerOcrModuleName = "TextExtractor";
private const string DefaultActivationShortcut = "Win + Shift + O";
private const int MaxNumberOfRetry = 5;

View File

@@ -0,0 +1,41 @@
#include <windows.h>
#include "resource.h"
#include "../../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@@ -8,6 +8,10 @@
#include <common/utils/winapi_error.h>
#include <common/utils/process_path.h>
#include <common/utils/elevation.h>
#include <common/notifications/NotificationUtil.h>
#include <Generated Files/resource.h>
#include <interop/shared_constants.h>
#include <trace.h>
@@ -489,6 +493,10 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept
break;
case EVENT_SYSTEM_FOREGROUND:
{
if (!is_process_elevated() && IsProcessOfWindowElevated(data->hwnd))
{
notifications::WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_ALWAYSONTOP), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_LEARN_MORE), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_DIALOG_DONT_SHOW_AGAIN));
}
RefreshBorders();
}
break;

View File

@@ -3,6 +3,9 @@
<!-- Project configurations -->
<!-- Props that should be disabled while building on CI server -->
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h AlwaysOnTop.base.rc AlwaysOnTop.rc" />
</Target>
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -141,9 +144,12 @@
<ItemGroup>
<ClInclude Include="AlwaysOnTop.h" />
<ClInclude Include="FrameDrawer.h" />
<ClInclude Include="Generated Files/resource.h" />
<ClInclude Include="ModuleConstants.h" />
<ClInclude Include="NotificationUtil.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
<None Include="resource.base.h" />
<ClInclude Include="ScalingUtils.h" />
<ClInclude Include="Settings.h" />
<ClInclude Include="SettingsConstants.h" />
@@ -167,10 +173,17 @@
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\notifications\notifications.vcxproj">
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="AlwaysOnTop.rc" />
<ResourceCompile Include="Generated Files/AlwaysOnTop.rc" />
<None Include="AlwaysOnTop.base.rc" />
</ItemGroup>
<ItemGroup>
<None Include="Resources.resx" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\..\deps\spdlog.props" />

View File

@@ -12,6 +12,9 @@
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{A74B5AAC-E913-410D-8941-D73346CF47AE}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
@@ -49,8 +52,22 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Generated Files/AlwaysOnTop.rc">
<Filter>Generated Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Resources.resx">
<Filter>Resource Files</Filter>
</None>
<None Include="resource.base.h">
<Filter>Header Files</Filter>
</None>
<None Include="AlwaysOnTop.base.rc">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
@@ -97,6 +114,9 @@
</ClInclude>
<ClInclude Include="ScalingUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Generated Files/resource.h">
<Filter>Generated Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AlwaysOnTop" xml:space="preserve">
<value>AlwaysOnTop</value>
<comment>AlwaysOnTop is a product name, keep as is.</comment>
</data>
<data name="System_Foreground_Elevated" xml:space="preserve">
<value>We've detected an application running with administrator privileges. This will prevent certain interactions with these applications.</value>
<comment>administrator is context of user account.</comment>
</data>
<data name="System_Foreground_Elevated_Learn_More" xml:space="preserve">
<value>Learn more</value>
</data>
<data name="System_Foreground_Elevated_Dialog_Dont_Show_Again" xml:space="preserve">
<value>Don't show again</value>
</data>
</root>

View File

@@ -0,0 +1,13 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by AlwaysOnTop.rc
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys.AlwaysOnTop"
#define INTERNAL_NAME "PowerToys.AlwaysOnTop"
#define ORIGINAL_FILENAME "PowerToys.AlwaysOnTop.exe"
// Non-localizable
//////////////////////////////

View File

@@ -2,7 +2,7 @@
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
@@ -24,10 +24,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->

View File

@@ -11,15 +11,9 @@ namespace Awake.Core
{
public static void AddRange<T>(this ICollection<T> target, IEnumerable<T> source)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
ArgumentNullException.ThrowIfNull(target);
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
ArgumentNullException.ThrowIfNull(source);
foreach (var element in source)
{

View File

@@ -28,6 +28,9 @@ namespace Awake.Core
/// </summary>
public class Manager
{
private static readonly CompositeFormat AwakeMinutes = System.Text.CompositeFormat.Parse(Properties.Resources.AWAKE_MINUTES);
private static readonly CompositeFormat AwakeHours = System.Text.CompositeFormat.Parse(Properties.Resources.AWAKE_HOURS);
private static BlockingCollection<ExecutionState> _stateQueue;
private static CancellationTokenSource _tokenSource;
@@ -276,9 +279,9 @@ namespace Awake.Core
{
Dictionary<string, int> optionsList = new Dictionary<string, int>
{
{ string.Format(CultureInfo.InvariantCulture, Resources.AWAKE_MINUTES, 30), 1800 },
{ string.Format(CultureInfo.InvariantCulture, AwakeMinutes, 30), 1800 },
{ Resources.AWAKE_1_HOUR, 3600 },
{ string.Format(CultureInfo.InvariantCulture, Resources.AWAKE_HOURS, 2), 7200 },
{ string.Format(CultureInfo.InvariantCulture, AwakeHours, 2), 7200 },
};
return optionsList;
}

View File

@@ -47,6 +47,11 @@ namespace Awake
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private static ManualResetEvent _exitSignal = new ManualResetEvent(false);
internal static readonly string[] AliasesConfigOption = new[] { "--use-pt-config", "-c" };
internal static readonly string[] AliasesDisplayOption = new[] { "--display-on", "-d" };
internal static readonly string[] AliasesTimeOption = new[] { "--time-limit", "-t" };
internal static readonly string[] AliasesPidOption = new[] { "--pid", "-p" };
internal static readonly string[] AliasesExpireAtOption = new[] { "--expire-at", "-e" };
private static int Main(string[] args)
{
@@ -86,7 +91,7 @@ namespace Awake
Logger.LogInfo("Parsing parameters...");
Option<bool> configOption = new(
aliases: new[] { "--use-pt-config", "-c" },
aliases: AliasesConfigOption,
getDefaultValue: () => false,
description: $"Specifies whether {Core.Constants.AppName} will be using the PowerToys configuration file for managing the state.")
{
@@ -95,7 +100,7 @@ namespace Awake
};
Option<bool> displayOption = new(
aliases: new[] { "--display-on", "-d" },
aliases: AliasesDisplayOption,
getDefaultValue: () => true,
description: "Determines whether the display should be kept awake.")
{
@@ -104,7 +109,7 @@ namespace Awake
};
Option<uint> timeOption = new(
aliases: new[] { "--time-limit", "-t" },
aliases: AliasesTimeOption,
getDefaultValue: () => 0,
description: "Determines the interval, in seconds, during which the computer is kept awake.")
{
@@ -113,7 +118,7 @@ namespace Awake
};
Option<int> pidOption = new(
aliases: new[] { "--pid", "-p" },
aliases: AliasesPidOption,
getDefaultValue: () => 0,
description: $"Bind the execution of {Core.Constants.AppName} to another process. When the process ends, the system will resume managing the current sleep and display state.")
{
@@ -122,7 +127,7 @@ namespace Awake
};
Option<string> expireAtOption = new(
aliases: new[] { "--expire-at", "-e" },
aliases: AliasesExpireAtOption,
getDefaultValue: () => string.Empty,
description: $"Determines the end date/time when {Core.Constants.AppName} will back off and let the system manage the current sleep and display state.")
{

View File

@@ -0,0 +1,69 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<ImplicitUsings>enable</ImplicitUsings>
<Authors>Microsoft Corporation</Authors>
<Product>PowerToys</Product>
<Nullable>enable</Nullable>
<Description>PowerToys CommandNotFound</Description>
<AssemblyName>PowerToys.CmdNotFound</AssemblyName>
<GenerateDependencyFile>false</GenerateDependencyFile>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<SelfContained>true</SelfContained>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<DefineConstants>TRACE;RELEASE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool">
<ExcludeAssets>contentFiles</ExcludeAssets>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; compile; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Management.Automation">
<ExcludeAssets>contentFiles</ExcludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<Content Include="WinGetCommandNotFound.psd1">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Management.Automation;
using System.Management.Automation.Subsystem;
using System.Management.Automation.Subsystem.Feedback;
using System.Management.Automation.Subsystem.Prediction;
namespace WinGetCommandNotFound
{
public sealed class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup
{
internal const string Id = "e5351aa4-dfde-4d4d-bf0f-1a2f5a37d8d6";
public void OnImport()
{
if (!Platform.IsWindows || !IsWinGetInstalled())
{
return;
}
SubsystemManager.RegisterSubsystem(SubsystemKind.FeedbackProvider, WinGetCommandNotFoundFeedbackPredictor.Singleton);
SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor, WinGetCommandNotFoundFeedbackPredictor.Singleton);
}
public void OnRemove(PSModuleInfo psModuleInfo)
{
if (!IsWinGetInstalled())
{
return;
}
SubsystemManager.UnregisterSubsystem<IFeedbackProvider>(new Guid(Id));
SubsystemManager.UnregisterSubsystem<ICommandPredictor>(new Guid(Id));
}
private bool IsWinGetInstalled()
{
// Ensure WinGet is installed
using (var pwsh = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
var results = pwsh.AddCommand("Get-Command")
.AddParameter("Name", "winget")
.AddParameter("CommandType", "Application")
.Invoke();
if (results.Count is 0)
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Extensions.ObjectPool;
namespace WinGetCommandNotFound
{
public sealed class PooledPowerShellObjectPolicy : IPooledObjectPolicy<PowerShell>
{
private static readonly string[] WingetClientModuleName = new[] { "Microsoft.WinGet.Client" };
public PowerShell Create()
{
var iss = InitialSessionState.CreateDefault2();
iss.ImportPSModule(WingetClientModuleName);
return PowerShell.Create(iss);
}
public bool Return(PowerShell obj)
{
if (obj != null)
{
obj.Commands.Clear();
obj.Streams.ClearStreams();
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace WinGetCommandNotFound.Telemetry
{
[EventData]
public class CmdNotFoundFeedbackProvidedEvent : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}
}

View File

@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace WinGetCommandNotFound.Telemetry
{
[EventData]
public class CmdNotFoundSuggestionProvidedEvent : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}
}

View File

@@ -0,0 +1,11 @@
@{
ModuleVersion = '0.1.0'
GUID = '28c9afa2-92e5-413e-8e53-44b2d7a83ac6'
Author = 'Carlos Zamora'
CompanyName = "Microsoft Corporation"
Copyright = "Copyright (c) Microsoft Corporation."
Description = 'Enable suggestions on how to install missing commands via winget'
PowerShellVersion = '7.4'
NestedModules = @('PowerToys.CmdNotFound.dll')
RequiredModules = @(@{ModuleName = 'Microsoft.WinGet.Client'; ModuleVersion = "0.2.1"; })
}

View File

@@ -0,0 +1,217 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Subsystem.Feedback;
using System.Management.Automation.Subsystem.Prediction;
using ManagedCommon;
using Microsoft.Extensions.ObjectPool;
using Microsoft.PowerToys.Telemetry;
namespace WinGetCommandNotFound
{
public sealed class WinGetCommandNotFoundFeedbackPredictor : IFeedbackProvider, ICommandPredictor
{
private readonly Guid _guid;
private readonly ObjectPool<PowerShell> _pool;
private const int _maxSuggestions = 20;
private List<string>? _candidates;
private bool _warmedUp;
public static WinGetCommandNotFoundFeedbackPredictor Singleton { get; } = new WinGetCommandNotFoundFeedbackPredictor(Init.Id);
private WinGetCommandNotFoundFeedbackPredictor(string guid)
{
Logger.InitializeLogger("\\CmdNotFound\\Logs");
_guid = new Guid(guid);
var provider = new DefaultObjectPoolProvider();
_pool = provider.Create(new PooledPowerShellObjectPolicy());
_pool.Return(_pool.Get());
Task.Run(() => WarmUp());
}
public Guid Id => _guid;
public string Name => "Windows Package Manager - WinGet";
public string Description => "Finds missing commands that can be installed via WinGet.";
public Dictionary<string, string>? FunctionsToDefine => null;
private void WarmUp()
{
var ps = _pool.Get();
try
{
ps.AddCommand("Find-WinGetPackage")
.AddParameter("Count", 1)
.Invoke();
}
finally
{
_pool.Return(ps);
_warmedUp = true;
}
}
/// <summary>
/// Gets feedback based on the given commandline and error record.
/// </summary>
public FeedbackItem? GetFeedback(FeedbackContext context, CancellationToken token)
{
var target = (string)context.LastError!.TargetObject;
if (target is not null)
{
try
{
bool tooManySuggestions = false;
string packageMatchFilterField = "command";
var pkgList = FindPackages(target, ref tooManySuggestions, ref packageMatchFilterField);
if (pkgList.Count == 0)
{
return null;
}
// Build list of suggestions
_candidates = new List<string>();
foreach (var pkg in pkgList)
{
_candidates.Add(string.Format(CultureInfo.InvariantCulture, "winget install --id {0}", pkg.Members["Id"].Value.ToString()));
}
// Build footer message
var footerMessage = tooManySuggestions ?
string.Format(CultureInfo.InvariantCulture, "Additional results can be found using \"winget search --{0} {1}\"", packageMatchFilterField, target) :
null;
PowerToysTelemetry.Log.WriteEvent(new Telemetry.CmdNotFoundFeedbackProvidedEvent());
return new FeedbackItem(
"Try installing this package using winget:",
_candidates,
footerMessage,
FeedbackDisplayLayout.Portrait);
}
catch (Exception ex)
{
Logger.LogError("GetFeedback failed to execute", ex);
return new FeedbackItem($"Failed to execute PowerToys Command Not Found.{Environment.NewLine}This is a known issue if PowerShell 7 is installed from the Store or MSIX. If that isn't your case, please report an issue.", new List<string>(), FeedbackDisplayLayout.Portrait);
}
}
return null;
}
private Collection<PSObject> FindPackages(string query, ref bool tooManySuggestions, ref string packageMatchFilterField)
{
if (!_warmedUp)
{
return new Collection<PSObject>();
}
var ps = _pool.Get();
try
{
var common = new Hashtable()
{
["Source"] = "winget",
};
// 1) Search by command
var pkgList = ps.AddCommand("Find-WinGetPackage")
.AddParameter("Command", query)
.AddParameter("MatchOption", "StartsWithCaseInsensitive")
.AddParameters(common)
.Invoke();
if (pkgList.Count > 0)
{
tooManySuggestions = pkgList.Count > _maxSuggestions;
packageMatchFilterField = "command";
return pkgList;
}
// 2) No matches found,
// search by name
ps.Commands.Clear();
pkgList = ps.AddCommand("Find-WinGetPackage")
.AddParameter("Name", query)
.AddParameter("MatchOption", "ContainsCaseInsensitive")
.AddParameters(common)
.Invoke();
if (pkgList.Count > 0)
{
tooManySuggestions = pkgList.Count > _maxSuggestions;
packageMatchFilterField = "name";
return pkgList;
}
// 3) No matches found,
// search by moniker
ps.Commands.Clear();
pkgList = ps.AddCommand("Find-WinGetPackage")
.AddParameter("Moniker", query)
.AddParameter("MatchOption", "ContainsCaseInsensitive")
.AddParameters(common)
.Invoke();
tooManySuggestions = pkgList.Count > _maxSuggestions;
packageMatchFilterField = "moniker";
return pkgList;
}
finally
{
_pool.Return(ps);
}
}
public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind feedback)
{
return feedback switch
{
PredictorFeedbackKind.CommandLineAccepted => true,
_ => false,
};
}
public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContext context, CancellationToken cancellationToken)
{
if (_candidates is not null)
{
string input = context.InputAst.Extent.Text;
List<PredictiveSuggestion>? result = null;
foreach (string c in _candidates)
{
if (c.StartsWith(input, StringComparison.OrdinalIgnoreCase))
{
result ??= new List<PredictiveSuggestion>(_candidates.Count);
result.Add(new PredictiveSuggestion(c));
}
}
if (result is not null)
{
PowerToysTelemetry.Log.WriteEvent(new Telemetry.CmdNotFoundSuggestionProvidedEvent());
return new SuggestionPackage(result);
}
}
return default;
}
public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList<string> history)
{
// Reset the candidate state.
_candidates = null;
}
}
}

View File

@@ -0,0 +1,108 @@
// Microsoft Visual C++ generated resource script.
//
#include <windows.h>
#include "resource.h"
#include "../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
END
END
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_CMD_NOT_FOUND_NAME "Command Not Found"
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{0014d652-901f-4456-8d65-06fc5f997fb0}</ProjectGuid>
<RootNamespace>CmdNotFoundModuleInterface</RootNamespace>
<TargetName>PowerToys.CmdNotFoundModuleInterface</TargetName>
<PlatformToolset>v143</PlatformToolset>
<ProjectName>CmdNotFoundModuleInterface</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;CMDNOTFOUNDMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;CMDNOTFOUNDMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>Shlwapi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="CmdNotFoundModuleInterface.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="CmdNotFoundModuleInterface.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,158 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <filesystem>
#include <string>
#include <common/logger/logger.h>
#include <common/logger/logger_settings.h>
#include <common/SettingsAPI/settings_objects.h>
#include <common/utils/gpo.h>
#include <common/utils/logger_helper.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <interface/powertoy_module_interface.h>
#include "resource.h"
#include "trace.h"
BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
}
return TRUE;
}
const static wchar_t* MODULE_NAME = L"Command Not Found";
const static wchar_t* MODULE_DESC = L"A module that detects an error thrown by a command in PowerShell and suggests a relevant WinGet package to install, if available.";
inline const std::wstring ModuleKey = L"CmdNotFound";
class CmdNotFound : public PowertoyModuleIface
{
std::wstring app_name;
std::wstring app_key;
private:
bool m_enabled = false;
void install_module()
{
auto module_path = get_module_folderpath();
std::string command = "pwsh.exe";
command += " ";
command += "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + winrt::to_string(module_path) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\EnableModule.ps1" + "\"" + " -scriptPath \"" + winrt::to_string(module_path) + "\"";
int ret = system(command.c_str());
if (ret != 0)
{
Logger::error("Running EnableModule.ps1 script failed.");
}
else
{
Logger::info("Module installed successfully.");
Trace::EnableCmdNotFoundGpo(true);
}
}
void uninstall_module()
{
auto module_path = get_module_folderpath();
std::string command = "pwsh.exe";
command += " ";
command += "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + winrt::to_string(module_path) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\DisableModule.ps1" + "\"";
int ret = system(command.c_str());
if (ret != 0)
{
Logger::error("Running EnableModule.ps1 script failed.");
}
else
{
Logger::info("Module uninstalled successfully.");
Trace::EnableCmdNotFoundGpo(false);
}
}
public:
CmdNotFound()
{
app_name = GET_RESOURCE_STRING(IDS_CMD_NOT_FOUND_NAME);
app_key = ModuleKey;
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::cmdNotFoundLoggerName);
Logger::info("CmdNotFound object is constructing");
powertoys_gpo::gpo_rule_configured_t gpo_rule_configured_value = gpo_policy_enabled_configuration();
if (gpo_rule_configured_value == powertoys_gpo::gpo_rule_configured_t::gpo_rule_configured_enabled)
{
install_module();
m_enabled = true;
}
else if (gpo_rule_configured_value == powertoys_gpo::gpo_rule_configured_t::gpo_rule_configured_disabled)
{
uninstall_module();
m_enabled = false;
}
}
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
{
return powertoys_gpo::getConfiguredCmdNotFoundEnabledValue();
}
virtual void destroy() override
{
delete this;
}
virtual const wchar_t* get_name() override
{
return MODULE_NAME;
}
virtual const wchar_t* get_key() override
{
return app_key.c_str();
}
virtual bool get_config(wchar_t* /*buffer*/, int* /*buffer_size*/) override
{
return false;
}
virtual void set_config(const wchar_t* config) override
{
}
virtual void enable()
{
}
virtual void disable()
{
}
virtual bool is_enabled() override
{
return m_enabled;
}
};
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new CmdNotFound();
}

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@@ -0,0 +1,16 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <ProjectTelemetry.h>
#endif //PCH_H

View File

@@ -0,0 +1,21 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Awake.rc
//
#define IDS_CMD_NOT_FOUND_NAME 101
#define FILE_DESCRIPTION "PowerToys Command Not Found"
#define INTERNAL_NAME "PowerToys.CmdNotFoundModuleInterface"
#define ORIGINAL_FILENAME "PowerToys.CmdNotFoundModuleInterface.dll"
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,30 @@
#include "pch.h"
#include "trace.h"
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider()
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider()
{
TraceLoggingUnregister(g_hProvider);
}
// Log if the user has CmdNotFound enabled or disabled
void Trace::EnableCmdNotFoundGpo(const bool enabled) noexcept
{
TraceLoggingWrite(
g_hProvider,
"CmdNotFound_EnableCmdNotFound",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingBoolean(enabled, "Enabled"));
}

View File

@@ -0,0 +1,11 @@
#pragma once
class Trace
{
public:
static void RegisterProvider();
static void UnregisterProvider();
// Log if the user has CmdNotFound enabled or disabled
static void EnableCmdNotFoundGpo(const bool enabled) noexcept;
};

View File

@@ -20,7 +20,7 @@ namespace ColorPicker.Behaviors
private static readonly TimeSpan _animationTimeSmaller = _animationTime;
private static readonly IEasingFunction _easeFunctionSmaller = new QuadraticEase() { EasingMode = EasingMode.EaseIn };
private static void CustomAnimation(DependencyProperty prop, IAnimatable sender, double fromValue, double toValue)
private static void CustomAnimation(DependencyProperty prop, FrameworkElement sender, double fromValue, double toValue)
{
// if the animation is to/from a value of 0, it will cancel the current animation
DoubleAnimation move = null;

View File

@@ -14,10 +14,10 @@
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup>
@@ -25,7 +25,7 @@
<OutputType>WinExe</OutputType>
<RootNamespace>ColorPicker</RootNamespace>
<AssemblyName>PowerToys.ColorPickerUI</AssemblyName>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

View File

@@ -28,10 +28,7 @@ namespace ColorPicker.Common
public void AddRange(IEnumerable<T> list)
{
if (list == null)
{
throw new ArgumentNullException(nameof(list));
}
ArgumentNullException.ThrowIfNull(list);
_suppressNotification = true;

View File

@@ -329,7 +329,7 @@ namespace ColorPicker.Controls
newHexString = newHexString.ToLowerInvariant();
// Return only with hashtag if user typed it before
bool addHashtag = oldValue.StartsWith("#", StringComparison.InvariantCulture);
bool addHashtag = oldValue.StartsWith('#');
return addHashtag ? "#" + newHexString : newHexString;
}
@@ -348,7 +348,7 @@ namespace ColorPicker.Controls
else
{
// Hex with or without hashtag and six characters
return hexCodeText.StartsWith("#", StringComparison.InvariantCulture) ? hexCodeText : "#" + hexCodeText;
return hexCodeText.StartsWith('#') ? hexCodeText : "#" + hexCodeText;
}
}

View File

@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows.Media;
using ColorPicker.Models;
@@ -21,6 +22,9 @@ namespace ColorPicker.Helpers
internal static class SerializationHelper
{
public static readonly JsonSerializerOptions DefaultOptions = new JsonSerializerOptions { WriteIndented = false };
public static readonly JsonSerializerOptions IndentedOptions = new JsonSerializerOptions { WriteIndented = true };
public static Dictionary<string, Dictionary<string, string>> ConvertToDesiredColorFormats(
IList colorsToExport,
IEnumerable<ColorFormatModel> colorRepresentations,
@@ -116,10 +120,7 @@ namespace ColorPicker.Helpers
public static string ToJson(this Dictionary<string, Dictionary<string, string>> source, bool indented = true)
{
var options = new JsonSerializerOptions
{
WriteIndented = indented,
};
var options = indented ? IndentedOptions : DefaultOptions;
return JsonSerializer.Serialize(source, options);
}

View File

@@ -91,7 +91,7 @@ namespace ColorPicker.Helpers
ShowZoomWindow(point);
}
private static BitmapSource BitmapToImageSource(Bitmap bitmap)
private static BitmapImage BitmapToImageSource(Bitmap bitmap)
{
using (MemoryStream memory = new MemoryStream())
{

View File

@@ -22,7 +22,7 @@ namespace ColorPicker.Settings
[Export(typeof(IUserSettings))]
public class UserSettings : IUserSettings
{
private readonly ISettingsUtils _settingsUtils;
private readonly SettingsUtils _settingsUtils;
private const string ColorPickerModuleName = "ColorPicker";
private const string ColorPickerHistoryFilename = "colorHistory.json";
private const string DefaultActivationShortcut = "Ctrl + Break";
@@ -36,6 +36,11 @@ namespace ColorPicker.Settings
private bool _loadingColorsHistory;
private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
{
WriteIndented = true,
};
[ImportingConstructor]
public UserSettings(Helpers.IThrottledActionInvoker throttledActionInvoker)
{
@@ -58,7 +63,7 @@ namespace ColorPicker.Settings
{
if (!_loadingColorsHistory)
{
_settingsUtils.SaveSettings(JsonSerializer.Serialize(ColorHistory, new JsonSerializerOptions { WriteIndented = true }), ColorPickerModuleName, ColorPickerHistoryFilename);
_settingsUtils.SaveSettings(JsonSerializer.Serialize(ColorHistory, _serializerOptions), ColorPickerModuleName, ColorPickerHistoryFilename);
}
}

View File

@@ -2,7 +2,7 @@
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<ProjectGuid>{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}</ProjectGuid>

View File

@@ -394,15 +394,6 @@ void FancyZones::WindowCreated(HWND window) noexcept
return;
}
// Hotfix
// Avoid automatically moving popup windows, as they can be just popup menus.
bool isPopup = FancyZonesWindowUtils::IsPopupWindow(window);
bool hasThickFrame = FancyZonesWindowUtils::HasThickFrame(window);
if (isPopup && !hasThickFrame)
{
return;
}
// Avoid already stamped (zoned) windows
const bool isZoned = !FancyZonesWindowProperties::RetrieveZoneIndexProperty(window).empty();
if (isZoned)
@@ -1005,41 +996,42 @@ void FancyZones::RefreshLayouts() noexcept
bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
{
auto window = GetForegroundWindow();
if (!FancyZonesSettings::settings().overrideSnapHotkeys)
{
return false;
}
auto window = GetForegroundWindow();
if (!FancyZonesWindowProcessing::IsProcessable(window))
{
return false;
}
if (FancyZonesSettings::settings().overrideSnapHotkeys)
HMONITOR monitor = WorkAreaKeyFromWindow(window);
auto workArea = m_workAreaConfiguration.GetWorkArea(monitor);
if (!workArea)
{
HMONITOR monitor = WorkAreaKeyFromWindow(window);
Logger::error(L"No work area for processing snap hotkey");
return false;
}
auto workArea = m_workAreaConfiguration.GetWorkArea(monitor);
if (!workArea)
const auto& layout = workArea->GetLayout();
if (!layout)
{
Logger::error(L"No layout for processing snap hotkey");
return false;
}
if (layout->Zones().size() > 0)
{
if (vkCode == VK_UP || vkCode == VK_DOWN)
{
Logger::error(L"No work area for processing snap hotkey");
return false;
return FancyZonesSettings::settings().moveWindowsBasedOnPosition;
}
const auto& layout = workArea->GetLayout();
if (!layout)
else
{
Logger::error(L"No layout for processing snap hotkey");
return false;
}
if (layout->Zones().size() > 0)
{
if (vkCode == VK_UP || vkCode == VK_DOWN)
{
return FancyZonesSettings::settings().moveWindowsBasedOnPosition;
}
else
{
return true;
}
return true;
}
}

View File

@@ -61,7 +61,6 @@
<ClInclude Include="ModuleConstants.h" />
<ClInclude Include="MonitorUtils.h" />
<ClInclude Include="WorkAreaConfiguration.h" />
<ClInclude Include="NotificationUtil.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="Generated Files/resource.h" />
<None Include="resource.base.h" />

View File

@@ -153,9 +153,6 @@
<ClInclude Include="HighlightedZones.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NotificationUtil.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HighlightedZones.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@@ -5,52 +5,69 @@
#include <FancyZonesLib/VirtualDesktop.h>
#include <FancyZonesLib/WindowUtils.h>
bool FancyZonesWindowProcessing::IsProcessable(HWND window) noexcept
FancyZonesWindowProcessing::ProcessabilityType FancyZonesWindowProcessing::DefineWindowType(HWND window) noexcept
{
const bool isSplashScreen = FancyZonesWindowUtils::IsSplashScreen(window);
if (isSplashScreen)
{
return false;
}
const bool windowMinimized = IsIconic(window);
if (windowMinimized)
{
return false;
return ProcessabilityType::Minimized;
}
const bool standard = FancyZonesWindowUtils::IsStandardWindow(window);
if (!standard)
auto style = GetWindowLong(window, GWL_STYLE);
auto exStyle = GetWindowLong(window, GWL_EXSTYLE);
if (!FancyZonesWindowUtils::HasStyle(style, WS_VISIBLE))
{
return false;
return ProcessabilityType::NotVisible;
}
// popup could be the window we don't want to snap: start menu, notification popup, tray window, etc.
// also, popup could be the windows we want to snap disregarding the "allowSnapPopupWindows" setting, e.g. Telegram
bool isPopup = FancyZonesWindowUtils::IsPopupWindow(window) && !FancyZonesWindowUtils::HasThickFrameAndMinimizeMaximizeButtons(window);
if (isPopup && !FancyZonesSettings::settings().allowSnapPopupWindows)
if (FancyZonesWindowUtils::HasStyle(exStyle, WS_EX_TOOLWINDOW))
{
return false;
return ProcessabilityType::ToolWindow;
}
if (!FancyZonesWindowUtils::IsRoot(window))
{
// child windows such as buttons, combo boxes, etc.
return ProcessabilityType::NonRootWindow;
}
bool isPopup = FancyZonesWindowUtils::HasStyle(style, WS_POPUP);
bool hasThickFrame = FancyZonesWindowUtils::HasStyle(style, WS_THICKFRAME);
bool hasCaption = FancyZonesWindowUtils::HasStyle(style, WS_CAPTION);
bool hasMinimizeMaximizeButtons = FancyZonesWindowUtils::HasStyle(style, WS_MINIMIZEBOX) || FancyZonesWindowUtils::HasStyle(style, WS_MAXIMIZEBOX);
if (isPopup && !(hasThickFrame && (hasCaption || hasMinimizeMaximizeButtons)))
{
// popup windows we want to snap: e.g. Calculator, Telegram
// popup windows we don't want to snap: start menu, notification popup, tray window, etc.
// WS_CAPTION, WS_MINIMIZEBOX, WS_MAXIMIZEBOX are used for filtering out menus,
// e.g., in Edge "Running as admin" menu when creating a new PowerToys issue.
return ProcessabilityType::NonProcessablePopupWindow;
}
// allow child windows
auto hasOwner = FancyZonesWindowUtils::HasVisibleOwner(window);
if (hasOwner && !FancyZonesSettings::settings().allowSnapChildWindows)
{
return false;
return ProcessabilityType::ChildWindow;
}
if (FancyZonesWindowUtils::IsExcluded(window))
{
return false;
return ProcessabilityType::Excluded;
}
// Switch between virtual desktops results with posting same windows messages that also indicate
// creation of new window. We need to check if window being processed is on currently active desktop.
if (!VirtualDesktop::instance().IsWindowOnCurrentDesktop(window))
{
return false;
return ProcessabilityType::NotCurrentVirtualDesktop;
}
return true;
return ProcessabilityType::Processable;
}
bool FancyZonesWindowProcessing::IsProcessable(HWND window) noexcept
{
return DefineWindowType(window) == ProcessabilityType::Processable;
}

View File

@@ -2,5 +2,20 @@
namespace FancyZonesWindowProcessing
{
enum class ProcessabilityType
{
Processable = 0,
SplashScreen,
Minimized,
ToolWindow,
NotVisible,
NonRootWindow,
NonProcessablePopupWindow,
ChildWindow,
Excluded,
NotCurrentVirtualDesktop
};
ProcessabilityType DefineWindowType(HWND window) noexcept;
bool IsProcessable(HWND window) noexcept;
}

View File

@@ -360,7 +360,7 @@ namespace MonitorUtils
if (GetMonitorInfo(monitor, &destMi))
{
RECT newPosition = FitOnScreen(placement.rcNormalPosition, originMi.rcWork, destMi.rcWork);
FancyZonesWindowUtils::SizeWindowToRect(window, newPosition);
FancyZonesWindowUtils::SizeWindowToRect(window, newPosition, false);
}
}
}

View File

@@ -1,35 +0,0 @@
#pragma once
#include <common/notifications/notifications.h>
#include <common/notifications/dont_show_again.h>
#include <common/utils/resources.h>
namespace FancyZonesNotifications
{
// Non-Localizable strings
namespace NonLocalizable
{
const wchar_t FancyZonesRunAsAdminInfoPage[] = L"https://aka.ms/powertoysDetectedElevatedHelp";
const wchar_t ToastNotificationButtonUrl[] = L"powertoys://cant_drag_elevated_disable/";
}
inline void WarnIfElevationIsRequired()
{
using namespace notifications;
using namespace NonLocalizable;
static bool warning_shown = false;
if (!warning_shown && !is_toast_disabled(CantDragElevatedDontShowAgainRegistryPath, CantDragElevatedDisableIntervalInDays))
{
std::vector<action_t> actions = {
link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), FancyZonesRunAsAdminInfoPage },
link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN), ToastNotificationButtonUrl }
};
show_toast_with_activations(GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED),
GET_RESOURCE_STRING(IDS_FANCYZONES),
{},
std::move(actions));
warning_shown = true;
}
}
}

View File

@@ -215,7 +215,7 @@
</data>
<data name="FancyZones" xml:space="preserve">
<value>FancyZones</value>
<comment>FancyZone is a product name, keep as is.</comment>
<comment>FancyZones is a product name, keep as is.</comment>
</data>
<data name="Cant_Drag_Elevated" xml:space="preserve">
<value>We've detected an application running with administrator privileges. This will prevent certain interactions with these applications.</value>
@@ -243,19 +243,19 @@
</data>
<data name="FancyZones_Data_Error" xml:space="preserve">
<value>FancyZones persisted data path not found. Please report the bug to</value>
<comment>"Report bug to" will have a URL after. FancyZone is a product name, keep as is.</comment>
<comment>"Report bug to" will have a URL after. FancyZones is a product name, keep as is.</comment>
</data>
<data name="FancyZones_Editor_Launch_Error" xml:space="preserve">
<value>The FancyZones editor failed to start. Please report the bug to</value>
<comment>"Report bug to" will have a URL after. FancyZone is a product name, keep as is.</comment>
<comment>"Report bug to" will have a URL after. FancyZones is a product name, keep as is.</comment>
</data>
<data name="FancyZones_Settings_Load_Error" xml:space="preserve">
<value>Failed to load the FancyZones settings. Default settings will be used.</value>
<comment>FancyZone is a product name, keep as is.</comment>
<comment>FancyZones is a product name, keep as is.</comment>
</data>
<data name="FancyZones_Settings_Save_Error" xml:space="preserve">
<value>Failed to save the FancyZones settings. Please retry again later, if the problem persists report the bug to</value>
<comment>"Report bug to" will have a URL after. FancyZone is a product name, keep as is.</comment>
<comment>"Report bug to" will have a URL after. FancyZones is a product name, keep as is.</comment>
</data>
<data name="Setting_Description_QuickLayoutSwitch" xml:space="preserve">
<value>Enable quick layout switch</value>

View File

@@ -33,7 +33,6 @@ namespace NonLocalizable
const wchar_t ShowOnAllMonitorsID[] = L"fancyzones_show_on_all_monitors";
const wchar_t SpanZonesAcrossMonitorsID[] = L"fancyzones_span_zones_across_monitors";
const wchar_t MakeDraggedWindowTransparentID[] = L"fancyzones_makeDraggedWindowTransparent";
const wchar_t AllowPopupWindowSnapID[] = L"fancyzones_allowPopupWindowSnap";
const wchar_t AllowChildWindowSnapID[] = L"fancyzones_allowChildWindowSnap";
const wchar_t DisableRoundCornersOnSnapping[] = L"fancyzones_disableRoundCornersOnSnap";
@@ -127,7 +126,6 @@ void FancyZonesSettings::LoadSettings()
SetBoolFlag(values, NonLocalizable::WindowSwitchingToggleID, SettingId::WindowSwitching, m_settings.windowSwitching);
SetBoolFlag(values, NonLocalizable::SystemThemeID, SettingId::SystemTheme, m_settings.systemTheme);
SetBoolFlag(values, NonLocalizable::ShowZoneNumberID, SettingId::ShowZoneNumber, m_settings.showZoneNumber);
SetBoolFlag(values, NonLocalizable::AllowPopupWindowSnapID, SettingId::AllowSnapPopupWindows, m_settings.allowSnapPopupWindows);
SetBoolFlag(values, NonLocalizable::AllowChildWindowSnapID, SettingId::AllowSnapChildWindows, m_settings.allowSnapChildWindows);
SetBoolFlag(values, NonLocalizable::DisableRoundCornersOnSnapping, SettingId::DisableRoundCornersOnSnapping, m_settings.disableRoundCorners);

View File

@@ -44,7 +44,6 @@ struct Settings
bool makeDraggedWindowTransparent = true;
bool systemTheme = true;
bool showZoneNumber = true;
bool allowSnapPopupWindows = false;
bool allowSnapChildWindows = false;
bool disableRoundCorners = false;
std::wstring zoneColor = L"#AACDFF";

View File

@@ -32,7 +32,6 @@ enum class SettingId
NextTabHotkey,
PrevTabHotkey,
ExcludedApps,
AllowSnapPopupWindows,
AllowSnapChildWindows,
DisableRoundCornersOnSnapping,
};

View File

@@ -4,7 +4,6 @@
#include <FancyZonesLib/FancyZonesData/AppZoneHistory.h>
#include <FancyZonesLib/FancyZonesWindowProcessing.h>
#include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <FancyZonesLib/NotificationUtil.h>
#include <FancyZonesLib/Settings.h>
#include <FancyZonesLib/WindowUtils.h>
#include <FancyZonesLib/WorkArea.h>
@@ -12,6 +11,7 @@
#include <FancyZonesLib/trace.h>
#include <common/utils/elevation.h>
#include <common/notifications/NotificationUtil.h>
WindowMouseSnap::WindowMouseSnap(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas) :
m_window(window),
@@ -20,8 +20,6 @@ WindowMouseSnap::WindowMouseSnap(HWND window, const std::unordered_map<HMONITOR,
m_snappingMode(false)
{
m_windowProperties.hasNoVisibleOwner = !FancyZonesWindowUtils::HasVisibleOwner(m_window);
m_windowProperties.isStandardWindow = FancyZonesWindowUtils::IsStandardWindow(m_window) &&
(!FancyZonesWindowUtils::IsPopupWindow(m_window) || FancyZonesSettings::settings().allowSnapPopupWindows);
}
WindowMouseSnap::~WindowMouseSnap()
@@ -31,16 +29,15 @@ WindowMouseSnap::~WindowMouseSnap()
std::unique_ptr<WindowMouseSnap> WindowMouseSnap::Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas)
{
if (!FancyZonesWindowProcessing::IsProcessable(window) ||
FancyZonesWindowUtils::IsCursorTypeIndicatingSizeEvent())
if (FancyZonesWindowUtils::IsCursorTypeIndicatingSizeEvent() || !FancyZonesWindowProcessing::IsProcessable(window))
{
return nullptr;
}
if (!is_process_elevated() && FancyZonesWindowUtils::IsProcessOfWindowElevated(window))
if (!is_process_elevated() && IsProcessOfWindowElevated(window))
{
// Notifies user if unable to drag elevated window
FancyZonesNotifications::WarnIfElevationIsRequired();
notifications::WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_FANCYZONES), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN));
return nullptr;
}
@@ -111,13 +108,8 @@ void WindowMouseSnap::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, bo
void WindowMouseSnap::MoveSizeEnd()
{
if (m_snappingMode)
{
const bool hasNoVisibleOwner = !FancyZonesWindowUtils::HasVisibleOwner(m_window);
const bool isStandardWindow = FancyZonesWindowUtils::IsStandardWindow(m_window);
if ((isStandardWindow == false && hasNoVisibleOwner == true &&
m_windowProperties.isStandardWindow == true && m_windowProperties.hasNoVisibleOwner == true) ||
FancyZonesWindowUtils::IsWindowMaximized(m_window))
{
if (FancyZonesWindowUtils::IsWindowMaximized(m_window))
{
// Abort the zoning, this is a Chromium based tab that is merged back with an existing window
// or if the window is maximized by Windows when the cursor hits the screen top border

View File

@@ -24,8 +24,6 @@ private:
struct WindowProperties
{
// True if from the styles the window looks like a standard window
bool isStandardWindow = false;
// True if the window is a top-level window that does not have a visible owner
bool hasNoVisibleOwner = false;
// Properties to restore after dragging

View File

@@ -15,7 +15,7 @@
namespace NonLocalizable
{
const wchar_t PowerToysAppFZEditor[] = L"POWERTOYS.FANCYZONESEDITOR.EXE";
const wchar_t SplashClassName[] = L"MsoSplash";
const char SplashClassName[] = "MsoSplash";
const wchar_t CoreWindow[] = L"Windows.UI.Core.CoreWindow";
const wchar_t SearchUI[] = L"SearchUI.exe";
const wchar_t SystemAppsFolder[] = L"SYSTEMAPPS";
@@ -122,17 +122,6 @@ namespace
}
}
bool FancyZonesWindowUtils::IsSplashScreen(HWND window)
{
wchar_t className[MAX_PATH];
if (GetClassName(window, className, MAX_PATH) == 0)
{
return false;
}
return wcscmp(NonLocalizable::SplashClassName, className) == 0;
}
bool FancyZonesWindowUtils::IsWindowMaximized(HWND window) noexcept
{
WINDOWPLACEMENT placement{};
@@ -164,71 +153,9 @@ bool FancyZonesWindowUtils::HasVisibleOwner(HWND window) noexcept
return rect.top != rect.bottom && rect.left != rect.right;
}
bool FancyZonesWindowUtils::IsStandardWindow(HWND window)
bool FancyZonesWindowUtils::IsRoot(HWND window) noexcept
{
// True if from the styles the window looks like a standard window
if (GetAncestor(window, GA_ROOT) != window)
{
return false;
}
auto style = GetWindowLong(window, GWL_STYLE);
auto exStyle = GetWindowLong(window, GWL_EXSTYLE);
bool isToolWindow = (exStyle & WS_EX_TOOLWINDOW) == WS_EX_TOOLWINDOW;
bool isVisible = (style & WS_VISIBLE) == WS_VISIBLE;
if (isToolWindow || !isVisible)
{
return false;
}
return true;
}
bool FancyZonesWindowUtils::IsPopupWindow(HWND window) noexcept
{
auto style = GetWindowLong(window, GWL_STYLE);
return ((style & WS_POPUP) == WS_POPUP);
}
bool FancyZonesWindowUtils::HasThickFrame(HWND window) noexcept
{
auto style = GetWindowLong(window, GWL_STYLE);
return ((style & WS_THICKFRAME) == WS_THICKFRAME);
}
bool FancyZonesWindowUtils::HasThickFrameAndMinimizeMaximizeButtons(HWND window) noexcept
{
auto style = GetWindowLong(window, GWL_STYLE);
return ((style & WS_THICKFRAME) == WS_THICKFRAME && (style & WS_MINIMIZEBOX) == WS_MINIMIZEBOX && (style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX);
}
bool FancyZonesWindowUtils::IsProcessOfWindowElevated(HWND window)
{
DWORD pid = 0;
GetWindowThreadProcessId(window, &pid);
if (!pid)
{
return false;
}
wil::unique_handle hProcess{ OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
FALSE,
pid) };
wil::unique_handle token;
if (OpenProcessToken(hProcess.get(), TOKEN_QUERY, &token))
{
TOKEN_ELEVATION elevation;
DWORD size;
if (GetTokenInformation(token.get(), TokenElevation, &elevation, sizeof(elevation), &size))
{
return elevation.TokenIsElevated != 0;
}
}
return false;
return GetAncestor(window, GA_ROOT) == window;
}
bool FancyZonesWindowUtils::IsExcluded(HWND window)
@@ -248,12 +175,12 @@ bool FancyZonesWindowUtils::IsExcluded(HWND window)
return false;
}
bool FancyZonesWindowUtils::IsExcludedByUser(const HWND& hwnd, std::wstring& processPath) noexcept
bool FancyZonesWindowUtils::IsExcludedByUser(const HWND& hwnd, const std::wstring& processPath) noexcept
{
return (check_excluded_app(hwnd, processPath, FancyZonesSettings::settings().excludedAppsArray));
}
bool FancyZonesWindowUtils::IsExcludedByDefault(const HWND& hwnd, std::wstring& processPath) noexcept
bool FancyZonesWindowUtils::IsExcludedByDefault(const HWND& hwnd, const std::wstring& processPath) noexcept
{
static std::vector<std::wstring> defaultExcludedFolders = { NonLocalizable::SystemAppsFolder };
if (find_folder_in_path(processPath, defaultExcludedFolders))
@@ -261,9 +188,14 @@ bool FancyZonesWindowUtils::IsExcludedByDefault(const HWND& hwnd, std::wstring&
return true;
}
std::array<char, 256> class_name;
GetClassNameA(hwnd, class_name.data(), static_cast<int>(class_name.size()));
if (is_system_window(hwnd, class_name.data()))
std::array<char, 256> className;
GetClassNameA(hwnd, className.data(), static_cast<int>(className.size()));
if (is_system_window(hwnd, className.data()))
{
return true;
}
if (strcmp(NonLocalizable::SplashClassName, className.data()) == 0)
{
return true;
}
@@ -294,7 +226,7 @@ void FancyZonesWindowUtils::SwitchToWindow(HWND window) noexcept
}
}
void FancyZonesWindowUtils::SizeWindowToRect(HWND window, RECT rect) noexcept
void FancyZonesWindowUtils::SizeWindowToRect(HWND window, RECT rect, BOOL snapZone) noexcept
{
WINDOWPLACEMENT placement{};
::GetWindowPlacement(window, &placement);
@@ -306,8 +238,15 @@ void FancyZonesWindowUtils::SizeWindowToRect(HWND window, RECT rect) noexcept
::GetWindowPlacement(window, &placement);
}
BOOL maximizeLater = false;
if (IsWindowVisible(window))
{
// If is not snap zone then need keep maximize state (move to active monitor)
if (!snapZone && placement.showCmd == SW_SHOWMAXIMIZED)
{
maximizeLater = true;
}
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
if ((placement.showCmd != SW_SHOWMINIMIZED) &&
(placement.showCmd != SW_MINIMIZE))
@@ -335,6 +274,12 @@ void FancyZonesWindowUtils::SizeWindowToRect(HWND window, RECT rect) noexcept
Logger::error(L"SetWindowPlacement failed, {}", get_last_error_or_default(GetLastError()));
}
// make sure window is moved to the correct monitor before maximize.
if (maximizeLater)
{
placement.showCmd = SW_SHOWMAXIMIZED;
}
// Do it again, allowing Windows to resize the window and set correct scaling
// This fixes Issue #365
result = ::SetWindowPlacement(window, &placement);

View File

@@ -15,21 +15,23 @@
namespace FancyZonesWindowUtils
{
bool IsSplashScreen(HWND window);
bool IsWindowMaximized(HWND window) noexcept;
bool HasVisibleOwner(HWND window) noexcept;
bool IsStandardWindow(HWND window);
bool IsPopupWindow(HWND window) noexcept;
bool HasThickFrame(HWND window) noexcept;
bool HasThickFrameAndMinimizeMaximizeButtons(HWND window) noexcept;
bool IsRoot(HWND window) noexcept;
constexpr bool HasStyle(LONG style, LONG styleToCheck) noexcept
{
return ((style & styleToCheck) == styleToCheck);
}
bool IsProcessOfWindowElevated(HWND window); // If HWND is already dead, we assume it wasn't elevated
bool IsExcluded(HWND window);
bool IsExcludedByUser(const HWND& hwnd, std::wstring& processPath) noexcept;
bool IsExcludedByDefault(const HWND& hwnd, std::wstring& processPath) noexcept;
bool IsExcludedByUser(const HWND& hwnd, const std::wstring& processPath) noexcept;
bool IsExcludedByDefault(const HWND& hwnd, const std::wstring& processPath) noexcept;
void SwitchToWindow(HWND window) noexcept;
void SizeWindowToRect(HWND window, RECT rect) noexcept; // Parameter rect must be in screen coordinates (e.g. obtained from GetWindowRect)
void SizeWindowToRect(HWND window, RECT rect, BOOL snapZone = true) noexcept; // Parameter rect must be in screen coordinates (e.g. obtained from GetWindowRect)
void SaveWindowSizeAndOrigin(HWND window) noexcept;
void RestoreWindowSize(HWND window) noexcept;
void RestoreWindowOrigin(HWND window) noexcept;

View File

@@ -57,7 +57,6 @@
#define SpanZonesAcrossMonitorsKey "SpanZonesAcrossMonitors"
#define MakeDraggedWindowTransparentKey "MakeDraggedWindowTransparent"
#define AllowSnapChildWindows "AllowSnapChildWindows"
#define AllowSnapPopupWindows "AllowSnapPopupWindows"
#define DisableRoundCornersOnSnapping "DisableRoundCornersOnSnapping"
#define ZoneColorKey "ZoneColor"
#define ZoneBorderColorKey "ZoneBorderColor"
@@ -323,7 +322,6 @@ void Trace::SettingsTelemetry(const Settings& settings) noexcept
TraceLoggingBoolean(settings.spanZonesAcrossMonitors, SpanZonesAcrossMonitorsKey),
TraceLoggingBoolean(settings.makeDraggedWindowTransparent, MakeDraggedWindowTransparentKey),
TraceLoggingBoolean(settings.allowSnapChildWindows, AllowSnapChildWindows),
TraceLoggingBoolean(settings.allowSnapPopupWindows, AllowSnapPopupWindows),
TraceLoggingBoolean(settings.disableRoundCorners, DisableRoundCornersOnSnapping),
TraceLoggingWideString(settings.zoneColor.c_str(), ZoneColorKey),
TraceLoggingWideString(settings.zoneBorderColor.c_str(), ZoneBorderColorKey),

View File

@@ -56,6 +56,7 @@
<ClCompile Include="Util.Spec.cpp" />
<ClCompile Include="Util.cpp" />
<ClCompile Include="WindowKeyboardSnap.Spec.cpp" />
<ClCompile Include="WindowProcessingTests.Spec.cpp" />
<ClCompile Include="WorkArea.Spec.cpp" />
<ClCompile Include="WorkAreaIdTests.Spec.cpp" />
<ClCompile Include="Zone.Spec.cpp" />

View File

@@ -66,6 +66,9 @@
<ClCompile Include="WindowKeyboardSnap.Spec.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WindowProcessingTests.Spec.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">

View File

@@ -8,8 +8,7 @@ namespace Mocks
class HwndCreator
{
public:
HwndCreator(const std::wstring& title = L"");
HwndCreator(const std::wstring& title, const std::wstring& className, DWORD exStyle, DWORD style, HWND parentWindow);
~HwndCreator();
HWND operator()(HINSTANCE hInst);
@@ -20,23 +19,30 @@ namespace Mocks
inline HINSTANCE getHInstance() const { return m_hInst; }
inline const std::wstring& getTitle() const { return m_windowTitle; }
inline const std::wstring& getWindowClassName() const { return m_windowClassName; }
inline DWORD getExStyle() const noexcept { return m_exStyle; }
inline DWORD getStyle() const noexcept { return m_style; }
inline HWND getParentWindow() const noexcept { return m_parentWindow; }
private:
std::wstring m_windowTitle;
std::wstring m_windowClassName;
DWORD m_exStyle{ 0 };
DWORD m_style{ 0 };
HWND m_parentWindow{ NULL };
std::mutex m_mutex;
std::condition_variable m_conditionVar;
bool m_conditionFlag;
HANDLE m_thread;
HINSTANCE m_hInst;
HINSTANCE m_hInst{};
HWND m_hWnd;
};
HWND WindowCreate(HINSTANCE hInst)
HWND WindowCreate(HINSTANCE hInst, const std::wstring& title /*= L""*/, const std::wstring& className /*= L""*/,
DWORD exStyle, DWORD style, HWND parentWindow)
{
return HwndCreator()(hInst);
return HwndCreator(title, className, exStyle, style, parentWindow)(hInst);
}
}
@@ -85,8 +91,21 @@ DWORD WINAPI ThreadProc(LPVOID lpParam)
if (RegisterDLLWindowClass(creator->getWindowClassName().c_str(), creator) != 0)
{
auto hWnd = CreateWindowEx(0, creator->getWindowClassName().c_str(), creator->getTitle().c_str(), WS_EX_APPWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 10, 10, nullptr, nullptr, creator->getHInstance(), NULL);
SetWindowPos(hWnd, HWND_TOPMOST, 10, 10, 100, 100, SWP_SHOWWINDOW);
auto hWnd = CreateWindowEx(creator->getExStyle(),
creator->getWindowClassName().c_str(),
creator->getTitle().c_str(),
creator->getStyle(),
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
creator->getParentWindow(),
nullptr,
creator->getHInstance(),
NULL);
ShowWindow(hWnd, SW_SHOW);
// wait after ShowWindow to make sure that it's finished and shown
std::this_thread::sleep_for(std::chrono::milliseconds(100));
creator->setHwnd(hWnd);
creator->setCondition(true);
@@ -95,8 +114,6 @@ DWORD WINAPI ThreadProc(LPVOID lpParam)
TranslateMessage(&messages);
DispatchMessage(&messages);
}
creator->setHwnd(hWnd);
}
else
{
@@ -108,8 +125,16 @@ DWORD WINAPI ThreadProc(LPVOID lpParam)
namespace Mocks
{
HwndCreator::HwndCreator(const std::wstring& title) :
m_windowTitle(title), m_windowClassName(std::to_wstring(++s_classId)), m_conditionFlag(false), m_thread(nullptr), m_hInst(HINSTANCE{}), m_hWnd(nullptr)
HwndCreator::HwndCreator(const std::wstring& title, const std::wstring& className, DWORD exStyle, DWORD style, HWND parentWindow) :
m_windowTitle(title),
m_windowClassName(className.empty() ? std::to_wstring(++s_classId) : className),
m_exStyle(exStyle),
m_style(style),
m_parentWindow(parentWindow),
m_conditionFlag(false),
m_thread(nullptr),
m_hInst(HINSTANCE{}),
m_hWnd(nullptr)
{
}

View File

@@ -123,7 +123,8 @@ namespace Mocks
return reinterpret_cast<HINSTANCE>(++s_nextInstance);
}
HWND WindowCreate(HINSTANCE hInst);
HWND WindowCreate(HINSTANCE hInst, const std::wstring& title = L"", const std::wstring& className = L""
, DWORD exStyle = 0, DWORD style = 0, HWND parentWindow = nullptr);
}
namespace Helpers

View File

@@ -0,0 +1,202 @@
#include "pch.h"
#include <FancyZonesLib/FancyZonesWindowProcessing.h>
#include <FancyZonesLib/Settings.h>
#include <FancyZonesLib/WindowUtils.h>
#include "Util.h"
#include <CppUnitTestLogger.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Microsoft
{
namespace VisualStudio
{
namespace CppUnitTestFramework
{
template<>
std::wstring ToString<FancyZonesWindowProcessing::ProcessabilityType>(const FancyZonesWindowProcessing::ProcessabilityType& type)
{
return std::to_wstring((int)type);
}
}
}
}
namespace FancyZonesUnitTests
{
TEST_CLASS (WindowProcessingUnitTests)
{
HINSTANCE hInst{};
TEST_METHOD_CLEANUP(CleanUp)
{
FancyZonesSettings::instance().SetSettings(Settings{});
}
TEST_METHOD (MinimizedWindow)
{
HWND window = Mocks::WindowCreate(hInst);
ShowWindow(window, SW_MINIMIZE);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // let ShowWindow finish
Assert::IsTrue(IsIconic(window));
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Minimized, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (ToolWindow)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", WS_EX_TOOLWINDOW);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::ToolWindow, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (InvisibleWindow)
{
HWND window = Mocks::WindowCreate(hInst);
ShowWindow(window, SW_HIDE);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // let ShowWindow finish
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::NotVisible, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD(NonRootWindow)
{
HWND rootWindow = Mocks::WindowCreate(hInst, L"RootWindow", L"", 0, WS_TILEDWINDOW | WS_CLIPCHILDREN);
Assert::IsTrue(FancyZonesWindowUtils::IsRoot(rootWindow));
HWND window = CreateWindow(WC_COMBOBOX, TEXT(""), CBS_DROPDOWN | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 0, 0, 10, 10, rootWindow, NULL, hInst, NULL);
Assert::IsFalse(FancyZonesWindowUtils::IsRoot(window));
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::NonRootWindow, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (Popup_App)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, WS_TILEDWINDOW | WS_POPUP);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Processable, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsTrue(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (Popup_Menu)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, WS_POPUP | WS_TILED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::NonProcessablePopupWindow, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (Popup_MenuEdge)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, WS_POPUP | WS_TILED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_THICKFRAME | WS_SIZEBOX);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::NonProcessablePopupWindow, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (Popup_Calculator)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, WS_BORDER | WS_CLIPSIBLINGS | WS_DLGFRAME | WS_GROUP | WS_POPUP | WS_POPUPWINDOW | WS_SIZEBOX | WS_TABSTOP | WS_TILEDWINDOW);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Processable, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsTrue(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (Popup_CalculatorTopmost)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, WS_BORDER | WS_CAPTION | WS_CLIPSIBLINGS | WS_DLGFRAME | WS_OVERLAPPED | WS_POPUP | WS_POPUPWINDOW | WS_SIZEBOX | WS_SYSMENU | WS_THICKFRAME);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Processable, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsTrue(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD(Popup_FacebookMessenger)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, WS_GROUP | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_POPUP | WS_TABSTOP | WS_THICKFRAME);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Processable, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsTrue(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (ChildWindow_OptionDisabled)
{
FancyZonesSettings::instance().SetSettings(Settings{ .allowSnapChildWindows = false });
HWND parentWindow = Mocks::WindowCreate(hInst, L"", L"", 0, WS_TILEDWINDOW);
if (!IsWindowVisible(parentWindow))
{
// skip the test if the parent window isn't visible.
// test can run locally, but will fail in CI because of the configuration
return;
}
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, 0, parentWindow);
Assert::IsTrue(IsWindowVisible(window), L"Child window not visible");
Assert::IsTrue(FancyZonesWindowUtils::HasVisibleOwner(window), L"Child window doesn't have visible owner");
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::ChildWindow, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (ChildWindow_OptionEnabled)
{
FancyZonesSettings::instance().SetSettings(Settings{ .allowSnapChildWindows = true });
HWND parentWindow = Mocks::WindowCreate(hInst, L"", L"", 0, WS_TILEDWINDOW);
if (!IsWindowVisible(parentWindow))
{
// skip the test if the parent window isn't visible.
// test can run locally, but will fail in CI because of the configuration
return;
}
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, 0, parentWindow);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Processable, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsTrue(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (ExcludedApp_ByDefault)
{
// set class from the excluded list
HWND window = Mocks::WindowCreate(hInst, L"", L"SysListView32");
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Excluded, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (ExcludedApp_ByDefault_SplashScreen)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"MsoSplash");
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Excluded, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (ExcludedApp_ByUser)
{
// case sensitive, should be uppercase
FancyZonesSettings::instance().SetSettings(Settings{ .excludedAppsArray = { L"TEST_EXCLUDED" } });
// exclude by window title
HWND window = Mocks::WindowCreate(hInst, L"Test_Excluded");
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Excluded, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsFalse(FancyZonesWindowProcessing::IsProcessable(window));
}
TEST_METHOD (ProcessableWindow)
{
HWND window = Mocks::WindowCreate(hInst, L"", L"", 0, WS_TILEDWINDOW);
Assert::AreEqual(FancyZonesWindowProcessing::ProcessabilityType::Processable, FancyZonesWindowProcessing::DefineWindowType(window));
Assert::IsTrue(FancyZonesWindowProcessing::IsProcessable(window));
}
};
}

View File

@@ -249,7 +249,7 @@ namespace FancyZonesUnitTests
AppliedLayouts::instance().ApplyLayout(m_workAreaId, layout);
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
const auto window = Mocks::WindowCreate(m_hInst);
const auto window = Mocks::WindowCreate(m_hInst, L"", L"", 0, WS_THICKFRAME);
SetWindowPos(window, nullptr, 150, 150, 450, 550, SWP_SHOWWINDOW);

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -74,8 +74,8 @@
TabIndex="2" />
<Button
HorizontalAlignment="Stretch"
Click="OnSaveApplyTemplate"
Content="{x:Static props:Resources.Save_Apply}"
Click="OnSave"
Content="{x:Static props:Resources.Save}"
Style="{StaticResource AccentButtonStyle}"
TabIndex="1" />
</Grid>

View File

@@ -237,7 +237,7 @@ namespace FancyZonesEditor
private SnappyHelperBase snappyX;
private SnappyHelperBase snappyY;
private SnappyHelperBase NewMagneticSnapper(bool isX, ResizeMode mode)
private SnappyHelperMagnetic NewMagneticSnapper(bool isX, ResizeMode mode)
{
Rect workingArea = App.Overlay.WorkArea;
int screenAxisOrigin = (int)(isX ? workingArea.Left : workingArea.Top);
@@ -245,7 +245,7 @@ namespace FancyZonesEditor
return new SnappyHelperMagnetic(Model.Zones, ZoneIndex, isX, mode, screenAxisOrigin, screenAxisSize);
}
private SnappyHelperBase NewNonMagneticSnapper(bool isX, ResizeMode mode)
private SnappyHelperNonMagnetic NewNonMagneticSnapper(bool isX, ResizeMode mode)
{
Rect workingArea = App.Overlay.WorkArea;
int screenAxisOrigin = (int)(isX ? workingArea.Left : workingArea.Top);

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Text;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
@@ -10,6 +11,8 @@ namespace FancyZonesEditor.Controls
{
internal sealed class CustomSliderAutomationPeer : SliderAutomationPeer
{
private static readonly CompositeFormat CustomSliderAnnounce = System.Text.CompositeFormat.Parse(Properties.Resources.Custom_slider_announce);
private string name = string.Empty;
public CustomSliderAutomationPeer(Slider owner)
@@ -29,7 +32,7 @@ namespace FancyZonesEditor.Controls
string announce = string.Format(
CultureInfo.CurrentCulture,
Properties.Resources.Custom_slider_announce,
CustomSliderAnnounce,
name,
element.Minimum,
element.Maximum,

View File

@@ -18,7 +18,7 @@ namespace FancyZonesEditor
EditingLayout = editingLayout;
}
protected void OnSaveApplyTemplate(object sender, RoutedEventArgs e)
protected void OnSave(object sender, RoutedEventArgs e)
{
Logger.LogTrace();
@@ -31,15 +31,8 @@ namespace FancyZonesEditor
EditingLayout.Persist();
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
settings.SetAppliedModel(EditingLayout);
App.Overlay.Monitors[App.Overlay.CurrentDesktop].SetLayoutSettings(EditingLayout);
App.FancyZonesEditorIO.SerializeLayoutTemplates();
App.FancyZonesEditorIO.SerializeCustomLayouts();
App.FancyZonesEditorIO.SerializeAppliedLayouts();
App.FancyZonesEditorIO.SerializeDefaultLayouts();
App.FancyZonesEditorIO.SerializeLayoutHotkeys();
Close();
}

Some files were not shown because too many files have changed in this diff Show More