Index: trunk/src/VBox/Frontends/VBoxShell/vboxshell.py
===================================================================
--- trunk/src/VBox/Frontends/VBoxShell/vboxshell.py	(revision 30380)
+++ trunk/src/VBox/Frontends/VBoxShell/vboxshell.py	(revision 30381)
@@ -429,21 +429,28 @@
 def monitorVBox2(ctx, dur):
     vbox = ctx['vb']
-    print vbox.eventSource
     listener = vbox.eventSource.createListener()
+    registered = False
     if dur == -1:
         # not infinity, but close enough
         dur = 100000
     try:
-        vbox.eventSource.registerListener(listener, [ctx['global'].constants.VBoxEventType_All], False)
+        vbox.eventSource.registerListener(listener, [ctx['global'].constants.VBoxEventType_Any], False)
+        registered = True
         end = time.time() + dur
         while  time.time() < end:
-            ev = vbox.eventSource.getEvent(500)
+            ev = vbox.eventSource.getEvent(listener, 500)
             if ev:
                 print "got event: %s %s" %(ev, str(ev.type))
+                if ev.type == ctx['global'].constants.VBoxEventType_OnMachineStateChange:
+                    scev = ctx['global'].queryInterface(ev, 'IMachineStateChangeEvent')
+                    if scev:
+                        print "state event: mach=%s state=%s" %(scev.machineId, scev.state)
     # We need to catch all exceptions here, otherwise callback will never be unregistered
-    except:
+    except Exception, e:
+        printErr(ctx,e)
         traceback.print_exc()
         pass
-    vbox.eventSource.unregisterListener(listener)
+    if listener and registered:
+        vbox.eventSource.unregisterListener(listener)
 
 
Index: trunk/src/VBox/Main/EventImpl.cpp
===================================================================
--- trunk/src/VBox/Main/EventImpl.cpp	(revision 30380)
+++ trunk/src/VBox/Main/EventImpl.cpp	(revision 30381)
@@ -26,4 +26,6 @@
 #include <iprt/semaphore.h>
 #include <iprt/critsect.h>
+#include <iprt/asm.h>
+
 #include <VBox/com/array.h>
 
@@ -37,9 +39,9 @@
         mProcessed(FALSE)
     {}
-    ComPtr<IEventSource>    mSource;
     VBoxEventType_T         mType;
     RTSEMEVENT              mWaitEvent;
     BOOL                    mWaitable;
     BOOL                    mProcessed;
+    ComPtr<IEventSource>    mSource;
 };
 
@@ -52,6 +54,10 @@
 void VBoxEvent::FinalRelease()
 {
-    uninit();
-    delete m;
+    if (m)
+    {
+        uninit();
+        delete m;
+        m = 0;
+    }
 }
 
@@ -62,5 +68,5 @@
 
     AssertReturn(aSource != NULL, E_INVALIDARG);
-     
+
     AutoInitSpan autoInitSpan(this);
     AssertReturn(autoInitSpan.isOk(), E_FAIL);
@@ -93,4 +99,7 @@
 void VBoxEvent::uninit()
 {
+    if (!m)
+        return;
+
     m->mProcessed = TRUE;
     m->mType = VBoxEventType_Invalid;
@@ -99,5 +108,7 @@
     if (m->mWaitEvent != NIL_RTSEMEVENT)
     {
+        Assert(m->mWaitable);
         ::RTSemEventDestroy(m->mWaitEvent);
+        m->mWaitEvent = NIL_RTSEMEVENT;
     }
 }
@@ -168,5 +179,14 @@
 
         if (m->mProcessed)
+        {
+            *aResult = TRUE;
             return S_OK;
+        }
+
+        if (aTimeout == 0)
+        {
+            *aResult = m->mProcessed;
+            return S_OK;
+        }
     }
 
@@ -175,5 +195,4 @@
               ("RTSemEventWait returned %Rrc\n", vrc));
 
