Skip to content

Commit

Permalink
C++/WinRT support for implementing COM interfaces that derive from ::…
Browse files Browse the repository at this point in the history
…IInspectable (#603)
  • Loading branch information
kennykerr authored Sep 24, 2019
1 parent dd4cf3c commit e7ad763
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "winrt/Windows.Foundation.h"
#include "catch.hpp"

#ifdef WINRT_WINDOWS_ABI
#error WINRT_WINDOWS_ABI must not be defined for this test.
#ifdef __IUnknown_INTERFACE_DEFINED__
#error __IUnknown_INTERFACE_DEFINED__ must not be defined for this test.
#endif

using namespace winrt;
Expand All @@ -11,7 +11,7 @@ using namespace Windows::Foundation;
namespace
{
// This is a variation of conditional_implements.cpp that builds without the Windows headers
// and validates that the conditional logic still works when WINRT_WINDOWS_ABI is not defined
// and validates that the conditional logic still works when __IUnknown_INTERFACE_DEFINED__ is not defined
// is_interface is defined more simply.

struct Base : implements<Base, IActivationFactory>
Expand Down
44 changes: 26 additions & 18 deletions src/tool/cppwinrt/strings/base_implements.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace winrt::impl
template <template <typename> typename Condition, typename T>
using tuple_if = typename tuple_if_base<Condition, T>::type;

#ifdef WINRT_WINDOWS_ABI
#ifdef __IUnknown_INTERFACE_DEFINED__

template <typename T>
struct is_interface : std::disjunction<std::is_base_of<Windows::Foundation::IInspectable, T>, std::conjunction<std::is_base_of<::IUnknown, T>, std::negation<is_implements<T>>>> {};
Expand Down Expand Up @@ -455,7 +455,7 @@ namespace winrt::impl

int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept override
{
return shim().GetIids(count, array);
return shim().GetIids(reinterpret_cast<count_type*>(count), reinterpret_cast<guid_type**>(array));
}

int32_t __stdcall GetRuntimeClassName(void** name) noexcept override
Expand All @@ -469,7 +469,7 @@ namespace winrt::impl
}
};

#ifdef WINRT_WINDOWS_ABI
#ifdef __IUnknown_INTERFACE_DEFINED__

template <typename D, typename I>
struct producer<D, I, std::enable_if_t<std::is_base_of_v< ::IUnknown, I> && !is_implements_v<I>>> : I
Expand Down Expand Up @@ -1037,6 +1037,11 @@ namespace winrt::impl
return result;
}

virtual Windows::Foundation::TrustLevel GetTrustLevel() const noexcept
{
return Windows::Foundation::TrustLevel::BaseTrust;
}

using is_factory = std::disjunction<std::is_same<Windows::Foundation::IActivationFactory, I>...>;

private:
Expand Down Expand Up @@ -1177,11 +1182,6 @@ namespace winrt::impl
virtual void* find_interface(guid const&) const noexcept = 0;
virtual inspectable_abi* find_inspectable() const noexcept = 0;

virtual Windows::Foundation::TrustLevel GetTrustLevel() const noexcept
{
return Windows::Foundation::TrustLevel::BaseTrust;
}

template <typename, typename, typename>
friend struct impl::produce_base;

Expand Down Expand Up @@ -1342,28 +1342,36 @@ WINRT_EXPORT namespace winrt
return result;
}

impl::hresult_type __stdcall QueryInterface(guid const& id, void** object) noexcept
impl::hresult_type __stdcall QueryInterface(impl::guid_type const& id, void** object) noexcept
{
return root_implements_type::QueryInterface(id, object);
return root_implements_type::QueryInterface(reinterpret_cast<guid const&>(id), object);
}

#ifdef WINRT_WINDOWS_ABI
impl::count_type __stdcall AddRef() noexcept
{
return root_implements_type::AddRef();
}

impl::hresult_type __stdcall QueryInterface(GUID const& id, void** object) noexcept
impl::count_type __stdcall Release() noexcept
{
return root_implements_type::QueryInterface(reinterpret_cast<guid const&>(id), object);
return root_implements_type::Release();
}

#endif
impl::hresult_type __stdcall GetIids(impl::count_type* count, impl::guid_type** iids) noexcept
{
return root_implements_type::GetIids(reinterpret_cast<uint32_t*>(count), reinterpret_cast<guid**>(iids));
}

impl::ref_count_type __stdcall AddRef() noexcept
impl::hresult_type __stdcall GetRuntimeClassName(impl::hstring_type* value) noexcept
{
return root_implements_type::AddRef();
return root_implements_type::abi_GetRuntimeClassName(reinterpret_cast<void**>(value));
}

impl::ref_count_type __stdcall Release() noexcept
using root_implements_type::GetTrustLevel;

impl::hresult_type __stdcall GetTrustLevel(impl::trust_level_type* value) noexcept
{
return root_implements_type::Release();
return root_implements_type::abi_GetTrustLevel(reinterpret_cast<Windows::Foundation::TrustLevel*>(value));
}

void* find_interface(guid const& id) const noexcept override
Expand Down
2 changes: 1 addition & 1 deletion src/tool/cppwinrt/strings/base_meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ namespace winrt::impl
static_assert(missing_guid_of<T>::value, "Support for non-WinRT interfaces is disabled. To enable, simply #include <unknwn.h> before any C++/WinRT headers.");
};

#ifdef WINRT_WINDOWS_ABI
#ifdef __IUnknown_INTERFACE_DEFINED__
template <typename T>
struct guid_storage
{
Expand Down
32 changes: 22 additions & 10 deletions src/tool/cppwinrt/strings/base_types.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@

namespace winrt::impl
{
#ifdef __IUnknown_INTERFACE_DEFINED__
#define WINRT_WINDOWS_ABI
using hresult_type = long;
using ref_count_type = unsigned long;
#else
using hresult_type = int32_t;
using ref_count_type = uint32_t;
#endif

using ptp_io = struct tp_io*;
using ptp_timer = struct tp_timer*;
using ptp_wait = struct tp_wait*;
Expand Down Expand Up @@ -54,7 +45,7 @@ WINRT_EXPORT namespace winrt
{
}

#ifdef WINRT_WINDOWS_ABI
#ifdef __IUnknown_INTERFACE_DEFINED__

constexpr guid(GUID const& value) noexcept :
Data1(value.Data1),
Expand Down Expand Up @@ -97,3 +88,24 @@ WINRT_EXPORT namespace winrt::Windows::Foundation
struct IInspectable;
struct IActivationFactory;
}

namespace winrt::impl
{
#ifdef __IUnknown_INTERFACE_DEFINED__
using hresult_type = long;
using count_type = unsigned long;
using guid_type = GUID;
#else
using hresult_type = int32_t;
using count_type = uint32_t;
using guid_type = guid;
#endif

#ifdef __IInspectable_INTERFACE_DEFINED__
using hstring_type = HSTRING;
using trust_level_type = ::TrustLevel;
#else
using hstring_type = void*;
using trust_level_type = Windows::Foundation::TrustLevel;
#endif
}
2 changes: 1 addition & 1 deletion src/tool/cppwinrt/strings/base_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ WINRT_EXPORT namespace winrt
}
}

#ifdef WINRT_WINDOWS_ABI
#ifdef __IUnknown_INTERFACE_DEFINED__

inline ::IUnknown* get_unknown(Windows::Foundation::IUnknown const& object) noexcept
{
Expand Down
64 changes: 64 additions & 0 deletions src/tool/cppwinrt/test/inspectable_interop.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <inspectable.h>
#include "winrt/Windows.Foundation.h"
#include "catch.hpp"

using namespace winrt;

namespace
{
struct __declspec(uuid("ed0dd761-c31e-4803-8cf9-22a2cb20ec47")) IBadInterop : ::IInspectable
{
virtual int32_t __stdcall JustSayNo() noexcept = 0;
};

struct Sample : implements<Sample, Windows::Foundation::IActivationFactory, IBadInterop>
{
Windows::Foundation::IInspectable ActivateInstance()
{
throw hresult_not_implemented();
}

hstring GetRuntimeClassName()
{
return L"Sample";
}

Windows::Foundation::TrustLevel GetTrustLevel()
{
return Windows::Foundation::TrustLevel::PartialTrust;
}

int32_t __stdcall JustSayNo() noexcept final
{
return 123;
}
};
}

TEST_CASE("inspectable_interop")
{
Windows::Foundation::IActivationFactory a = make<Sample>();
REQUIRE(a != nullptr);

Windows::Foundation::IActivationFactory b = a.as<Windows::Foundation::IActivationFactory>();
REQUIRE(b != nullptr);

com_ptr<IBadInterop> c = a.as<IBadInterop>();
REQUIRE(c != nullptr);
REQUIRE(c->JustSayNo() == 123);

Windows::Foundation::IActivationFactory d = c.as<Windows::Foundation::IActivationFactory>();
REQUIRE(a == d);

Windows::Foundation::IInspectable f = c.as<Windows::Foundation::IInspectable>();
REQUIRE(f != nullptr);

Windows::Foundation::IInspectable e(c.detach(), take_ownership_from_abi);

REQUIRE(winrt::get_class_name(e) == L"Sample");
REQUIRE(winrt::get_trust_level(e) == Windows::Foundation::TrustLevel::PartialTrust);

auto interfaces = winrt::get_interfaces(e);
REQUIRE(interfaces.size() == 1);
REQUIRE(interfaces[0] == guid_of<Windows::Foundation::IActivationFactory>());
}
6 changes: 6 additions & 0 deletions src/tool/cppwinrt/test/test.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@
<ClCompile Include="GetMany.cpp" />
<ClCompile Include="get_activation_factory.cpp" />
<ClCompile Include="iid_ppv_args.cpp" />
<ClCompile Include="inspectable_interop.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="interop.cpp" />
<ClCompile Include="invalid_events.cpp" />
<ClCompile Include="in_params.cpp" />
Expand Down

0 comments on commit e7ad763

Please sign in to comment.