Compare commits

..

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
8e25ecf77e Fix CmdPal failing to show from Quick Access when running in background
When CmdPal is in the background, SetForegroundWindow fails without the
foreground lock. Replace it with StealForeground() which uses
AttachThreadInput to reliably bring the window to the front.

Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/3f47281c-b02a-4622-8b0f-60c7108d8961

Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
2026-04-29 09:41:21 +00:00
copilot-swe-agent[bot]
8dcc3f134b Initial plan 2026-04-29 08:50:02 +00:00
3 changed files with 15 additions and 47 deletions

View File

@@ -655,7 +655,15 @@ public sealed partial class MainWindow : WindowEx,
// Once we're done, uncloak to avoid all animations
Uncloak();
PInvoke.SetForegroundWindow(hwnd);
// Use StealForeground to reliably bring the window to the foreground.
// A plain SetForegroundWindow call can fail when the process does not
// hold the foreground lock (e.g. when summoned via Quick Access or a
// named-event trigger while another app is in the foreground).
// StealForeground uses AttachThreadInput to temporarily borrow the
// foreground thread's input context, which gives us permission to call
// SetForegroundWindow regardless of which process currently owns the
// foreground.
StealForeground();
PInvoke.SetActiveWindow(hwnd);
// Push our window to the top of the Z-order and make it the topmost, so that it appears above all other windows.

View File

@@ -1,34 +0,0 @@
// 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.Diagnostics;
using System.IO;
using System.Reflection;
using Microsoft.PowerToys.Settings.UI.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ViewModelTests
{
[TestClass]
public class NewPlus
{
[TestMethod]
public void CreateExplorerProcessStartInfoShouldQuoteTemplatePathAndUseFullExplorerPath()
{
// Arrange
const string templatePath = @"C:\Users\Test User\Documents\My Templates";
var createExplorerProcessStartInfoMethod = typeof(NewPlusViewModel).GetMethod("CreateExplorerProcessStartInfo", BindingFlags.NonPublic | BindingFlags.Static);
// Act
var processStartInfo = (ProcessStartInfo)createExplorerProcessStartInfoMethod.Invoke(null, new object[] { templatePath });
// Assert
Assert.IsNotNull(processStartInfo);
Assert.AreEqual(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe"), processStartInfo.FileName);
Assert.AreEqual($"\"{templatePath}\"", processStartInfo.Arguments);
}
}
}

View File

@@ -330,8 +330,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
private static readonly string ExplorerExePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe");
private bool _isNewPlusEnabled;
private string _templateLocation;
private bool _hideFileExtension;
@@ -358,7 +356,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
CopyTemplateExamples(_templateLocation);
Process.Start(CreateExplorerProcessStartInfo(_templateLocation));
var process = new ProcessStartInfo()
{
FileName = _templateLocation,
UseShellExecute = true,
};
Process.Start(process);
}
catch (Exception ex)
{
@@ -366,15 +369,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
private static ProcessStartInfo CreateExplorerProcessStartInfo(string templateLocation)
{
return new ProcessStartInfo
{
FileName = ExplorerExePath,
Arguments = $"\"{templateLocation}\"",
};
}
private async void PickNewTemplateFolder()
{
var newPath = await PickFolderDialog();