-
     if (RT_SUCCESS(vrc))
     {
@@ -194,11 +213,12 @@
 static const int NumEvents  = LastEvent - FirstEvent;
 
-struct ListenerRecord;
+class ListenerRecord;
 typedef std::list<ListenerRecord*> EventMap[NumEvents];
 typedef std::map<IEvent*, int32_t> PendingEventsMap;
 typedef std::deque<ComPtr<IEvent> > PassiveQueue;
 
-struct ListenerRecord
-{
+class ListenerRecord
+{
+private:
     ComPtr<IEventListener>        mListener;
     BOOL                          mActive;
@@ -208,5 +228,7 @@
     RTCRITSECT                    mcsQLock;
     PassiveQueue                  mQueue;
-
+    int32_t                       mRefCnt;
+
+public:
     ListenerRecord(IEventListener*                    aListener,
                    com::SafeArray<VBoxEventType_T>&   aInterested,
@@ -219,7 +241,77 @@
     HRESULT dequeue(IEvent* *aEvent, LONG aTimeout);
     HRESULT eventProcessed(IEvent * aEvent, PendingEventsMap::iterator& pit);
+    void addRef()
+    {
+        ASMAtomicIncS32(&mRefCnt);
+    }
+    void release()
+    {
+        if (ASMAtomicDecS32(&mRefCnt) <= 0) delete this;
+    }
+    BOOL isActive()
+    {
+        return mActive;
+    }
 };
 
-typedef std::map<IEventListener*, ListenerRecord>  Listeners;
+/* Handy class with semantics close to ComPtr, but for ListenerRecord */
+class ListenerRecordHolder
+{
+public:
+    ListenerRecordHolder(ListenerRecord* lr)
+    :
+    held(lr)
+    {
+        addref();
+    }
+    ListenerRecordHolder(const ListenerRecordHolder& that)
+    :
+    held(that.held)
+    {
+        addref();
+    }
+    ListenerRecordHolder()
+    :
+    held(0)
+    {
+    }
+    ~ListenerRecordHolder()
+    {
+        release();
+    }
+
+    ListenerRecord* obj()
+    {
+        return held;
+    }
+
+    ListenerRecordHolder &operator=(const ListenerRecordHolder &that)
+    {
+        safe_assign(that.held);
+        return *this;
+    }
+private:
+    ListenerRecord* held;
+
+    void addref()
+    {
+        if (held)
+            held->addRef();
+    }
+    void release()
+    {
+        if (held)
+            held->release();
+    }
+    void safe_assign (ListenerRecord *that_p)
+    {
+        if (that_p)
+            that_p->addRef();
+        release();
+        held = that_p;
+    }
+};
+
+typedef std::map<IEventListener*, ListenerRecordHolder>  Listeners;
 
 struct EventSource::Data
@@ -231,4 +323,7 @@
 };
 
+/**
+ * This function defines what wildcard expands to.
+ */
 static BOOL implies(VBoxEventType_T who, VBoxEventType_T what)
 {
@@ -240,5 +335,12 @@
             return     (what == VBoxEventType_OnMachineStateChange)
                     || (what == VBoxEventType_OnMachineDataChange)
-                    || (what == VBoxEventType_OnMachineRegistered);
+                    || (what == VBoxEventType_OnMachineRegistered)
+                    || (what == VBoxEventType_OnSessionStateChange)
+                    || (what == VBoxEventType_OnGuestPropertyChange);
+        case VBoxEventType_SnapshotEvent:
+            return     (what == VBoxEventType_OnSnapshotTaken)
+                    || (what == VBoxEventType_OnSnapshotDeleted)
+                    || (what == VBoxEventType_OnSnapshotChange)
+                    ;
         case VBoxEventType_Invalid:
             return FALSE;
@@ -253,5 +355,6 @@
     :
     mActive(aActive),
-    mOwner(aOwner)
+    mOwner(aOwner),
+    mRefCnt(0)
 {
     mListener = aListener;
@@ -273,5 +376,5 @@
     if (!mActive)
     {
-        ::RTCritSectInitEx(&mcsQLock, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
+        ::RTCritSectInit(&mcsQLock);
         ::RTSemEventCreate (&mQEvent);
     }
@@ -311,11 +414,11 @@
 {
     AssertMsg(!mActive, ("must be passive\n"));
+    // put an event the queue
     ::RTCritSectEnter(&mcsQLock);
-
     mQueue.push_back(aEvent);
-    // notify waiters
+    ::RTCritSectLeave(&mcsQLock);
+
+     // notify waiters
     ::RTSemEventSignal(mQEvent);
-
-    ::RTCritSectLeave(&mcsQLock);
 
     return S_OK;
@@ -330,4 +433,10 @@
     {
         ::RTCritSectLeave(&mcsQLock);
+        // Speed up common case
+        if (aTimeout == 0)
+        {
+            *aEvent = NULL;
+            return S_OK;
+        }
         ::RTSemEventWait(mQEvent, aTimeout);
         ::RTCritSectEnter(&mcsQLock);
@@ -350,4 +459,5 @@
     if (--pit->second == 0)
     {
+        Assert(pit->first == aEvent);
         aEvent->SetProcessed();
         mOwner->m->mPendingMap.erase(pit);
@@ -358,5 +468,4 @@
 }
 
-
 EventSource::EventSource()
 {}
@@ -377,5 +486,5 @@
 }
 
-HRESULT EventSource::init(IUnknown * aParent)
+HRESULT EventSource::init(IUnknown *)
 {
     HRESULT rc = S_OK;
@@ -393,21 +502,4 @@
     m->mListeners.clear();
     // m->mEvMap shall be cleared at this point too by destructors
-}
-
-STDMETHODIMP EventSource::CreateListener(IEventListener ** aListener)
-{
-    CheckComArgOutPointerValid(aListener);
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    ComPtr<IEventListener> listener;
-
-    HRESULT rc = listener.createLocalObject(CLSID_CallbackWrapper);
-    ComAssertMsgRet(SUCCEEDED(rc), ("Could not create wrapper object (%Rrc)", rc),
-                    E_FAIL);
-
-    listener.queryInterfaceTo(aListener);
-    return S_OK;
 }
 
@@ -430,8 +522,6 @@
 
     com::SafeArray<VBoxEventType_T> interested(ComSafeArrayInArg (aInterested));
-    m->mListeners.insert(
-        Listeners::value_type(aListener,
-                              ListenerRecord(aListener, interested, aActive, this))
-                         );
+    ListenerRecordHolder lrh(new ListenerRecord(aListener, interested, aActive, this));
+    m->mListeners.insert(Listeners::value_type(aListener, lrh));
 
     return S_OK;
@@ -475,34 +565,42 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    VBoxEventType_T evType;
-    HRESULT hrc = aEvent->COMGETTER(Type)(&evType);
-    AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
-
+    HRESULT hrc;
     BOOL aWaitable = FALSE;
     aEvent->COMGETTER(Waitable)(&aWaitable);
 
-    std::list<ListenerRecord*>& listeners = m->mEvMap[(int)evType-FirstEvent];
-
-    uint32_t cListeners = listeners.size();
-    PendingEventsMap::iterator pit;
-
-    if (cListeners > 0 && aWaitable)
-    {
-        m->mPendingMap.insert(PendingEventsMap::value_type(aEvent, cListeners));
-        // we keep it here to allow processing active listeners without pending events lookup
-        pit = m->mPendingMap.find(aEvent);
-    }
-    for(std::list<ListenerRecord*>::const_iterator it = listeners.begin();
-        it != listeners.end(); ++it)
-    {
-        ListenerRecord* record = *it;
-        HRESULT cbRc;
-
-        // @todo: callback under (read) lock, is it good?
-        cbRc = record->process(aEvent, aWaitable, pit);
-        // what to do with cbRc?
-    }
+    {
+        /* See comment in EventSource::GetEvent() */
+        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+        VBoxEventType_T evType;
+        hrc = aEvent->COMGETTER(Type)(&evType);
+        AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
+
+        std::list<ListenerRecord*>& listeners = m->mEvMap[(int)evType-FirstEvent];
+
+        uint32_t cListeners = listeners.size();
+        PendingEventsMap::iterator pit;
+
+        if (cListeners > 0 && aWaitable)
+        {
+            m->mPendingMap.insert(PendingEventsMap::value_type(aEvent, cListeners));
+            // we keep iterator here to allow processing active listeners without
+            // pending events lookup
+            pit = m->mPendingMap.find(aEvent);
+        }
+        for(std::list<ListenerRecord*>::const_iterator it = listeners.begin();
+            it != listeners.end(); ++it)
+        {
+            ListenerRecord* record = *it;
+            HRESULT cbRc;
+
+            // @todo: callback under (read) lock, is it good?
+            // We could make copy of per-event listener's list, but real issue
+            // is that we don't want to allow removal of a listener while iterating
+            cbRc = record->process(aEvent, aWaitable, pit);
+            // what to do with cbRc?
+        }
+    }
+    /* We leave the lock here */
 
     if (aWaitable)
@@ -516,6 +614,6 @@
 
 STDMETHODIMP EventSource::GetEvent(IEventListener * aListener,
-                                   LONG      aTimeout,
-                                   IEvent  * *aEvent)
+                                   LONG             aTimeout,
+                                   IEvent  **       aEvent)
 {
 
@@ -525,4 +623,11 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
+    /**
+     * There's subtle dependency between this lock and one in FireEvent():
+     * we need to be able to access event queue in FireEvent() while waiting
+     * here, to make this wait preemptible, thus both take read lock (write
+     * lock in FireEvent() would do too, and probably is a bit stricter),
+     * but will interfere with .
+     */
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
@@ -531,5 +636,5 @@
 
     if (it != m->mListeners.end())
-        rc = it->second.dequeue(aEvent, aTimeout);
+        rc = it->second.obj()->dequeue(aEvent, aTimeout);
     else
         rc = setError(VBOX_E_OBJECT_NOT_FOUND,
@@ -558,7 +663,7 @@
     if (it != m->mListeners.end())
     {
-        ListenerRecord& aRecord = it->second;
-
-        if (aRecord.mActive)
+        ListenerRecord* aRecord = it->second.obj();
+
+        if (aRecord->isActive())
             return setError(E_INVALIDARG,
                         tr("Only applicable to passive listeners"));
@@ -575,5 +680,5 @@
             }
             else
-                rc = aRecord.eventProcessed(aEvent, pit);
+                rc = aRecord->eventProcessed(aEvent, pit);
         }
         else
@@ -591,2 +696,71 @@
     return rc;
 }
+
+/**
+ * This class serves as feasible listener implementation
+ * which could be used by clients not able to create local
+ * COM objects, but still willing to recieve event
+ * notifications in passive mode, such as webservices.
+ */
+class ATL_NO_VTABLE PassiveEventListener :
+    public VirtualBoxBase,
+    public VirtualBoxSupportErrorInfoImpl<PassiveEventListener, IEventListener>,
+    public VirtualBoxSupportTranslation<PassiveEventListener>,
+    VBOX_SCRIPTABLE_IMPL(IEventListener)
+{
+public:
+
+    VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(PassiveEventListener)
+
+    DECLARE_NOT_AGGREGATABLE(PassiveEventListener)
+
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+    BEGIN_COM_MAP(PassiveEventListener)
+        COM_INTERFACE_ENTRY(ISupportErrorInfo)
+        COM_INTERFACE_ENTRY(IEventListener)
+        COM_INTERFACE_ENTRY(IDispatch)
+    END_COM_MAP()
+
+    PassiveEventListener()
+    {}
+    ~PassiveEventListener()
+    {}
+
+    HRESULT FinalConstruct()
+    {
+        return S_OK;
+    }
+    void FinalRelease()
+    {}
+
+    // IEventListener methods
+    STDMETHOD(HandleEvent)(IEvent *)
+    {
+        ComAssertMsgRet(false, ("HandleEvent() of wrapper shall never be called"),
+                        E_FAIL);
+    }
+    // for VirtualBoxSupportErrorInfoImpl
+    static const wchar_t *getComponentName() { return L"PassiveEventListener"; }
+};
+
+#ifdef VBOX_WITH_XPCOM
+NS_DECL_CLASSINFO(PassiveEventListener)
+NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PassiveEventListener, IEventListener)
+#endif
+
+STDMETHODIMP EventSource::CreateListener(IEventListener ** aListener)
+{
+    CheckComArgOutPointerValid(aListener);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    ComObjPtr<PassiveEventListener> listener;
+
+    HRESULT rc = listener.createObject();
+    ComAssertMsgRet(SUCCEEDED(rc), ("Could not create wrapper object (%Rrc)", rc),
+                    E_FAIL);
+    listener.queryInterfaceTo(aListener);
+    return S_OK;
+}
Index: trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- trunk/src/VBox/Main/Makefile.kmk	(revision 30380)
+++ trunk/src/VBox/Main/Makefile.kmk	(revision 30381)
@@ -320,4 +320,5 @@
 	HostPower.cpp \
 	EventImpl.cpp \
+	VBoxEvents.cpp \
 	$(if $(VBOX_WITH_VRDP),VRDPServerImpl.cpp,) \
 	$(if $(VBOX_WITH_XPCOM),xpcom/server.cpp,) \
@@ -647,4 +648,5 @@
 	VMMDevInterface.cpp \
 	EventImpl.cpp \
+	VBoxEvents.cpp \
 	$(VBOX_XML_SCHEMADEFS_CPP)
 VBoxC_SOURCES.win = \
Index: trunk/src/VBox/Main/VBoxEvents.cpp
===================================================================
--- trunk/src/VBox/Main/VBoxEvents.cpp	(revision 30381)
+++ trunk/src/VBox/Main/VBoxEvents.cpp	(revision 30381)
@@ -0,0 +1,604 @@
+/* $Id$ */
+/** @file
+ * VirtualBox-specific event classes implementation
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#include "EventImpl.h"
+
+/**
+ * @todo: Technically, this file better be autogenerated,
+ *        as contains almost no semantic meat. We use aggregation
+ *        of VBoxEvent to simplify multiple inheritance ambiguity.
+ */
+#define EVENT_CLASS_TRIVIA(klazz, iface) \
+  public:                                \
+    DECLARE_NOT_AGGREGATABLE(klazz)      \
+                                         \
+    DECLARE_PROTECT_FINAL_CONSTRUCT()    \
+                                         \
+    BEGIN_COM_MAP(klazz)                                \
+        COM_INTERFACE_ENTRY(iface)                      \
+        COM_INTERFACE_ENTRY(IEvent)                     \
+        COM_INTERFACE_ENTRY(IDispatch)                  \
+    END_COM_MAP()                                       \
+                                                        \
+    klazz () {}                                         \
+    virtual ~klazz () {}                                \
+                                                        \
+    HRESULT FinalConstruct()                            \
+    {                                                   \
+        return mEvent.createObject();                   \
+    }                                                   \
+    void FinalRelease() {                               \
+        mEvent->FinalRelease();                         \
+    }                                                   \
+    STDMETHOD(COMGETTER(Type)) (VBoxEventType_T *aType) \
+    {                                                   \
+        return mEvent->COMGETTER(Type) (aType);                 \
+    }                                                           \
+    STDMETHOD(COMGETTER(Source)) (IEventSource * *aSource)      \
+    {                                                           \
+        return mEvent->COMGETTER(Source) (aSource);             \
+    }                                                           \
+    STDMETHOD(COMGETTER(Waitable)) (BOOL *aWaitable)            \
+    {                                                           \
+        return mEvent->COMGETTER(Waitable) (aWaitable);         \
+    }                                                           \
+    STDMETHOD(SetProcessed)()                                   \
+    {                                                           \
+        return mEvent->SetProcessed();                          \
+    }                                                           \
+    STDMETHOD(WaitProcessed)(LONG aTimeout, BOOL *aResult)      \
+    {                                                           \
+        return mEvent->WaitProcessed(aTimeout, aResult);        \
+    }                                                           \
+private:                                                        \
+    ComObjPtr<VBoxEvent>      mEvent;
+
+//    operator VBoxEvent&() { return mEvent; }
+//    operator IEvent&()    { return mEvent; }
+
+
+class ATL_NO_VTABLE MachineStateChangeEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(IMachineStateChangeEvent)
+{
+    EVENT_CLASS_TRIVIA(MachineStateChangeEvent, IMachineStateChangeEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aId, MachineState_T aState)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aId;
+            mState = aState;
+        }
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+    // IMachineStateChangeEvent methods
+    STDMETHOD(COMGETTER(State))(MachineState_T * aState)
+    {
+        *aState = mState;
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId;
+    MachineState_T mState;
+};
+
+class ATL_NO_VTABLE MachineDataChangeEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(IMachineDataChangeEvent)
+{
+    EVENT_CLASS_TRIVIA(MachineDataChangeEvent, IMachineDataChangeEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aId)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+            mMachineId = aId;
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId;
+};
+
+class ATL_NO_VTABLE MachineRegisteredEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(IMachineRegisteredEvent)
+{
+    EVENT_CLASS_TRIVIA(MachineRegisteredEvent, IMachineRegisteredEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aId, BOOL aRegistered)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aId;
+            mRegistered = aRegistered;
+        }
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+    // IMachineRegisteredEvent properties
+    STDMETHOD(COMGETTER(Registered))(BOOL * aRegistered)
+    {
+        *aRegistered = mRegistered;
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId;
+    BOOL           mRegistered;
+};
+
+class ATL_NO_VTABLE MachineSessionStateEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(IMachineSessionStateEvent)
+{
+    EVENT_CLASS_TRIVIA(MachineSessionStateEvent, IMachineSessionStateEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aId, SessionState_T aState)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aId;
+            mState = aState;
+        }
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+    // IMachineSessionStateEvent properties
+    STDMETHOD(COMGETTER(State))(SessionState_T * aState)
+    {
+        *aState = mState;
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId;
+    SessionState_T mState;
+};
+
+class ATL_NO_VTABLE GuestPropertyChangeEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(IGuestPropertyChangeEvent)
+{
+    EVENT_CLASS_TRIVIA(GuestPropertyChangeEvent, IGuestPropertyChangeEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType,
+                  IN_BSTR aMachineId, IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aMachineId;
+            mName = aName;
+            mValue = aValue;
+            mFlags = aFlags;
+        }
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+    // IGuestPropertyChangeEvent properties
+    STDMETHOD(COMGETTER(Name))(BSTR * aName)
+    {
+        mName.cloneTo(aName);
+        return S_OK;
+    }
+    STDMETHOD(COMGETTER(Value))(BSTR * aValue)
+    {
+        mValue.cloneTo(aValue);
+        return S_OK;
+    }
+    STDMETHOD(COMGETTER(Flags))(BSTR * aFlags)
+    {
+        mFlags.cloneTo(aFlags);
+        return S_OK;
+    }
+  private:
+    Bstr           mMachineId, mName, mValue, mFlags;
+};
+
+class ATL_NO_VTABLE SnapshotTakenEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(ISnapshotTakenEvent)
+{
+    EVENT_CLASS_TRIVIA(SnapshotTakenEvent, ISnapshotTakenEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aMachineId,  IN_BSTR aSnapshotId)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aMachineId;
+            mSnapshotId = aSnapshotId;
+        }
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+    // ISnapshotEvent properties
+    STDMETHOD(COMGETTER(SnapshotId)) (BSTR *aSnapshotId)
+    {
+        mSnapshotId.cloneTo(aSnapshotId);
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId, mSnapshotId;
+};
+
+class ATL_NO_VTABLE SnapshotChangeEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(ISnapshotChangeEvent)
+{
+    EVENT_CLASS_TRIVIA(SnapshotChangeEvent, ISnapshotChangeEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aMachineId,  IN_BSTR aSnapshotId)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aMachineId;
+            mSnapshotId = aSnapshotId;
+        }
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+    // ISnapshotEvent properties
+    STDMETHOD(COMGETTER(SnapshotId)) (BSTR *aSnapshotId)
+    {
+        mSnapshotId.cloneTo(aSnapshotId);
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId, mSnapshotId;
+};
+
+class ATL_NO_VTABLE SnapshotDeletedEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(ISnapshotDeletedEvent)
+{
+    EVENT_CLASS_TRIVIA(SnapshotDeletedEvent, ISnapshotDeletedEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aMachineId,  IN_BSTR aSnapshotId)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aMachineId;
+            mSnapshotId = aSnapshotId;
+        }
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IMachineEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+    // ISnapshotEvent properties
+    STDMETHOD(COMGETTER(SnapshotId)) (BSTR *aSnapshotId)
+    {
+        mSnapshotId.cloneTo(aSnapshotId);
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId, mSnapshotId;
+};
+
+class ATL_NO_VTABLE ExtraDataChangeEvent :
+    public VirtualBoxBase,
+    VBOX_SCRIPTABLE_IMPL(IExtraDataChangeEvent)
+{
+    EVENT_CLASS_TRIVIA(ExtraDataChangeEvent, IExtraDataChangeEvent)
+
+public:
+    HRESULT init (IEventSource* aSource, VBoxEventType_T aType, IN_BSTR aMachineId,  IN_BSTR aKey,  IN_BSTR aValue)
+    {
+        HRESULT rc;
+
+        rc = mEvent->init(aSource, aType, FALSE);
+        if (SUCCEEDED(rc))
+        {
+            mMachineId = aMachineId;
+            mKey = aKey;
+            mValue = aValue;
+        }
+
+        return rc;
+    }
+
+    void uninit()
+    {
+        mEvent->uninit();
+    }
+
+    // IExtraDataChangeEvent properties
+    STDMETHOD(COMGETTER(MachineId)) (BSTR *aMachineId)
+    {
+        mMachineId.cloneTo(aMachineId);
+        return S_OK;
+    }
+
+    STDMETHOD(COMGETTER(Key)) (BSTR *aKey)
+    {
+        mKey.cloneTo(aKey);
+        return S_OK;
+    }
+
+    STDMETHOD(COMGETTER(Value)) (BSTR *aValue)
+    {
+        mValue.cloneTo(aValue);
+        return S_OK;
+    }
+
+  private:
+    Bstr           mMachineId, mKey, mValue;
+};
+
+
+#ifdef VBOX_WITH_XPCOM
+NS_DECL_CLASSINFO(VBoxEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VBoxEvent, IEvent)
+NS_DECL_CLASSINFO(MachineStateChangeEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(MachineStateChangeEvent, IMachineStateChangeEvent, IEvent)
+NS_DECL_CLASSINFO(MachineDataChangeEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(MachineDataChangeEvent, IMachineDataChangeEvent, IEvent)
+NS_DECL_CLASSINFO(MachineRegisteredEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(MachineRegisteredEvent, IMachineRegisteredEvent, IEvent)
+NS_DECL_CLASSINFO(MachineSessionStateEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(MachineSessionStateEvent, IMachineSessionStateEvent, IEvent)
+NS_DECL_CLASSINFO(GuestPropertyChangeEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(GuestPropertyChangeEvent, IGuestPropertyChangeEvent, IEvent)
+NS_DECL_CLASSINFO(SnapshotTakenEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SnapshotTakenEvent, ISnapshotTakenEvent, IEvent)
+NS_DECL_CLASSINFO(SnapshotDeletedEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SnapshotDeletedEvent, ISnapshotDeletedEvent, IEvent)
+NS_DECL_CLASSINFO(SnapshotChangeEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SnapshotChangeEvent, ISnapshotChangeEvent, IEvent)
+NS_DECL_CLASSINFO(ExtraDataChangeEvent)
+NS_IMPL_THREADSAFE_ISUPPORTS2_CI(ExtraDataChangeEvent, IExtraDataChangeEvent, IEvent)
+#endif
+
+HRESULT VBoxEventDesc::init(IEventSource* source, VBoxEventType_T aType, ...)
+{
+    va_list args;
+    va_start(args, aType);
+    switch (aType)
+    {
+        case VBoxEventType_OnMachineStateChange:
+        {
+            ComObjPtr<MachineStateChangeEvent> obj; obj.createObject();
+            BSTR aId = va_arg(args, BSTR);
+            MachineState_T aState = va_arg(args, MachineState_T);
+            obj->init(source, aType, aId, aState);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+        case VBoxEventType_OnMachineDataChange:
+        {
+            ComObjPtr<MachineDataChangeEvent> obj; obj.createObject();
+            BSTR aId = va_arg(args, BSTR);
+            obj->init(source, aType, aId);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+        case VBoxEventType_OnMachineRegistered:
+        {
+            ComObjPtr<MachineRegisteredEvent> obj; obj.createObject();
+            BSTR aId = va_arg(args, BSTR);
+            BOOL aRegistered = va_arg(args, BOOL);
+            obj->init(source, aType, aId, aRegistered);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+        case VBoxEventType_OnSessionStateChange:
+        {
+            ComObjPtr<MachineSessionStateEvent> obj; obj.createObject();
+            BSTR aId = va_arg(args, BSTR);
+            SessionState_T aState = va_arg(args, SessionState_T);
+            obj->init(source, aType, aId, aState);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+        case VBoxEventType_OnGuestPropertyChange:
+        {
+            ComObjPtr<GuestPropertyChangeEvent> obj; obj.createObject();
+            BSTR aMachineId = va_arg(args, BSTR);
+            BSTR aName = va_arg(args, BSTR);
+            BSTR aValue = va_arg(args, BSTR);
+            BSTR aFlags = va_arg(args, BSTR);
+            obj->init(source, aType, aMachineId, aName, aValue, aFlags);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+
+        case VBoxEventType_OnSnapshotTaken:
+        {
+            ComObjPtr<SnapshotTakenEvent> obj; obj.createObject();
+            BSTR aMachineId = va_arg(args, BSTR);
+            BSTR aSnapshotId = va_arg(args, BSTR);
+            obj->init(source, aType, aMachineId, aSnapshotId);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+        case VBoxEventType_OnSnapshotDeleted:
+        {
+            ComObjPtr<SnapshotDeletedEvent> obj; obj.createObject();
+            BSTR aMachineId = va_arg(args, BSTR);
+            BSTR aSnapshotId = va_arg(args, BSTR);
+            obj->init(source, aType, aMachineId, aSnapshotId);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+        case VBoxEventType_OnSnapshotChange:
+        {
+            ComObjPtr<SnapshotChangeEvent> obj; obj.createObject();
+            BSTR aMachineId = va_arg(args, BSTR);
+            BSTR aSnapshotId = va_arg(args, BSTR);
+            obj->init(source, aType, aMachineId, aSnapshotId);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+        case VBoxEventType_OnExtraDataChange:
+        {
+            ComObjPtr<ExtraDataChangeEvent> obj; obj.createObject();
+            BSTR aMachineId = va_arg(args, BSTR);
+            BSTR aKey = va_arg(args, BSTR);
+            BSTR aValue = va_arg(args, BSTR);
+            obj->init(source, aType, aMachineId, aKey, aValue);
+            obj.queryInterfaceTo(mEvent.asOutParam());
+            break;
+        }
+
+        default:
+            if (0) AssertFailed();
+    }
+    va_end(args);
+
+    return S_OK;
+}
+
+void VBoxEventDesc::getEvent(IEvent ** aEvent)
+{
+    mEvent.queryInterfaceTo(aEvent);
+}
Index: trunk/src/VBox/Main/VirtualBoxCallbackImpl.cpp
===================================================================
--- trunk/src/VBox/Main/VirtualBoxCallbackImpl.cpp	(revision 30380)
+++ trunk/src/VBox/Main/VirtualBoxCallbackImpl.cpp	(revision 30381)
@@ -322,7 +322,2 @@
 }
 
-STDMETHODIMP CallbackWrapper::HandleEvent(IEvent * aEvent)
-{
-    ComAssertMsgRet(false, ("HandleEvent() of wrapper shall never be called"),
-                    E_FAIL);
-}
Index: trunk/src/VBox/Main/VirtualBoxImpl.cpp
===================================================================
--- trunk/src/VBox/Main/VirtualBoxImpl.cpp	(revision 30380)
+++ trunk/src/VBox/Main/VirtualBoxImpl.cpp	(revision 30381)
@@ -205,6 +205,8 @@
 
     virtual HRESULT handleCallback(const ComPtr<IVirtualBoxCallback> &aCallback) = 0;
+    virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc) = 0;
+
 #ifdef RT_OS_WINDOWS
-    virtual HRESULT prepareEventDesc(ComEventDesc& aEvDesc) = 0;
+    virtual HRESULT prepareComEventDesc(ComEventDesc& aEvDesc) = 0;
 #endif
 
@@ -536,11 +538,7 @@
 
         /* events */
-#if 0
-        // disabled for now
         if (SUCCEEDED(rc = unconst(m->pEventSource).createObject()))
-            rc = m->pEventSource->init(this);
+            rc = m->pEventSource->init(static_cast<IVirtualBox*>(this));
         if (FAILED(rc)) throw rc;
-#endif
-
     }
     catch (HRESULT err)
@@ -748,11 +746,4 @@
     }
 
-    LogFlowThisFunc(("Releasing event source...\n"));
-    if (m->pEventSource)
-    {
-        m->pEventSource->uninit();
-        unconst(m->pEventSource).setNull();
-    }
-
 #ifdef VBOX_WITH_RESOURCE_USAGE_API
     if (m->pPerformanceCollector)
@@ -795,4 +786,11 @@
         unconst(m->threadAsyncEvent) = NIL_RTTHREAD;
         unconst(m->pAsyncEventQ) = NULL;
+    }
+
+    LogFlowThisFunc(("Releasing event source...\n"));
+    if (m->pEventSource)
+    {
+        // we don't perform uninit() as it's possible that some pending event refers to this source
+        unconst(m->pEventSource).setNull();
     }
 
@@ -2593,14 +2591,14 @@
 {
     MachineEvent(VirtualBox *aVB, const Guid &aId)
-        : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnMachineDataChange), id(aId)
+        : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnMachineDataChange), id(aId.toUtf16())
         {}
 
     MachineEvent(VirtualBox *aVB, const Guid &aId, MachineState_T aState)
-        : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnMachineStateChange), id(aId)
+        : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnMachineStateChange), id(aId.toUtf16())
         , state(aState)
         {}
 
     MachineEvent(VirtualBox *aVB, const Guid &aId, BOOL aRegistered)
-        : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnMachineRegistered), id(aId)
+        : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnMachineRegistered), id(aId.toUtf16())
         , registered(aRegistered)
         {}
@@ -2611,16 +2609,16 @@
         {
             case VirtualBoxCallbackRegistration::kOnMachineDataChange:
-                LogFlow(("OnMachineDataChange: id={%RTuuid}\n", id.ptr()));
-                return aCallback->OnMachineDataChange(id.toUtf16());
+                LogFlow(("OnMachineDataChange: id={%ls}\n", id.raw()));
+                return aCallback->OnMachineDataChange(id);
 
             case VirtualBoxCallbackRegistration::kOnMachineStateChange:
-                LogFlow(("OnMachineStateChange: id={%RTuuid}, state=%d\n",
-                          id.ptr(), state));
-                return aCallback->OnMachineStateChange(id.toUtf16(), state);
+                LogFlow(("OnMachineStateChange: id={%ls}, state=%d\n",
+                         id.raw(), state));
+                return aCallback->OnMachineStateChange(id, state);
 
             case VirtualBoxCallbackRegistration::kOnMachineRegistered:
-                LogFlow(("OnMachineRegistered: id={%RTuuid}, registered=%d\n",
-                          id.ptr(), registered));
-                return aCallback->OnMachineRegistered(id.toUtf16(), registered);
+                LogFlow(("OnMachineRegistered: id={%ls}, registered=%d\n",
+                         id.raw(), registered));
+                return aCallback->OnMachineRegistered(id, registered);
 
             default:
@@ -2629,5 +2627,5 @@
     }
 #ifdef RT_OS_WINDOWS
-    HRESULT prepareEventDesc(ComEventDesc& aEvDesc)
+    HRESULT prepareComEventDesc(ComEventDesc& aEvDesc)
     {
         switch (mWhat)
@@ -2635,15 +2633,15 @@
             case VirtualBoxCallbackRegistration::kOnMachineDataChange:
                 aEvDesc.init("OnMachineDataChange", 1);
-                aEvDesc.add(id.toUtf16());
+                aEvDesc.add(id);
                 break;
 
             case VirtualBoxCallbackRegistration::kOnMachineStateChange:
                 aEvDesc.init("OnMachineStateChange", 2);
-                aEvDesc.add(id.toUtf16()).add((int)state);
+                aEvDesc.add(id).add((int)state);
                 break;
 
             case VirtualBoxCallbackRegistration::kOnMachineRegistered:
                 aEvDesc.init("OnMachineRegistered", 2);
-                aEvDesc.add(id.toUtf16()).add((BOOL)registered);
+                aEvDesc.add(id).add(registered);
                 break;
 
@@ -2654,6 +2652,27 @@
     }
 #endif
-
-    Guid id;
+    virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc)
+    {
+        switch (mWhat)
+        {
+            case VirtualBoxCallbackRegistration::kOnMachineDataChange:
+                aEvDesc.init(aSource, VBoxEventType_OnMachineDataChange, id.raw());
+                break;
+
+            case VirtualBoxCallbackRegistration::kOnMachineStateChange:
+                aEvDesc.init(aSource, VBoxEventType_OnMachineStateChange, id.raw(), state);
+                break;
+
+            case VirtualBoxCallbackRegistration::kOnMachineRegistered:
+                aEvDesc.init(aSource, VBoxEventType_OnMachineRegistered, id.raw(), registered);
+                break;
+
+            default:
+                AssertFailedReturn(S_OK);
+         }
+         return S_OK;
+    }
+
+    Bstr id;
     MachineState_T state;
     BOOL registered;
@@ -2741,24 +2760,27 @@
                    IN_BSTR aKey, IN_BSTR aVal)
         : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnExtraDataChange)
-        , machineId(aMachineId), key(aKey), val(aVal)
+        , machineId(aMachineId.toUtf16()), key(aKey), val(aVal)
     {}
 
     HRESULT handleCallback(const ComPtr<IVirtualBoxCallback> &aCallback)
     {
-        LogFlow(("OnExtraDataChange: machineId={%RTuuid}, key='%ls', val='%ls'\n",
-                 machineId.ptr(), key.raw(), val.raw()));
-        return aCallback->OnExtraDataChange(machineId.toUtf16(), key, val);
+        LogFlow(("OnExtraDataChange: machineId={%ls}, key='%ls', val='%ls'\n",
+                 machineId.raw(), key.raw(), val.raw()));
+        return aCallback->OnExtraDataChange(machineId, key, val);
     }
 #ifdef RT_OS_WINDOWS
-    HRESULT prepareEventDesc(ComEventDesc& aEvDesc)
+    HRESULT prepareComEventDesc(ComEventDesc& aEvDesc)
     {
        aEvDesc.init("OnExtraDataChange", 3);
-       aEvDesc.add(machineId.toUtf16()).add(key).add(val);
+       aEvDesc.add(machineId).add(key).add(val);
        return S_OK;
     }
 #endif
-
-    Guid machineId;
-    Bstr key, val;
+    virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc)
+    {
+        return aEvDesc.init(aSource, VBoxEventType_OnExtraDataChange, machineId.raw(), key.raw(), val.raw());
+    }
+
+    Bstr machineId, key, val;
 };
 
@@ -2784,24 +2806,27 @@
     SessionEvent(VirtualBox *aVB, const Guid &aMachineId, SessionState_T aState)
         : CallbackEvent(aVB, VirtualBoxCallbackRegistration::kOnSessionStateChange)
-        , machineId(aMachineId), sessionState(aState)
+        , machineId(aMachineId.toUtf16()), sessionState(aState)
     {}
 
     HRESULT handleCallback(const ComPtr<IVirtualBoxCallback> &aCallback)
     {
-        LogFlow(("OnSessionStateChange: machineId={%RTuuid}, sessionState=%d\n",
-                 machineId.ptr(), sessionState));
-        return aCallback->OnSessionStateChange(machineId.toUtf16(), sessionState);
+        LogFlow(("OnSessionStateChange: machineId={%ls}, sessionState=%d\n",
+                 machineId.raw(), sessionState));
+        return aCallback->OnSessionStateChange(machineId, sessionState);
     }
 
 #ifdef RT_OS_WINDOWS
-    HRESULT prepareEventDesc(ComEventDesc& aEvDesc)
+    HRESULT prepareComEventDesc(ComEventDesc& aEvDesc)
     {
        aEvDesc.init("OnSessionStateChange", 2);
-       aEvDesc.add(machineId.toUtf16()).add((int)sessionState);
+       aEvDesc.add(machineId).add((int)sessionState);
        return S_OK;
     }
 #endif
-
-    Guid machineId;
+    virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc)
+    {
+        return aEvDesc.init(aSource, VBoxEventType_OnSessionStateChange, machineId.raw(), sessionState);
+    }
+    Bstr machineId;
     SessionState_T sessionState;
 };
