Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for exception handling from unmanaged caller #1578

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/WinRT.Runtime/ExceptionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,47 @@ private static bool Initialize()
return true;
}

/// <summary>
/// Unhandled WinRT server exception event.
/// </summary>
public static event EventHandler<UnhandledWinRTServerExceptionEventArgs> 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<UnhandledWinRTServerExceptionEventArgs> 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)
Expand Down
5 changes: 5 additions & 0 deletions src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
MembersMustExist : Member 'public void WinRT.ExceptionHelpers.add_UnhandledWinRTServerException(System.EventHandler<WinRT.ExceptionHelpers.UnhandledWinRTServerExceptionEventArgs>)' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public void WinRT.ExceptionHelpers.remove_UnhandledWinRTServerException(System.EventHandler<WinRT.ExceptionHelpers.UnhandledWinRTServerExceptionEventArgs>)' 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
36 changes: 23 additions & 13 deletions src/cswinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -5255,17 +5255,20 @@ return eventSource.EventActions;
w.write(
R"(%
%
%
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);
Expand Down Expand Up @@ -5340,7 +5343,8 @@ private static unsafe int Do_Abi_%%
bind<write_abi_signature>(method),
bind<write_managed_method_call>(
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(),
Expand Down Expand Up @@ -5376,7 +5380,8 @@ private static unsafe int Do_Abi_%%
bind<write_abi_signature>(setter),
bind<write_managed_method_call>(
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(),
Expand Down Expand Up @@ -5406,7 +5411,8 @@ private static unsafe int Do_Abi_%%
bind<write_abi_signature>(getter),
bind<write_managed_method_call>(
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(),
Expand Down Expand Up @@ -5455,23 +5461,25 @@ 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;
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<write_abi_signature>(add_method),
type_name,
settings.netstandard_compat ? "" : "*",
add_handler_event_token_name,
type_name,
Expand All @@ -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;
Expand All @@ -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<write_abi_signature>(remove_method),
type_name,
type_name,
evt.Name(),
remove_handler_event_token_name,
evt.Name());
Expand Down Expand Up @@ -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) =>
{
Expand All @@ -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",
Expand Down