Index: /trunk/src/VBox/Main/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 28958)
+++ /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 28959)
@@ -242,4 +242,138 @@
 };
 
+// ConsoleCallbackRegistration
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Registered IConsoleCallback, used by Console::CallbackList and
+ * Console::mCallbacks.
+ *
+ * In addition to keeping the interface pointer this also keeps track of the
+ * methods that asked to not be called again.  The latter is for reducing
+ * unnecessary IPC.
+ */
+class ConsoleCallbackRegistration
+{
+public:
+    ComPtr<IConsoleCallback> ptrICb;
+    /** Bitmap of disabled callback methods, that is methods that has return
+     * VBOX_E_DONT_CALL_AGAIN. */
+    uint32_t                    bmDisabled;
+    /** Callback bit indexes (for bmDisabled). */
+    typedef enum
+    {
+        kOnMousePointerShapeChange = 0,
+        kOnMouseCapabilityChange,
+        kOnKeyboardLedsChange,
+        kOnStateChange,
+        kOnAdditionsStateChange,
+        kOnNetworkAdapterChange,
+        kOnSerialPortChange,
+        kOnParallelPortChange,
+        kOnStorageControllerChange,
+        kOnMediumChange,
+        kOnCPUChange,
+        kOnVRDPServerChange,
+        kOnRemoteDisplayInfoChange,
+        kOnUSBControllerChange,
+        kOnUSBDeviceStateChange,
+        kOnSharedFolderChange,
+        kOnRuntimeError,
+        kOnCanShowWindow,
+        kOnShowWindow
+    } CallbackBit;
+
+    ConsoleCallbackRegistration(IConsoleCallback *pIConsoleCallback)
+        : ptrICb(pIConsoleCallback), bmDisabled(0)
+    {
+        /* nothing */
+    }
+
+    ~ConsoleCallbackRegistration()
+    {
+       /* nothing */
+    }
+
+    /** Equal operator for std::find. */
+    bool operator==(const ConsoleCallbackRegistration &rThat) const
+    {
+        return this->ptrICb == rThat.ptrICb;
+    }
+
+    /**
+     * Checks if the callback is wanted, i.e. if the method hasn't yet returned
+     * VBOX_E_DONT_CALL_AGAIN.
+     * @returns @c true if it is wanted, @c false if not.
+     * @param   enmBit      The callback, be sure to get this one right!
+     */
+    inline bool isWanted(CallbackBit enmBit) const
+    {
+        return !ASMBitTest(&bmDisabled, enmBit);
+    }
+
+    /**
+     * Called in response to VBOX_E_DONT_CALL_AGAIN.
+     * @param   enmBit      The callback, be sure to get this one right!
+     */
+    inline void setDontCallAgain(CallbackBit enmBit)
+    {
+        ASMAtomicBitSet(&bmDisabled, enmBit);
+    }
+
+    /**
+     * Handle a callback return code, picking up VBOX_E_DONT_CALL_AGAIN.
+     *
+     * @returns hrc or S_OK if VBOX_E_DONT_CALL_AGAIN.
+     * @param   enmBit      The callback, be sure to get this one right!
+     * @param   hrc         The status code returned by the callback.
+     */
+    inline HRESULT handleResult(CallbackBit enmBit, HRESULT hrc)
+    {
+        if (hrc == VBOX_E_DONT_CALL_AGAIN)
+        {
+            setDontCallAgain(enmBit);
+            hrc = S_OK;
+        }
+        return hrc;
+    }
+};
+
+/**
+ * Macro for iterating the callback list (Console::mCallbacks) and invoking the
+ * given method on each entry.
+ *
+ * This handles VBOX_E_DONT_CALL_AGAIN as well as removing dead interfaces
+ * which.  This makes the code a big and clunky, thus this macro.  It may make
+ * debugging and selective logging a bit of a pain, but duplicating this code
+ * some seventeen times is much more of a pain.
+ *
+ * The caller must hold the console object lock - read or write, we don't care.
+ * The caller must be a Console method - the console members accessible thru the
+ * 'this' pointer.
+ *
+ * @param   CallbackMethod      The callback method, like OnKeyboardLedsChange.
+ * @param   Args                The method arguments enclosed in parentheses.
+ */
+#define CONSOLE_DO_CALLBACKS(CallbackMethod, Args) \
+    do \
+    { \
+        CallbackList::iterator it = this->mCallbacks.begin(); \
+        while (it != this->mCallbacks.end()) \
+        { \
+            if (it->isWanted(ConsoleCallbackRegistration::k ## CallbackMethod)) \
+            { \
+                HRESULT hrc = it->ptrICb-> CallbackMethod Args; \
+                hrc = it->handleResult(ConsoleCallbackRegistration::k ## CallbackMethod, hrc); \
+                if (FAILED_DEAD_INTERFACE(hrc)) \
+                { \
+                    it = this->mCallbacks.erase(it); \
+                    continue; \
+                } \
+            } \
+            ++it; \
+        } \
+    } while (0)
+
+
 // constructor / destructor
 /////////////////////////////////////////////////////////////////////////////
@@ -2622,9 +2756,5 @@
 
     /* notify console callbacks after the folder is added to the list */
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnSharedFolderChange(Scope_Session);
-    }
+    CONSOLE_DO_CALLBACKS(OnSharedFolderChange,(Scope_Session));
 
     return rc;
@@ -2683,9 +2813,5 @@
 
     /* notify console callbacks after the folder is removed to the list */
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnSharedFolderChange(Scope_Session);
-    }
+    CONSOLE_DO_CALLBACKS(OnSharedFolderChange,(Scope_Session));
 
     return rc;
@@ -3380,9 +3506,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnNetworkAdapterChange(aNetworkAdapter);
-    }
+        CONSOLE_DO_CALLBACKS(OnNetworkAdapterChange,(aNetworkAdapter));
 
     LogFlowThisFunc(("Leaving rc=%#x\n", rc));
