diff --git a/.github/workflows/package-submissions.yml b/.github/workflows/package-submissions.yml index 5ef20fec67c..e99a5e73789 100644 --- a/.github/workflows/package-submissions.yml +++ b/.github/workflows/package-submissions.yml @@ -1,4 +1,4 @@ -name: Submit Microsoft.PowerToys package to Windows Package Manager Community Repository +name: Submit Microsoft.PowerToys package to Windows Package Manager Community Repository # based off of https://github.com/nushell/nushell/blob/main/.github/workflows/winget-submission.yml on: @@ -7,24 +7,25 @@ on: types: [published] jobs: - winget: name: Publish winget package runs-on: windows-latest steps: - name: Submit package to Windows Package Manager Community Repository run: | - + $wingetPackage = "Microsoft.PowerToys" $gitToken = "${{ secrets.PT_WINGET }}" - + $github = Invoke-RestMethod -uri "https://api.github.com/repos/Microsoft/PowerToys/releases" - + $targetRelease = $github | Where-Object -Property name -match 'Release'| Select -First 1 - $installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'PowerToysSetup.*x64' | Select -ExpandProperty browser_download_url - $installerUrlArm = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'PowerToysSetup.*arm64' | Select -ExpandProperty browser_download_url + $installerUserX64Url = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'PowerToysUserSetup.*x64' | Select -ExpandProperty browser_download_url + $installerMachineX64Url = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'PowerToysSetup.*x64' | Select -ExpandProperty browser_download_url + $installerUserArmUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'PowerToysUserSetup.*arm64' | Select -ExpandProperty browser_download_url + $installerMachineArmUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'PowerToysSetup.*arm64' | Select -ExpandProperty browser_download_url $ver = $targetRelease.tag_name.Trim("v") - + # getting latest wingetcreate file iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe - .\wingetcreate.exe update $wingetPackage -s -v $ver -u $installerUrl $installerUrlArm -t $gitToken + .\wingetcreate.exe update $wingetPackage -s -v $ver -u $installerUserX64Url $installerMachineX64Url $installerUserArmUrl $installerMachineArmUrl -t $gitToken diff --git a/README.md b/README.md index 1c9fb7fc426..0031147aba5 100644 --- a/README.md +++ b/README.md @@ -37,10 +37,10 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline Go to [Microsoft PowerToys GitHub releases page][github-release-link], click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user. - - **For x64 processors (most common) per-user installer:** [PowerToysUserSetup-0.69.0-x64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.0/PowerToysUserSetup-0.69.0-x64.exe) - - **For x64 processors per-machine installer:** [PowerToysSetup-0.69.0-x64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.0/PowerToysSetup-0.69.0-x64.exe) - - **For ARM64 processors per-user installer:** [PowerToysUserSetup-0.69.0-arm64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.0/PowerToysUserSetup-0.69.0-arm64.exe) - - **For ARM64 processors per-machine installer:** [PowerToysSetup-0.69.0-arm64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.0/PowerToysSetup-0.69.0-arm64.exe) + - **For x64 processors (most common) per-user installer:** [PowerToysUserSetup-0.69.1-x64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysUserSetup-0.69.1-x64.exe) + - **For x64 processors per-machine installer:** [PowerToysSetup-0.69.1-x64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysSetup-0.69.1-x64.exe) + - **For ARM64 processors per-user installer:** [PowerToysUserSetup-0.69.1-arm64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysUserSetup-0.69.1-arm64.exe) + - **For ARM64 processors per-machine installer:** [PowerToysSetup-0.69.1-arm64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysSetup-0.69.1-arm64.exe) This is our preferred method. diff --git a/installer/PowerToysSetup/FileLocksmith.wxs b/installer/PowerToysSetup/FileLocksmith.wxs index d0d49c3bb5a..f2417ed0f0a 100644 --- a/installer/PowerToysSetup/FileLocksmith.wxs +++ b/installer/PowerToysSetup/FileLocksmith.wxs @@ -35,6 +35,15 @@ + + + + + + + + + @@ -42,8 +51,11 @@ + + + diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 8ed3729a452..a45d0e40448 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -452,6 +452,9 @@ + + + @@ -501,6 +504,9 @@ + + + diff --git a/installer/PowerToysSetup/RegistryPreview.wxs b/installer/PowerToysSetup/RegistryPreview.wxs index 7beeb08f4fb..74804f6c6e8 100644 --- a/installer/PowerToysSetup/RegistryPreview.wxs +++ b/installer/PowerToysSetup/RegistryPreview.wxs @@ -22,6 +22,15 @@ + + + + + + + + + @@ -29,7 +38,10 @@ + + + diff --git a/installer/PowerToysSetup/generateFileList.ps1 b/installer/PowerToysSetup/generateFileList.ps1 index 5925ebedb20..7e0d8548a0a 100644 --- a/installer/PowerToysSetup/generateFileList.ps1 +++ b/installer/PowerToysSetup/generateFileList.ps1 @@ -49,7 +49,7 @@ if ($isWinAppSdkProj -eq $True) { $fileExclusionList = @("*Test*", "*.pdb", "*.lastcodeanalysissucceeded", "createdump.exe") + $interopFilesList + $winAppSDKfilesList -$fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*png", "*gif", "*ico", "*cur", "*svg", "index.html", "reg.js", "monacoSpecialLanguages.js", "resources.pri") +$fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*png", "*gif", "*ico", "*cur", "*svg", "index.html", "reg.js", "monacoSpecialLanguages.js", "resources.pri", "NLog.config") $dllsToIgnore = @("System.CodeDom.dll", "WindowsBase.dll") diff --git a/src/modules/registrypreview/RegistryPreviewUI/FileName.cs b/src/modules/registrypreview/RegistryPreviewUI/FileName.cs new file mode 100644 index 00000000000..7464fff039e --- /dev/null +++ b/src/modules/registrypreview/RegistryPreviewUI/FileName.cs @@ -0,0 +1,39 @@ +// 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; +using System.Runtime.InteropServices; + +namespace RegistryPreview +{ + // Workaround for File Pickers that don't work while running as admin, per: + // https://github.com/microsoft/WindowsAppSDK/issues/2504 + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct FileName + { + public int StructSize; + public IntPtr HwndOwner; + public IntPtr Instance; + public string Filter; + public string CustomFilter; + public int MaxCustFilter; + public int FilterIndex; + public string File; + public int MaxFile; + public string FileTitle; + public int MaxFileTitle; + public string InitialDir; + public string Title; + public int Flags; + public short FileOffset; + public short FileExtension; + public string DefExt; + public IntPtr CustData; + public IntPtr Hook; + public string TemplateName; + public IntPtr PtrReserved; + public int Reserved; + public int FlagsEx; + } +} diff --git a/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs b/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs index 949bb3b7b0c..90eb9f2c24e 100644 --- a/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs +++ b/src/modules/registrypreview/RegistryPreviewUI/MainWindow.Events.cs @@ -134,18 +134,18 @@ private async void OpenButton_Click(object sender, RoutedEventArgs e) } } - // Pull in a new REG file - FileOpenPicker fileOpenPicker = new FileOpenPicker(); - fileOpenPicker.ViewMode = PickerViewMode.List; - fileOpenPicker.CommitButtonText = resourceLoader.GetString("OpenButtonText"); - fileOpenPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; - fileOpenPicker.FileTypeFilter.Add(".reg"); + // Pull in a new REG file - we have to use the direct Win32 method because FileOpenPicker crashes when it's + // called while running as admin + string filename = OpenFilePicker.ShowDialog( + resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0', + resourceLoader.GetString("OpenDialogTitle")); - // Get the HWND so we an open the modal - IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); - InitializeWithWindow.Initialize(fileOpenPicker, hWnd); + if (filename == string.Empty || File.Exists(filename) == false) + { + return; + } - StorageFile storageFile = await fileOpenPicker.PickSingleFileAsync(); + StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filename); if (storageFile != null) { @@ -174,27 +174,23 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) /// /// Uses a picker to save out a copy of the current reg file /// - private async void SaveAsButton_Click(object sender, RoutedEventArgs e) + private void SaveAsButton_Click(object sender, RoutedEventArgs e) { - // Save out a new REG file and then open it - FileSavePicker fileSavePicker = new FileSavePicker(); - fileSavePicker.CommitButtonText = resourceLoader.GetString("SaveButtonText"); - fileSavePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; - fileSavePicker.FileTypeChoices.Add("Registry file", new List() { ".reg" }); - fileSavePicker.SuggestedFileName = resourceLoader.GetString("SuggestFileName"); - - // Get the HWND so we an save the modal - IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); - InitializeWithWindow.Initialize(fileSavePicker, hWnd); - - StorageFile storageFile = await fileSavePicker.PickSaveFileAsync(); - - if (storageFile != null) + // Save out a new REG file and then open it - we have to use the direct Win32 method because FileOpenPicker crashes when it's + // called while running as admin + string filename = SaveFilePicker.ShowDialog( + resourceLoader.GetString("SuggestFileName"), + resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0', + resourceLoader.GetString("SaveDialogTitle")); + + if (filename == string.Empty) { - App.AppFilename = storageFile.Path; - SaveFile(); - UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename)); + return; } + + App.AppFilename = filename; + SaveFile(); + UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename)); } /// diff --git a/src/modules/registrypreview/RegistryPreviewUI/MainWindow.xaml b/src/modules/registrypreview/RegistryPreviewUI/MainWindow.xaml index e8c8e4b4ae3..b3125844bbf 100644 --- a/src/modules/registrypreview/RegistryPreviewUI/MainWindow.xaml +++ b/src/modules/registrypreview/RegistryPreviewUI/MainWindow.xaml @@ -53,6 +53,7 @@ + + + @@ -75,11 +78,13 @@ x:Uid="SaveButton" HorizontalAlignment="Left" Click="SaveButton_Click" - Icon="Save" IsEnabled="False" IsTabStop="False"> + + + - + + + + - + + + + @@ -110,8 +119,10 @@ x:Uid="RefreshButton" HorizontalAlignment="Left" Click="RefreshButton_Click" - Icon="Refresh" IsTabStop="False"> + + + @@ -121,8 +132,10 @@ x:Uid="WriteButton" HorizontalAlignment="Left" Click="WriteButton_Click" - Icon="Share" IsTabStop="False"> + + + @@ -132,8 +145,10 @@ x:Uid="RegistryButton" HorizontalAlignment="Left" Click="RegistryButton_Click" - Icon="Go" IsTabStop="False"> + + + @@ -161,7 +176,9 @@ ScrollViewer.IsVerticalRailEnabled="True" ScrollViewer.VerticalScrollBarVisibility="Visible" TabIndex="0" - TextWrapping="NoWrap" /> + TextWrapping="NoWrap" + CornerRadius="{StaticResource OverlayCornerRadius}" + /> PowerToys RegistryPreview RegistryPreview true + true diff --git a/src/modules/registrypreview/RegistryPreviewUI/SaveFileName.cs b/src/modules/registrypreview/RegistryPreviewUI/SaveFileName.cs new file mode 100644 index 00000000000..0e0f2d58a79 --- /dev/null +++ b/src/modules/registrypreview/RegistryPreviewUI/SaveFileName.cs @@ -0,0 +1,38 @@ +// 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.Runtime.InteropServices; + +namespace RegistryPreview +{ + // Workaround for File Pickers that don't work while running as admin, per: + // https://github.com/microsoft/WindowsAppSDK/issues/2504 + public static partial class SaveFilePicker + { + [DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern bool GetSaveFileName(ref FileName saveFileName); + + public static string ShowDialog(string suggestedFilename, string filter, string dialogTitle) + { + FileName saveFileName = default(FileName); + saveFileName.StructSize = Marshal.SizeOf(saveFileName); + + saveFileName.Filter = filter; + saveFileName.File = new string(new char[256]); + saveFileName.MaxFile = saveFileName.File.Length; + saveFileName.File = string.Concat(suggestedFilename, saveFileName.File); + saveFileName.FileTitle = new string(new char[64]); + saveFileName.MaxFileTitle = saveFileName.FileTitle.Length; + saveFileName.Title = dialogTitle; + saveFileName.DefExt = "reg"; + + if (GetSaveFileName(ref saveFileName)) + { + return saveFileName.File; + } + + return string.Empty; + } + } +} diff --git a/src/modules/registrypreview/RegistryPreviewUI/Strings/en-US/Resources.resw b/src/modules/registrypreview/RegistryPreviewUI/Strings/en-US/Resources.resw index 6108bf8eec5..d64bc8f063c 100644 --- a/src/modules/registrypreview/RegistryPreviewUI/Strings/en-US/Resources.resw +++ b/src/modules/registrypreview/RegistryPreviewUI/Strings/en-US/Resources.resw @@ -132,6 +132,12 @@ The REG file cannot be written to. + + All files (*.*) + + + Registry files (*.reg) + doesn't appear to be a valid registry file! @@ -153,8 +159,8 @@ Open file... - - Open + + Open Registry file... Reload from file diff --git a/src/settings-ui/Settings.UI.Library/AwakeProperties.cs b/src/settings-ui/Settings.UI.Library/AwakeProperties.cs index e83161f8e64..6e9735d7b60 100644 --- a/src/settings-ui/Settings.UI.Library/AwakeProperties.cs +++ b/src/settings-ui/Settings.UI.Library/AwakeProperties.cs @@ -16,7 +16,7 @@ public AwakeProperties() Mode = AwakeMode.PASSIVE; IntervalHours = 0; IntervalMinutes = 0; - ExpirationDateTime = DateTimeOffset.MinValue; + ExpirationDateTime = DateTimeOffset.Now; CustomTrayTimes = new Dictionary(); } diff --git a/src/settings-ui/Settings.UI.Library/AwakeSettings.cs b/src/settings-ui/Settings.UI.Library/AwakeSettings.cs index e47cf82bc02..f811dbca375 100644 --- a/src/settings-ui/Settings.UI.Library/AwakeSettings.cs +++ b/src/settings-ui/Settings.UI.Library/AwakeSettings.cs @@ -37,7 +37,9 @@ public object Clone() KeepDisplayOn = Properties.KeepDisplayOn, IntervalMinutes = Properties.IntervalMinutes, IntervalHours = Properties.IntervalHours, - ExpirationDateTime = Properties.ExpirationDateTime, + + // Fix old buggy default value that might be saved in Settings. Some components don't deal well with negative time zones and minimum time offsets. + ExpirationDateTime = Properties.ExpirationDateTime.Year < 2 ? DateTimeOffset.Now : Properties.ExpirationDateTime, }, }; } diff --git a/src/settings-ui/Settings.UI/Controls/ShortcutControl/ShortcutControl.xaml.cs b/src/settings-ui/Settings.UI/Controls/ShortcutControl/ShortcutControl.xaml.cs index 38ae3adb595..c9b9035049d 100644 --- a/src/settings-ui/Settings.UI/Controls/ShortcutControl/ShortcutControl.xaml.cs +++ b/src/settings-ui/Settings.UI/Controls/ShortcutControl/ShortcutControl.xaml.cs @@ -89,7 +89,10 @@ public ShortcutControl() hook = new HotkeySettingsControlHook(Hotkey_KeyDown, Hotkey_KeyUp, Hotkey_IsActive, FilterAccessibleKeyboardEvents); ResourceLoader resourceLoader = ResourceLoader.GetForViewIndependentUse(); - App.GetSettingsWindow().Activated += ShortcutDialog_SettingsWindow_Activated; + if (App.GetSettingsWindow() != null) + { + App.GetSettingsWindow().Activated += ShortcutDialog_SettingsWindow_Activated; + } // We create the Dialog in C# because doing it in XAML is giving WinUI/XAML Island bugs when using dark theme. shortcutDialog = new ContentDialog @@ -113,10 +116,18 @@ private void ShortcutControl_Unloaded(object sender, RoutedEventArgs e) shortcutDialog.Opened -= ShortcutDialog_Opened; shortcutDialog.Closing -= ShortcutDialog_Closing; - App.GetSettingsWindow().Activated -= ShortcutDialog_SettingsWindow_Activated; + if (App.GetSettingsWindow() != null) + { + App.GetSettingsWindow().Activated -= ShortcutDialog_SettingsWindow_Activated; + } // Dispose the HotkeySettingsControlHook object to terminate the hook threads when the textbox is unloaded - hook.Dispose(); + if (hook != null) + { + hook.Dispose(); + } + + hook = null; } private void KeyEventHandler(int key, bool matchValue, int matchValueCode) @@ -371,15 +382,16 @@ private static bool ComboIsValid(HotkeySettings settings) private void ShortcutDialog_SettingsWindow_Activated(object sender, WindowActivatedEventArgs args) { args.Handled = true; - if (args.WindowActivationState != WindowActivationState.Deactivated && hook.GetDisposedState() == true) + if (args.WindowActivationState != WindowActivationState.Deactivated && (hook == null || hook.GetDisposedState() == true)) { // If the PT settings window gets focussed/activated again, we enable the keyboard hook to catch the keyboard input. hook = new HotkeySettingsControlHook(Hotkey_KeyDown, Hotkey_KeyUp, Hotkey_IsActive, FilterAccessibleKeyboardEvents); } - else if (args.WindowActivationState == WindowActivationState.Deactivated && hook.GetDisposedState() == false) + else if (args.WindowActivationState == WindowActivationState.Deactivated && hook != null && hook.GetDisposedState() == false) { // If the PT settings window lost focus/activation, we disable the keyboard hook to allow keyboard input on other windows. hook.Dispose(); + hook = null; } } @@ -394,7 +406,12 @@ private void Dispose(bool disposing) { if (disposing) { - hook.Dispose(); + if (hook != null) + { + hook.Dispose(); + } + + hook = null; } disposedValue = true; diff --git a/src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml.cs b/src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml.cs index fd35eafc395..d5cece086ba 100644 --- a/src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml.cs +++ b/src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml.cs @@ -55,8 +55,9 @@ public OobeWhatsNew() /// /// Regex to remove installer hash sections from the release notes. /// - private const string RemoveInstallerHashesRegex = @"((\r\n)+#+ installer hashes)?((\r\n)+#+( x64)?( arm64)? installer( SHA256)? hash(\r\n)+[0-9A-F]{64})+"; - private const RegexOptions RemoveInstallerHashesRegexOptions = RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant; + private const string RemoveInstallerHashesRegex = @"(\r\n)+## Installer Hashes(\r\n.*)+## Highlights"; + private const string RemoveHotFixInstallerHashesRegex = @"(\r\n)+## Installer Hashes(\r\n.*)+$"; + private const RegexOptions RemoveInstallerHashesRegexOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant; private static async Task GetReleaseNotesMarkdown() { @@ -86,10 +87,14 @@ private static async Task GetReleaseNotesMarkdown() // Regex to remove installer hash sections from the release notes. Regex removeHashRegex = new Regex(RemoveInstallerHashesRegex, RemoveInstallerHashesRegexOptions); + // Regex to remove installer hash sections from the release notes, since there'll be no Highlights section for hotfix releases. + Regex removeHotfixHashRegex = new Regex(RemoveHotFixInstallerHashesRegex, RemoveInstallerHashesRegexOptions); + foreach (var release in latestReleases) { releaseNotesHtmlBuilder.AppendLine("# " + release.Name); - var notes = removeHashRegex.Replace(release.ReleaseNotes, string.Empty); + var notes = removeHashRegex.Replace(release.ReleaseNotes, "\r\n## Highlights"); + notes = removeHotfixHashRegex.Replace(notes, string.Empty); releaseNotesHtmlBuilder.AppendLine(notes); releaseNotesHtmlBuilder.AppendLine(" "); }