diff --git a/src/Tests/TestComponentCSharp/Class.cpp b/src/Tests/TestComponentCSharp/Class.cpp index b5025c37c..616018bb4 100644 --- a/src/Tests/TestComponentCSharp/Class.cpp +++ b/src/Tests/TestComponentCSharp/Class.cpp @@ -1213,6 +1213,14 @@ namespace winrt::TestComponentCSharp::implementation winrt::check_hresult(_asyncResult); } + void Class::SetFailingCompletedHandler(IAsyncAction const& action) + { + action.Completed([](IAsyncAction const&, AsyncStatus) + { + throw winrt::hresult_error(E_FAIL, L"Intentional failure in completion handler"); + }); + } + IAsyncActionWithProgress Class::DoitAsyncWithProgress() { _asyncResult = E_PENDING; diff --git a/src/Tests/TestComponentCSharp/Class.h b/src/Tests/TestComponentCSharp/Class.h index 69074abaf..f6eb603c7 100644 --- a/src/Tests/TestComponentCSharp/Class.h +++ b/src/Tests/TestComponentCSharp/Class.h @@ -351,6 +351,8 @@ namespace winrt::TestComponentCSharp::implementation Windows::Foundation::IAsyncOperation AddAsync(int32_t lhs, int32_t rhs); Windows::Foundation::IAsyncOperationWithProgress AddAsyncWithProgress(int32_t lhs, int32_t rhs); + void SetFailingCompletedHandler(Windows::Foundation::IAsyncAction const& action); + Windows::Foundation::Point PointProperty(); void PointProperty(Windows::Foundation::Point const& value); Windows::Foundation::Rect RectProperty(); diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index 1cbc4ee92..45a0d2c89 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -429,6 +429,8 @@ namespace TestComponentCSharp Windows.Foundation.IAsyncOperation AddAsync(Int32 lhs, Int32 rhs); Windows.Foundation.IAsyncOperationWithProgress AddAsyncWithProgress(Int32 lhs, Int32 rhs); + void SetFailingCompletedHandler(Windows.Foundation.IAsyncAction action); + // Type mappings // "Simple" structs (blittable with changes to add properties/functions/constructors/etc.) Windows.Foundation.Point PointProperty; diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index b228fc54a..ebd58540f 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -4092,5 +4092,24 @@ public void TestNontProjectedClassAsBaseClass() // Non projected class changes the behavior of the Value property to double it. Assert.AreEqual(6, customEquals.Value); } + + [TestMethod] + public async Task TestFailingCompletionHandlerCrashesProcess() + { + // Create an IAsyncAction from a C# task that completes after 2 seconds. + var asyncAction = AsyncInfo.Run(_ => Task.Delay(TimeSpan.FromSeconds(2))); + + // Pass it to native code which sets a Completed handler that throws. + var instance = new Class(); + instance.SetFailingCompletedHandler(asyncAction); + + // Wait long enough for the async action to complete and the native + // completion handler to fire. If the throwing handler crashes the + // process, we will never reach the assertion below. + await Task.Delay(TimeSpan.FromSeconds(5)); + + // If we get here, the process survived the throwing completion handler. + Assert.IsTrue(true, "Process survived the throwing native completion handler."); + } } } \ No newline at end of file