@@ -2852,5 +2877,5 @@
 
 #ifdef RT_OS_WINDOWS
-    HRESULT prepareEventDesc(ComEventDesc& aEvDesc)
+    HRESULT prepareComEventDesc(ComEventDesc& aEvDesc)
     {
        aEvDesc.init("OnSnapshotTaken", 2);
@@ -2859,5 +2884,9 @@
     }
 #endif
-
+    virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc)
+    {
+        return aEvDesc.init(aSource, VBoxEventType_OnSnapshotTaken,
+                            machineId.toUtf16().raw(), snapshotId.toUtf16().raw());
+    }
 
     Guid machineId;
@@ -2912,5 +2941,5 @@
 
 #ifdef RT_OS_WINDOWS
-    HRESULT prepareEventDesc(ComEventDesc& aEvDesc)
+    HRESULT prepareComEventDesc(ComEventDesc& aEvDesc)
     {
        aEvDesc.init("OnGuestPropertyChange", 4);
@@ -2919,4 +2948,9 @@
     }
 #endif
+    virtual HRESULT prepareEventDesc(IEventSource* aSource, VBoxEventDesc& aEvDesc)
+    {
+        return aEvDesc.init(aSource, VBoxEventType_OnGuestPropertyChange,
+                            machineId.toUtf16().raw(), name.raw(), value.raw(), flags.raw());
+    }
 
     Guid machineId;