@@ -3600,9 +3722,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnSerialPortChange(aSerialPort);
-    }
+        CONSOLE_DO_CALLBACKS(OnSerialPortChange,(aSerialPort));
 
     LogFlowThisFunc(("Leaving rc=%#x\n", rc));
@@ -3638,9 +3756,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnParallelPortChange(aParallelPort);
-    }
+        CONSOLE_DO_CALLBACKS(OnParallelPortChange,(aParallelPort));
 
     LogFlowThisFunc(("Leaving rc=%#x\n", rc));
@@ -3676,9 +3790,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnStorageControllerChange();
-    }
+        CONSOLE_DO_CALLBACKS(OnStorageControllerChange,());
 
     LogFlowThisFunc(("Leaving rc=%#x\n", rc));
@@ -3714,9 +3824,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnMediumChange(aMediumAttachment);
-    }
+        CONSOLE_DO_CALLBACKS(OnMediumChange,(aMediumAttachment));
 
     LogFlowThisFunc(("Leaving rc=%#x\n", rc));
@@ -3755,9 +3861,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnCPUChange(aCPU, aRemove);
-    }
+        CONSOLE_DO_CALLBACKS(OnCPUChange,(aCPU, aRemove));
 
     LogFlowThisFunc(("Leaving rc=%#x\n", rc));
@@ -3820,9 +3922,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnVRDPServerChange();
-    }
+        CONSOLE_DO_CALLBACKS(OnVRDPServerChange,());
 
     return rc;
@@ -3839,7 +3937,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-        (*it++)->OnRemoteDisplayInfoChange();
+    CONSOLE_DO_CALLBACKS(OnRemoteDisplayInfoChange,());
 }
 
@@ -3879,9 +3975,5 @@
     /* notify console callbacks on success */
     if (SUCCEEDED(rc))
-    {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnUSBControllerChange();
-    }
+        CONSOLE_DO_CALLBACKS(OnUSBControllerChange,());
 
     return rc;
@@ -3907,8 +3999,8 @@
     if (SUCCEEDED(rc))
     {
-        CallbackList::iterator it = mCallbacks.begin();
-        while (it != mCallbacks.end())
-            (*it++)->OnSharedFolderChange(aGlobal ? (Scope_T)Scope_Global
-                                                  : (Scope_T)Scope_Machine);
+        if (aGlobal)
+            CONSOLE_DO_CALLBACKS(OnSharedFolderChange,(Scope_Global));
+        else
+            CONSOLE_DO_CALLBACKS(OnSharedFolderChange,(Scope_Machine));
     }
 
