mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
Pass FG rights to extensions when we access them (#38068)
Calling Win32 APIs from C# is usually easy! but mixing C#+WinRT+COM is dark and full of terrors Closes https://github.com/zadjii-msft/PowerToys/issues/546 Co-authored-by: Manodasan Wignarajah <mawign@microsoft.com>
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
// 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;
|
||||
using System.Runtime.Versioning;
|
||||
using CommunityToolkit.Common;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
@@ -13,7 +15,7 @@ using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Windows.Win32;
|
||||
using WinRT;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
@@ -148,14 +150,16 @@ public partial class ShellViewModel(IServiceProvider _serviceProvider, TaskSched
|
||||
// need to handle that
|
||||
_activeExtension = extension;
|
||||
|
||||
var extensionComObject = _activeExtension?.GetExtensionObject();
|
||||
if (extensionComObject != null)
|
||||
var extensionWinRtObject = _activeExtension?.GetExtensionObject();
|
||||
if (extensionWinRtObject != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var hr = PInvoke.CoAllowSetForegroundWindow(extensionComObject);
|
||||
var winrtObj = (IWinRTObject)extensionWinRtObject;
|
||||
var intPtr = winrtObj.NativeObject.ThisPtr;
|
||||
var hr = Native.CoAllowSetForegroundWindow(intPtr);
|
||||
if (hr != 0)
|
||||
{
|
||||
Logger.LogWarning($"Error giving foreground rights: 0x{hr.Value:X8}");
|
||||
@@ -174,4 +178,18 @@ public partial class ShellViewModel(IServiceProvider _serviceProvider, TaskSched
|
||||
{
|
||||
SetActiveExtension(null);
|
||||
}
|
||||
|
||||
// You may ask yourself, why aren't we using CsWin32 for this?
|
||||
// The CsWin32 projected version includes some object marshalling, like so:
|
||||
//
|
||||
// HRESULT CoAllowSetForegroundWindow([MarshalAs(UnmanagedType.IUnknown)] object pUnk,...)
|
||||
//
|
||||
// And if you do it like that, then the IForegroundTransfer interface isn't marshalled correctly
|
||||
internal sealed class Native
|
||||
{
|
||||
[DllImport("OLE32.dll", ExactSpelling = true)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
internal static extern unsafe global::Windows.Win32.Foundation.HRESULT CoAllowSetForegroundWindow(nint pUnk, [Optional] void* lpvReserved);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,14 +130,36 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
// Or the command may be a stub. Future us problem.
|
||||
try
|
||||
{
|
||||
// In the case that we're coming from a top-level command, the
|
||||
// current page's host is the global instance. We only really want
|
||||
// to use that as the host of last resort.
|
||||
var pageHost = ViewModel.CurrentPage?.ExtensionHost;
|
||||
if (pageHost == CommandPaletteHost.Instance)
|
||||
{
|
||||
pageHost = null;
|
||||
}
|
||||
|
||||
var messageHost = message.ExtensionHost;
|
||||
|
||||
// Use the host from the current page if it has one, else use the
|
||||
// one specified in the PerformMessage for a top-level command,
|
||||
// else just use the global one.
|
||||
var host = pageHost ?? messageHost ?? CommandPaletteHost.Instance;
|
||||
CommandPaletteHost host;
|
||||
|
||||
// Top level items can come through without a Extension set on the
|
||||
// message. In that case, the `Context` is actually the
|
||||
// TopLevelViewModel itself, and we can use that to get at the
|
||||
// extension object.
|
||||
extension = pageHost?.Extension ?? messageHost?.Extension ?? null;
|
||||
if (extension == null && message.Context is TopLevelViewModel topLevelViewModel)
|
||||
{
|
||||
extension = topLevelViewModel.ExtensionHost?.Extension;
|
||||
host = pageHost ?? messageHost ?? topLevelViewModel?.ExtensionHost ?? CommandPaletteHost.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
host = pageHost ?? messageHost ?? CommandPaletteHost.Instance;
|
||||
}
|
||||
|
||||
if (extension != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user