diff --git a/src/WinRT.Runtime/ExceptionHelpers.cs b/src/WinRT.Runtime/ExceptionHelpers.cs index 6f0f23752..4727c8a7f 100644 --- a/src/WinRT.Runtime/ExceptionHelpers.cs +++ b/src/WinRT.Runtime/ExceptionHelpers.cs @@ -98,6 +98,47 @@ private static bool Initialize() return true; } + /// + /// Unhandled WinRT server exception event. + /// + public static event EventHandler UnhandledWinRTServerException; + + public class UnhandledWinRTServerExceptionEventArgs : EventArgs + { + public Exception Exception { get; } + public bool Handled { get; set; } + + public UnhandledWinRTServerExceptionEventArgs(Exception exception) + { + Exception = exception; + } + } + + public static int HandleWinRTServerException(object sender, Exception ex, bool dispatchExceptionToUnmanagedCode) + { + EventHandler handler = UnhandledWinRTServerException; + + if (handler != null) + { + UnhandledWinRTServerExceptionEventArgs args = new(ex); + handler.Invoke(sender, args); + if (args.Handled) + { + return 0; + } + } + + if (dispatchExceptionToUnmanagedCode) + { + SetErrorInfo(ex); + return GetHRForException(ex); + } + else + { + return ex.HResult; + } + } + public static void ThrowExceptionForHR(int hr) { if (hr < 0) diff --git a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt new file mode 100644 index 000000000..0493e23d1 --- /dev/null +++ b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt @@ -0,0 +1,5 @@ +MembersMustExist : Member 'public void WinRT.ExceptionHelpers.add_UnhandledWinRTServerException(System.EventHandler)' does not exist in the reference but it does exist in the implementation. +MembersMustExist : Member 'public void WinRT.ExceptionHelpers.remove_UnhandledWinRTServerException(System.EventHandler)' does not exist in the reference but it does exist in the implementation. +TypesMustExist : Type 'WinRT.ExceptionHelpers.UnhandledWinRTServerExceptionEventArgs' does not exist in the reference but it does exist in the implementation. +MembersMustExist : Member 'public System.Int32 WinRT.ExceptionHelpers.HandleWinRTServerException(System.Object, System.Exception, System.Boolean)' does not exist in the reference but it does exist in the implementation. +Total Issues: 4 diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 9ae6c4844..dc280a9bc 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -5242,7 +5242,7 @@ return eventSource.EventActions; return std::pair{ marshalers, managed_marshaler{} }; } - void write_managed_method_call(writer& w, method_signature signature, std::string invoke_expression_format) + void write_managed_method_call(writer& w, method_signature signature, std::string type_name, std::string invoke_expression_format) { auto generic_abi_types = get_generic_abi_types(w, signature); bool have_generic_params = std::find_if(generic_abi_types.begin(), generic_abi_types.end(), @@ -5255,6 +5255,7 @@ return eventSource.EventActions; w.write( R"(% % +% try { % @@ -5262,10 +5263,12 @@ try } catch (Exception __exception__) { -global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); -return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); +return global::WinRT.ExceptionHelpers.HandleWinRTServerException(__this__, __exception__, true); } return 0;)", + [&](writer& w) { + w.write(R"(% __this__ = default;)", type_name); + }, [&](writer& w) { if (!return_sig) return; return_marshaler.write_local(w); @@ -5340,7 +5343,8 @@ private static unsafe int Do_Abi_%% bind(method), bind( signature, - w.write_temp("global::WinRT.ComWrappersSupport.FindObject<%>(%).%%", + type_name, + w.write_temp("(__this__ = global::WinRT.ComWrappersSupport.FindObject<%>(%)).%%", type_name, have_generic_params ? "new IntPtr(thisPtr)" : "thisPtr", method.Name(), @@ -5376,7 +5380,8 @@ private static unsafe int Do_Abi_%% bind(setter), bind( setter_sig, - w.write_temp("global::WinRT.ComWrappersSupport.FindObject<%>(%).% = %", + type_name, + w.write_temp("(__this__ = global::WinRT.ComWrappersSupport.FindObject<%>(%)).% = %", type_name, have_generic_params ? "new IntPtr(thisPtr)" : "thisPtr", prop.Name(), @@ -5406,7 +5411,8 @@ private static unsafe int Do_Abi_%% bind(getter), bind( getter_sig, - w.write_temp("global::WinRT.ComWrappersSupport.FindObject<%>(%).%%", + type_name, + w.write_temp("(__this__ = global::WinRT.ComWrappersSupport.FindObject<%>(%)).%%", type_name, have_generic_params ? "new IntPtr(thisPtr)" : "thisPtr", prop.Name(), @@ -5455,10 +5461,11 @@ private static global::System.Runtime.CompilerServices.ConditionalWeakTable<%, g % private static unsafe int Do_Abi_%% { +% __this = default; %% = default; try { -var __this = global::WinRT.ComWrappersSupport.FindObject<%>(thisPtr); +__this = global::WinRT.ComWrappersSupport.FindObject<%>(thisPtr); var __handler = %.FromAbi(%); %% = _%_TokenTables.GetOrCreateValue(__this).AddEventHandler(__handler); __this.% += __handler; @@ -5466,12 +5473,13 @@ return 0; } catch (Exception __ex) { -return __ex.HResult; +return global::WinRT.ExceptionHelpers.TryHandleWinRTServerException(__this, __ex, false); } })", !settings.netstandard_compat && !generic_type ? "[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]" : "", get_vmethod_name(w, add_method.Parent(), add_method), bind(add_method), + type_name, settings.netstandard_compat ? "" : "*", add_handler_event_token_name, type_name, @@ -5486,9 +5494,10 @@ return __ex.HResult; % private static unsafe int Do_Abi_%% { +% __this = default; try { -var __this = global::WinRT.ComWrappersSupport.FindObject<%>(thisPtr); +__this = global::WinRT.ComWrappersSupport.FindObject<%>(thisPtr); if(__this != null && _%_TokenTables.TryGetValue(__this, out var __table) && __table.RemoveEventHandler(%, out var __handler)) { __this.% -= __handler; @@ -5497,13 +5506,14 @@ return 0; } catch (Exception __ex) { -return __ex.HResult; +return global::WinRT.ExceptionHelpers.TryHandleWinRTServerException(__this, __ex, false); } })", !settings.netstandard_compat && !generic_type ? "[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]" : "", get_vmethod_name(w, remove_method.Parent(), remove_method), bind(remove_method), type_name, + type_name, evt.Name(), remove_handler_event_token_name, evt.Name()); @@ -7082,7 +7092,7 @@ public static Guid PIID = GuidGenerator.CreateIID(typeof(%));)", [&](writer& w) { if (settings.netstandard_compat) { - write_managed_method_call(w, signature, + write_managed_method_call(w, signature, type_name, w.write_temp(R"( global::WinRT.ComWrappersSupport.MarshalDelegateInvoke(%, (% invoke) => { @@ -7105,9 +7115,9 @@ global::WinRT.ComWrappersSupport.MarshalDelegateInvoke(%, (% invoke) => } else { - write_managed_method_call(w, signature, + write_managed_method_call(w, signature, type_name, w.write_temp(R"( -global::WinRT.ComWrappersSupport.FindObject<%>(%).Invoke(%) +(__this__ = global::WinRT.ComWrappersSupport.FindObject<%>(%)).Invoke(%) )", type_name, is_generic ? "new IntPtr(thisPtr)" : "thisPtr",