@@ -4586,8 +4678,5 @@
     mCallbackData.mpsc.valid = true;
 
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-        (*it++)->OnMousePointerShapeChange(fVisible, fAlpha, xHot, yHot,
-                                           width, height, (BYTE *) pShape);
+    CONSOLE_DO_CALLBACKS(OnMousePointerShapeChange,(fVisible, fAlpha, xHot, yHot, width, height, (BYTE *) pShape));
 
 #if 0
@@ -4616,10 +4705,5 @@
     mCallbackData.mcc.valid = true;
 
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-    {
-        Log2(("Console::onMouseCapabilityChange: calling %p\n", (void*)*it));
-        (*it++)->OnMouseCapabilityChange(supportsAbsolute, supportsRelative, needsHostCursor);
-    }
+    CONSOLE_DO_CALLBACKS(OnMouseCapabilityChange,(supportsAbsolute, supportsRelative, needsHostCursor));
 }
 
@@ -4633,8 +4717,5 @@
 
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-        (*it++)->OnStateChange(machineState);
+    CONSOLE_DO_CALLBACKS(OnStateChange,(machineState));
 }
 
@@ -4648,8 +4729,5 @@
 
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-        (*it++)->OnAdditionsStateChange();
+    CONSOLE_DO_CALLBACKS(OnAdditionsStateChange,());
 }
 
@@ -4688,7 +4766,5 @@
     mCallbackData.klc.valid = true;
 
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-        (*it++)->OnKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
+    CONSOLE_DO_CALLBACKS(OnKeyboardLedsChange,(fNumLock, fCapsLock, fScrollLock));
 }
 
@@ -4703,8 +4779,5 @@
 
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-        (*it++)->OnUSBDeviceStateChange(aDevice, aAttached, aError);
+    CONSOLE_DO_CALLBACKS(OnUSBDeviceStateChange,(aDevice, aAttached, aError));
 }
 
@@ -4718,8 +4791,5 @@
 
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    CallbackList::iterator it = mCallbacks.begin();
-    while (it != mCallbacks.end())
-        (*it++)->OnRuntimeError(aFatal, aErrorID, aMessage);
+    CONSOLE_DO_CALLBACKS(OnRuntimeError,(aFatal, aErrorID, aMessage));
 }
 
@@ -4739,17 +4809,24 @@
 
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    HRESULT rc = S_OK;
     CallbackList::iterator it = mCallbacks.begin();
-
     if (aCheck)
     {
         while (it != mCallbacks.end())
         {
-            BOOL canShow = FALSE;
-            rc = (*it++)->OnCanShowWindow(&canShow);
-            AssertComRC(rc);
-            if (FAILED(rc) || !canShow)
-                return rc;
+            if (it->isWanted(ConsoleCallbackRegistration::kOnCanShowWindow))
+            {
+                BOOL canShow = FALSE;
+                HRESULT hrc = it->ptrICb->OnCanShowWindow(&canShow);
+                hrc = it->handleResult(ConsoleCallbackRegistration::kOnCanShowWindow, hrc);
+                if (FAILED_DEAD_INTERFACE(hrc))
+                {
+                    it = this->mCallbacks.erase(it);
+                    continue;
+                }
+                AssertComRC(hrc);
+                if (FAILED(hrc) || !canShow)
+                    return hrc;
+            }
+            ++it;
         }
         *aCanShow = TRUE;
@@ -4759,13 +4836,23 @@
         while (it != mCallbacks.end())
         {
-            ULONG64 winId = 0;
-            rc = (*it++)->OnShowWindow(&winId);
-            AssertComRC(rc);
-            if (FAILED(rc))
-                return rc;
-            /* only one callback may return non-null winId */
-            Assert(*aWinId == 0 || winId == 0);
-            if (*aWinId == 0)
-                *aWinId = winId;
+            if (it->isWanted(ConsoleCallbackRegistration::kOnShowWindow))
+            {
+                ULONG64 winId = 0;
+                HRESULT hrc = it->ptrICb->OnShowWindow(&winId);
+                hrc = it->handleResult(ConsoleCallbackRegistration::kOnCanShowWindow, hrc);
+                if (FAILED_DEAD_INTERFACE(hrc))
+                {
+                    it = this->mCallbacks.erase(it);
+                    continue;
+                }
+                AssertComRC(hrc);
+                if (FAILED(hrc))
+                    return hrc;
+
+                /* only one callback may return non-null winId */
+                Assert(*aWinId == 0 || winId == 0);
+                if (*aWinId == 0)
+                    *aWinId = winId;
+            }
         }
     }
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 28958)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 28959)
@@ -6161,4 +6161,7 @@
         Notification when the guest mouse pointer shape has
         changed. The new shape data is given.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="visible" type="boolean" dir="in">
