From 051d9354ed3f0109291c84b14c23c241966faf93 Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Wed, 14 Feb 2024 10:13:47 -0800 Subject: [PATCH] Work around bug in WPF when running in .NET Core See https://github.com/dotnet/wpf/issues/4181 and https://github.com/dotnet/wpf/pull/7345 for more information. --- src/Eto.WinForms/Win32.cs | 3 +++ src/Eto.Wpf/Forms/DialogHandler.cs | 39 ++++++++++++++++++++++++++- src/Eto.Wpf/Forms/FormHandler.cs | 43 +++++++++++++++--------------- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/Eto.WinForms/Win32.cs b/src/Eto.WinForms/Win32.cs index 372af85c13..15d73fcf52 100755 --- a/src/Eto.WinForms/Win32.cs +++ b/src/Eto.WinForms/Win32.cs @@ -632,5 +632,8 @@ public struct SCROLLINFO [DllImport("User32.dll", SetLastError = true)] public static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw); + + [DllImport("kernel32.dll")] + public static extern void SetLastError(uint dwErrCode); } } diff --git a/src/Eto.Wpf/Forms/DialogHandler.cs b/src/Eto.Wpf/Forms/DialogHandler.cs index 87187adc64..73f6f84be0 100644 --- a/src/Eto.Wpf/Forms/DialogHandler.cs +++ b/src/Eto.Wpf/Forms/DialogHandler.cs @@ -1,6 +1,43 @@ +using System.Windows.Automation.Peers; using Eto.Wpf.Forms.Controls; namespace Eto.Wpf.Forms { + class EtoWindowAutomationPeer : WindowAutomationPeer + { + public EtoWindowAutomationPeer(sw.Window owner) : base(owner) + { + } + + protected override string GetNameCore() + { + try + { + // due to windows message hooks, we can already be in error state which causes exceptions here. +#if NET + Marshal.SetLastSystemError(0); +#else + Win32.SetLastError(0); +#endif + return base.GetNameCore(); + } + catch (Win32Exception) + { + // See https://github.com/dotnet/wpf/issues/4181 and https://github.com/dotnet/wpf/pull/7345 + // Until that fix is in, we fix it ourselves to avoid random crashes + return (Owner as sw.Window)?.Title ?? string.Empty; + } + } + } + + + public class EtoWindow : sw.Window + { + protected override AutomationPeer OnCreateAutomationPeer() + { + return new EtoWindowAutomationPeer(this); + } + } + public class DialogHandler : WpfWindow, Dialog.IHandler { Button defaultButton; @@ -8,7 +45,7 @@ public class DialogHandler : WpfWindow, Dia swc.DockPanel dockMain; swc.Grid gridButtons; - public DialogHandler() : this(new sw.Window()) { } + public DialogHandler() : this(new EtoWindow()) { } public DialogHandler(sw.Window window) { diff --git a/src/Eto.Wpf/Forms/FormHandler.cs b/src/Eto.Wpf/Forms/FormHandler.cs index 27458aa716..41c6169dbf 100644 --- a/src/Eto.Wpf/Forms/FormHandler.cs +++ b/src/Eto.Wpf/Forms/FormHandler.cs @@ -1,33 +1,32 @@ namespace Eto.Wpf.Forms { - public class FormHandler : WpfWindow, Form.IHandler + public class EtoFormWindow : EtoWindow { - public class EtoWindow : sw.Window + public EtoFormWindow() { + AllowDrop = true; + } - public EtoWindow() - { - AllowDrop = true; - } - - protected override void OnActivated(EventArgs e) - { - if (!Focusable) - return; - base.OnActivated(e); - } + protected override void OnActivated(EventArgs e) + { + if (!Focusable) + return; + base.OnActivated(e); + } - protected override void OnPreviewGotKeyboardFocus(swi.KeyboardFocusChangedEventArgs e) + protected override void OnPreviewGotKeyboardFocus(swi.KeyboardFocusChangedEventArgs e) + { + if (!Focusable) { - if (!Focusable) - { - e.Handled = true; - return; - } - base.OnPreviewGotKeyboardFocus(e); + e.Handled = true; + return; } + base.OnPreviewGotKeyboardFocus(e); } - + } + + public class FormHandler : WpfWindow, Form.IHandler + { public FormHandler(sw.Window window) { Control = window; @@ -35,7 +34,7 @@ public FormHandler(sw.Window window) public FormHandler() { - Control = new EtoWindow(); + Control = new EtoFormWindow(); } public virtual void Show()