From 33c1d17dc63e960b2da02eab49df651e4a515a3d Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Fri, 21 Nov 2014 07:07:05 +0200 Subject: [PATCH] Exceptions thrown by UIA server in UI thread in WPF should be caught and redirected to automating thread in order to report error correctly. Otherwise automated app just crashes as with usual uncaught exception in dispatcher. On UIA client side added UiaCallFailedException because otherwise it is TargetInvocationException without any details, which is very common. --- .../AutomationPeerAugmentationHelper.cs | 50 +++++++++++++++---- .../ManagedUiaCustomizationCore.csproj | 1 + ManagedUiaCustomizationCore/NativeMethods.cs | 8 +++ .../UiaCallFailedException.cs | 27 ++++++++++ 4 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 ManagedUiaCustomizationCore/UiaCallFailedException.cs diff --git a/ManagedUiaCustomizationCore/AutomationPeerAugmentationHelper.cs b/ManagedUiaCustomizationCore/AutomationPeerAugmentationHelper.cs index ca1aaa8..3246aea 100644 --- a/ManagedUiaCustomizationCore/AutomationPeerAugmentationHelper.cs +++ b/ManagedUiaCustomizationCore/AutomationPeerAugmentationHelper.cs @@ -159,6 +159,42 @@ public object WrapObjectReplacer(AutomationPeer peer, object iface) } } + private static void GuardUiaServerInvocation(Action invocation, Dispatcher dispatcher) + { + if (dispatcher == null) + throw new ElementNotAvailableException(); + Exception remoteException = null; + bool completed = false; + dispatcher.Invoke(DispatcherPriority.Send, TimeSpan.FromMinutes(3.0), (Action)(() => + { + try + { + invocation(); + } + catch (Exception e) + { + remoteException = e; + } + catch + { + remoteException = null; + } + finally + { + completed = true; + } + })); + if (completed) + { + if (remoteException != null) + throw remoteException; + } + else if (dispatcher.HasShutdownStarted) + throw new InvalidOperationException("AutomationDispatcherShutdown"); + else + throw new TimeoutException("AutomationTimeout"); + } + private class StandalonePropertyGetter { private readonly AutomationProperty _property; @@ -172,7 +208,9 @@ public object Getter(AutomationPeer peer) { var propertyProvider = peer as IStandalonePropertyProvider; if (propertyProvider == null) return null; - return propertyProvider.GetPropertyValue(_property); + object result = null; + GuardUiaServerInvocation(() => result = propertyProvider.GetPropertyValue(_property), peer.Dispatcher); + return result; } } @@ -187,15 +225,7 @@ public SendingToUIThreadInterceptor(AutomationPeer peer) public void Intercept(IInvocation invocation) { - if (_dispatcher.CheckAccess()) - { - invocation.Proceed(); - } - else - { - Action a = invocation.Proceed; - _dispatcher.Invoke(a); - } + GuardUiaServerInvocation(invocation.Proceed, _dispatcher); } } } diff --git a/ManagedUiaCustomizationCore/ManagedUiaCustomizationCore.csproj b/ManagedUiaCustomizationCore/ManagedUiaCustomizationCore.csproj index a343f38..57fdf6c 100644 --- a/ManagedUiaCustomizationCore/ManagedUiaCustomizationCore.csproj +++ b/ManagedUiaCustomizationCore/ManagedUiaCustomizationCore.csproj @@ -81,6 +81,7 @@ + diff --git a/ManagedUiaCustomizationCore/NativeMethods.cs b/ManagedUiaCustomizationCore/NativeMethods.cs index 77fae80..fd267c7 100644 --- a/ManagedUiaCustomizationCore/NativeMethods.cs +++ b/ManagedUiaCustomizationCore/NativeMethods.cs @@ -33,6 +33,14 @@ public static void WrapUiaComCall(Action call) throw newEx; throw; } + catch (Exception e) + { + throw new UiaCallFailedException("Automation call failure", e); + } + catch + { + throw new UiaCallFailedException("Automation call failure"); + } } #region Taken from UIAComWrapper - exception wrapping diff --git a/ManagedUiaCustomizationCore/UiaCallFailedException.cs b/ManagedUiaCustomizationCore/UiaCallFailedException.cs new file mode 100644 index 0000000..d3cb80b --- /dev/null +++ b/ManagedUiaCustomizationCore/UiaCallFailedException.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; + +namespace ManagedUiaCustomizationCore +{ + [Serializable] + public class UiaCallFailedException : Exception + { + public UiaCallFailedException() + { + } + + public UiaCallFailedException(string message) : base(message) + { + } + + public UiaCallFailedException(string message, Exception inner) : base(message, inner) + { + } + + protected UiaCallFailedException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file