@@ -4623,5 +4657,4 @@
 
 #ifdef RT_OS_WINDOWS
-    // WIP
     {
      ComEventDesc evDesc;
@@ -4630,5 +4663,5 @@
      /* Only prepare args if someone really needs them */
      if (nConnections)
-        prepareEventDesc(evDesc);
+        prepareComEventDesc(evDesc);
 
      for (int i=0; i<nConnections; i++)
@@ -4652,4 +4685,18 @@
         }
      }
+    }
+#endif
+
+#if 0
+    // We disable generic events firing for now to not harm performance, but it is already functional
+    {
+        VBoxEventDesc evDesc;
+        prepareEventDesc(mVirtualBox->m->pEventSource, evDesc);
+        ComPtr<IEvent> aEvent;
+        BOOL fDelivered;
+
+        evDesc.getEvent(aEvent.asOutParam());
+        if (aEvent && mVirtualBox && mVirtualBox->m->pEventSource)
+            mVirtualBox->m->pEventSource->FireEvent(aEvent, /* don't wait for delivery */ 0, &fDelivered);
     }
 #endif
Index: trunk/src/VBox/Main/glue/vboxapi.py
===================================================================
--- trunk/src/VBox/Main/glue/vboxapi.py	(revision 30380)
+++ trunk/src/VBox/Main/glue/vboxapi.py	(revision 30381)
@@ -217,5 +217,4 @@
             win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
             win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
