Allow capturing from a raw pointer (#896)

This commit is contained in:
Raymond Chen 2021-03-23 06:01:15 -07:00 коммит произвёл GitHub
Родитель 1502e293d6
Коммит ede68ed9e7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 70 добавлений и 38 удалений

Просмотреть файл

@ -1,4 +1,28 @@
WINRT_EXPORT namespace winrt
{
template <typename T>
struct com_ptr;
}
namespace winrt::impl
{
template <typename T, typename F, typename...Args>
int32_t capture_to(void**result, F function, Args&& ...args)
{
return function(args..., guid_of<T>(), result);
}
template <typename T, typename O, typename M, typename...Args, std::enable_if_t<std::is_class_v<O> || std::is_union_v<O>, int> = 0>
int32_t capture_to(void** result, O* object, M method, Args&& ...args)
{
return (object->*method)(args..., guid_of<T>(), result);
}
template <typename T, typename O, typename M, typename...Args>
int32_t capture_to(void** result, com_ptr<O> const& object, M method, Args&& ...args);
}
WINRT_EXPORT namespace winrt
{
template <typename T>
@ -162,28 +186,16 @@ WINRT_EXPORT namespace winrt
*other = m_ptr;
}
template <typename F, typename...Args>
bool try_capture(F function, Args&&...args)
template <typename...Args>
bool try_capture(Args&&...args)
{
return function(args..., guid_of<T>(), put_void()) >= 0;
return impl::capture_to<T>(put_void(), std::forward<Args>(args)...) >= 0;
}
template <typename O, typename M, typename...Args>
bool try_capture(com_ptr<O> const& object, M method, Args&&...args)
template <typename...Args>
void capture(Args&&...args)
{
return (object.get()->*(method))(args..., guid_of<T>(), put_void()) >= 0;
}
template <typename F, typename...Args>
void capture(F function, Args&&...args)
{
check_hresult(function(args..., guid_of<T>(), put_void()));
}
template <typename O, typename M, typename...Args>
void capture(com_ptr<O> const& object, M method, Args&&...args)
{
check_hresult((object.get()->*(method))(args..., guid_of<T>(), put_void()));
check_hresult(impl::capture_to<T>(put_void(), std::forward<Args>(args)...));
}
private:
@ -225,33 +237,19 @@ WINRT_EXPORT namespace winrt
type* m_ptr{};
};
template <typename T, typename F, typename...Args>
impl::com_ref<T> try_capture(F function, Args&& ...args)
template <typename T, typename...Args>
impl::com_ref<T> try_capture(Args&& ...args)
{
void* result{};
function(args..., guid_of<T>(), &result);
impl::capture_to<T>(&result, std::forward<Args>(args)...);
return { result, take_ownership_from_abi };
}
template <typename T, typename O, typename M, typename...Args>
impl::com_ref<T> try_capture(com_ptr<O> const& object, M method, Args&& ...args)
template <typename T, typename...Args>
impl::com_ref<T> capture(Args&& ...args)
{
void* result{};
(object.get()->*(method))(args..., guid_of<T>(), &result);
return { result, take_ownership_from_abi };
}
template <typename T, typename F, typename...Args>
impl::com_ref<T> capture(F function, Args&& ...args)
{
void* result{};
check_hresult(function(args..., guid_of<T>(), &result));
return { result, take_ownership_from_abi };
}
template <typename T, typename O, typename M, typename...Args>
impl::com_ref<T> capture(com_ptr<O> const& object, M method, Args && ...args)
{
void* result{};
check_hresult((object.get()->*(method))(args..., guid_of<T>(), &result));
check_hresult(impl::capture_to<T>(&result, std::forward<Args>(args)...));
return { result, take_ownership_from_abi };
}
@ -340,6 +338,15 @@ WINRT_EXPORT namespace winrt
}
}
namespace winrt::impl
{
template <typename T, typename O, typename M, typename...Args>
int32_t capture_to(void** result, com_ptr<O> const& object, M method, Args&& ...args)
{
return (object.get()->*(method))(args..., guid_of<T>(), result);
}
}
template <typename T>
void** IID_PPV_ARGS_Helper(winrt::com_ptr<T>* ptr) noexcept
{

Просмотреть файл

@ -39,46 +39,71 @@ HRESULT __stdcall CreateCapture(int value, GUID const& iid, void** object) noexc
TEST_CASE("capture")
{
// Capture from global function.
com_ptr<ICapture> a = capture<ICapture>(CreateCapture, 10);
REQUIRE(a->GetValue() == 10);
a = nullptr;
a.capture(CreateCapture, 20);
REQUIRE(a->GetValue() == 20);
// Capture from com_ptr + method.
auto b = capture<ICapture>(a, &ICapture::CreateMemberCapture, 30);
REQUIRE(b->GetValue() == 30);
b = nullptr;
b.capture(a, &ICapture::CreateMemberCapture, 40);
REQUIRE(b->GetValue() == 40);
// Capture from raw pointer + method.
b = nullptr;
b = capture<ICapture>(a.get(), &ICapture::CreateMemberCapture, 30);
REQUIRE(b->GetValue() == 30);
b = nullptr;
b.capture(a.get(), &ICapture::CreateMemberCapture, 40);
REQUIRE(b->GetValue() == 40);
com_ptr<IDispatch> d;
REQUIRE_THROWS_AS(capture<IDispatch>(CreateCapture, 0), hresult_no_interface);
REQUIRE_THROWS_AS(d.capture(CreateCapture, 0), hresult_no_interface);
REQUIRE_THROWS_AS(capture<IDispatch>(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface);
REQUIRE_THROWS_AS(d.capture(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface);
REQUIRE_THROWS_AS(capture<IDispatch>(a.get(), &ICapture::CreateMemberCapture, 0), hresult_no_interface);
REQUIRE_THROWS_AS(d.capture(a.get(), &ICapture::CreateMemberCapture, 0), hresult_no_interface);
}
TEST_CASE("try_capture")
{
// Identical to the "capture" test above, just with different
// error handling.
// Capture from global function.
com_ptr<ICapture> a = try_capture<ICapture>(CreateCapture, 10);
REQUIRE(a->GetValue() == 10);
a = nullptr;
REQUIRE(a.try_capture(CreateCapture, 20));
REQUIRE(a->GetValue() == 20);
// Capture from com_ptr + method.
auto b = try_capture<ICapture>(a, &ICapture::CreateMemberCapture, 30);
REQUIRE(b->GetValue() == 30);
b = nullptr;
REQUIRE(b.try_capture(a, &ICapture::CreateMemberCapture, 40));
REQUIRE(b->GetValue() == 40);
// Capture from raw pointer + method.
b = nullptr;
b = try_capture<ICapture>(a.get(), &ICapture::CreateMemberCapture, 30);
REQUIRE(b->GetValue() == 30);
b = nullptr;
b.try_capture(a.get(), &ICapture::CreateMemberCapture, 40);
REQUIRE(b->GetValue() == 40);
com_ptr<IDispatch> d;
REQUIRE(!try_capture<IDispatch>(CreateCapture, 0));
REQUIRE(!d.try_capture(CreateCapture, 0));
REQUIRE(!try_capture<IDispatch>(a, &ICapture::CreateMemberCapture, 0));
REQUIRE(!d.try_capture(a, &ICapture::CreateMemberCapture, 0));
REQUIRE(!try_capture<IDispatch>(a.get(), &ICapture::CreateMemberCapture, 0));
REQUIRE(!d.try_capture(a.get(), &ICapture::CreateMemberCapture, 0));
}