[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
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 @@ namespace RegistryPreview
/// <summary>
/// Uses a picker to save out a copy of the current reg file
/// </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
FileSavePicker fileSavePicker = new FileSavePicker();
fileSavePicker.CommitButtonText = resourceLoader.GetString("SaveButtonText");
fileSavePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
fileSavePicker.FileTypeChoices.Add("Registry file", new List<string>() { ".reg" });
fileSavePicker.SuggestedFileName = resourceLoader.GetString("SuggestFileName");
// 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"));
// 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)
if (filename == string.Empty)
{
App.AppFilename = storageFile.Path;
SaveFile();
UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename));
return;
}
App.AppFilename = filename;
SaveFile();
UpdateToolBarAndUI(OpenRegistryFile(App.AppFilename));
}
/// <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>
<RootNamespace>RegistryPreview</RootNamespace>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<!-- 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">
<value>The REG file cannot be written to.</value>
</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">
<value> doesn't appear to be a valid registry file!</value>
</data>
@@ -153,8 +159,8 @@
<data name="OpenButton.Label" xml:space="preserve">
<value>Open file...</value>
</data>
<data name="OpenButtonText" xml:space="preserve">
<value>Open</value>
<data name="OpenDialogTitle" xml:space="preserve">
<value>Open Registry file...</value>
</data>
<data name="RefreshButton.Label" xml:space="preserve">
<value>Reload from file</value>