From 954f37b9d1f977a15c17a2ed3fe0e7f9d8571d8b Mon Sep 17 00:00:00 2001 From: Kristen Schau <47155823+krschau@users.noreply.github.com> Date: Mon, 20 May 2024 17:21:34 -0400 Subject: [PATCH 1/3] get unsafe widget --- .../ComSafeWidgetObjects/ComSafeWidget.cs | 5 ++++ .../ViewModels/WidgetViewModel.cs | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs b/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs index 993b11cc8b..a8e5719da7 100644 --- a/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs +++ b/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs @@ -359,4 +359,9 @@ public static async Task GetIdFromUnsafeWidgetAsync(Widget widget) return string.Empty; }); } + + public Widget GetUnsafeWidgetObject() + { + return _oopWidget; + } } diff --git a/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs b/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs index 98e61d94d8..63e0aa3371 100644 --- a/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs +++ b/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Runtime.InteropServices; using System.Threading.Tasks; using AdaptiveCards.ObjectModel.WinUI3; using AdaptiveCards.Rendering.WinUI3; @@ -21,6 +22,7 @@ using Microsoft.Windows.Widgets.Hosts; using Serilog; using Windows.Data.Json; +using WinRT; namespace DevHome.Dashboard.ViewModels; @@ -317,6 +319,16 @@ private async void HandleAdaptiveAction(RenderedAdaptiveCard sender, AdaptiveAct } _log.Information($"Verb = {executeAction.Verb}, Data = {dataToSend}"); + + try + { + CoAllowSetForegroundWindow(Widget.GetUnsafeWidgetObject()); + } + catch (Exception ex) + { + _log.Warning(ex, "Failed to call CoAllowSetForegroundWindow"); + } + await Widget.NotifyActionInvokedAsync(executeAction.Verb, dataToSend); } @@ -339,4 +351,15 @@ public void UnsubscribeFromWidgetUpdates() { Widget.WidgetUpdated -= HandleWidgetUpdated; } + + // CoAllowSetForegroundWindow must be called on a raw COM interface, not a .NET CCW, in order to work correctly, since + // the underlying functionality is implemented by COM runtime and the object itself. CoAllowSetForegroundWindow wrapper + // below takes a WinRT object and extracts the raw COM interface pointer from it before calling native CoAllowSetForegroundWindow. + [DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)] + private static extern void CoAllowSetForegroundWindow(IntPtr pUnk, IntPtr lpvReserved); + + private void CoAllowSetForegroundWindow(Widget widget) + { + CoAllowSetForegroundWindow(((IWinRTObject)widget).NativeObject.ThisPtr, 0); + } } From dd2679d7e22df776eda40a595c6e231a3fcde544 Mon Sep 17 00:00:00 2001 From: Kristen Schau <47155823+krschau@users.noreply.github.com> Date: Mon, 20 May 2024 17:25:32 -0400 Subject: [PATCH 2/3] Move foreground call to inside NotifyActionInvokedAsync --- .../ComSafeWidgetObjects/ComSafeWidget.cs | 22 ++++++++++++++++++ .../ViewModels/WidgetViewModel.cs | 23 ------------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs b/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs index a8e5719da7..596bca2c66 100644 --- a/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs +++ b/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs @@ -11,6 +11,7 @@ using Microsoft.Windows.Widgets.Hosts; using Serilog; using Windows.Foundation; +using WinRT; namespace DevHome.Dashboard.ComSafeWidgetObjects; @@ -186,6 +187,16 @@ public async Task NotifyActionInvokedAsync(string verb, string data) try { await LazilyLoadOopWidget(); + try + { + CoAllowSetForegroundWindow(_oopWidget); + } + catch (Exception ex) + { + // If CoAllowSetForegroundWindow fails, we should still continue with the call to NotifyActionInvokedAsync. + _log.Warning(ex, $"Call to CoAllowSetForegroundWindow failed"); + } + await Task.Run(async () => await _oopWidget.NotifyActionInvokedAsync(verb, data)); return; } @@ -364,4 +375,15 @@ public Widget GetUnsafeWidgetObject() { return _oopWidget; } + + // CoAllowSetForegroundWindow must be called on a raw COM interface, not a .NET CCW, in order to work correctly, since + // the underlying functionality is implemented by COM runtime and the object itself. CoAllowSetForegroundWindow wrapper + // below takes a WinRT object and extracts the raw COM interface pointer from it before calling native CoAllowSetForegroundWindow. + [DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)] + private static extern void CoAllowSetForegroundWindow(IntPtr pUnk, IntPtr lpvReserved); + + private void CoAllowSetForegroundWindow(Widget widget) + { + CoAllowSetForegroundWindow(((IWinRTObject)widget).NativeObject.ThisPtr, 0); + } } diff --git a/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs b/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs index 63e0aa3371..98e61d94d8 100644 --- a/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs +++ b/tools/Dashboard/DevHome.Dashboard/ViewModels/WidgetViewModel.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Runtime.InteropServices; using System.Threading.Tasks; using AdaptiveCards.ObjectModel.WinUI3; using AdaptiveCards.Rendering.WinUI3; @@ -22,7 +21,6 @@ using Microsoft.Windows.Widgets.Hosts; using Serilog; using Windows.Data.Json; -using WinRT; namespace DevHome.Dashboard.ViewModels; @@ -319,16 +317,6 @@ private async void HandleAdaptiveAction(RenderedAdaptiveCard sender, AdaptiveAct } _log.Information($"Verb = {executeAction.Verb}, Data = {dataToSend}"); - - try - { - CoAllowSetForegroundWindow(Widget.GetUnsafeWidgetObject()); - } - catch (Exception ex) - { - _log.Warning(ex, "Failed to call CoAllowSetForegroundWindow"); - } - await Widget.NotifyActionInvokedAsync(executeAction.Verb, dataToSend); } @@ -351,15 +339,4 @@ public void UnsubscribeFromWidgetUpdates() { Widget.WidgetUpdated -= HandleWidgetUpdated; } - - // CoAllowSetForegroundWindow must be called on a raw COM interface, not a .NET CCW, in order to work correctly, since - // the underlying functionality is implemented by COM runtime and the object itself. CoAllowSetForegroundWindow wrapper - // below takes a WinRT object and extracts the raw COM interface pointer from it before calling native CoAllowSetForegroundWindow. - [DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)] - private static extern void CoAllowSetForegroundWindow(IntPtr pUnk, IntPtr lpvReserved); - - private void CoAllowSetForegroundWindow(Widget widget) - { - CoAllowSetForegroundWindow(((IWinRTObject)widget).NativeObject.ThisPtr, 0); - } } From e1eb8d91319c6ac7684a815ffab505fdaaebc388 Mon Sep 17 00:00:00 2001 From: Kristen Schau <47155823+krschau@users.noreply.github.com> Date: Thu, 30 May 2024 17:42:26 -0400 Subject: [PATCH 3/3] log any error --- .../ComSafeWidgetObjects/ComSafeWidget.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs b/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs index 596bca2c66..76343a910e 100644 --- a/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs +++ b/tools/Dashboard/DevHome.Dashboard/ComSafeWidgetObjects/ComSafeWidget.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Globalization; using System.Runtime.InteropServices; using System.Threading.Tasks; using DevHome.Common.Extensions; @@ -11,7 +12,6 @@ using Microsoft.Windows.Widgets.Hosts; using Serilog; using Windows.Foundation; -using WinRT; namespace DevHome.Dashboard.ComSafeWidgetObjects; @@ -190,6 +190,7 @@ public async Task NotifyActionInvokedAsync(string verb, string data) try { CoAllowSetForegroundWindow(_oopWidget); + Log.Information("CoAllowSetForegroundWindow result: {GetLastError}", Marshal.GetLastWin32Error().ToString(CultureInfo.CurrentCulture)); } catch (Exception ex) { @@ -379,11 +380,11 @@ public Widget GetUnsafeWidgetObject() // CoAllowSetForegroundWindow must be called on a raw COM interface, not a .NET CCW, in order to work correctly, since // the underlying functionality is implemented by COM runtime and the object itself. CoAllowSetForegroundWindow wrapper // below takes a WinRT object and extracts the raw COM interface pointer from it before calling native CoAllowSetForegroundWindow. - [DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)] + [DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false, SetLastError = true)] private static extern void CoAllowSetForegroundWindow(IntPtr pUnk, IntPtr lpvReserved); private void CoAllowSetForegroundWindow(Widget widget) { - CoAllowSetForegroundWindow(((IWinRTObject)widget).NativeObject.ThisPtr, 0); + CoAllowSetForegroundWindow(Marshal.GetIUnknownForObject(widget), IntPtr.Zero); } }