STLdoc
STLdocumentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
agile.h
Go to the documentation of this file.
1 //
2 // Copyright (C) Microsoft Corporation
3 // All rights reserved.
4 //
5 // Code in Details namespace is for internal usage within the library code
6 //
7 
8 #ifndef _PLATFORM_AGILE_H_
9 #define _PLATFORM_AGILE_H_
10 
11 #ifdef _MSC_VER
12 #pragma once
13 #endif // _MSC_VER
14 
15 #include <algorithm>
16 #include <wrl\client.h>
17 
18 #if !defined(__cplusplus_winrt)
19 #error agile.h can only be used with /ZW
20 #endif
21 
22 namespace Platform
23 {
24  namespace Details
25  {
26  __declspec(dllimport) IUnknown* __stdcall GetObjectContext();
27  __declspec(dllimport) HRESULT __stdcall GetProxyImpl(::IUnknown*, REFIID, ::IUnknown*, ::IUnknown**);
28  __declspec(dllimport) HRESULT __stdcall ReleaseInContextImpl(::IUnknown*, ::IUnknown*);
29 
30  template <typename T>
31  __declspec(no_refcount) inline HRESULT GetProxy(T ^ObjectIn, ::IUnknown *ContextCallBack, T ^*Proxy)
32  {
33  return GetProxyImpl(*reinterpret_cast<IUnknown**>(&ObjectIn), __uuidof(T^) , ContextCallBack, reinterpret_cast< ::IUnknown**>(Proxy));
34  }
35 
36  template <typename T>
37  inline HRESULT ReleaseInContext(T *ObjectIn, ::IUnknown *ContextCallBack)
38  {
39  return ReleaseInContextImpl(ObjectIn, ContextCallBack);
40  }
41 
42  template <typename T>
44  {
45  __abi_IUnknown* _p;
46  bool _release;
47  public:
48  AgileHelper(__abi_IUnknown* p, bool release = true) : _p(p), _release(release)
49  {
50  }
51  AgileHelper(AgileHelper && other) : _p(other._p), _release(other._release)
52  {
53  _other._p = nullptr;
54  _other._release = true;
55  }
57  {
58  _p = other._p;
59  _release = other._release;
60  _other._p = nullptr;
61  _other._release = true;
62  return *this;
63  }
64 
66  {
67  if (_release && _p)
68  {
69  _p->__abi_Release();
70  }
71  }
72 
73  __declspec(no_refcount) __declspec(no_release_return)
74  T^ operator->()
75  {
76  return reinterpret_cast<T^>(_p);
77  }
78 
79  __declspec(no_refcount) __declspec(no_release_return)
80  operator T^()
81  {
82  return reinterpret_cast<T^>(_p);
83  }
84  private:
85  AgileHelper(const AgileHelper&);
87  };
88  template <typename T>
89  struct __remove_hat
90  {
91  typedef T type;
92  };
93  template <typename T>
94  struct __remove_hat<T^>
95  {
96  typedef T type;
97  };
98  template <typename T>
100  {
101  typename typedef __remove_hat<T>::type type;
103  };
104  } // namespace Details
105 
106 #pragma warning(push)
107 #pragma warning(disable: 4451) // Usage of ref class inside this context can lead to invalid marshaling of object across contexts
108 
109  template <
110  typename T,
111  bool TIsNotAgile = (__is_win_class(typename Details::AgileTypeHelper<T>::type) && !__is_winrt_agile(typename Details::AgileTypeHelper<T>::type)) ||
112  __is_win_interface(typename Details::AgileTypeHelper<T>::type)
113  >
114  class Agile
115  {
116  static_assert(__is_win_class(typename Details::AgileTypeHelper<T>::type) || __is_win_interface(typename Details::AgileTypeHelper<T>::type), "Agile can only be used with ref class or interface class types");
118  TypeT _object;
119  ::Microsoft::WRL::ComPtr< ::IUnknown> _contextCallback;
120  ULONG_PTR _contextToken;
121 
122  enum class AgileState
123  {
124  NonAgilePointer = 0,
125  AgilePointer = 1,
126  Unknown = 2
127  };
129 
131  {
132  _contextCallback = Details::GetObjectContext();
133  __abi_ThrowIfFailed(CoGetContextToken(&_contextToken));
134  }
135 
136  void SetObject(TypeT object)
137  {
138  // Capture context before setting the pointer
139  // If context capture fails then nothing to cleanup
140  Release();
141  if (object != nullptr)
142  {
143  ::Microsoft::WRL::ComPtr< ::IAgileObject> checkIfAgile;
144  HRESULT hr = reinterpret_cast< ::IUnknown*>(object)->QueryInterface(__uuidof(::IAgileObject), &checkIfAgile);
145  // Don't Capture context if object is agile
146  if (hr != S_OK)
147  {
148  _agileState = AgileState::NonAgilePointer;
149  CaptureContext();
150  }
151  else
152  {
153  _agileState = AgileState::AgilePointer;
154  }
155  }
156  _object = object;
157  }
158 
159  public:
160  Agile() throw() : _object(nullptr), _contextToken(0), _agileState(AgileState::Unknown)
161  {
162  }
163 
164  Agile(nullptr_t) throw() : _object(nullptr), _contextToken(0), _agileState(AgileState::Unknown)
165  {
166  }
167 
168  explicit Agile(TypeT object) throw() : _object(nullptr), _contextToken(0), _agileState(AgileState::Unknown)
169  {
170  // Assumes that the source object is from the current context
171  SetObject(object);
172  }
173 
174  Agile(const Agile& object) throw() : _object(nullptr), _contextToken(0), _agileState(AgileState::Unknown)
175  {
176  // Get returns pointer valid for current context
177  SetObject(object.Get());
178  }
179 
180  Agile(Agile && object) throw() : _object(nullptr), _contextToken(0), _agileState(AgileState::Unknown)
181  {
182  // Assumes that the source object is from the current context
183  Swap(object);
184  }
185 
186  ~Agile() throw()
187  {
188  Release();
189  }
190 
191  TypeT Get() const
192  {
193  // Agile object, no proxy required
194  if (_agileState == AgileState::AgilePointer || _object == nullptr)
195  {
196  return _object;
197  }
198 
199  // Do the check for same context
200  ULONG_PTR currentContextToken;
201  __abi_ThrowIfFailed(CoGetContextToken(&currentContextToken));
202  if (currentContextToken == _contextToken)
203  {
204  return _object;
205  }
206 
207  // Different context and holding on to a non agile object
208  // Do the costly work of getting a proxy
209  TypeT localObject;
210  __abi_ThrowIfFailed(Details::GetProxy(_object, _contextCallback.Get(), &localObject));
211 
212  if (_agileState == AgileState::Unknown)
213  {
214  // Object is agile if it implements IAgileObject
215  // GetAddressOf captures the context with out knowing the type of object that it will hold
216  ::Microsoft::WRL::ComPtr< ::IAgileObject> checkIfAgile;
217  HRESULT hr = reinterpret_cast<IUnknown*>(localObject)->QueryInterface(__uuidof(::IAgileObject), &checkIfAgile);
218  if (hr == S_OK)
219  {
220  auto pThis = const_cast<Agile*>(this);
222  pThis->_contextToken = 0;
223  pThis->_contextCallback = nullptr;
224  return _object;
225  }
226  else
227  {
228  auto pThis = const_cast<Agile*>(this);
230  }
231  }
232 
233  return localObject;
234  }
235 
236  TypeT* GetAddressOf() throw()
237  {
238  Release();
239  CaptureContext();
240  return &_object;
241  }
242 
243  TypeT* GetAddressOfForInOut() throw()
244  {
245  CaptureContext();
246  return &_object;
247  }
248 
249  TypeT operator->() const throw()
250  {
251  return Get();
252  }
253 
254  Agile& operator=(nullptr_t) throw()
255  {
256  Release();
257  return *this;
258  }
259 
260  Agile& operator=(TypeT object) throw()
261  {
262  Agile(object).Swap(*this);
263  return *this;
264  }
265 
266  Agile& operator=(Agile object) throw()
267  {
268  // parameter is by copy which gets pointer valid for current context
269  object.Swap(*this);
270  return *this;
271  }
272 
273  void Swap(Agile& object)
274  {
275  std::swap(_object, object._object);
276  std::swap(_contextCallback, object._contextCallback);
277  std::swap(_contextToken, object._contextToken);
278  std::swap(_agileState, object._agileState);
279  }
280 
281  // Release the interface and set to NULL
282  void Release() throw()
283  {
284  if (_object)
285  {
286  // Cast to IInspectable (no QI)
287  IUnknown* pObject = *(::IUnknown**) (&_object);
288  // Set ^ to null without release
289  *(IUnknown**) (&_object) = nullptr;
290 
291  ULONG_PTR currentContextToken;
292  __abi_ThrowIfFailed(CoGetContextToken(&currentContextToken));
293  if (_contextToken == 0 || _contextCallback == nullptr || _contextToken == currentContextToken)
294  {
295  pObject->Release();
296  }
297  else
298  {
299  Details::ReleaseInContext(pObject, _contextCallback.Get());
300  }
301  _contextCallback = nullptr;
302  _contextToken = 0;
303  _agileState = AgileState::Unknown;
304  }
305  }
306 
307  bool operator==(nullptr_t) const throw()
308  {
309  return _object == nullptr;
310  }
311 
312  bool operator==(const Agile& other) const throw()
313  {
314  return _object == other._object && _contextToken == other._contextToken;
315  }
316 
317  bool operator < (const Agile& other) const throw()
318  {
319  if (reinterpret_cast<void*>(_object) < reinterpret_cast<void*>(other._object))
320  {
321  return true;
322  }
323 
324  return _object == other._object && _contextToken < other._contextToken;
325  }
326  };
327 
328  template <typename T>
329  class Agile<T, false>
330  {
331  static_assert(__is_win_class(typename Details::AgileTypeHelper<T>::type) || __is_win_interface(typename Details::AgileTypeHelper<T>::type), "Agile can only be used with ref class or interface class types");
333  TypeT _object;
334 
335  public:
336  Agile() throw() : _object(nullptr)
337  {
338  }
339 
340  Agile(nullptr_t) throw() : _object(nullptr)
341  {
342  }
343 
344  explicit Agile(TypeT object) throw() : _object(object)
345  {
346  }
347 
348  Agile(const Agile& object) throw() : _object(object._object)
349  {
350  }
351 
352  Agile(Agile && object) throw() : _object(nullptr)
353  {
354  Swap(object);
355  }
356 
357  ~Agile() throw()
358  {
359  Release();
360  }
361 
362  TypeT Get() const
363  {
364  return _object;
365  }
366 
367  TypeT* GetAddressOf() throw()
368  {
369  Release();
370  return &_object;
371  }
372 
373  TypeT* GetAddressOfForInOut() throw()
374  {
375  return &_object;
376  }
377 
378  TypeT operator->() const throw()
379  {
380  return Get();
381  }
382 
383  Agile& operator=(nullptr_t) throw()
384  {
385  Release();
386  return *this;
387  }
388 
389  Agile& operator=(TypeT object) throw()
390  {
391  if (_object != object)
392  {
393  _object = object;
394  }
395  return *this;
396  }
397 
398  Agile& operator=(Agile object) throw()
399  {
400  object.Swap(*this);
401  return *this;
402  }
403 
404  // Release the interface and set to NULL
405  void Release() throw()
406  {
407  _object = nullptr;
408  }
409 
410  void Swap(Agile& object)
411  {
412  std::swap(_object, object._object);
413  }
414 
415  bool operator==(nullptr_t) const throw()
416  {
417  return _object == nullptr;
418  }
419 
420  bool operator==(const Agile& other) const throw()
421  {
422  return _object == other._object;
423  }
424 
425  bool operator < (const Agile& other) const throw()
426  {
427  return reinterpret_cast<void*>(_object) < reinterpret_cast<void*>(other._object);
428  }
429  };
430 
431 #pragma warning(pop)
432 
433  template<class U>
434  bool operator==(nullptr_t, const Agile<U>& a) throw()
435  {
436  return a == nullptr;
437  }
438 
439  template<class U>
440  bool operator!=(const Agile<U>& a, nullptr_t) throw()
441  {
442  return !(a == nullptr);
443  }
444 
445  template<class U>
446  bool operator!=(nullptr_t, const Agile<U>& a) throw()
447  {
448  return !(a == nullptr);
449  }
450 
451  template<class U>
452  bool operator!=(const Agile<U>& a, const Agile<U>& b) throw()
453  {
454  return !(a == b);
455  }
456 
457 } // namespace Platform
458 
459 #endif // _PLATFORM_AGILE_H_
Definition: agile.h:22
Definition: agile.h:43
Agile(const Agile &object)
Definition: agile.h:348
Agile(TypeT object)
Definition: agile.h:168
__declspec(no_refcount) __declspec(no_release_return) operator T^()
Definition: agile.h:79
__declspec(dllimport) HRESULT __stdcall GetProxyImpl(__declspec(dllimport) HRESULT __stdcall ReleaseInContextImpl(::IUnknown * ContextCallBack
Definition: agile.h:31
~Agile()
Definition: agile.h:186
#define S_OK
Definition: comutil.h:62
TypeT * GetAddressOfForInOut()
Definition: agile.h:243
void Swap(Agile &object)
Definition: agile.h:410
void SetObject(TypeT object)
Definition: agile.h:136
Agile(TypeT object)
Definition: agile.h:344
Agile(Agile &&object)
Definition: agile.h:180
TypeT * GetAddressOfForInOut()
Definition: agile.h:373
Agile & operator=(nullptr_t)
Definition: agile.h:254
Agile & operator=(TypeT object)
Definition: agile.h:389
AgileHelper operator=(AgileHelper &&other)
Definition: agile.h:56
TypeT * GetAddressOf()
Definition: agile.h:236
Agile & operator=(TypeT object)
Definition: agile.h:260
~AgileHelper()
Definition: agile.h:65
Agile(const Agile &object)
Definition: agile.h:174
Definition: agile.h:114
TypeT _object
Definition: agile.h:118
AgileHelper(__abi_IUnknown *p, bool release=true)
Definition: agile.h:48
Agile & operator=(Agile object)
Definition: agile.h:398
Agile(nullptr_t)
Definition: agile.h:340
~Agile()
Definition: agile.h:357
T type
Definition: agile.h:91
bool operator==(nullptr_t) const
Definition: agile.h:415
bool _release
Definition: agile.h:46
bool operator==(const Agile &other) const
Definition: agile.h:312
bool operator==(const Agile &other) const
Definition: agile.h:420
Agile()
Definition: agile.h:336
void Release()
Definition: agile.h:282
Agile & operator=(nullptr_t)
Definition: agile.h:383
bool operator!=(const Agile< U > &a, nullptr_t)
Definition: agile.h:440
AgileState
Definition: agile.h:122
Details::AgileTypeHelper< T >::agileMemberType TypeT
Definition: agile.h:116
void __abi_ThrowIfFailed(long __hrArg)
Definition: vccorlib.h:96
::Microsoft::WRL::ComPtr< ::IUnknown > _contextCallback
Definition: agile.h:119
Definition: agile.h:89
TypeT operator->() const
Definition: agile.h:378
void swap(array< _Ty, _Size > &_Left, array< _Ty, _Size > &_Right) _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
Definition: array:433
Agile()
Definition: agile.h:160
__abi_IUnknown * _p
Definition: agile.h:45
Agile(Agile &&object)
Definition: agile.h:352
#define false
Definition: stdbool.h:16
HRESULT ReleaseInContext(T *ObjectIn,::IUnknown *ContextCallBack)
Definition: agile.h:37
ULONG_PTR _contextToken
Definition: agile.h:120
void CaptureContext()
Definition: agile.h:130
Agile & operator=(Agile object)
Definition: agile.h:266
__remove_hat< T >::type type
Definition: agile.h:101
Details::AgileTypeHelper< T >::agileMemberType TypeT
Definition: agile.h:331
TypeT operator->() const
Definition: agile.h:249
AgileHelper(AgileHelper &&other)
Definition: agile.h:51
TypeT Get() const
Definition: agile.h:191
AgileState _agileState
Definition: agile.h:128
__declspec(dllimport) IUnknown *__stdcall GetObjectContext()
bool operator==(nullptr_t, const Agile< U > &a)
Definition: agile.h:434
__declspec(dllimport) HRESULT __stdcall GetProxyImpl(__declspec(dllimport) HRESULT __stdcall ReleaseInContextImpl(::IUnknown T * Proxy
Definition: agile.h:32
void Swap(Agile &object)
Definition: agile.h:273
Agile(nullptr_t)
Definition: agile.h:164
__declspec(no_refcount) __declspec(no_release_return) T^operator->()
Definition: agile.h:73
void Release()
Definition: agile.h:405
TypeT Get() const
Definition: agile.h:362
bool operator==(nullptr_t) const
Definition: agile.h:307
TypeT _object
Definition: agile.h:333
__remove_hat< T >::type agileMemberType
Definition: agile.h:102
TypeT * GetAddressOf()
Definition: agile.h:367
bool operator<(const Agile &other) const
Definition: agile.h:317
T type
Definition: agile.h:96