Nui
Loading...
Searching...
No Matches
event.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#pragma once
8
9#include <type_traits>
10
11#include <wrl\def.h>
12#include <wrl\internal.h>
13#include <wrl\client.h>
14#include <wrl\implements.h>
16#include <eventtoken.h>
17
18#define WrlSealed
19
20// Set packing
21#pragma pack(push, 8)
22
23#ifdef ____x_Windows_CFoundation_CIDeferral_FWD_DEFINED__
24namespace ABI
25{
26 namespace Windows
27 {
28 namespace Foundation
29 {
30 typedef ::Windows::Foundation::IDeferral IDeferral;
31 typedef ::Windows::Foundation::IDeferralFactory IDeferralFactory;
32 typedef ::Windows::Foundation::IDeferralCompletedHandler IDeferralCompletedHandler;
33 }
34 }
35}
36#endif
37
38namespace Microsoft
39{
40 namespace WRL
41 {
42 // Enum to specify the behavior on checking delegate return results
44 {
45 NoCheck = 1
46 };
47 extern __declspec(selectany) const DelegateCheckMode DefaultDelegateCheckMode = NoCheck;
48
49 template <DelegateCheckMode delegateCheckMode>
51
52 template <>
54 {
55 static HRESULT CheckReturn(HRESULT hr)
56 {
57 return hr;
58 }
59 };
60
61 // Enum to specify the behavior when firing event delegates
63 {
66 };
67
68 // Event error options
69 template <InvokeMode invokeModeValue>
71 {
72 static const InvokeMode invokeMode = invokeModeValue;
73 };
74
75 // Forward Declaration
76 template <InvokeMode invokeMode>
78 template <typename TDelegateInterface, typename EventSourceOptions>
79 class EventSource;
80
81 namespace Details
82 {
83
84 template <typename TDelegateInterface>
85 void* GetDelegateBucketAssist(TDelegateInterface* pDelegate)
86 {
87 // By ABI contract, delegates satisfy the below as a mechanism of getting at the invocation
88 // function (the fourth slot in the V-Table of the delegate interface). We do not care about
89 // the signature of the function, only its address as a means of improving bucketing.
90 void*** pVT = reinterpret_cast<void***>(pDelegate);
91 return (*pVT)[3];
92 }
93
94 // ArgTraits allows to determine amount of parameters
95 // on Invoke method of delegate interface
96 template <typename TMemberFunction>
97 struct ArgTraits
98 {
99 static const int args = -1; // Indicates that we cannot match Invoke method signature
100 };
101
102 template <typename TDelegateInterface>
103 struct ArgTraits<HRESULT (STDMETHODCALLTYPE TDelegateInterface::*)(void)>
104 {
105 static const int args = 0;
106 };
107
108 template <typename TDelegateInterface, typename TArg1>
109 struct ArgTraits<HRESULT (STDMETHODCALLTYPE TDelegateInterface::*)(TArg1)>
110 {
111 static const int args = 1;
112 typedef TArg1 Arg1Type;
113 };
114
115 template <typename TDelegateInterface, typename TArg1, typename TArg2>
116 struct ArgTraits<HRESULT (STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2)>
117 {
118 static const int args = 2;
119 typedef TArg1 Arg1Type;
120 typedef TArg2 Arg2Type;
121 };
122
123 template <typename TDelegateInterface, typename TArg1, typename TArg2, typename TArg3>
124 struct ArgTraits<HRESULT (STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2, TArg3)>
125 {
126 static const int args = 3;
127 typedef TArg1 Arg1Type;
128 typedef TArg2 Arg2Type;
129 typedef TArg3 Arg3Type;
130 };
131
132 template <typename TDelegateInterface, typename TArg1, typename TArg2, typename TArg3, typename TArg4>
133 struct ArgTraits<HRESULT (STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2, TArg3, TArg4)>
134 {
135 static const int args = 4;
136 typedef TArg1 Arg1Type;
137 typedef TArg2 Arg2Type;
138 typedef TArg3 Arg3Type;
139 typedef TArg4 Arg4Type;
140 };
141
142 template <
143 typename TDelegateInterface,
144 typename TArg1,
145 typename TArg2,
146 typename TArg3,
147 typename TArg4,
148 typename TArg5>
149 struct ArgTraits<HRESULT (STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2, TArg3, TArg4, TArg5)>
150 {
151 static const int args = 5;
152 typedef TArg1 Arg1Type;
153 typedef TArg2 Arg2Type;
154 typedef TArg3 Arg3Type;
155 typedef TArg4 Arg4Type;
156 typedef TArg5 Arg5Type;
157 };
158
159 template <
160 typename TDelegateInterface,
161 typename TArg1,
162 typename TArg2,
163 typename TArg3,
164 typename TArg4,
165 typename TArg5,
166 typename TArg6>
167 struct ArgTraits<HRESULT (
168 STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6)>
169 {
170 static const int args = 6;
171 typedef TArg1 Arg1Type;
172 typedef TArg2 Arg2Type;
173 typedef TArg3 Arg3Type;
174 typedef TArg4 Arg4Type;
175 typedef TArg5 Arg5Type;
176 typedef TArg6 Arg6Type;
177 };
178
179 template <
180 typename TDelegateInterface,
181 typename TArg1,
182 typename TArg2,
183 typename TArg3,
184 typename TArg4,
185 typename TArg5,
186 typename TArg6,
187 typename TArg7>
188 struct ArgTraits<HRESULT (
189 STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7)>
190 {
191 static const int args = 7;
192 typedef TArg1 Arg1Type;
193 typedef TArg2 Arg2Type;
194 typedef TArg3 Arg3Type;
195 typedef TArg4 Arg4Type;
196 typedef TArg5 Arg5Type;
197 typedef TArg6 Arg6Type;
198 typedef TArg7 Arg7Type;
199 };
200
201 template <
202 typename TDelegateInterface,
203 typename TArg1,
204 typename TArg2,
205 typename TArg3,
206 typename TArg4,
207 typename TArg5,
208 typename TArg6,
209 typename TArg7,
210 typename TArg8>
211 struct ArgTraits<HRESULT (
212 STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8)>
213 {
214 static const int args = 8;
215 typedef TArg1 Arg1Type;
216 typedef TArg2 Arg2Type;
217 typedef TArg3 Arg3Type;
218 typedef TArg4 Arg4Type;
219 typedef TArg5 Arg5Type;
220 typedef TArg6 Arg6Type;
221 typedef TArg7 Arg7Type;
222 typedef TArg8 Arg8Type;
223 };
224
225 template <
226 typename TDelegateInterface,
227 typename TArg1,
228 typename TArg2,
229 typename TArg3,
230 typename TArg4,
231 typename TArg5,
232 typename TArg6,
233 typename TArg7,
234 typename TArg8,
235 typename TArg9>
236 struct ArgTraits<HRESULT (
237 STDMETHODCALLTYPE TDelegateInterface::*)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9)>
238 {
239 static const int args = 9;
240 typedef TArg1 Arg1Type;
241 typedef TArg2 Arg2Type;
242 typedef TArg3 Arg3Type;
243 typedef TArg4 Arg4Type;
244 typedef TArg5 Arg5Type;
245 typedef TArg6 Arg6Type;
246 typedef TArg7 Arg7Type;
247 typedef TArg8 Arg8Type;
248 typedef TArg9 Arg9Type;
249 };
250
251 // Traits factory extract appropriate ArgTraits type
252 // for delegate interface
253 // template <typename TDelegateInterface, bool isImplements = __is_base_of(ImplementsBase,
254 // TDelegateInterface)>
255 template <
256 typename TDelegateInterface,
257 bool isImplements = std::is_base_of_v<ImplementsBase, TDelegateInterface>>
259
260 // Specialization for the none Implements based interface
261 template <typename TDelegateInterface>
262 struct ArgTraitsHelper<TDelegateInterface, false>
263 {
264 typedef decltype(&TDelegateInterface::Invoke) methodType;
266 static const int args = Traits::args;
267 typedef TDelegateInterface Interface;
268 // Make sure that you are using STDMETHOD macro to define delegate interfaces
269 static_assert(
270 args != -1,
271 "Delegate Invoke signature doesn't match. Possible reasons: wrong calling convention, wrong "
272 "returned type or passed too many parameters to 'Callback'");
273 };
274
275 // Specialization for Implements based interface
276 template <typename TDelegateInterface>
277 struct ArgTraitsHelper<TDelegateInterface, true>
278 : ArgTraitsHelper<typename TDelegateInterface::FirstInterface>
279 {};
280
281 // Invoke helper provide implementation of invoke method
282 // depending on amount and type of arguments from ArgTraitsHelper
283 template <typename TDelegateInterface, typename TCallback, unsigned int argCount>
285
286 template <typename TDelegateInterface, typename TCallback>
287 struct InvokeHelper<TDelegateInterface, TCallback, 0> WrlSealed
288 : public ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
289 {
290 explicit InvokeHelper(TCallback callback) throw()
291 : callback_(callback)
292 {}
293
294 STDMETHOD(Invoke)()
295 {
297 }
298 TCallback callback_;
299 };
300
301 template <typename TDelegateInterface, typename TCallback>
302 struct InvokeHelper<TDelegateInterface, TCallback, 1> WrlSealed
303 : public ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
304 {
306
307 explicit InvokeHelper(TCallback callback) throw()
308 : callback_(callback)
309 {}
310
311 STDMETHOD(Invoke)(typename Traits::Arg1Type arg1)
312 {
314 }
315 TCallback callback_;
316 };
317
318 template <typename TDelegateInterface, typename TCallback>
319 struct InvokeHelper<TDelegateInterface, TCallback, 2> WrlSealed
320 : public ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
321 {
323
324 explicit InvokeHelper(TCallback callback) throw()
325 : callback_(callback)
326 {}
327
328 STDMETHOD(Invoke)(typename Traits::Arg1Type arg1, typename Traits::Arg2Type arg2)
329 {
330 return DelegateTraits<DefaultDelegateCheckMode>::CheckReturn(callback_(arg1, arg2));
331 }
332 TCallback callback_;
333 };
334
335 template <typename TDelegateInterface, typename TCallback>
336 struct InvokeHelper<TDelegateInterface, TCallback, 3> WrlSealed
337 : public ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
338 {
340
341 explicit InvokeHelper(TCallback callback) throw()
342 : callback_(callback)
343 {}
344
345 STDMETHOD(Invoke)
346 (typename Traits::Arg1Type arg1, typename Traits::Arg2Type arg2, typename Traits::Arg3Type arg3)
347 {
348 return DelegateTraits<DefaultDelegateCheckMode>::CheckReturn(callback_(arg1, arg2, arg3));
349 }
350 TCallback callback_;
351 };
352
353 template <typename TDelegateInterface, typename TCallback>
354 struct InvokeHelper<TDelegateInterface, TCallback, 4> WrlSealed
355 : ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
356 {
358
359 explicit InvokeHelper(TCallback callback) throw()
360 : callback_(callback)
361 {}
362
363 STDMETHOD(Invoke)
364 (typename Traits::Arg1Type arg1,
365 typename Traits::Arg2Type arg2,
366 typename Traits::Arg3Type arg3,
367 typename Traits::Arg4Type arg4)
368 {
369 return DelegateTraits<DefaultDelegateCheckMode>::CheckReturn(callback_(arg1, arg2, arg3, arg4));
370 }
371 TCallback callback_;
372 };
373
374 template <typename TDelegateInterface, typename TCallback>
375 struct InvokeHelper<TDelegateInterface, TCallback, 5> WrlSealed
376 : ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
377 {
379
380 explicit InvokeHelper(TCallback callback) throw()
381 : callback_(callback)
382 {}
383
384 STDMETHOD(Invoke)
385 (typename Traits::Arg1Type arg1,
386 typename Traits::Arg2Type arg2,
387 typename Traits::Arg3Type arg3,
388 typename Traits::Arg4Type arg4,
389 typename Traits::Arg5Type arg5)
390 {
392 callback_(arg1, arg2, arg3, arg4, arg5));
393 }
394 TCallback callback_;
395 };
396
397 template <typename TDelegateInterface, typename TCallback>
398 struct InvokeHelper<TDelegateInterface, TCallback, 6> WrlSealed
399 : ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
400 {
402
403 explicit InvokeHelper(TCallback callback) throw()
404 : callback_(callback)
405 {}
406
407 STDMETHOD(Invoke)
408 (typename Traits::Arg1Type arg1,
409 typename Traits::Arg2Type arg2,
410 typename Traits::Arg3Type arg3,
411 typename Traits::Arg4Type arg4,
412 typename Traits::Arg5Type arg5,
413 typename Traits::Arg6Type arg6)
414 {
416 callback_(arg1, arg2, arg3, arg4, arg5, arg6));
417 }
418 TCallback callback_;
419 };
420
421 template <typename TDelegateInterface, typename TCallback>
422 struct InvokeHelper<TDelegateInterface, TCallback, 7> WrlSealed
423 : ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
424 {
426
427 explicit InvokeHelper(TCallback callback) throw()
428 : callback_(callback)
429 {}
430
431 STDMETHOD(Invoke)
432 (typename Traits::Arg1Type arg1,
433 typename Traits::Arg2Type arg2,
434 typename Traits::Arg3Type arg3,
435 typename Traits::Arg4Type arg4,
436 typename Traits::Arg5Type arg5,
437 typename Traits::Arg6Type arg6,
438 typename Traits::Arg7Type arg7)
439 {
441 callback_(arg1, arg2, arg3, arg4, arg5, arg6, arg7));
442 }
443 TCallback callback_;
444 };
445
446 template <typename TDelegateInterface, typename TCallback>
447 struct InvokeHelper<TDelegateInterface, TCallback, 8> WrlSealed
448 : ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
449 {
451
452 explicit InvokeHelper(TCallback callback) throw()
453 : callback_(callback)
454 {}
455
456 STDMETHOD(Invoke)
457 (typename Traits::Arg1Type arg1,
458 typename Traits::Arg2Type arg2,
459 typename Traits::Arg3Type arg3,
460 typename Traits::Arg4Type arg4,
461 typename Traits::Arg5Type arg5,
462 typename Traits::Arg6Type arg6,
463 typename Traits::Arg7Type arg7,
464 typename Traits::Arg8Type arg8)
465 {
467 callback_(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
468 }
469 TCallback callback_;
470 };
471
472 template <typename TDelegateInterface, typename TCallback>
473 struct InvokeHelper<TDelegateInterface, TCallback, 9> WrlSealed
474 : ::Microsoft::WRL::RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
475 {
477
478 explicit InvokeHelper(TCallback callback) throw()
479 : callback_(callback)
480 {}
481
482 STDMETHOD(Invoke)
483 (typename Traits::Arg1Type arg1,
484 typename Traits::Arg2Type arg2,
485 typename Traits::Arg3Type arg3,
486 typename Traits::Arg4Type arg4,
487 typename Traits::Arg5Type arg5,
488 typename Traits::Arg6Type arg6,
489 typename Traits::Arg7Type arg7,
490 typename Traits::Arg8Type arg8,
491 typename Traits::Arg9Type arg9)
492 {
494 callback_(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9));
495 }
496 TCallback callback_;
497 };
498
499#ifdef NUI_WRL_AGILE_INVOKE
500 template <typename TDelegateInterface, unsigned int argCount>
501 struct AgileInvokeHelper;
502
503 template <typename TDelegateInterface>
504 struct AgileInvokeHelper<TDelegateInterface, 0>
506 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
507 TDelegateInterface,
508 Microsoft::WRL::FtmBase>
509 {
511
512 public:
513 HRESULT Initialize(_In_ TDelegateInterface* delegateInterface)
514 {
515 return Microsoft::WRL::AsAgile(delegateInterface, &_agileptr);
516 }
517
518 virtual HRESULT STDMETHODCALLTYPE Invoke()
519 {
520 ComPtr<TDelegateInterface> localDelegate;
521
522 HRESULT hr = _agileptr.CopyTo(localDelegate.GetAddressOf());
523 if (SUCCEEDED(hr))
524 {
525 hr = localDelegate->Invoke();
526 }
527 return hr;
528 }
529
530 private:
531 AgileRef _agileptr;
532 };
533
534 template <typename TDelegateInterface>
535 struct AgileInvokeHelper<TDelegateInterface, 1>
537 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
538 TDelegateInterface,
539 Microsoft::WRL::FtmBase>
540 {
542
543 public:
544 HRESULT Initialize(_In_ TDelegateInterface* delegateInterface)
545 {
546 return Microsoft::WRL::AsAgile(delegateInterface, &_agileptr);
547 }
548
549 virtual HRESULT STDMETHODCALLTYPE Invoke(typename Traits::Arg1Type arg1)
550 {
551 ComPtr<TDelegateInterface> localDelegate;
552
553 HRESULT hr = _agileptr.CopyTo(localDelegate.GetAddressOf());
554 if (SUCCEEDED(hr))
555 {
556 hr = localDelegate->Invoke(arg1);
557 }
558 return hr;
559 }
560
561 private:
562 AgileRef _agileptr;
563 };
564
565 template <typename TDelegateInterface>
566 struct AgileInvokeHelper<TDelegateInterface, 2>
568 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
569 TDelegateInterface,
570 Microsoft::WRL::FtmBase>
571 {
573
574 public:
575 HRESULT Initialize(_In_ TDelegateInterface* delegateInterface)
576 {
577 return Microsoft::WRL::AsAgile(delegateInterface, &_agileptr);
578 }
579
580 virtual HRESULT STDMETHODCALLTYPE Invoke(typename Traits::Arg1Type arg1, typename Traits::Arg2Type arg2)
581 {
582 ComPtr<TDelegateInterface> localDelegate;
583
584 HRESULT hr = _agileptr.CopyTo(localDelegate.GetAddressOf());
585 if (SUCCEEDED(hr))
586 {
587 hr = localDelegate->Invoke(arg1, arg2);
588 }
589 return hr;
590 }
591
592 private:
593 AgileRef _agileptr;
594 };
595
596 template <typename TDelegateInterface>
597 struct AgileInvokeHelper<TDelegateInterface, 3>
599 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
600 TDelegateInterface,
601 Microsoft::WRL::FtmBase>
602 {
604
605 public:
606 HRESULT Initialize(_In_ TDelegateInterface* delegateInterface)
607 {
608 return Microsoft::WRL::AsAgile(delegateInterface, &_agileptr);
609 }
610
611 virtual HRESULT STDMETHODCALLTYPE
612 Invoke(typename Traits::Arg1Type arg1, typename Traits::Arg2Type arg2, typename Traits::Arg3Type arg3)
613 {
614 ComPtr<TDelegateInterface> localDelegate;
615
616 HRESULT hr = _agileptr.CopyTo(localDelegate.GetAddressOf());
617 if (SUCCEEDED(hr))
618 {
619 hr = localDelegate->Invoke(arg1, arg2, arg3);
620 }
621 return hr;
622 }
623
624 private:
625 AgileRef _agileptr;
626 };
627
628 template <typename TDelegateInterface>
629 HRESULT
630 CreateAgileHelper(_In_ TDelegateInterface* delegateInterface, _COM_Outptr_ TDelegateInterface** wrapper)
631 {
632 *wrapper = nullptr;
633 ComPtr<AgileInvokeHelper<
634 TDelegateInterface,
636 invokeHelper;
637
638 static_assert(
639 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
640 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
641
642 invokeHelper = Make<AgileInvokeHelper<
643 TDelegateInterface,
645 HRESULT hr = invokeHelper ? S_OK : E_OUTOFMEMORY;
646 if (SUCCEEDED(hr))
647 {
648 hr = invokeHelper->Initialize(delegateInterface);
649 if (SUCCEEDED(hr))
650 {
651 hr = invokeHelper.CopyTo(wrapper);
652 }
653 }
654 return hr;
655 }
656
657#endif // NUI_WRL_AGILE_INVOKE
658
659 } // namespace Details
660
661 // Implementation of Callback helper that wire delegate interfaces
662 // and provide object implementation for Invoke method
663 // Specialization for lambda, function pointer and functor
664 template <typename TDelegateInterface, typename TCallback>
666 {
667 static_assert(
668 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
669 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
670
671 return Make<
672 Details::
673 InvokeHelper<TDelegateInterface, TCallback, Details::ArgTraitsHelper<TDelegateInterface>::args>>(
674 callback);
675 }
676
677 // Specialization for pointer to the method
678 template <typename TDelegateInterface, typename TCallbackObject>
679 ComPtr<typename Details::ArgTraitsHelper<TDelegateInterface>::Interface>
680 Callback(_In_ TCallbackObject* object, _In_ HRESULT (TCallbackObject::*method)()) throw()
681 {
682 static_assert(
683 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
684 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
685 static_assert(
687 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
688
689 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<ClassicCom>, TDelegateInterface>
690 {
691 ComObject(TCallbackObject* object, HRESULT (TCallbackObject::*method)()) throw()
692 : object_(object)
693 , method_(method)
694 {}
695
696 STDMETHOD(Invoke)()
697 {
698 return (object_->*method_)();
699 }
700
701 TCallbackObject* object_;
702 HRESULT (TCallbackObject::*method_)();
703 };
704
705 return Make<ComObject>(object, method);
706 }
707
708 template <typename TDelegateInterface, typename TCallbackObject, typename TArg1>
709 ComPtr<typename Details::ArgTraitsHelper<TDelegateInterface>::Interface>
710 Callback(_In_ TCallbackObject* object, _In_ HRESULT (TCallbackObject::*method)(TArg1)) throw()
711 {
712 static_assert(
713 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
714 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
715 static_assert(
717 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
718 static_assert(
720 "Argument 1 from object method doesn't match Invoke argument 1");
721
722 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
723 {
724 ComObject(TCallbackObject* object, HRESULT (TCallbackObject::*method)(TArg1)) throw()
725 : object_(object)
726 , method_(method)
727 {}
728
729 STDMETHOD(Invoke)(TArg1 arg1)
730 {
731 return (object_->*method_)(arg1);
732 }
733
734 TCallbackObject* object_;
735 HRESULT (TCallbackObject::*method_)(TArg1);
736 };
737
738 return Make<ComObject>(object, method);
739 }
740
741 template <typename TDelegateInterface, typename TCallbackObject, typename TArg1, typename TArg2>
742 ComPtr<typename Details::ArgTraitsHelper<TDelegateInterface>::Interface>
743 Callback(_In_ TCallbackObject* object, _In_ HRESULT (TCallbackObject::*method)(TArg1, TArg2)) throw()
744 {
745 static_assert(
746 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
747 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
748 static_assert(
750 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
751 static_assert(
753 "Argument 1 from object method doesn't match Invoke argument 1");
754 static_assert(
756 "Argument 2 from object method doesn't match Invoke argument 2");
757
758 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
759 {
760 ComObject(TCallbackObject* object, HRESULT (TCallbackObject::*method)(TArg1, TArg2)) throw()
761 : object_(object)
762 , method_(method)
763 {}
764
765 STDMETHOD(Invoke)(TArg1 arg1, TArg2 arg2)
766 {
767 return (object_->*method_)(arg1, arg2);
768 }
769
770 TCallbackObject* object_;
771 HRESULT (TCallbackObject::*method_)(TArg1, TArg2);
772 };
773
774 return Make<ComObject>(object, method);
775 }
776
777 template <typename TDelegateInterface, typename TCallbackObject, typename TArg1, typename TArg2, typename TArg3>
778 ComPtr<typename Details::ArgTraitsHelper<TDelegateInterface>::Interface>
779 Callback(_In_ TCallbackObject* object, _In_ HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3)) throw()
780 {
781 static_assert(
782 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
783 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
784 static_assert(
786 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
787 static_assert(
789 "Argument 1 from object method doesn't match Invoke argument 1");
790 static_assert(
792 "Argument 2 from object method doesn't match Invoke argument 2");
793 static_assert(
795 "Argument 3 from object method doesn't match Invoke argument 3");
796
797 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
798 {
799 ComObject(TCallbackObject* object, HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3)) throw()
800 : object_(object)
801 , method_(method)
802 {}
803
804 STDMETHOD(Invoke)(TArg1 arg1, TArg2 arg2, TArg3 arg3)
805 {
806 return (object_->*method_)(arg1, arg2, arg3);
807 }
808
809 TCallbackObject* object_;
810 HRESULT (TCallbackObject::*method_)(TArg1, TArg2, TArg3);
811 };
812
813 return Make<ComObject>(object, method);
814 }
815
816 template <
817 typename TDelegateInterface,
818 typename TCallbackObject,
819 typename TArg1,
820 typename TArg2,
821 typename TArg3,
822 typename TArg4>
824 _In_ TCallbackObject* object,
825 _In_ HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4)) throw()
826 {
827 static_assert(
828 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
829 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
830 static_assert(
832 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
833 static_assert(
835 "Argument 1 from object method doesn't match Invoke argument 1");
836 static_assert(
838 "Argument 2 from object method doesn't match Invoke argument 2");
839 static_assert(
841 "Argument 3 from object method doesn't match Invoke argument 3");
842 static_assert(
844 "Argument 4 from object method doesn't match Invoke argument 4");
845
846 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
847 {
848 ComObject(
849 TCallbackObject* object,
850 HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4)) throw()
851 : object_(object)
852 , method_(method)
853 {}
854
855 STDMETHOD(Invoke)(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
856 {
857 return (object_->*method_)(arg1, arg2, arg3, arg4);
858 }
859
860 TCallbackObject* object_;
861 HRESULT (TCallbackObject::*method_)(TArg1, TArg2, TArg3, TArg4);
862 };
863
864 return Make<ComObject>(object, method);
865 }
866
867 template <
868 typename TDelegateInterface,
869 typename TCallbackObject,
870 typename TArg1,
871 typename TArg2,
872 typename TArg3,
873 typename TArg4,
874 typename TArg5>
876 _In_ TCallbackObject* object,
877 _In_ HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5)) throw()
878 {
879 static_assert(
880 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
881 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
882 static_assert(
884 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
885 static_assert(
887 "Argument 1 from object method doesn't match Invoke argument 1");
888 static_assert(
890 "Argument 2 from object method doesn't match Invoke argument 2");
891 static_assert(
893 "Argument 3 from object method doesn't match Invoke argument 3");
894 static_assert(
896 "Argument 4 from object method doesn't match Invoke argument 4");
897 static_assert(
899 "Argument 5 from object method doesn't match Invoke argument 5");
900
901 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
902 {
903 ComObject(
904 TCallbackObject* object,
905 HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5)) throw()
906 : object_(object)
907 , method_(method)
908 {}
909
910 STDMETHOD(Invoke)(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
911 {
912 return (object_->*method_)(arg1, arg2, arg3, arg4, arg5);
913 }
914
915 TCallbackObject* object_;
916 HRESULT (TCallbackObject::*method_)(TArg1, TArg2, TArg3, TArg4, TArg5);
917 };
918
919 return Make<ComObject>(object, method);
920 }
921
922 template <
923 typename TDelegateInterface,
924 typename TCallbackObject,
925 typename TArg1,
926 typename TArg2,
927 typename TArg3,
928 typename TArg4,
929 typename TArg5,
930 typename TArg6>
932 _In_ TCallbackObject* object,
933 _In_ HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6)) throw()
934 {
935 static_assert(
936 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
937 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
938 static_assert(
940 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
941 static_assert(
943 "Argument 1 from object method doesn't match Invoke argument 1");
944 static_assert(
946 "Argument 2 from object method doesn't match Invoke argument 2");
947 static_assert(
949 "Argument 3 from object method doesn't match Invoke argument 3");
950 static_assert(
952 "Argument 4 from object method doesn't match Invoke argument 4");
953 static_assert(
955 "Argument 5 from object method doesn't match Invoke argument 5");
956 static_assert(
958 "Argument 6 from object method doesn't match Invoke argument 6");
959
960 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
961 {
962 ComObject(
963 TCallbackObject* object,
964 HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6)) throw()
965 : object_(object)
966 , method_(method)
967 {}
968
969 STDMETHOD(Invoke)(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6)
970 {
971 return (object_->*method_)(arg1, arg2, arg3, arg4, arg5, arg6);
972 }
973
974 TCallbackObject* object_;
975 HRESULT (TCallbackObject::*method_)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6);
976 };
977
978 return Make<ComObject>(object, method);
979 }
980
981 template <
982 typename TDelegateInterface,
983 typename TCallbackObject,
984 typename TArg1,
985 typename TArg2,
986 typename TArg3,
987 typename TArg4,
988 typename TArg5,
989 typename TArg6,
990 typename TArg7>
992 _In_ TCallbackObject* object,
993 _In_ HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7)) throw()
994 {
995 static_assert(
996 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
997 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
998 static_assert(
1000 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
1001 static_assert(
1003 "Argument 1 from object method doesn't match Invoke argument 1");
1004 static_assert(
1006 "Argument 2 from object method doesn't match Invoke argument 2");
1007 static_assert(
1009 "Argument 3 from object method doesn't match Invoke argument 3");
1010 static_assert(
1012 "Argument 4 from object method doesn't match Invoke argument 4");
1013 static_assert(
1015 "Argument 5 from object method doesn't match Invoke argument 5");
1016 static_assert(
1018 "Argument 6 from object method doesn't match Invoke argument 6");
1019 static_assert(
1021 "Argument 7 from object method doesn't match Invoke argument 7");
1022
1023 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
1024 {
1025 ComObject(
1026 TCallbackObject* object,
1027 HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7)) throw()
1028 : object_(object)
1029 , method_(method)
1030 {}
1031
1032 STDMETHOD(Invoke)(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7)
1033 {
1034 return (object_->*method_)(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1035 }
1036
1037 TCallbackObject* object_;
1038 HRESULT (TCallbackObject::*method_)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7);
1039 };
1040
1041 return Make<ComObject>(object, method);
1042 }
1043
1044 template <
1045 typename TDelegateInterface,
1046 typename TCallbackObject,
1047 typename TArg1,
1048 typename TArg2,
1049 typename TArg3,
1050 typename TArg4,
1051 typename TArg5,
1052 typename TArg6,
1053 typename TArg7,
1054 typename TArg8>
1056 _In_ TCallbackObject* object,
1057 _In_ HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8)) throw()
1058 {
1059 static_assert(
1060 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
1061 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
1062 static_assert(
1064 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
1065 static_assert(
1067 "Argument 1 from object method doesn't match Invoke argument 1");
1068 static_assert(
1070 "Argument 2 from object method doesn't match Invoke argument 2");
1071 static_assert(
1073 "Argument 3 from object method doesn't match Invoke argument 3");
1074 static_assert(
1076 "Argument 4 from object method doesn't match Invoke argument 4");
1077 static_assert(
1079 "Argument 5 from object method doesn't match Invoke argument 5");
1080 static_assert(
1082 "Argument 6 from object method doesn't match Invoke argument 6");
1083 static_assert(
1085 "Argument 7 from object method doesn't match Invoke argument 7");
1086 static_assert(
1088 "Argument 8 from object method doesn't match Invoke argument 8");
1089
1090 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
1091 {
1092 ComObject(
1093 TCallbackObject* object,
1094 HRESULT (TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8)) throw()
1095 : object_(object)
1096 , method_(method)
1097 {}
1098
1099 STDMETHOD(Invoke)
1100 (TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8)
1101 {
1102 return (object_->*method_)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
1103 }
1104
1105 TCallbackObject* object_;
1106 HRESULT (TCallbackObject::*method_)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8);
1107 };
1108
1109 return Make<ComObject>(object, method);
1110 }
1111
1112 template <
1113 typename TDelegateInterface,
1114 typename TCallbackObject,
1115 typename TArg1,
1116 typename TArg2,
1117 typename TArg3,
1118 typename TArg4,
1119 typename TArg5,
1120 typename TArg6,
1121 typename TArg7,
1122 typename TArg8,
1123 typename TArg9>
1125 _In_ TCallbackObject* object,
1126 _In_ HRESULT (
1127 TCallbackObject::*method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9)) throw()
1128 {
1129 static_assert(
1130 __is_base_of(IUnknown, TDelegateInterface) && !__is_base_of(IInspectable, TDelegateInterface),
1131 "Delegates objects must be 'IUnknown' base and not 'IInspectable'");
1132 static_assert(
1134 "Number of arguments on object method doesn't match number of arguments on Delegate::Invoke");
1135 static_assert(
1137 "Argument 1 from object method doesn't match Invoke argument 1");
1138 static_assert(
1140 "Argument 2 from object method doesn't match Invoke argument 2");
1141 static_assert(
1143 "Argument 3 from object method doesn't match Invoke argument 3");
1144 static_assert(
1146 "Argument 4 from object method doesn't match Invoke argument 4");
1147 static_assert(
1149 "Argument 5 from object method doesn't match Invoke argument 5");
1150 static_assert(
1152 "Argument 6 from object method doesn't match Invoke argument 6");
1153 static_assert(
1155 "Argument 7 from object method doesn't match Invoke argument 7");
1156 static_assert(
1158 "Argument 8 from object method doesn't match Invoke argument 8");
1159 static_assert(
1161 "Argument 9 from object method doesn't match Invoke argument 9");
1162
1163 struct ComObject WrlSealed : RuntimeClass<RuntimeClassFlags<Delegate>, TDelegateInterface>
1164 {
1165 ComObject(
1166 TCallbackObject* object,
1167 HRESULT (TCallbackObject::*
1168 method)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9)) throw()
1169 : object_(object)
1170 , method_(method)
1171 {}
1172
1173 STDMETHOD(Invoke)
1174 (TArg1 arg1,
1175 TArg2 arg2,
1176 TArg3 arg3,
1177 TArg4 arg4,
1178 TArg5 arg5,
1179 TArg6 arg6,
1180 TArg7 arg7,
1181 TArg8 arg8,
1182 TArg9 arg9)
1183 {
1184 return (object_->*method_)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
1185 }
1186
1187 TCallbackObject* object_;
1188 HRESULT (TCallbackObject::*method_)(TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9);
1189 };
1190
1191 return Make<ComObject>(object, method);
1192 }
1193
1194 namespace Details
1195 {
1196
1197 // EventTargetArray is used to keep array of event targets. This array is fixed-length.
1198 // Every time element is added/removed from array EventSource allocate new array. This array
1199 // is optimize-for-invoke lock strategy in EventSource
1200 class EventTargetArray WrlSealed
1201 : public ::Microsoft::WRL::RuntimeClass<::Microsoft::WRL::RuntimeClassFlags<ClassicCom>, IUnknown>
1202 {
1203 public:
1205 : begin_(nullptr)
1206 , end_(nullptr)
1207 , bucketAssists_(nullptr)
1208 {}
1209
1210 HRESULT RuntimeClassInitialize(size_t items) throw()
1211 {
1212 begin_ = new (std::nothrow) ComPtr<IUnknown>[items];
1213 bucketAssists_ = new (std::nothrow) void*[items];
1214 if (begin_ == nullptr || bucketAssists_ == nullptr)
1215 {
1216 // Don't check against nullptr because delete does it
1217 delete[] begin_;
1218 delete[] bucketAssists_;
1219
1220 // Set member pointers to nullptr so destructor does not try to delete them again
1221 begin_ = nullptr;
1222 bucketAssists_ = nullptr;
1223
1224 return E_OUTOFMEMORY;
1225 }
1226
1227 end_ = begin_;
1228 return S_OK;
1229 }
1230
1232 {
1233 // Don't check against nullptr because delete does it
1234 delete[] begin_;
1235 delete[] bucketAssists_;
1236 }
1237
1239 {
1240 return begin_;
1241 }
1242
1244 {
1245 return end_;
1246 }
1247
1248 void AddTail(_In_ IUnknown* element) throw()
1249 {
1250 AddTail(element, nullptr);
1251 }
1252
1253 void AddTail(_In_ IUnknown* element, void* bucketAssist) throw()
1254 {
1255 // We'll run over the end if you call AddTail too many times, but the alternate would be an extra
1256 // variable to keep track of the number of items allocated. This class is only privately used by
1257 // EventSourceBase.
1258 *end_ = element;
1259 *(bucketAssists_ + (end_ - begin_)) = bucketAssist;
1260 end_++;
1261 }
1262
1263 size_t Length() throw()
1264 {
1265 return static_cast<size_t>(end_ - begin_);
1266 }
1267
1269 {
1270 return bucketAssists_;
1271 }
1272
1274 {
1275 return bucketAssists_ + (end_ - begin_);
1276 }
1277
1278 private:
1279 ComPtr<IUnknown>* begin_;
1280 ComPtr<IUnknown>* end_;
1281 void** bucketAssists_;
1282 };
1283
1284 } // namespace Details
1285
1286 template <>
1288 {
1289 template <typename TInvokeMethod, typename TDelegateInterface>
1290 static HRESULT InvokeDelegates(
1291 TInvokeMethod invokeOne,
1292 Details::EventTargetArray* targetArray,
1293 EventSource<TDelegateInterface, InvokeModeOptions<FireAll>>* pEvent)
1294 {
1296 targets = targetArray;
1297
1298 for (auto element = targets->Begin(); element != targets->End(); element++)
1299 {
1300 HRESULT hr = (invokeOne)(*element);
1301 if (FAILED(hr))
1302 {
1303 // ::RoTransformError(hr, S_OK, nullptr);
1304 // Remove event that is already disconnected
1305 if (hr == RPC_E_DISCONNECTED || hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) ||
1306 hr == static_cast<HRESULT>(JSCRIPT_E_CANTEXECUTE))
1307 {
1309 token.value = reinterpret_cast<__int64>(element->Get());
1310 pEvent->Remove(token);
1311 }
1312 }
1313 }
1314 return S_OK;
1315 }
1316 };
1317
1318 template <>
1320 {
1321 template <typename TInvokeMethod, typename TDelegateInterface>
1322 static HRESULT InvokeDelegates(
1323 TInvokeMethod invokeOne,
1324 Details::EventTargetArray* targetArray,
1325 EventSource<TDelegateInterface, InvokeModeOptions<StopOnFirstError>>* pEvent)
1326 {
1327 HRESULT hr = S_OK;
1329 targets = targetArray;
1330
1331 for (auto element = targets->Begin(); element != targets->End(); element++)
1332 {
1333 hr = (invokeOne)(*element);
1334 // Remove event that is already disconnected
1335 if (hr == RPC_E_DISCONNECTED || hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) ||
1336 hr == static_cast<HRESULT>(JSCRIPT_E_CANTEXECUTE))
1337 {
1338 // if we get the above errors, treat it as success and unregister the delegate
1339 //::RoTransformError(hr, S_OK, nullptr);
1341 token.value = reinterpret_cast<__int64>(element->Get());
1342 pEvent->Remove(token);
1343 hr = S_OK;
1344 }
1345 if (FAILED(hr))
1346 {
1347 // break out of the loop on the first unhandled error
1348 break;
1349 }
1350 }
1351 return hr;
1352 }
1353 };
1354
1355#if (defined(BUILD_WINDOWS) && (NTDDI_VERSION >= NTDDI_WINBLUE))
1356 template <
1357 typename TDelegateInterface,
1358 typename TEventSourceOptions = InvokeModeOptions<ReportUnhandledOnFirstErrorWithWin8Quirk>>
1359#else
1360 template <typename TDelegateInterface, typename TEventSourceOptions = InvokeModeOptions<FireAll>>
1361#endif // (defined(BUILD_WINDOWS) && (NTDDI_VERSION >= NTDDI_WINBLUE))
1363 {
1364 public:
1365 EventSource() throw()
1366 : targets_(nullptr)
1367 {}
1368
1369 HRESULT Add(_In_opt_ TDelegateInterface* delegateInterface, _Out_ EventRegistrationToken* token) throw()
1370 {
1371 // Make sure that delegate interface pointer is not null
1372 if (delegateInterface == nullptr)
1373 {
1374 return E_INVALIDARG;
1375 }
1376
1377 return AddInternal(
1378 delegateInterface, Microsoft::WRL::Details::GetDelegateBucketAssist(delegateInterface), token);
1379 }
1380
1381 HRESULT Remove(EventRegistrationToken token) throw()
1382 {
1383 // Used for deleting the current array without holding the addRemoveLock.
1385 { // lock scope for addRemoveLock_
1386 // The addRemoveLock_ prevents multiple threads from doing simultaneous adds/removes.
1387 // An invoke may be occurring during an add or remove operation.
1389
1390 if (targets_ == nullptr)
1391 {
1392 return S_OK; // List is currently empty - thus token wasn't found, just return
1393 }
1394
1396 size_t availableSlots = targets_->Length() - 1;
1397 bool removed = false;
1398 // If one element in the array
1399 if (availableSlots == 0)
1400 {
1401 if (reinterpret_cast<__int64>(targets_->Begin()->Get()) == token.value)
1402 {
1403 removed = true;
1404 }
1405 }
1406 else
1407 {
1408 // Instantiate EventTargetArray
1409 HRESULT hr =
1410 MakeAndInitialize<Details::EventTargetArray>(pNewList.GetAddressOf(), availableSlots);
1411 if (FAILED(hr))
1412 {
1413 return hr;
1414 }
1415
1416 void** bucketElement = targets_->Begin_BucketAssists();
1417
1418 for (auto element = targets_->Begin(); element != targets_->End(); element++)
1419 {
1420 if (!removed && token.value == reinterpret_cast<__int64>(element->Get()))
1421 {
1422 removed = true;
1423 continue;
1424 }
1425
1426 // The ComPtr<TDelegateInterface> contained in p is assigned to a
1427 // ComPtr<TDelegateInterface> of a new node in pNewList. The net result is
1428 // an addref on the interface.
1429 if (availableSlots == 0)
1430 {
1431 // We don't have any availableSlots left in the target array, hence every item was
1432 // copied from the source array. This means we didn't find the item in the list - just
1433 // return.
1435 !removed && "Attempt to remove token that was not added to this EventSource<>");
1436 break;
1437 }
1438
1439 // Copy every registrant from old list except the item being removed
1440 // The ComPtr<TDelegateInterface> contained in p is assigned to a
1441 // ComPtr<TDelegateInterface> of a new node in pNewList. The net result is
1442 // an addref on the interface.
1443 pNewList->AddTail(element->Get(), *bucketElement);
1444 bucketElement++;
1445 availableSlots--;
1446 }
1447 }
1448
1449 if (removed)
1450 {
1451 // lock scope for targetsPointerLock
1452 // The targetsPointerLock_ protects the exchanging of the new list (with the removal)
1453 // for the old list (which could be used currently for firing events)
1455
1456 // We move targets_ to pTempList so that we can actually delete the list while
1457 // not holding any locks. The InvokeAll method may still have a reference to targets_ so
1458 // even when pTempList releases, this might not delete what was in targets_.
1459 pTempList = Details::Move(targets_);
1460
1461 // We still have some items left inside pNewList, so move it to targets_.
1462 targets_ = Details::Move(pNewList);
1463
1464 // If we don't have any items added, the Details::Move(targets_) above already set targets_ to
1465 // nullptr. The result is that now when pTempList destructs, it will cause what used to be
1466 // targets_ to be freed.
1467
1468 } // end lock scope for targetsPointerLock
1469
1470 } // end lock scope for addRemoveLock
1471
1472 // Destroys pTempList here (this is the old targets_)
1473
1474 return S_OK;
1475 }
1476
1477 protected:
1478 HRESULT
1479 Add(_In_opt_ TDelegateInterface* delegateInterface,
1480 _In_opt_ void* bucketAssist,
1481 _Out_ EventRegistrationToken* token) throw()
1482 {
1483 // Make sure that delegate interface pointer is not null
1484 if (delegateInterface == nullptr)
1485 {
1486 return E_INVALIDARG;
1487 }
1488
1489 return AddInternal(delegateInterface, bucketAssist, token);
1490 }
1491
1492 private:
1493 HRESULT AddInternal(
1494 _In_ TDelegateInterface* delegateInterface,
1495 _In_opt_ void* bucketAssist,
1496 _Out_ EventRegistrationToken* token) throw()
1497 {
1498 // Clear token value
1499 token->value = 0;
1500
1501 // This must be defined outside of the scope where the addRemoveLock is taken to ensure that it's
1502 // destructor is called after the lock is released
1504
1505 { // lock scope for addRemoveLock
1506 // We are doing "copy to new list and add" so as not to disturb the list that may be
1507 // currently undergoing a walk and fire (invoke).
1508
1509 // The addRemoveLock_ prevents multiple threads from doing simultaneous adds.
1510 // An invoke may be occurring during an add or remove operation.
1512
1514
1515 // Allocate event array
1516 HRESULT hr = MakeAndInitialize<Details::EventTargetArray>(
1517 pNewList.GetAddressOf(), targets_ == nullptr ? 1 : targets_->Length() + 1);
1518 // Make sure allocation succeeded
1519 if (FAILED(hr))
1520 {
1521 return hr;
1522 }
1523
1524 // The list may not exist if nobody has registered
1525 if (targets_)
1526 {
1527 void** bucketElement = targets_->Begin_BucketAssists();
1528 for (auto element = targets_->Begin(); element != targets_->End(); element++)
1529 {
1530 // The ComPtr<TDelegateInterface> contained in the current targets_ node
1531 // is assigned to a ComPtr<TDelegateInterface> of a new node in pNewList
1532 // the net result is an addref on the interface.
1533
1534 pNewList->AddTail(element->Get(), *bucketElement);
1535 bucketElement++;
1536 }
1537 }
1538
1539 // Get unique token value
1540 token->value = reinterpret_cast<__int64>(delegateInterface);
1541
1542 // AddTail operation will take a reference which will result in
1543 // this function adding one reference count on delegateInterface.
1544 pNewList->AddTail(delegateInterface, bucketAssist);
1545
1546 {
1547 // lock scope for targetsPointerLock
1548 // The targetsPointerLock_ protects the exchanging of the new list (with the addition)
1549 // for the old list (which could be used currently for firing events)
1551
1552 // We move targets_ to pTempList so that we can actually delete the list while
1553 // not holding any locks. The InvokeAll method may still have a reference to targets_ so
1554 // even when pTempList releases, this might not delete what was in targets_.
1555 pTempList = Details::Move(targets_);
1556
1557 // We're done with pNewList, so just move it to targets_.
1558 targets_ = Details::Move(pNewList);
1559
1560 } // end lock scope for targetsPointerLock
1561 } // end lock scope for addRemoveLock
1562
1563 // Destroys pTempList here (this is the old targets_)
1564
1565 return S_OK;
1566 }
1567
1568 // TInvokeMethod is a functor that performs the appropriate invoke, depending on the
1569 // number of arguments specified.
1570 template <typename TInvokeMethod>
1571 _Check_return_ HRESULT DoInvoke(TInvokeMethod invokeOne) throw()
1572 {
1573 HRESULT hr = S_OK;
1574 // The targetsPointerLock_ protects the acquisition of an AddRef'd pointer to
1575 // "current list". An Add/Remove operation may occur during the
1576 // firing of events (but occurs on a copy of the list). i.e. both
1577 // InvokeAll/invoke and Add/Remove are readers of the "current list".
1578 // NOTE: EventSource<TDelegateInterface>::InvokeAll(...) must never take the addRemoveLock_.
1579 ComPtr<Details::EventTargetArray> targets;
1580
1581 // Scoping for lock
1582 {
1584 targets = targets_;
1585 }
1586
1587 // The list may not exist if nobody has registered
1588 if (targets)
1589 {
1590 hr = InvokeTraits<TEventSourceOptions::invokeMode>::InvokeDelegates(invokeOne, targets.Get(), this);
1591 }
1592 return hr;
1593 }
1594
1595 public:
1596 _Check_return_ HRESULT InvokeAll() throw()
1597 {
1598 return DoInvoke([](ComPtr<IUnknown>& p) -> HRESULT {
1599 return static_cast<TDelegateInterface*>(p.Get())->Invoke();
1600 });
1601 }
1602
1603 template <typename T0>
1604 _Check_return_ HRESULT InvokeAll(T0 arg0) throw()
1605 {
1606 return DoInvoke([arg0](ComPtr<IUnknown>& p) -> HRESULT {
1607 return static_cast<TDelegateInterface*>(p.Get())->Invoke(arg0);
1608 });
1609 }
1610
1611 template <typename T0, typename T1>
1612 _Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1) throw()
1613 {
1614 return DoInvoke([arg0, arg1](ComPtr<IUnknown>& p) -> HRESULT {
1615 return static_cast<TDelegateInterface*>(p.Get())->Invoke(arg0, arg1);
1616 });
1617 }
1618
1619 template <typename T0, typename T1, typename T2>
1620 _Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2) throw()
1621 {
1622 return DoInvoke([arg0, arg1, arg2](ComPtr<IUnknown>& p) -> HRESULT {
1623 return static_cast<TDelegateInterface*>(p.Get())->Invoke(arg0, arg1, arg2);
1624 });
1625 }
1626
1627 template <typename T0, typename T1, typename T2, typename T3>
1628 _Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3) throw()
1629 {
1630 return DoInvoke([arg0, arg1, arg2, arg3](ComPtr<IUnknown>& p) -> HRESULT {
1631 return static_cast<TDelegateInterface*>(p.Get())->Invoke(arg0, arg1, arg2, arg3);
1632 });
1633 }
1634
1635 template <typename T0, typename T1, typename T2, typename T3, typename T4>
1636 _Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) throw()
1637 {
1638 return DoInvoke([arg0, arg1, arg2, arg3, arg4](ComPtr<IUnknown>& p) -> HRESULT {
1639 return static_cast<TDelegateInterface*>(p.Get())->Invoke(arg0, arg1, arg2, arg3, arg4);
1640 });
1641 }
1642
1643 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
1644 _Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) throw()
1645 {
1646 return DoInvoke([arg0, arg1, arg2, arg3, arg4, arg5](ComPtr<IUnknown>& p) -> HRESULT {
1647 return static_cast<TDelegateInterface*>(p.Get())->Invoke(arg0, arg1, arg2, arg3, arg4, arg5);
1648 });
1649 }
1650
1651 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
1652 _Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) throw()
1653 {
1654 return DoInvoke([arg0, arg1, arg2, arg3, arg4, arg5, arg6](ComPtr<IUnknown>& p) -> HRESULT {
1655 return static_cast<TDelegateInterface*>(p.Get())->Invoke(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
1656 });
1657 }
1658
1659 template <
1660 typename T0,
1661 typename T1,
1662 typename T2,
1663 typename T3,
1664 typename T4,
1665 typename T5,
1666 typename T6,
1667 typename T7>
1668 _Check_return_ HRESULT
1669 InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) throw()
1670 {
1671 return DoInvoke([arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7](ComPtr<IUnknown>& p) -> HRESULT {
1672 return static_cast<TDelegateInterface*>(p.Get())->Invoke(
1673 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1674 });
1675 }
1676
1677 template <
1678 typename T0,
1679 typename T1,
1680 typename T2,
1681 typename T3,
1682 typename T4,
1683 typename T5,
1684 typename T6,
1685 typename T7,
1686 typename T8>
1687 _Check_return_ HRESULT
1688 InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) throw()
1689 {
1690 return DoInvoke([arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8](ComPtr<IUnknown>& p) -> HRESULT {
1691 return static_cast<TDelegateInterface*>(p.Get())->Invoke(
1692 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
1693 });
1694 }
1695
1696 template <
1697 typename T0,
1698 typename T1,
1699 typename T2,
1700 typename T3,
1701 typename T4,
1702 typename T5,
1703 typename T6,
1704 typename T7,
1705 typename T8,
1706 typename T9>
1707 _Check_return_ HRESULT
1708 InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) throw()
1709 {
1710 return DoInvoke(
1711 [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9](ComPtr<IUnknown>& p) -> HRESULT {
1712 return static_cast<TDelegateInterface*>(p.Get())->Invoke(
1713 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
1714 });
1715 }
1716
1717 size_t GetSize() const throw()
1718 {
1719 return targets_ == nullptr ? 0 : targets_->Length();
1720 }
1721
1722 protected:
1726 };
1727
1728#ifdef __windows2Efoundation_h__
1729
1730 template <typename TEventArgsInterface, typename TEventArgsClass>
1731 class DeferrableEventArgs : public TEventArgsInterface
1732 {
1733 public:
1734 STDMETHOD(GetDeferral)(_COM_Outptr_ ::ABI::Windows::Foundation::IDeferral** result)
1735 {
1736 *result = nullptr;
1737 auto lockGuard = lock_.LockExclusive();
1738 if (raised_)
1739 {
1740 // Cannot ask for a deferral after the event handler returned.
1741 ::RoOriginateError(E_ILLEGAL_METHOD_CALL, nullptr);
1742 return E_ILLEGAL_METHOD_CALL;
1743 }
1744
1746 HRESULT hr = GetActivationFactory(
1747 Wrappers::HStringReference(RuntimeClass_Windows_Foundation_Deferral).Get(), &factory);
1748 if (FAILED(hr))
1749 {
1750 return hr;
1751 }
1752
1754 auto callback =
1755 Microsoft::WRL::Callback<::ABI::Windows::Foundation::IDeferralCompletedHandler>([lifetime]() {
1756 return lifetime->Complete();
1757 });
1758 if (callback == nullptr)
1759 {
1760 return E_OUTOFMEMORY;
1761 }
1762
1764 hr = factory->Create(callback.Get(), &deferral);
1765 if (FAILED(hr))
1766 {
1767 return hr;
1768 }
1769
1770 completionsRequired_++;
1771 return deferral.CopyTo(result);
1772 }
1773
1774 // InvokeAllFinished() should be called after the event source calls InvokeAll. This will prevent further
1775 // deferrals from being taken, and cause the completion handler to execute if no deferrals were taken.
1776 void InvokeAllFinished()
1777 {
1778 bool invokeNeeded;
1779
1780 // We need to hold a lock while modifying private state, but release it before invoking a completion
1781 // handler.
1782 {
1783 auto lockGuard = lock_.LockExclusive();
1784 raised_ = true;
1785 invokeNeeded = (completionsRequired_ == 0);
1786 }
1787
1788 if (invokeNeeded)
1789 {
1790 static_cast<TEventArgsClass*>(this)->InvokeCompleteHandler();
1791 }
1792 }
1793
1794 private:
1795 _Requires_lock_not_held_(lock_) HRESULT Complete()
1796 {
1797 bool invokeNeeded;
1798
1799 // We need to hold a lock while modifying private state, but release it before invoking a completion
1800 // handler.
1801 {
1802 auto lockGuard = lock_.LockExclusive();
1803 if (completionsRequired_ == 0)
1804 {
1805 // This should never happen since Complete() should only be called by
1806 // Windows.Foundation.Deferral which will only invoke our completion handler once.
1807 ::RoOriginateError(E_ILLEGAL_METHOD_CALL, nullptr);
1808 return E_ILLEGAL_METHOD_CALL;
1809 }
1810 completionsRequired_--;
1811 invokeNeeded = (raised_ && (completionsRequired_ == 0));
1812 }
1813
1814 if (invokeNeeded)
1815 {
1816 static_cast<TEventArgsClass*>(this)->InvokeCompleteHandler();
1817 }
1818
1819 return S_OK;
1820 }
1821
1822 Wrappers::SRWLock lock_;
1823 _Guarded_by_(lock_) bool raised_ = false;
1824 _Guarded_by_(lock_) long completionsRequired_ = 0;
1825 };
1826
1827#endif // __windows2Efoundation_h__
1828
1829#ifdef NUI_WRL_AGILE_INVOKE
1830# if defined(BUILD_WINDOWS)
1831 template <
1832 typename TDelegateInterface,
1833 typename TEventSourceOptions =
1835# else
1836 template <
1837 typename TDelegateInterface,
1838 typename TEventSourceOptions = Microsoft::WRL::InvokeModeOptions<FireAll>>
1839# endif // defined(BUILD_WINDOWS)
1840 class AgileEventSource : public Microsoft::WRL::EventSource<TDelegateInterface, TEventSourceOptions>
1841 {
1842 // defining type 'Super' for other compilers since '__super' is a VC++-specific language extension
1844
1845 public:
1846 HRESULT Add(_In_ TDelegateInterface* delegateInterface, _Out_ EventRegistrationToken* token)
1847 {
1848 if (delegateInterface == nullptr)
1849 {
1850 // We do not want to store a null interface pointer in the event list. This makes the behavior of
1851 // AgileEvent similar to the behavior of Event.
1852 return E_INVALIDARG;
1853 }
1854
1856 HRESULT hr = Details::CreateAgileHelper<TDelegateInterface>(delegateInterface, &agileCallback);
1857 if (SUCCEEDED(hr))
1858 {
1859 hr = Super::Add(
1860 agileCallback.Get(),
1862 token);
1863 }
1864 return hr;
1865 }
1866 };
1867#endif // NUI_WRL_AGILE_INVOKE
1868
1869 }
1870} // namespace ::Microsoft::WRL
1871
1872// Restore packing
1873#pragma pack(pop)
1874
1875#ifdef BUILD_WINDOWS
1876# include <wrl\internalevent.h>
1877#endif
Definition client.h:100
InterfaceType * Get() const
Definition client.h:223
HRESULT CopyTo(InterfaceType **ptr) const
Definition client.h:281
InterfaceType *const * GetAddressOf() const
Definition client.h:243
Definition event.h:1363
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3)
Definition event.h:1628
HRESULT Remove(EventRegistrationToken token)
Definition event.h:1381
HRESULT Add(_In_opt_ TDelegateInterface *delegateInterface, _In_opt_ void *bucketAssist, _Out_ EventRegistrationToken *token)
Definition event.h:1479
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
Definition event.h:1636
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
Definition event.h:1669
Wrappers::SRWLock addRemoveLock_
Definition event.h:1725
Wrappers::SRWLock targetsPointerLock_
Definition event.h:1724
size_t GetSize() const
Definition event.h:1717
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1)
Definition event.h:1612
EventSource()
Definition event.h:1365
_Check_return_ HRESULT InvokeAll(T0 arg0)
Definition event.h:1604
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
Definition event.h:1644
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2)
Definition event.h:1620
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
Definition event.h:1708
ComPtr< Details::EventTargetArray > targets_
Definition event.h:1723
HRESULT Add(_In_opt_ TDelegateInterface *delegateInterface, _Out_ EventRegistrationToken *token)
Definition event.h:1369
_Check_return_ HRESULT InvokeAll()
Definition event.h:1596
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
Definition event.h:1688
_Check_return_ HRESULT InvokeAll(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
Definition event.h:1652
Definition implements.h:2422
Definition corewrappers.h:975
Definition corewrappers.h:708
Details::SyncLockExclusive SyncLockExclusive
Definition corewrappers.h:710
_Acquires_exclusive_lock_ return _Post_same_lock_ return SyncLockExclusive LockExclusive()
Definition corewrappers.h:722
#define WrlSealed
Definition event.h:18
#define __WRL_ASSERT__(cond)
Definition internal.h:13
Definition client.h:369
RemoveReference< T >::Type && Move(_Inout_ T &&arg)
Definition internal.h:95
void * GetDelegateBucketAssist(TDelegateInterface *pDelegate)
Definition event.h:85
__declspec(selectany) const DelegateCheckMode DefaultDelegateCheckMode
InvokeMode
Definition event.h:63
@ FireAll
Definition event.h:65
@ StopOnFirstError
Definition event.h:64
DelegateCheckMode
Definition event.h:44
@ NoCheck
Definition event.h:45
ComPtr< typename Details::ArgTraitsHelper< TDelegateInterface >::Interface > Callback(TCallback callback)
Definition event.h:665
This file has no copyright assigned and is placed in the Public Domain.
Definition client.h:26
Definition client.h:351
constexpr auto JSCRIPT_E_CANTEXECUTE
Definition patch.h:4
Definition eventtoken.h:44
__int64 value
Definition eventtoken.h:45
static HRESULT CheckReturn(HRESULT hr)
Definition event.h:55
Definition event.h:50
ArgTraits< methodType > Traits
Definition event.h:265
decltype(&TDelegateInterface::Invoke) methodType
Definition event.h:264
static const int args
Definition event.h:99
Definition internal.h:66
void ** End_BucketAssists()
Definition event.h:1273
EventTargetArray()
Definition event.h:1204
void AddTail(_In_ IUnknown *element)
Definition event.h:1248
ComPtr< IUnknown > * Begin()
Definition event.h:1238
Traits::Arg1Type Traits::Arg2Type Traits::Arg3Type Traits::Arg4Type Traits::Arg5Type Traits::Arg6Type arg6
Definition event.h:414
Traits::Arg1Type Traits::Arg2Type Traits::Arg3Type Traits::Arg4Type Traits::Arg5Type Traits::Arg6Type Traits::Arg7Type arg7
Definition event.h:439
HRESULT RuntimeClassInitialize(size_t items)
Definition event.h:1210
ArgTraitsHelper< TDelegateInterface >::Traits Traits
Definition event.h:305
void AddTail(_In_ IUnknown *element, void *bucketAssist)
Definition event.h:1253
void ** Begin_BucketAssists()
Definition event.h:1268
ComPtr< IUnknown > * End()
Definition event.h:1243
~EventTargetArray()
Definition event.h:1231
Traits::Arg1Type arg1
Definition event.h:346
InvokeHelper(TCallback callback)
Definition event.h:290
Traits::Arg1Type Traits::Arg2Type Traits::Arg3Type Traits::Arg4Type Traits::Arg5Type Traits::Arg6Type Traits::Arg7Type Traits::Arg8Type arg8
Definition event.h:465
TCallback callback_
Definition event.h:298
size_t Length()
Definition event.h:1263
Traits::Arg1Type Traits::Arg2Type Traits::Arg3Type Traits::Arg4Type Traits::Arg5Type arg5
Definition event.h:390
Traits::Arg1Type Traits::Arg2Type Traits::Arg3Type Traits::Arg4Type Traits::Arg5Type Traits::Arg6Type Traits::Arg7Type Traits::Arg8Type Traits::Arg9Type arg9
Definition event.h:492
Traits::Arg1Type Traits::Arg2Type Traits::Arg3Type Traits::Arg4Type arg4
Definition event.h:368
static const InvokeMode invokeMode
Definition event.h:72
static HRESULT InvokeDelegates(TInvokeMethod invokeOne, Details::EventTargetArray *targetArray, EventSource< TDelegateInterface, InvokeModeOptions< FireAll > > *pEvent)
Definition event.h:1290
static HRESULT InvokeDelegates(TInvokeMethod invokeOne, Details::EventTargetArray *targetArray, EventSource< TDelegateInterface, InvokeModeOptions< StopOnFirstError > > *pEvent)
Definition event.h:1322
Definition event.h:77