@@ -6229,4 +6232,7 @@
         Notification when the mouse capabilities reported by the
         guest have changed. The new capabilities are passed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="supportsAbsolute" type="boolean" dir="in"/>
@@ -6239,4 +6245,7 @@
         Notification when the guest OS executes the KBD_CMD_SET_LEDS command
         to alter the state of the keyboard LEDs.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="numLock" type="boolean" dir="in"/>
@@ -6249,4 +6258,7 @@
         Notification when the execution state of the machine has changed.
         The new state will be given.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="state" type="MachineState" dir="in"/>
@@ -6267,4 +6279,7 @@
         changes.  Interested callees should use INetworkAdapter methods and
         attributes to find out what has changed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="networkAdapter" type="INetworkAdapter" dir="in">
@@ -6279,4 +6294,7 @@
         Interested callees should use ISerialPort methods and attributes
         to find out what has changed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="serialPort" type="ISerialPort" dir="in">
@@ -6291,4 +6309,7 @@
         changes.  Interested callees should use ISerialPort methods and
         attributes to find out what has changed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="parallelPort" type="IParallelPort" dir="in">
@@ -6303,4 +6324,7 @@
         changes. Interested callees should query the corresponding collections
         to find out what has changed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
     </method>
@@ -6311,4 +6335,7 @@
         <link to="IMachine::mediumAttachments">medium attachment</link>
         changes.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="mediumAttachment" type="IMediumAttachment" dir="in">
@@ -6320,4 +6347,7 @@
       <desc>
         Notification when a CPU changes.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="cpu" type="unsigned long" dir="in">
@@ -6335,4 +6365,7 @@
         Interested callees should use IVRDPServer methods and attributes to
         find out what has changed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
     </method>
@@ -6343,4 +6376,7 @@
         should use <link to="IConsole::RemoteDisplayInfo">IRemoteDisplayInfo</link>
         attributes to find out what is the current status.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
     </method>
@@ -6352,4 +6388,7 @@
         Interested callees should use IUSBController methods and attributes to
         find out what has changed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
     </method>
@@ -6375,4 +6414,7 @@
         message describing the failure.
 
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="device" type="IUSBDevice" dir="in">
@@ -6403,4 +6445,7 @@
         should use query the corresponding collections to find out what has
         changed.
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="scope" type="Scope" dir="in">
@@ -6469,4 +6514,7 @@
         </note>
 
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="fatal" type="boolean" dir="in">
@@ -6501,4 +6549,8 @@
           actually manages console window activation.
         </note>
+
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="canShow" type="boolean" dir="return">
@@ -6545,4 +6597,8 @@
           manages console window activation.
         </note>
+
+        <result name="VBOX_E_DONT_CALL_AGAIN">
+          Do not call again, this method is a NOP.
+        </result>
       </desc>
       <param name="winId" type="unsigned long long" dir="return">
Index: /trunk/src/VBox/Main/include/ConsoleImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 28958)
+++ /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 28959)
@@ -34,4 +34,5 @@
 class AudioSniffer;
 class ConsoleVRDPServer;
+class ConsoleCallbackRegistration;      /* See ConsoleImpl.cpp. */
 class VMMDev;
 class Progress;
@@ -650,5 +651,5 @@
     ComObjPtr<Progress> mptrCancelableProgress;
 
-    typedef std::list <ComPtr<IConsoleCallback> > CallbackList;
+    typedef std::list<ConsoleCallbackRegistration> CallbackList;
     CallbackList mCallbacks;
 
