mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-09-01 19:51:34 +02:00
Fix Keyboard Manager editor file picker not opening when elevated (#48876)
## Summary Fixes #48845. In the new WinUI 3 Keyboard Manager editor, clicking the **browse icon** to select a program path (or "start in" folder) for the *Run Program* action did nothing — no dialog appeared. ### Root cause The editor (`PowerToys.KeyboardManagerEditorUI.exe`) is launched by the Keyboard Manager module DLL via `ShellExecuteExW` from inside the PowerToys runner (`src/modules/keyboardmanager/dll/dllmain.cpp`). When PowerToys runs elevated, the editor **inherits that elevation**. The browse buttons used the legacy **`Windows.Storage.Pickers`** (`FileOpenPicker` / `FolderPicker` + `InitializeWithWindow`). Those pickers activate through the UWP runtime broker, which fails with `E_ACCESSDENIED` in an elevated process. The handlers were `async void` with no `try/catch`, so the exception was swallowed and no dialog ever opened. Typing/pasting a path into the field still worked — matching the bug report. ### Fix Switch both handlers to the Windows App SDK **`Microsoft.Windows.Storage.Pickers`** API, constructed with a `WindowId`. Those pickers are a thin wrapper over the in-process Win32 Common Item Dialog (`IFileOpenDialog`, `CLSCTX_INPROC_SERVER`) and work correctly in elevated processes — the same mechanism already used elsewhere in PowerToys (e.g. Settings UI `IFileDialog`/`GetOpenFileName`, and CmdPal which already uses this exact namespace). Also wrapped the handlers in `try/catch` with `Logger.LogError` so any future failure is logged instead of silently swallowed. ### Verification - Built `KeyboardManagerEditorUI.csproj` (Release / x64) with all native dependencies — exit code 0. - Confirmed against the Windows App SDK source that `Microsoft.Windows.Storage.Pickers.FileOpenPicker` uses `create_instance<IFileOpenDialog>(CLSID_FileOpenDialog, CLSCTX_INPROC_SERVER)` and `dialog->Show(hwnd)`, i.e. the elevation-safe in-process dialog. ### Notes / out of scope The report also mentions some apps (e.g. `visio.exe`) not launching while others (`winword.exe`) do. That's a separate issue in the launch path (`run_non_elevated` uses `CreateProcessW`, which ignores registry App Paths / shell activation, unlike `ShellExecute` used by the *Open URI* action) and is **not** addressed here. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Copilot-Session: 1f00def4-e790-4071-96c6-a81c9c2adba5
This commit is contained in:
@@ -8,10 +8,10 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using KeyboardManagerEditorUI.Helpers;
|
||||
using KeyboardManagerEditorUI.Interop;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Pickers;
|
||||
using Microsoft.Windows.Storage.Pickers;
|
||||
using Windows.System;
|
||||
using WinRT.Interop;
|
||||
using static KeyboardManagerEditorUI.Interop.ShortcutKeyMapping;
|
||||
@@ -632,36 +632,54 @@ namespace KeyboardManagerEditorUI.Controls
|
||||
|
||||
private async void ProgramPathSelectButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var picker = new FileOpenPicker();
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(App.MainWindow);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
picker.FileTypeFilter.Add(".exe");
|
||||
|
||||
StorageFile file = await picker.PickSingleFileAsync();
|
||||
|
||||
if (file != null)
|
||||
try
|
||||
{
|
||||
ProgramPathInput.Text = file.Path;
|
||||
RaiseValidationStateChanged();
|
||||
var hwnd = WindowNative.GetWindowHandle(App.MainWindow);
|
||||
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
|
||||
|
||||
var picker = new FileOpenPicker(windowId)
|
||||
{
|
||||
SuggestedStartLocation = PickerLocationId.ComputerFolder,
|
||||
};
|
||||
|
||||
picker.FileTypeFilter.Add(".exe");
|
||||
|
||||
var file = await picker.PickSingleFileAsync();
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
ProgramPathInput.Text = file.Path;
|
||||
RaiseValidationStateChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to pick program path", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async void StartInSelectButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var picker = new FolderPicker();
|
||||
|
||||
var hwnd = WindowNative.GetWindowHandle(App.MainWindow);
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
picker.FileTypeFilter.Add("*");
|
||||
|
||||
StorageFolder folder = await picker.PickSingleFolderAsync();
|
||||
|
||||
if (folder != null)
|
||||
try
|
||||
{
|
||||
StartInPathInput.Text = folder.Path;
|
||||
var hwnd = WindowNative.GetWindowHandle(App.MainWindow);
|
||||
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
|
||||
|
||||
var picker = new FolderPicker(windowId)
|
||||
{
|
||||
SuggestedStartLocation = PickerLocationId.ComputerFolder,
|
||||
};
|
||||
|
||||
var folder = await picker.PickSingleFolderAsync();
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
StartInPathInput.Text = folder.Path;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to pick start-in folder", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user