VirtualBox

source: vbox/trunk/src/VBox/Main/EventImpl.cpp@ 30553

最後變更 在這個檔案從30553是 30553,由 vboxsync 提交於 15 年 前

Main: console events, sample of veto events use (enabled by default, could be pretty dangerous, report issues into 4975)

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 22.4 KB
 
1/* $Id: EventImpl.cpp 30553 2010-07-01 13:36:06Z vboxsync $ */
2/** @file
3 * VirtualBox COM Event class implementation
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <list>
19#include <map>
20#include <deque>
21
22#include "EventImpl.h"
23#include "AutoCaller.h"
24#include "Logging.h"
25
26#include <iprt/semaphore.h>
27#include <iprt/critsect.h>
28#include <iprt/asm.h>
29
30#include <VBox/com/array.h>
31
32struct VBoxEvent::Data
33{
34 Data()
35 :
36 mType(VBoxEventType_Invalid),
37 mWaitEvent(NIL_RTSEMEVENT),
38 mWaitable(FALSE),
39 mProcessed(FALSE)
40 {}
41 VBoxEventType_T mType;
42 RTSEMEVENT mWaitEvent;
43 BOOL mWaitable;
44 BOOL mProcessed;
45 ComPtr<IEventSource> mSource;
46};
47
48HRESULT VBoxEvent::FinalConstruct()
49{
50 m = new Data;
51 return S_OK;
52}
53
54void VBoxEvent::FinalRelease()
55{
56 if (m)
57 {
58 uninit();
59 delete m;
60 m = 0;
61 }
62}
63
64
65HRESULT VBoxEvent::init(IEventSource *aSource, VBoxEventType_T aType, BOOL aWaitable)
66{
67 HRESULT rc = S_OK;
68
69 AssertReturn(aSource != NULL, E_INVALIDARG);
70
71 AutoInitSpan autoInitSpan(this);
72 AssertReturn(autoInitSpan.isOk(), E_FAIL);
73
74 m->mSource = aSource;
75 m->mType = aType;
76 m->mWaitable = aWaitable;
77 m->mProcessed = !aWaitable;
78
79 do {
80 if (aWaitable)
81 {
82 int vrc = ::RTSemEventCreate (&m->mWaitEvent);
83
84 if (RT_FAILURE(vrc))
85 {
86 AssertFailed ();
87 return setError(E_FAIL,
88 tr("Internal error (%Rrc)"), vrc);
89 }
90 }
91 } while (0);
92
93 /* Confirm a successful initialization */
94 autoInitSpan.setSucceeded();
95
96 return rc;
97}
98
99void VBoxEvent::uninit()
100{
101 if (!m)
102 return;
103
104 m->mProcessed = TRUE;
105 m->mType = VBoxEventType_Invalid;
106 m->mSource.setNull();
107
108 if (m->mWaitEvent != NIL_RTSEMEVENT)
109 {
110 Assert(m->mWaitable);
111 ::RTSemEventDestroy(m->mWaitEvent);
112 m->mWaitEvent = NIL_RTSEMEVENT;
113 }
114}
115
116STDMETHODIMP VBoxEvent::COMGETTER(Type)(VBoxEventType_T *aType)
117{
118 CheckComArgNotNull(aType);
119
120 AutoCaller autoCaller(this);
121 if (FAILED(autoCaller.rc())) return autoCaller.rc();
122
123 // never changes till event alive, no locking?
124 *aType = m->mType;
125 return S_OK;
126}
127
128STDMETHODIMP VBoxEvent::COMGETTER(Source)(IEventSource* *aSource)
129{
130 CheckComArgOutPointerValid(aSource);
131
132 AutoCaller autoCaller(this);
133 if (FAILED(autoCaller.rc())) return autoCaller.rc();
134
135 m->mSource.queryInterfaceTo(aSource);
136 return S_OK;
137}
138
139STDMETHODIMP VBoxEvent::COMGETTER(Waitable)(BOOL *aWaitable)
140{
141 CheckComArgNotNull(aWaitable);
142
143 AutoCaller autoCaller(this);
144 if (FAILED(autoCaller.rc())) return autoCaller.rc();
145
146 // never changes till event alive, no locking?
147 *aWaitable = m->mWaitable;
148 return S_OK;
149}
150
151
152STDMETHODIMP VBoxEvent::SetProcessed()
153{
154 AutoCaller autoCaller(this);
155 if (FAILED(autoCaller.rc())) return autoCaller.rc();
156
157 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
158
159 if (m->mProcessed)
160 return S_OK;
161
162 m->mProcessed = TRUE;
163
164 // notify waiters
165 ::RTSemEventSignal(m->mWaitEvent);
166
167 return S_OK;
168}
169
170STDMETHODIMP VBoxEvent::WaitProcessed(LONG aTimeout, BOOL *aResult)
171{
172 CheckComArgNotNull(aResult);
173
174 AutoCaller autoCaller(this);
175 if (FAILED(autoCaller.rc())) return autoCaller.rc();
176
177 {
178 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
179
180 if (m->mProcessed)
181 {
182 *aResult = TRUE;
183 return S_OK;
184 }
185
186 if (aTimeout == 0)
187 {
188 *aResult = m->mProcessed;
189 return S_OK;
190 }
191 }
192
193 int vrc = ::RTSemEventWait(m->mWaitEvent, aTimeout);
194 AssertMsg(RT_SUCCESS(vrc) || vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED,
195 ("RTSemEventWait returned %Rrc\n", vrc));
196
197 if (RT_SUCCESS(vrc))
198 {
199 AssertMsg(m->mProcessed,
200 ("mProcessed must be set here\n"));
201 *aResult = m->mProcessed;
202 }
203 else
204 {
205 *aResult = FALSE;
206 }
207
208 return S_OK;
209}
210
211typedef std::list<Bstr> VetoList;
212struct VBoxVetoEvent::Data
213{
214 Data()
215 :
216 mVetoed(FALSE)
217 {}
218 BOOL mVetoed;
219 VetoList mVetoList;
220};
221
222HRESULT VBoxVetoEvent::FinalConstruct()
223{
224 VBoxEvent::FinalConstruct();
225 m = new Data;
226 return S_OK;
227}
228
229void VBoxVetoEvent::FinalRelease()
230{
231 if (m)
232 {
233 uninit();
234 delete m;
235 m = 0;
236 }
237 VBoxEvent::FinalRelease();
238}
239
240
241HRESULT VBoxVetoEvent::init(IEventSource *aSource, VBoxEventType_T aType)
242{
243 HRESULT rc = S_OK;
244 // all veto events are waitable
245 rc = VBoxEvent::init(aSource, aType, TRUE);
246 if (FAILED(rc)) return rc;
247
248 m->mVetoed = FALSE;
249 m->mVetoList.clear();
250
251 return rc;
252}
253
254void VBoxVetoEvent::uninit()
255{
256 VBoxEvent::uninit();
257 if (!m)
258 return;
259 m->mVetoed = FALSE;
260}
261
262STDMETHODIMP VBoxVetoEvent::AddVeto(IN_BSTR aVeto)
263{
264 AutoCaller autoCaller(this);
265 if (FAILED(autoCaller.rc())) return autoCaller.rc();
266
267 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
268
269 if (aVeto)
270 m->mVetoList.push_back(aVeto);
271
272 m->mVetoed = TRUE;
273
274 return S_OK;
275}
276
277STDMETHODIMP VBoxVetoEvent::IsVetoed(BOOL * aResult)
278{
279 CheckComArgOutPointerValid(aResult);
280
281 AutoCaller autoCaller(this);
282 if (FAILED(autoCaller.rc())) return autoCaller.rc();
283
284 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
285
286 *aResult = m->mVetoed;
287
288 return S_OK;
289}
290
291STDMETHODIMP VBoxVetoEvent::GetVetos(ComSafeArrayOut(BSTR, aVetos))
292{
293 if (ComSafeArrayOutIsNull(aVetos))
294 return E_POINTER;
295
296 AutoCaller autoCaller(this);
297 if (FAILED(autoCaller.rc())) return autoCaller.rc();
298
299 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
300 com::SafeArray<BSTR> vetos(m->mVetoList.size());
301 int i = 0;
302 for (VetoList::const_iterator it = m->mVetoList.begin();
303 it != m->mVetoList.end();
304 ++it, ++i)
305 {
306 const Bstr &str = *it;
307 str.cloneTo(&vetos[i]);
308 }
309 vetos.detachTo(ComSafeArrayOutArg(aVetos));
310
311 return S_OK;
312
313}
314
315static const int FirstEvent = (int)VBoxEventType_LastWildcard + 1;
316static const int LastEvent = (int)VBoxEventType_Last;
317static const int NumEvents = LastEvent - FirstEvent;
318
319class ListenerRecord;
320typedef std::list<ListenerRecord*> EventMap[NumEvents];
321typedef std::map<IEvent*, int32_t> PendingEventsMap;
322typedef std::deque<ComPtr<IEvent> > PassiveQueue;
323
324class ListenerRecord
325{
326private:
327 ComPtr<IEventListener> mListener;
328 BOOL mActive;
329 EventSource* mOwner;
330
331 RTSEMEVENT mQEvent;
332 RTCRITSECT mcsQLock;
333 PassiveQueue mQueue;
334 int32_t mRefCnt;
335
336public:
337 ListenerRecord(IEventListener* aListener,
338 com::SafeArray<VBoxEventType_T>& aInterested,
339 BOOL aActive,
340 EventSource* aOwner);
341 ~ListenerRecord();
342
343 HRESULT process(IEvent* aEvent, BOOL aWaitable, PendingEventsMap::iterator& pit, AutoLockBase& alock);
344 HRESULT enqueue(IEvent* aEvent);
345 HRESULT dequeue(IEvent* *aEvent, LONG aTimeout, AutoLockBase& aAlock);
346 HRESULT eventProcessed(IEvent * aEvent, PendingEventsMap::iterator& pit);
347 void addRef()
348 {
349 ASMAtomicIncS32(&mRefCnt);
350 }
351 void release()
352 {
353 if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this;
354 }
355 BOOL isActive()
356 {
357 return mActive;
358 }
359};
360
361/* Handy class with semantics close to ComPtr, but for ListenerRecord */
362class ListenerRecordHolder
363{
364public:
365 ListenerRecordHolder(ListenerRecord* lr)
366 :
367 held(lr)
368 {
369 addref();
370 }
371 ListenerRecordHolder(const ListenerRecordHolder& that)
372 :
373 held(that.held)
374 {
375 addref();
376 }
377 ListenerRecordHolder()
378 :
379 held(0)
380 {
381 }
382 ~ListenerRecordHolder()
383 {
384 release();
385 }
386
387 ListenerRecord* obj()
388 {
389 return held;
390 }
391
392 ListenerRecordHolder &operator=(const ListenerRecordHolder &that)
393 {
394 safe_assign(that.held);
395 return *this;
396 }
397private:
398 ListenerRecord* held;
399
400 void addref()
401 {
402 if (held)
403 held->addRef();
404 }
405 void release()
406 {
407 if (held)
408 held->release();
409 }
410 void safe_assign (ListenerRecord *that_p)
411 {
412 if (that_p)
413 that_p->addRef();
414 release();
415 held = that_p;
416 }
417};
418
419typedef std::map<IEventListener*, ListenerRecordHolder> Listeners;
420
421struct EventSource::Data
422{
423 Data() {}
424 Listeners mListeners;
425 EventMap mEvMap;
426 PendingEventsMap mPendingMap;
427};
428
429/**
430 * This function defines what wildcard expands to.
431 */
432static BOOL implies(VBoxEventType_T who, VBoxEventType_T what)
433{
434 switch (who)
435 {
436 case VBoxEventType_Any:
437 return TRUE;
438 case VBoxEventType_MachineEvent:
439 return (what == VBoxEventType_OnMachineStateChange)
440 || (what == VBoxEventType_OnMachineDataChange)
441 || (what == VBoxEventType_OnMachineRegistered)
442 || (what == VBoxEventType_OnSessionStateChange)
443 || (what == VBoxEventType_OnGuestPropertyChange);
444 case VBoxEventType_SnapshotEvent:
445 return (what == VBoxEventType_OnSnapshotTaken)
446 || (what == VBoxEventType_OnSnapshotDeleted)
447 || (what == VBoxEventType_OnSnapshotChange)
448 ;
449 case VBoxEventType_Invalid:
450 return FALSE;
451 }
452 return who == what;
453}
454
455ListenerRecord::ListenerRecord(IEventListener* aListener,
456 com::SafeArray<VBoxEventType_T>& aInterested,
457 BOOL aActive,
458 EventSource* aOwner)
459 :
460 mActive(aActive),
461 mOwner(aOwner),
462 mRefCnt(0)
463{
464 mListener = aListener;
465 EventMap* aEvMap = &aOwner->m->mEvMap;
466
467 for (size_t i = 0; i < aInterested.size(); ++i)
468 {
469 VBoxEventType_T interested = aInterested[i];
470 for (int j = FirstEvent; j < LastEvent; j++)
471 {
472 VBoxEventType_T candidate = (VBoxEventType_T)j;
473 if (implies(interested, candidate))
474 {
475 (*aEvMap)[j - FirstEvent].push_back(this);
476 }
477 }
478 }
479
480 if (!mActive)
481 {
482 ::RTCritSectInit(&mcsQLock);
483 ::RTSemEventCreate (&mQEvent);
484 }
485}
486
487ListenerRecord::~ListenerRecord()
488{
489 /* Remove references to us from the event map */
490 EventMap* aEvMap = &mOwner->m->mEvMap;
491 for (int j = FirstEvent; j < LastEvent; j++)
492 {
493 (*aEvMap)[j - FirstEvent].remove(this);
494 }
495
496 if (!mActive)
497 {
498 ::RTCritSectDelete(&mcsQLock);
499 ::RTSemEventDestroy(mQEvent);
500 }
501}
502
503HRESULT ListenerRecord::process(IEvent* aEvent,
504 BOOL aWaitable,
505 PendingEventsMap::iterator& pit,
506 AutoLockBase& aAlock)
507{
508 if (mActive)
509 {
510 /*
511 * We release lock here to allow modifying ops on EventSource inside callback.
512 */
513 HRESULT rc = S_OK;
514 if (mListener)
515 {
516 aAlock.release();
517 rc = mListener->HandleEvent(aEvent);
518 aAlock.acquire();
519 }
520 if (aWaitable)
521 eventProcessed(aEvent, pit);
522 return rc;
523 }
524 else
525 return enqueue(aEvent);
526}
527
528
529HRESULT ListenerRecord::enqueue (IEvent* aEvent)
530{
531 AssertMsg(!mActive, ("must be passive\n"));
532 // put an event the queue
533 ::RTCritSectEnter(&mcsQLock);
534 mQueue.push_back(aEvent);
535 ::RTCritSectLeave(&mcsQLock);
536
537 // notify waiters
538 ::RTSemEventSignal(mQEvent);
539
540 return S_OK;
541}
542
543HRESULT ListenerRecord::dequeue (IEvent* *aEvent,
544 LONG aTimeout,
545 AutoLockBase& aAlock)
546{
547 AssertMsg(!mActive, ("must be passive\n"));
548
549 ::RTCritSectEnter(&mcsQLock);
550 if (mQueue.empty())
551 {
552 // retain listener record
553 ListenerRecordHolder holder(this);
554 ::RTCritSectLeave(&mcsQLock);
555 // Speed up common case
556 if (aTimeout == 0)
557 {
558 *aEvent = NULL;
559 return S_OK;
560 }
561 // release lock while waiting, listener will not go away due to above holder
562 aAlock.release();
563 ::RTSemEventWait(mQEvent, aTimeout);
564 // reacquire lock
565 aAlock.acquire();
566 ::RTCritSectEnter(&mcsQLock);
567 }
568 if (mQueue.empty())
569 {
570 *aEvent = NULL;
571 }
572 else
573 {
574 mQueue.front().queryInterfaceTo(aEvent);
575 mQueue.pop_front();
576 }
577 ::RTCritSectLeave(&mcsQLock);
578 return S_OK;
579}
580
581HRESULT ListenerRecord::eventProcessed (IEvent* aEvent, PendingEventsMap::iterator& pit)
582{
583 if (--pit->second == 0)
584 {
585 Assert(pit->first == aEvent);
586 aEvent->SetProcessed();
587 mOwner->m->mPendingMap.erase(pit);
588 }
589
590 Assert(pit->second >= 0);
591 return S_OK;
592}
593
594EventSource::EventSource()
595{}
596
597EventSource::~EventSource()
598{}
599
600HRESULT EventSource::FinalConstruct()
601{
602 m = new Data;
603 return S_OK;
604}
605
606void EventSource::FinalRelease()
607{
608 uninit();
609 delete m;
610}
611
612HRESULT EventSource::init(IUnknown *)
613{
614 HRESULT rc = S_OK;
615
616 AutoInitSpan autoInitSpan(this);
617 AssertReturn(autoInitSpan.isOk(), E_FAIL);
618
619 /* Confirm a successful initialization */
620 autoInitSpan.setSucceeded();
621 return rc;
622}
623
624void EventSource::uninit()
625{
626 AutoUninitSpan autoUninitSpan(this);
627 if (autoUninitSpan.uninitDone())
628 return;
629 m->mListeners.clear();
630 // m->mEvMap shall be cleared at this point too by destructors, assert?
631}
632
633STDMETHODIMP EventSource::RegisterListener(IEventListener * aListener,
634 ComSafeArrayIn(VBoxEventType_T, aInterested),
635 BOOL aActive)
636{
637 CheckComArgNotNull(aListener);
638 CheckComArgSafeArrayNotNull(aInterested);
639
640 AutoCaller autoCaller(this);
641 if (FAILED(autoCaller.rc())) return autoCaller.rc();
642
643 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
644
645 Listeners::const_iterator it = m->mListeners.find(aListener);
646 if (it != m->mListeners.end())
647 return setError(E_INVALIDARG,
648 tr("This listener already registered"));
649
650 com::SafeArray<VBoxEventType_T> interested(ComSafeArrayInArg (aInterested));
651 ListenerRecordHolder lrh(new ListenerRecord(aListener, interested, aActive, this));
652 m->mListeners.insert(Listeners::value_type(aListener, lrh));
653
654 return S_OK;
655}
656
657STDMETHODIMP EventSource::UnregisterListener(IEventListener * aListener)
658{
659 CheckComArgNotNull(aListener);
660
661 AutoCaller autoCaller(this);
662 if (FAILED(autoCaller.rc())) return autoCaller.rc();
663
664 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
665
666 Listeners::iterator it = m->mListeners.find(aListener);
667 HRESULT rc;
668
669 if (it != m->mListeners.end())
670 {
671 m->mListeners.erase(it);
672 // destructor removes refs from the event map
673 rc = S_OK;
674 }
675 else
676 {
677 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
678 tr("Listener was never registered"));
679 }
680
681 return rc;
682}
683
684STDMETHODIMP EventSource::FireEvent(IEvent * aEvent,
685 LONG aTimeout,
686 BOOL *aProcessed)
687{
688 CheckComArgNotNull(aEvent);
689 CheckComArgOutPointerValid(aProcessed);
690
691 AutoCaller autoCaller(this);
692 if (FAILED(autoCaller.rc())) return autoCaller.rc();
693
694 HRESULT hrc;
695 BOOL aWaitable = FALSE;
696 aEvent->COMGETTER(Waitable)(&aWaitable);
697
698 do {
699 /* See comment in EventSource::GetEvent() */
700 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
701
702 VBoxEventType_T evType;
703 hrc = aEvent->COMGETTER(Type)(&evType);
704 AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
705
706 std::list<ListenerRecord*>& listeners = m->mEvMap[(int)evType-FirstEvent];
707
708 /* Anyone interested in this event? */
709 uint32_t cListeners = listeners.size();
710 if (cListeners == 0)
711 {
712 aEvent->SetProcessed();
713 break; // just leave the lock and update event object state
714 }
715
716 PendingEventsMap::iterator pit;
717
718 if (aWaitable)
719 {
720 m->mPendingMap.insert(PendingEventsMap::value_type(aEvent, cListeners));
721 // we keep iterator here to allow processing active listeners without
722 // pending events lookup
723 pit = m->mPendingMap.find(aEvent);
724 }
725 for(std::list<ListenerRecord*>::const_iterator it = listeners.begin();
726 it != listeners.end(); ++it)
727 {
728 HRESULT cbRc;
729 // keep listener record reference, in case someone will remove it while in callback
730 ListenerRecordHolder record(*it);
731
732 /**
733 * We pass lock here to allow modifying ops on EventSource inside callback
734 * in active mode. Note that we expect list iterator stability as 'alock'
735 * could be temporary released when calling event handler.
736 */
737 cbRc = record.obj()->process(aEvent, aWaitable, pit, alock);
738 // what to do with cbRc?
739 }
740 } while (0);
741 /* We leave the lock here */
742
743 if (aWaitable)
744 hrc = aEvent->WaitProcessed(aTimeout, aProcessed);
745 else
746 *aProcessed = TRUE;
747
748 return hrc;
749}
750
751
752STDMETHODIMP EventSource::GetEvent(IEventListener * aListener,
753 LONG aTimeout,
754 IEvent ** aEvent)
755{
756
757 CheckComArgNotNull(aListener);
758
759 AutoCaller autoCaller(this);
760 if (FAILED(autoCaller.rc())) return autoCaller.rc();
761
762 /**
763 * There's subtle dependency between this lock and one in FireEvent():
764 * we need to be able to access event queue in FireEvent() while waiting
765 * here, to make this wait preemptible, thus both take read lock (write
766 * lock in FireEvent() would do too, and probably is a bit stricter),
767 * but will be unable to .
768 */
769 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
770
771 Listeners::iterator it = m->mListeners.find(aListener);
772 HRESULT rc;
773
774 if (it != m->mListeners.end())
775 rc = it->second.obj()->dequeue(aEvent, aTimeout, alock);
776 else
777 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
778 tr("Listener was never registered"));
779
780 return rc;
781}
782
783STDMETHODIMP EventSource::EventProcessed(IEventListener * aListener,
784 IEvent * aEvent)
785{
786 CheckComArgNotNull(aListener);
787 CheckComArgNotNull(aEvent);
788
789 AutoCaller autoCaller(this);
790 if (FAILED(autoCaller.rc())) return autoCaller.rc();
791
792 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
793
794 Listeners::iterator it = m->mListeners.find(aListener);
795 HRESULT rc;
796
797 BOOL aWaitable = FALSE;
798 aEvent->COMGETTER(Waitable)(&aWaitable);
799
800 if (it != m->mListeners.end())
801 {
802 ListenerRecord* aRecord = it->second.obj();
803
804 if (aRecord->isActive())
805 return setError(E_INVALIDARG,
806 tr("Only applicable to passive listeners"));
807
808 if (aWaitable)
809 {
810 PendingEventsMap::iterator pit = m->mPendingMap.find(aEvent);
811
812 if (pit == m->mPendingMap.end())
813 {
814 AssertFailed();
815 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
816 tr("Unknown event"));
817 }
818 else
819 rc = aRecord->eventProcessed(aEvent, pit);
820 }
821 else
822 {
823 // for non-waitable events we're done
824 rc = S_OK;
825 }
826 }
827 else
828 {
829 rc = setError(VBOX_E_OBJECT_NOT_FOUND,
830 tr("Listener was never registered"));
831 }
832
833 return rc;
834}
835
836/**
837 * This class serves as feasible listener implementation
838 * which could be used by clients not able to create local
839 * COM objects, but still willing to recieve event
840 * notifications in passive mode, such as webservices.
841 */
842class ATL_NO_VTABLE PassiveEventListener :
843 public VirtualBoxBase,
844 public VirtualBoxSupportErrorInfoImpl<PassiveEventListener, IEventListener>,
845 public VirtualBoxSupportTranslation<PassiveEventListener>,
846 VBOX_SCRIPTABLE_IMPL(IEventListener)
847{
848public:
849
850 VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(PassiveEventListener)
851
852 DECLARE_NOT_AGGREGATABLE(PassiveEventListener)
853
854 DECLARE_PROTECT_FINAL_CONSTRUCT()
855
856 BEGIN_COM_MAP(PassiveEventListener)
857 COM_INTERFACE_ENTRY(ISupportErrorInfo)
858 COM_INTERFACE_ENTRY(IEventListener)
859 COM_INTERFACE_ENTRY(IDispatch)
860 END_COM_MAP()
861
862 PassiveEventListener()
863 {}
864 ~PassiveEventListener()
865 {}
866
867 HRESULT FinalConstruct()
868 {
869 return S_OK;
870 }
871 void FinalRelease()
872 {}
873
874 // IEventListener methods
875 STDMETHOD(HandleEvent)(IEvent *)
876 {
877 ComAssertMsgRet(false, ("HandleEvent() of wrapper shall never be called"),
878 E_FAIL);
879 }
880 // for VirtualBoxSupportErrorInfoImpl
881 static const wchar_t *getComponentName() { return L"PassiveEventListener"; }
882};
883
884#ifdef VBOX_WITH_XPCOM
885NS_DECL_CLASSINFO(PassiveEventListener)
886NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PassiveEventListener, IEventListener)
887NS_DECL_CLASSINFO(VBoxEvent)
888NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VBoxEvent, IEvent)
889NS_DECL_CLASSINFO(VBoxVetoEvent)
890NS_IMPL_ISUPPORTS_INHERITED1(VBoxVetoEvent, VBoxEvent, IVetoEvent)
891#endif
892
893STDMETHODIMP EventSource::CreateListener(IEventListener ** aListener)
894{
895 CheckComArgOutPointerValid(aListener);
896
897 AutoCaller autoCaller(this);
898 if (FAILED(autoCaller.rc())) return autoCaller.rc();
899
900 ComObjPtr<PassiveEventListener> listener;
901
902 HRESULT rc = listener.createObject();
903 ComAssertMsgRet(SUCCEEDED(rc), ("Could not create wrapper object (%Rrc)", rc),
904 E_FAIL);
905 listener.queryInterfaceTo(aListener);
906 return S_OK;
907}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette