[Registry Preview] Moving to a different API to call the File Picker (#25260)

* Moving from FileOpenPicker

Moving from FileOpenPicker to a Win32/PInvoke version, so it can be opened while running as Admin.

* Update Resources.resw

Replacing a lost string.

* Save file picker also crashed

Switched to Win32-based SafeFilePicker
Cleaned up some of the code which should now pass spell checking and removed pragmas
This commit is contained in:
Randy
2023-04-11 14:29:40 -07:00
committed by GitHub
parent d0a1e40b5d
commit 1dc013f412
6 changed files with 145 additions and 29 deletions

View File

@@ -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;
}
}

View File

@@ -134,18 +134,18 @@ namespace RegistryPreview
} }
} }
// Pull in a new REG file // Pull in a new REG file - we have to use the direct Win32 method because FileOpenPicker crashes when it's
FileOpenPicker fileOpenPicker = new FileOpenPicker(); // called while running as admin
fileOpenPicker.ViewMode = PickerViewMode.List; string filename = OpenFilePicker.ShowDialog(
fileOpenPicker.CommitButtonText = resourceLoader.GetString("OpenButtonText"); resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0',
fileOpenPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; resourceLoader.GetString("OpenDialogTitle"));
fileOpenPicker.FileTypeFilter.Add(".reg");
// Get the HWND so we an open the modal if (filename == string.Empty || File.Exists(filename) == false)
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); {
InitializeWithWindow.Initialize(fileOpenPicker, hWnd); return;
}
StorageFile storageFile = await fileOpenPicker.PickSingleFileAsync(); StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filename);
if (storageFile != null) if (storageFile != null)
{ {
@@ -174,27 +174,23 @@ namespace RegistryPreview
/// <summary> /// <summary>
/// Uses a picker to save out a copy of the current reg file /// Uses a picker to save out a copy of the current reg file
/// </summary> /// </summary>
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 // Save out a new REG file and then open it - we have to use the direct Win32 method because FileOpenPicker crashes when it's
FileSavePicker fileSavePicker = new FileSavePicker(); // called while running as admin
fileSavePicker.CommitButtonText = resourceLoader.GetString("SaveButtonText"); string filename = SaveFilePicker.ShowDialog(
fileSavePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; resourceLoader.GetString("SuggestFileName"),
fileSavePicker.FileTypeChoices.Add("Registry file", new List<string>() { ".reg" }); resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0',
fileSavePicker.SuggestedFileName = resourceLoader.GetString("SuggestFileName"); resourceLoader.GetString("SaveDialogTitle"));
// Get the HWND so we an save the modal if (filename == string.Empty)
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
InitializeWithWindow.Initialize(fileSavePicker, hWnd);
StorageFile storageFile = await fileSavePicker.PickSaveFileAsync();
if (storageFile != null)
{ {
App.AppFilename = storageFile.Path; return;
SaveFile();
UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename));
} }
App.AppFilename = filename;
SaveFile();
UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename));
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,36 @@
// 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 OpenFilePicker
{
[DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool GetOpenFileName(ref FileName openFileName);
public static string ShowDialog(string filter, string dialogTitle)
{
FileName openFileName = default(FileName);
openFileName.StructSize = Marshal.SizeOf(openFileName);
openFileName.Filter = filter;
openFileName.File = new string(new char[256]);
openFileName.MaxFile = openFileName.File.Length;
openFileName.FileTitle = new string(new char[64]);
openFileName.MaxFileTitle = openFileName.FileTitle.Length;
openFileName.Title = dialogTitle;
if (GetOpenFileName(ref openFileName))
{
return openFileName.File;
}
return string.Empty;
}
}
}

View File

@@ -24,6 +24,7 @@
<AssemblyDescription>PowerToys RegistryPreview</AssemblyDescription> <AssemblyDescription>PowerToys RegistryPreview</AssemblyDescription>
<RootNamespace>RegistryPreview</RootNamespace> <RootNamespace>RegistryPreview</RootNamespace>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference> <DisableWinExeOutputInference>true</DisableWinExeOutputInference>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<!-- SelfContained=true requires RuntimeIdentifier to be set --> <!-- SelfContained=true requires RuntimeIdentifier to be set -->

View File

@@ -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;
}
}
}

View File

@@ -132,6 +132,12 @@
<data name="FileSaveError" xml:space="preserve"> <data name="FileSaveError" xml:space="preserve">
<value>The REG file cannot be written to.</value> <value>The REG file cannot be written to.</value>
</data> </data>
<data name="FilterAllFiles" xml:space="preserve">
<value>All files (*.*)</value>
</data>
<data name="FilterRegistryName" xml:space="preserve">
<value>Registry files (*.reg)</value>
</data>
<data name="InvalidRegistryFile" xml:space="preserve"> <data name="InvalidRegistryFile" xml:space="preserve">
<value> doesn't appear to be a valid registry file!</value> <value> doesn't appear to be a valid registry file!</value>
</data> </data>
@@ -153,8 +159,8 @@
<data name="OpenButton.Label" xml:space="preserve"> <data name="OpenButton.Label" xml:space="preserve">
<value>Open file...</value> <value>Open file...</value>
</data> </data>
<data name="OpenButtonText" xml:space="preserve"> <data name="OpenDialogTitle" xml:space="preserve">
<value>Open</value> <value>Open Registry file...</value>
</data> </data>
<data name="RefreshButton.Label" xml:space="preserve"> <data name="RefreshButton.Label" xml:space="preserve">
<value>Reload from file</value> <value>Reload from file</value>