-            win32com.client.gencache.EnsureDispatch('VirtualBox.Console')
             win32com.client.gencache.EnsureDispatch('VirtualBox.CallbackWrapper')
 
@@ -312,4 +311,7 @@
         pass
 
+    def queryInterface(self, obj, klazzName):
+        from win32com.client import CastTo 
+        return CastTo(obj, klazzName)
 
 class PlatformXPCOM:
@@ -370,4 +372,8 @@
         import xpcom
         xpcom._xpcom.DeinitCOM()
+
+    def queryInterface(self, obj, klazzName):
+        import xpcom.components
+        return obj.queryInterface(getattr(xpcom.components.interfaces, klazzName))
 
 class PlatformWEBSERVICE:
@@ -452,4 +458,8 @@
            pass
 
+    def queryInterface(self, obj, klazzName):
+        # wrong, need to test if class indeed implements this interface
+        return globals()[klazzName](obj.mgr, obj.handle)
+
 class SessionManager:
     def __init__(self, mgr):
@@ -544,2 +554,5 @@
         global VboxSdkDir
         return VboxSdkDir
+
+    def queryInterface(self, obj, klazzName):
+        return self.platform.queryInterface(obj, klazzName)
Index: trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 30380)
+++ trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 30381)
@@ -14580,4 +14580,12 @@
       </desc>
     </const>
