VirtualBox

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

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

Main: uninit, correct COM map for veto event

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

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