forked from microsoft/cppwinrt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathagility.cpp
More file actions
140 lines (109 loc) · 3.82 KB
/
agility.cpp
File metadata and controls
140 lines (109 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "pch.h"
#include "winrt/test_component.Delegates.h"
//
// These tests confirm the COM identity and other behaviours for agile implementations.
//
using namespace winrt;
using namespace Windows::Foundation;
namespace
{
struct TestAgile : implements<TestAgile, IClosable>
{
bool& m_destroyed;
TestAgile(bool& destroyed) : m_destroyed(destroyed) { m_destroyed = false; }
~TestAgile() { m_destroyed = true; }
void Close() {}
};
struct TestNonAgile : implements<TestNonAgile, non_agile, IClosable>
{
void Close() {}
};
}
TEST_CASE("agility")
{
using Windows::Foundation::IUnknown;
using Windows::Foundation::IInspectable;
// Test agility
{
bool destroyed = false;
{
IInspectable object = make<TestAgile>(destroyed);
// Confirm agility
object.as<IAgileObject>();
// Confirm legacy agility
com_ptr<IMarshal> marshal = object.as<IMarshal>();
// Confirm tear-off identity
IUnknown object_identity = object.as<IUnknown>();
IUnknown marshal_identity = marshal.as<IUnknown>();
REQUIRE(object_identity == marshal_identity);
REQUIRE(!destroyed);
}
// Confirm tear-off does not leak reference
REQUIRE(destroyed);
}
// Test non-agility
{
IInspectable object = make<TestNonAgile>();
// Does not implement IAgileObject
REQUIRE_THROWS_AS(object.as<IAgileObject>(), hresult_no_interface);
// Does not implement IMarshal
REQUIRE_THROWS_AS(object.as<IMarshal>(), hresult_no_interface);
}
// Test IMarshal tearoff lifetime
{
bool destroyed = false;
IInspectable object = make<TestAgile>(destroyed);
com_ptr<IMarshal> marshal = object.as<IMarshal>();
object = nullptr;
REQUIRE(!destroyed);
// Confirm agility (back to object)
marshal.as<IAgileObject>();
// QI on tearoff itself
com_ptr<IMarshal> marshal2 = marshal.as<IMarshal>();
REQUIRE(marshal == marshal2);
marshal2 = nullptr;
// Confirm tear-off does not leak reference
REQUIRE(!destroyed);
marshal = nullptr;
REQUIRE(destroyed);
}
// Test agile delegate
{
IUnknown object = test_component::Delegates::AgileDelegate([] {});
com_ptr<IMarshal> marshal = object.as<IMarshal>();
object = nullptr;
// Confirm agility (back to object)
marshal.as<IAgileObject>();
// QI on tearoff itself
com_ptr<IMarshal> marshal2 = marshal.as<IMarshal>();
REQUIRE(marshal == marshal2);
}
// Test agile weak reference
{
bool destroyed = false;
IClosable object = make<TestAgile>(destroyed);
com_ptr<winrt::impl::IWeakReferenceSource> source = object.as<winrt::impl::IWeakReferenceSource>();
// Clear object but source keeps object alive
object = nullptr;
source.as<IMarshal>();
com_ptr<winrt::impl::IWeakReference> ref;
check_hresult(source->GetWeakReference(ref.put()));
// Drop the source object
REQUIRE(S_OK == ref->Resolve(guid_of<IClosable>(), put_abi(object)));
REQUIRE(object != nullptr);
source = nullptr;
REQUIRE(!destroyed);
object = nullptr;
REQUIRE(destroyed);
REQUIRE(S_OK == ref->Resolve(guid_of<IClosable>(), put_abi(object)));
REQUIRE(object == nullptr);
// Marshaling support on weak ref
com_ptr<IMarshal> marshal = ref.as<IMarshal>();
ref = nullptr;
// Confirm agility (back to object):
marshal.as<IAgileObject>();
// QI on tearoff itself
com_ptr<IMarshal> marshal2 = marshal.as<IMarshal>();
REQUIRE(marshal == marshal2);
}
}