+   
+    <const name="SnapshotEvent" value="3">
+      <desc>
+        Wildcard for all snapshot events. Events of this type are never delivered, and only used in
+        registerListener() call to simplify registration.
+      </desc>
+    </const>
+
 
     <const name="LastWildcard" value="31">
@@ -14966,5 +14974,5 @@
 
    <interface
-     name="ISnapshotChangedEvent" extends="ISnapshotEvent"
+     name="ISnapshotChangeEvent" extends="ISnapshotEvent"
      uuid="07541941-8079-447a-a33e-47a69c7980db"
      wsmap="managed"
@@ -15023,10 +15031,9 @@
     </class>
 
-    <class name="CallbackWrapper" uuid="bcacd681-7f53-4409-a2a5-8534911f9358"
+    <class name="CallbackWrapper" uuid="0AD9C4CE-3C33-4C2D-AC7B-B008196787A0"
            namespace="virtualbox.org">
       <interface name="ILocalOwner" default="yes"/>
       <interface name="IVirtualBoxCallback"/>
       <interface name="IConsoleCallback"/>
-      <interface name="IEventListener"/>
     </class>
   </module>
Index: trunk/src/VBox/Main/include/EventImpl.h
===================================================================
--- trunk/src/VBox/Main/include/EventImpl.h	(revision 30380)
+++ trunk/src/VBox/Main/include/EventImpl.h	(revision 30381)
@@ -22,7 +22,7 @@
 
 class ATL_NO_VTABLE VBoxEvent :
