diff --git a/strings/base_activation.h b/strings/base_activation.h index 7f35e1a79..685d9f5c0 100644 --- a/strings/base_activation.h +++ b/strings/base_activation.h @@ -487,6 +487,12 @@ WINRT_EXPORT namespace winrt impl::get_factory_cache().clear(); } + template + auto try_create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) + { + return try_capture(WINRT_IMPL_CoCreateInstance, clsid, outer, context); + } + template auto create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) { diff --git a/strings/base_com_ptr.h b/strings/base_com_ptr.h index 46867a73a..3ae9d88cd 100644 --- a/strings/base_com_ptr.h +++ b/strings/base_com_ptr.h @@ -153,6 +153,18 @@ WINRT_EXPORT namespace winrt *other = m_ptr; } + template + bool try_capture(F function, Args&&...args) + { + return function(args..., guid_of(), put_void()) >= 0; + } + + template + bool try_capture(com_ptr const& object, M method, Args&&...args) + { + return (object.get()->*(method))(args..., guid_of(), put_void()) >= 0; + } + template void capture(F function, Args&&...args) { @@ -204,6 +216,21 @@ WINRT_EXPORT namespace winrt type* m_ptr{}; }; + template + impl::com_ref try_capture(F function, Args&& ...args) + { + void* result{}; + function(args..., guid_of(), &result); + return { result, take_ownership_from_abi }; + } + + template + impl::com_ref try_capture(com_ptr const& object, M method, Args&& ...args) + { + void* result{}; + (object.get()->*(method))(args..., guid_of(), &result); + return { result, take_ownership_from_abi }; + } template impl::com_ref capture(F function, Args&& ...args) { diff --git a/test/old_tests/UnitTests/capture.cpp b/test/old_tests/UnitTests/capture.cpp index e88a29056..d1c4e41de 100644 --- a/test/old_tests/UnitTests/capture.cpp +++ b/test/old_tests/UnitTests/capture.cpp @@ -58,3 +58,27 @@ TEST_CASE("capture") REQUIRE_THROWS_AS(capture(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface); REQUIRE_THROWS_AS(d.capture(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface); } + +TEST_CASE("try_capture") +{ + // Identical to the "capture" test above, just with different + // error handling. + com_ptr a = try_capture(CreateCapture, 10); + REQUIRE(a->GetValue() == 10); + a = nullptr; + REQUIRE(a.try_capture(CreateCapture, 20)); + REQUIRE(a->GetValue() == 20); + + auto b = try_capture(a, &ICapture::CreateMemberCapture, 30); + REQUIRE(b->GetValue() == 30); + b = nullptr; + REQUIRE(b.try_capture(a, &ICapture::CreateMemberCapture, 40)); + REQUIRE(b->GetValue() == 40); + + com_ptr d; + + REQUIRE(!try_capture(CreateCapture, 0)); + REQUIRE(!d.try_capture(CreateCapture, 0)); + REQUIRE(!try_capture(a, &ICapture::CreateMemberCapture, 0)); + REQUIRE(!d.try_capture(a, &ICapture::CreateMemberCapture, 0)); +} diff --git a/test/old_tests/UnitTests/create_instance.cpp b/test/old_tests/UnitTests/create_instance.cpp index 38f1bf031..fa1c2ee53 100644 --- a/test/old_tests/UnitTests/create_instance.cpp +++ b/test/old_tests/UnitTests/create_instance.cpp @@ -9,3 +9,12 @@ TEST_CASE("create_instance") com_ptr dialog = create_instance(guid_of()); REQUIRE(dialog); } + +TEST_CASE("try_create_instance") +{ + com_ptr dialog = try_create_instance(guid_of()); + REQUIRE(dialog); + + dialog = try_create_instance(CLSID_NULL); + REQUIRE(!dialog); +}