+    public VirtualBoxBase,
     public VirtualBoxSupportErrorInfoImpl<VBoxEvent, IEvent>,
     public VirtualBoxSupportTranslation<VBoxEvent>,
-    public VirtualBoxBase,
     VBOX_SCRIPTABLE_IMPL(IEvent)
 {
@@ -54,5 +54,5 @@
     STDMETHOD(COMGETTER(Source)) (IEventSource * *aSource);
     STDMETHOD(COMGETTER(Waitable)) (BOOL *aWaitable);
-    
+
     // IEvent methods
     STDMETHOD(SetProcessed)();
@@ -99,5 +99,5 @@
     // IEventSource methods
     STDMETHOD(CreateListener)(IEventListener ** aListener);
-    STDMETHOD(RegisterListener)(IEventListener * aListener, 
+    STDMETHOD(RegisterListener)(IEventListener * aListener,
                                 ComSafeArrayIn(VBoxEventType_T, aInterested),
                                 BOOL             aActive);
@@ -123,3 +123,19 @@
 };
 
+class VBoxEventDesc
+{
+public:
+ VBoxEventDesc()
+ : mEvent(0)
+ {}
+ ~VBoxEventDesc()
+ {}
+
+ HRESULT init(IEventSource* aSource, VBoxEventType_T aType, ...);
+ void getEvent(IEvent ** aEvent);
+
+private:
+ ComPtr<IEvent>  mEvent;
+};
+
 #endif // ____H_EVENTIMPL
Index: trunk/src/VBox/Main/include/VirtualBoxCallbackImpl.h
===================================================================
--- trunk/src/VBox/Main/include/VirtualBoxCallbackImpl.h	(revision 30380)
+++ trunk/src/VBox/Main/include/VirtualBoxCallbackImpl.h	(revision 30381)
@@ -25,6 +25,5 @@
     VBOX_SCRIPTABLE_IMPL(ILocalOwner),
     VBOX_SCRIPTABLE_IMPL(IConsoleCallback),
-    VBOX_SCRIPTABLE_IMPL(IVirtualBoxCallback),
-    VBOX_SCRIPTABLE_IMPL(IEventListener)
+    VBOX_SCRIPTABLE_IMPL(IVirtualBoxCallback)
 #ifdef RT_OS_WINDOWS
     , public CComCoClass<CallbackWrapper, &CLSID_CallbackWrapper>
@@ -46,5 +45,4 @@
         COM_INTERFACE_ENTRY(IVirtualBoxCallback)
         COM_INTERFACE_ENTRY(IConsoleCallback)
-        COM_INTERFACE_ENTRY(IEventListener)
     END_COM_MAP()
 
@@ -97,7 +95,4 @@
     STDMETHOD(OnShowWindow)(ULONG64 *winId);
 
-    // IEventListener
-    STDMETHOD(HandleEvent)(IEvent *aEvent);
-
     // for VirtualBoxSupportErrorInfoImpl
     static const wchar_t *getComponentName() { return L"CallbackWrapper"; }
