Index: /trunk/doc/manual/en_US/SDKRef.xml
===================================================================
--- /trunk/doc/manual/en_US/SDKRef.xml	(revision 55213)
+++ /trunk/doc/manual/en_US/SDKRef.xml	(revision 55214)
@@ -3856,4 +3856,54 @@
 
       <itemizedlist>
+        <listitem>
+          <para>The methods for saving state, adopting a saved state file,
+          discarding saved state, taking a snapshot, restoring
+          a snapshot and deleting a snapshot have been moved from
+          <computeroutput>IConsole</computeroutput> to
+          <computeroutput>IMachine</computeroutput>. This straightens out the
+          logical placement of methods and was necessary to resolve a
+          long-standing issue, preventing 32 bit API clients from invokingi
+          those operations in the case where no VM is running.
+          Method
+          <xref linkend="IMachine__saveState"
+          xreflabel="IMachine::saveState()" /> replaces
+          <computeroutput>IConsole::saveState()</computeroutput>,
+          <xref linkend="IMachine__adoptSavedState"
+          xreflabel="IMachine::adoptSavedState()" /> replaces
+          <computeroutput>IConsole::adoptSavedState()</computeroutput>,
+          <xref linkend="IMachine__discardSavedState"
+          xreflabel="IMachine::discardSavedState()" /> replaces
+          <computeroutput>IConsole::discardSavedState()</computeroutput>,
+          <xref linkend="IMachine__takeSnapshot"
+          xreflabel="IMachine::takeSnapshot()" /> replaces
+          <computeroutput>IConsole::takeSnapshot()</computeroutput>,
+          <xref linkend="IMachine__deleteSnapshot"
+          xreflabel="IMachine::deleteSnapshot()" /> replaces
+          <computeroutput>IConsole::deleteSnapshot()</computeroutput>,
+          <xref linkend="IMachine__deleteSnapshotAndAllChildren"
+          xreflabel="IMachine::deleteSnapshotAndAllChildren()" /> replaces
+          <computeroutput>IConsole::deleteSnapshotAndAllChildren()</computeroutput>,
+          <xref linkend="IMachine__deleteSnapshotRange"
+          xreflabel="IMachine::deleteSnapshotRange()" /> replaces
+          <computeroutput>IConsole::deleteSnapshotRange()</computeroutput> and
+          <xref linkend="IMachine__restoreSnapshot"
+          xreflabel="IMachine::restoreSnapshot()" /> replaces
+          <computeroutput>IConsole::restoreSnapshot()</computeroutput>.
+          Small adjustments to the parameter lists have been made to reduce
+          the number of API calls when taking online snapshots etc.</para>
+        </listitem>
+
+        <listitem>
+          <para>Two new machine states have been introduced to allow proper
+          distinction between saving state and taking a snapshot.
+          <xref linkend="MachineState__Saving" xreflabel="MachineState_Saving" />
+          now is used exclusively while the VM's state is being saved, without
+          any overlaps with snapshot functionality. The new state
+          <xref linkend="MachineState__Snapshotting" xreflabel="MachineState_Snapshotting" />
+          is used when an offline snapshot is taken and likewise the new state
+          <xref linkend="MachineState__OnlineSnapshotting" xreflabel="MachineState_OnlineSnapshotting" />
+          is used when an online snapshot is taken.</para>
+        </listitem>
+
         <listitem>
           <para>The method <xref linkend="IVirtualBox__createMedium"
Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp	(revision 55214)
@@ -51,4 +51,5 @@
 {
     HRESULT rc = S_OK;
+    ComPtr<IMachine> machine;
     ComPtr<IProgress> progress;
 
@@ -83,5 +84,6 @@
         }
 
-        CHECK_ERROR(console, SaveState(progress.asOutParam()));
+        CHECK_ERROR(console, COMGETTER(Machine)(machine.asOutParam()));
+        CHECK_ERROR(machine, SaveState(progress.asOutParam()));
         if (FAILED(rc))
         {
Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartUtils.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartUtils.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartUtils.cpp	(revision 55214)
@@ -48,8 +48,8 @@
         case MachineState_Saved:
             return "saved";
+        case MachineState_Teleported:
+            return "teleported";
         case MachineState_Aborted:
             return "aborted";
-        case MachineState_Teleported:
-            return "teleported";
         case MachineState_Running:
             return "running";
@@ -58,8 +58,8 @@
         case MachineState_Stuck:
             return fShort ? "gurumeditation"       : "guru meditation";
+        case MachineState_Teleporting:
+            return "teleporting";
         case MachineState_LiveSnapshotting:
             return fShort ? "livesnapshotting"     : "live snapshotting";
-        case MachineState_Teleporting:
-            return "teleporting";
         case MachineState_Starting:
             return "starting";
@@ -74,14 +74,18 @@
         case MachineState_TeleportingIn:
             return fShort ? "teleportingin"        : "teleporting (incoming)";
+        case MachineState_DeletingSnapshotOnline:
+            return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
+        case MachineState_DeletingSnapshotPaused:
+            return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
+        case MachineState_OnlineSnapshotting:
+            return fShort ? "onlinesnapshotting"   : "online snapshotting";
         case MachineState_RestoringSnapshot:
             return fShort ? "restoringsnapshot"    : "restoring snapshot";
         case MachineState_DeletingSnapshot:
             return fShort ? "deletingsnapshot"     : "deleting snapshot";
-        case MachineState_DeletingSnapshotOnline:
-            return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
-        case MachineState_DeletingSnapshotPaused:
-            return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
         case MachineState_SettingUp:
             return fShort ? "settingup"           : "setting up";
+        case MachineState_Snapshotting:
+            return "snapshotting";
         default:
             break;
Index: /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModAPIMonitor.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModAPIMonitor.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModAPIMonitor.cpp	(revision 55214)
@@ -1,3 +1,2 @@
-
 /* $Id$ */
 /** @file
@@ -6,5 +5,5 @@
 
 /*
- * Copyright (C) 2012 Oracle Corporation
+ * Copyright (C) 2012-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -214,4 +213,7 @@
                 ComPtr<IConsole> console;
                 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
+                /* Get the associated session machine. */
+                ComPtr<IMachine> sessionMachine;
+                CHECK_ERROR_BREAK(g_pSession, COMGETTER(Machine)(sessionMachine.asOutParam()));
 
                 ComPtr<IProgress> progress;
@@ -269,5 +271,5 @@
                         }
 
-                        CHECK_ERROR(console, SaveState(progress.asOutParam()));
+                        CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
                         if (SUCCEEDED(rc))
                         {
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp	(revision 55214)
@@ -262,5 +262,5 @@
 
             ComPtr<IProgress> progress;
-            CHECK_ERROR(console, SaveState(progress.asOutParam()));
+            CHECK_ERROR(sessionMachine, SaveState(progress.asOutParam()));
             if (FAILED(rc))
             {
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 55214)
@@ -139,8 +139,8 @@
         case MachineState_Saved:
             return "saved";
+        case MachineState_Teleported:
+            return "teleported";
         case MachineState_Aborted:
             return "aborted";
-        case MachineState_Teleported:
-            return "teleported";
         case MachineState_Running:
             return "running";
@@ -149,8 +149,8 @@
         case MachineState_Stuck:
             return fShort ? "gurumeditation"       : "guru meditation";
+        case MachineState_Teleporting:
+            return "teleporting";
         case MachineState_LiveSnapshotting:
             return fShort ? "livesnapshotting"     : "live snapshotting";
-        case MachineState_Teleporting:
-            return "teleporting";
         case MachineState_Starting:
             return "starting";
@@ -165,14 +165,20 @@
         case MachineState_TeleportingIn:
             return fShort ? "teleportingin"        : "teleporting (incoming)";
+        case MachineState_FaultTolerantSyncing:
+            return fShort ? "faulttolerantsyncing" : "fault tolerant syncing";
+        case MachineState_DeletingSnapshotOnline:
+            return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
+        case MachineState_DeletingSnapshotPaused:
+            return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
+        case MachineState_OnlineSnapshotting:
+            return fShort ? "onlinesnapshotting"   : "online snapshotting";
         case MachineState_RestoringSnapshot:
             return fShort ? "restoringsnapshot"    : "restoring snapshot";
         case MachineState_DeletingSnapshot:
             return fShort ? "deletingsnapshot"     : "deleting snapshot";
-        case MachineState_DeletingSnapshotOnline:
-            return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
-        case MachineState_DeletingSnapshotPaused:
-            return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
         case MachineState_SettingUp:
-            return fShort ? "settingup"           : "setting up";
+            return fShort ? "settingup"            : "setting up";
+        case MachineState_Snapshotting:
+            return fShort ? "snapshotting"         : "offline snapshotting";
         default:
             break;
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 55214)
@@ -650,6 +650,6 @@
             do
             {
-                ComPtr<IConsole> console;
-                CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
+                ComPtr<IMachine> console;
+                CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(machine.asOutParam()));
                 CHECK_ERROR_BREAK(console, DiscardSavedState(true /* fDeleteFile */));
             } while (0);
@@ -687,7 +687,7 @@
             do
             {
-                ComPtr<IConsole> console;
-                CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
-                CHECK_ERROR_BREAK(console, AdoptSavedState(Bstr(szStateFileAbs).raw()));
+                ComPtr<IMachine> machine;
+                CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(machine.asOutParam()));
+                CHECK_ERROR_BREAK(machine, AdoptSavedState(Bstr(szStateFileAbs).raw()));
             } while (0);
             CHECK_ERROR_BREAK(a->session, UnlockMachine());
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp	(revision 55214)
@@ -281,10 +281,10 @@
         return 1;
 
+    /* we have to open a session for this task (new or shared) */
+    CHECK_ERROR_RET(pMachine, LockMachine(a->session, LockType_Shared), 1);
     do
     {
-        /* we have to open a session for this task (new or shared) */
-        rc = pMachine->LockMachine(a->session, LockType_Shared);
-        ComPtr<IConsole> pConsole;
-        CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(pConsole.asOutParam()));
+        /* replace the (read-only) IMachine object by a writable one */
+        CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(pMachine.asOutParam()));
 
         /* switch based on the command */
@@ -346,33 +346,11 @@
                 break;
 
-            if (fPause)
-            {
-                MachineState_T machineState;
-                CHECK_ERROR_BREAK(pConsole, COMGETTER(State)(&machineState));
-                if (machineState == MachineState_Running)
-                    CHECK_ERROR_BREAK(pConsole, Pause());
-                else
-                    fPause = false;
-            }
-
             ComPtr<IProgress> progress;
-            CHECK_ERROR_BREAK(pConsole, TakeSnapshot(name.raw(), desc.raw(),
+            CHECK_ERROR_BREAK(pMachine, TakeSnapshot(name.raw(), desc.raw(),
+                                                     fPause,
                                                      progress.asOutParam()));
 
             rc = showProgress(progress);
             CHECK_PROGRESS_ERROR(progress, ("Failed to take snapshot"));
-
-            if (fPause)
-            {
-                MachineState_T machineState;
-                CHECK_ERROR_BREAK(pConsole, COMGETTER(State)(&machineState));
-                if (machineState == MachineState_Paused)
-                {
-                    if (SUCCEEDED(rc))
-                        CHECK_ERROR_BREAK(pConsole, Resume());
-                    else
-                        pConsole->Resume();
-                }
-            }
         }
         else if (    (fDelete = !strcmp(a->argv[1], "delete"))
@@ -417,5 +395,5 @@
             if (fDelete)
             {
-                CHECK_ERROR_BREAK(pConsole, DeleteSnapshot(bstrSnapGuid.raw(),
+                CHECK_ERROR_BREAK(pMachine, DeleteSnapshot(bstrSnapGuid.raw(),
                                                            pProgress.asOutParam()));
             }
@@ -424,5 +402,5 @@
                 // restore or restore current
                 RTPrintf("Restoring snapshot %ls\n", bstrSnapGuid.raw());
-                CHECK_ERROR_BREAK(pConsole, RestoreSnapshot(pSnapshot, pProgress.asOutParam()));
+                CHECK_ERROR_BREAK(pMachine, RestoreSnapshot(pSnapshot, pProgress.asOutParam()));
             }
 
Index: /trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp	(revision 55214)
@@ -1838,5 +1838,5 @@
         if (machineState == MachineState_Saved)
         {
-            CHECK_ERROR(gpConsole, DiscardSavedState(true /* fDeleteFile */));
+            CHECK_ERROR(gpMachine, DiscardSavedState(true /* fDeleteFile */));
         }
         /*
@@ -1855,5 +1855,5 @@
                 goto leave;
 
-            CHECK_ERROR(gpConsole, RestoreSnapshot(pCurrentSnapshot, gpProgress.asOutParam()));
+            CHECK_ERROR(gpMachine, RestoreSnapshot(pCurrentSnapshot, gpProgress.asOutParam()));
             rc = gpProgress->WaitForCompletion(-1);
         }
@@ -4200,5 +4200,5 @@
     UpdateTitlebar(TITLEBAR_SAVE);
     gpProgress = NULL;
-    HRESULT rc = gpConsole->SaveState(gpProgress.asOutParam());
+    HRESULT rc = gpMachine->SaveState(gpProgress.asOutParam());
     if (FAILED(rc))
     {
@@ -4950,6 +4950,7 @@
             gpProgress = NULL;
             HRESULT rc;
-            CHECK_ERROR(gpConsole, TakeSnapshot(Bstr(pszSnapshotName).raw(),
+            CHECK_ERROR(gpMachine, TakeSnapshot(Bstr(pszSnapshotName).raw(),
                                                 Bstr("Taken by VBoxSDL").raw(),
+						TRUE,
                                                 gpProgress.asOutParam()));
             if (FAILED(rc))
Index: /trunk/src/VBox/Frontends/VBoxShell/vboxshell.py
===================================================================
--- /trunk/src/VBox/Frontends/VBoxShell/vboxshell.py	(revision 55213)
+++ /trunk/src/VBox/Frontends/VBoxShell/vboxshell.py	(revision 55214)
@@ -250,7 +250,11 @@
     print "removing machine ", mach.name, "with UUID", uuid
     cmdClosedVm(ctx, mach, detachVmDevice, ["ALL"])
-    mach = mach.unregister(ctx['global'].constants.CleanupMode_Full)
+    disks = mach.unregister(ctx['global'].constants.CleanupMode_Full)
     if mach:
-        mach.deleteSettings()
+        progress = mach.deleteConfig(disks)
+        if progressBar(ctx, progress, 100) and int(progress.resultCode) == 0:
+            print "Success!"
+        else:
+            reportError(ctx, progress)
     # update cache
     getMachines(ctx, True)
@@ -718,5 +722,5 @@
            'ginfo':           lambda: ginfo(ctx, console, args),
            'guestlambda':     lambda: args[0](ctx, mach, console, args[1:]),
-           'save':            lambda: progressBar(ctx, console.saveState()),
+           'save':            lambda: progressBar(ctx, session.machine.saveState()),
            'screenshot':      lambda: takeScreenshot(ctx, console, args),
            'teleport':        lambda: teleport(ctx, session, console, args),
@@ -2631,5 +2635,5 @@
         else:
             desc = ""
-        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, console.takeSnapshot(name, desc)))
+        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.takeSnapshot(name, desc, true)))
         return 0
 
@@ -2640,5 +2644,5 @@
         name = args[3]
         snap = mach.findSnapshot(name)
-        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, console.restoreSnapshot(snap)))
+        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.restoreSnapshot(snap)))
         return 0
 
@@ -2648,5 +2652,5 @@
             return 0
         snap = mach.currentSnapshot()
-        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, console.restoreSnapshot(snap)))
+        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.restoreSnapshot(snap)))
         return 0
 
@@ -2657,5 +2661,5 @@
         name = args[3]
         snap = mach.findSnapshot(name)
-        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, console.deleteSnapshot(snap.id)))
+        cmdAnyVm(ctx, mach, lambda ctx, mach, console, args: progressBar(ctx, mach.deleteSnapshot(snap.id)))
         return 0
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendCOM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendCOM.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/converter/UIConverterBackendCOM.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2012-2014 Oracle Corporation
+ * Copyright (C) 2012-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -73,4 +73,6 @@
         case KMachineState_Stuck:                  return QColor(Qt::darkMagenta);
         case KMachineState_Teleporting:            return QColor(Qt::blue);
+        case KMachineState_Snapshotting:           return QColor(Qt::green);
+        case KMachineState_OnlineSnapshotting:     return QColor(Qt::green);
         case KMachineState_LiveSnapshotting:       return QColor(Qt::green);
         case KMachineState_Starting:               return QColor(Qt::green);
@@ -108,4 +110,6 @@
         case KMachineState_Stuck:                  return UIIconPool::iconSet(":/state_stuck_16px.png");
         case KMachineState_Teleporting:            return UIIconPool::iconSet(":/state_running_16px.png");
+        case KMachineState_Snapshotting:           return UIIconPool::iconSet(":/state_saving_16px.png");
+        case KMachineState_OnlineSnapshotting:     return UIIconPool::iconSet(":/state_running_16px.png");
         case KMachineState_LiveSnapshotting:       return UIIconPool::iconSet(":/state_running_16px.png");
         case KMachineState_Starting:               return UIIconPool::iconSet(":/state_running_16px.png");
@@ -143,4 +147,6 @@
         case KMachineState_Stuck:                  return QApplication::translate("VBoxGlobal", "Guru Meditation", "MachineState");
         case KMachineState_Teleporting:            return QApplication::translate("VBoxGlobal", "Teleporting", "MachineState");
+        case KMachineState_Snapshotting:           return QApplication::translate("VBoxGlobal", "Taking Snapshot", "MachineState");
+        case KMachineState_OnlineSnapshotting:     return QApplication::translate("VBoxGlobal", "Taking Online Snapshot", "MachineState");
         case KMachineState_LiveSnapshotting:       return QApplication::translate("VBoxGlobal", "Taking Live Snapshot", "MachineState");
         case KMachineState_Starting:               return QApplication::translate("VBoxGlobal", "Starting", "MachineState");
Index: /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -766,18 +766,18 @@
 }
 
-void UIMessageCenter::cannotDiscardSavedState(const CConsole &console) const
+void UIMessageCenter::cannotDiscardSavedState(const CMachine &machine) const
 {
     error(0, MessageType_Error,
           tr("Failed to discard the saved state of the virtual machine <b>%1</b>.")
-             .arg(CConsole(console).GetMachine().GetName()),
-          formatErrorInfo(console));
-}
-
-void UIMessageCenter::cannotSaveMachineState(const CConsole &console)
+             .arg(machine.GetName()),
+          formatErrorInfo(machine));
+}
+
+void UIMessageCenter::cannotSaveMachineState(const CMachine &machine)
 {
     error(0, MessageType_Error,
           tr("Failed to save the state of the virtual machine <b>%1</b>.")
-             .arg(CConsole(console).GetMachine().GetName()),
-          formatErrorInfo(console));
+             .arg(machine.GetName()),
+          formatErrorInfo(machine));
 }
 
@@ -866,10 +866,10 @@
 }
 
-void UIMessageCenter::cannotTakeSnapshot(const CConsole &console, const QString &strMachineName, QWidget *pParent /* = 0*/) const
+void UIMessageCenter::cannotTakeSnapshot(const CMachine &machine, const QString &strMachineName, QWidget *pParent /* = 0*/) const
 {
     error(pParent, MessageType_Error,
           tr("Failed to create a snapshot of the virtual machine <b>%1</b>.")
              .arg(strMachineName),
-          formatErrorInfo(console));
+          formatErrorInfo(machine));
 }
 
@@ -882,10 +882,10 @@
 }
 
-bool UIMessageCenter::cannotRestoreSnapshot(const CConsole &console, const QString &strSnapshotName, const QString &strMachineName) const
+bool UIMessageCenter::cannotRestoreSnapshot(const CMachine &machine, const QString &strSnapshotName, const QString &strMachineName) const
 {
     error(0, MessageType_Error,
           tr("Failed to restore the snapshot <b>%1</b> of the virtual machine <b>%2</b>.")
              .arg(strSnapshotName, strMachineName),
-          formatErrorInfo(console));
+          formatErrorInfo(machine));
     return false;
 }
@@ -900,10 +900,10 @@
 }
 
-void UIMessageCenter::cannotRemoveSnapshot(const CConsole &console, const QString &strSnapshotName, const QString &strMachineName) const
+void UIMessageCenter::cannotRemoveSnapshot(const CMachine &machine, const QString &strSnapshotName, const QString &strMachineName) const
 {
     error(0, MessageType_Error,
           tr("Failed to delete the snapshot <b>%1</b> of the virtual machine <b>%2</b>.")
              .arg(strSnapshotName, strMachineName),
-          formatErrorInfo(console));
+          formatErrorInfo(machine));
 }
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h	(revision 55214)
@@ -4,5 +4,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -191,6 +191,6 @@
     void cannotPauseMachine(const CConsole &console) const;
     void cannotResumeMachine(const CConsole &console) const;
-    void cannotDiscardSavedState(const CConsole &console) const;
-    void cannotSaveMachineState(const CConsole &console);
+    void cannotDiscardSavedState(const CMachine &machine) const;
+    void cannotSaveMachineState(const CMachine &machine);
     void cannotSaveMachineState(const CProgress &progress, const QString &strMachineName);
     void cannotACPIShutdownMachine(const CConsole &console) const;
@@ -203,9 +203,9 @@
     bool warnAboutSnapshotRemovalFreeSpace(const QString &strSnapshotName, const QString &strTargetImageName,
                                            const QString &strTargetImageMaxSize, const QString &strTargetFileSystemFree) const;
-    void cannotTakeSnapshot(const CConsole &console, const QString &strMachineName, QWidget *pParent = 0) const;
+    void cannotTakeSnapshot(const CMachine &machine, const QString &strMachineName, QWidget *pParent = 0) const;
     void cannotTakeSnapshot(const CProgress &progress, const QString &strMachineName, QWidget *pParent = 0) const;
-    bool cannotRestoreSnapshot(const CConsole &console, const QString &strSnapshotName, const QString &strMachineName) const;
+    bool cannotRestoreSnapshot(const CMachine &machine, const QString &strSnapshotName, const QString &strMachineName) const;
     bool cannotRestoreSnapshot(const CProgress &progress, const QString &strSnapshotName, const QString &strMachineName) const;
-    void cannotRemoveSnapshot(const CConsole &console, const QString &strSnapshotName, const QString &strMachineName) const;
+    void cannotRemoveSnapshot(const CMachine &machine, const QString &strSnapshotName, const QString &strMachineName) const;
     void cannotRemoveSnapshot(const CProgress &progress, const QString &strSnapshotName, const QString &strMachineName) const;
 
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachine.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachine.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachine.cpp	(revision 55214)
@@ -62,10 +62,8 @@
         CSnapshot snapshot = machine.GetCurrentSnapshot();
 
-        /* Open corresponding console: */
-        CConsole console  = session.GetConsole();
         /* Prepare restore-snapshot progress: */
-        CProgress progress = console.RestoreSnapshot(snapshot);
-        if (!console.isOk())
-            return msgCenter().cannotRestoreSnapshot(console, snapshot.GetName(), machine.GetName());
+        CProgress progress = machine.RestoreSnapshot(snapshot);
+        if (!machine.isOk())
+            return msgCenter().cannotRestoreSnapshot(machine, snapshot.GetName(), machine.GetName());
 
         /* Show the snapshot-discarding progress: */
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp	(revision 55214)
@@ -1391,14 +1391,4 @@
         return;
 
-    /* Remember the paused state: */
-    bool fWasPaused = uisession()->isPaused();
-    if (!fWasPaused)
-    {
-        /* Suspend the VM and ignore the close event if failed to do so.
-         * pause() will show the error message to the user. */
-        if (!uisession()->pause())
-            return;
-    }
-
     /* Create take-snapshot dialog: */
     QWidget *pDlgParent = windowManager().realParentWindow(activeMachineWindow());
@@ -1433,6 +1423,6 @@
     {
         /* Prepare the take-snapshot progress: */
-        CProgress progress = console().TakeSnapshot(strSnapshotName, strSnapshotDescription);
-        if (console().isOk())
+        CProgress progress = machine().TakeSnapshot(strSnapshotName, strSnapshotDescription, true);
+        if (machine().isOk())
         {
             /* Show the take-snapshot progress: */
@@ -1442,14 +1432,5 @@
         }
         else
-            msgCenter().cannotTakeSnapshot(console(), machineName());
-    }
-
-    /* Restore the running state if needed: */
-    if (!fWasPaused)
-    {
-        /* Make sure machine-state-change callback is processed: */
-        QApplication::sendPostedEvents(uisession(), UIConsoleEventType_StateChange);
-        /* Unpause VM: */
-        uisession()->unpause();
+            msgCenter().cannotTakeSnapshot(machine(), machineName());
     }
 }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -300,6 +300,6 @@
 {
     /* Prepare the saving progress: */
-    CProgress progress = console().SaveState();
-    if (console().isOk())
+    CProgress progress = machine().SaveState();
+    if (machine().isOk())
     {
         /* Show the saving progress: */
@@ -315,5 +315,5 @@
     {
         /* Failed in console: */
-        msgCenter().cannotSaveMachineState(console());
+        msgCenter().cannotSaveMachineState(machine());
         return false;
     }
@@ -408,28 +408,28 @@
         do
         {
-            /* Acquire console for this session: */
-            CConsole cons = sess.GetConsole();
-            if (cons.isNull())
+            /* Acquire machine for this session: */
+            CMachine machine = sess.GetMachine();
+            if (machine.isNull())
             {
-                /* Unable to acquire console: */
+                /* Unable to acquire machine: */
                 break;
             }
 
             /* Prepare the snapshot-discard progress: */
-            const CSnapshot snap = mach.GetCurrentSnapshot();
-            CProgress prog = cons.RestoreSnapshot(snap);
-            if (!cons.isOk() || prog.isNull())
+            const CSnapshot snap = machine.GetCurrentSnapshot();
+            CProgress prog = machine.RestoreSnapshot(snap);
+            if (!machine.isOk() || prog.isNull())
             {
                 /* Unable to restore snapshot: */
-                msgCenter().cannotRestoreSnapshot(cons, snap.GetName(), machineName());
+                msgCenter().cannotRestoreSnapshot(machine, snap.GetName(), machineName());
                 break;
             }
 
             /* Show the snapshot-discard progress: */
-            msgCenter().showModalProgressDialog(prog, mach.GetName(), ":/progress_snapshot_discard_90px.png");
+            msgCenter().showModalProgressDialog(prog, machine.GetName(), ":/progress_snapshot_discard_90px.png");
             if (prog.GetResultCode() != 0)
             {
                 /* Unable to restore snapshot: */
-                msgCenter().cannotRestoreSnapshot(prog, snap.GetName(), mach.GetName());
+                msgCenter().cannotRestoreSnapshot(prog, snap.GetName(), machine.GetName());
                 break;
             }
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -498,9 +498,9 @@
             return;
 
-        /* Get session console: */
-        CConsole console = session.GetConsole();
-        console.DiscardSavedState(true);
-        if (!console.isOk())
-            msgCenter().cannotDiscardSavedState(console);
+        /* Get session machine: */
+        CMachine machine = session.GetMachine();
+        machine.DiscardSavedState(true);
+        if (!machine.isOk())
+            msgCenter().cannotDiscardSavedState(machine);
 
         /* Unlock machine finally: */
@@ -623,4 +623,6 @@
         /* Get session console: */
         CConsole console = session.GetConsole();
+        /* Get session machine: */
+        CMachine machine = session.GetMachine();
         /* Pause VM first: */
         console.Pause();
@@ -628,9 +630,8 @@
         {
             /* Prepare machine state saving: */
-            CProgress progress = console.SaveState();
-            if (console.isOk())
+            CProgress progress = machine.SaveState();
+            if (machine.isOk())
             {
                 /* Show machine state saving progress: */
-                CMachine machine = session.GetMachine();
                 msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_save_90px.png");
                 if (!progress.isOk() || progress.GetResultCode() != 0)
@@ -638,5 +639,5 @@
             }
             else
-                msgCenter().cannotSaveMachineState(console);
+                msgCenter().cannotSaveMachineState(machine);
         }
         else
Index: /trunk/src/VBox/Frontends/VirtualBox/src/selector/VBoxSnapshotsWgt.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/selector/VBoxSnapshotsWgt.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/selector/VBoxSnapshotsWgt.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -641,7 +641,7 @@
 
     /* Restore chosen snapshot: */
-    CConsole console = session.GetConsole();
-    CProgress progress = console.RestoreSnapshot(snapshot);
-    if (console.isOk())
+    CMachine machine = session.GetMachine();
+    CProgress progress = machine.RestoreSnapshot(snapshot);
+    if (machine.isOk())
     {
         msgCenter().showModalProgressDialog(progress, mMachine.GetName(), ":/progress_snapshot_restore_90px.png");
@@ -650,5 +650,5 @@
     }
     else
-        msgCenter().cannotRestoreSnapshot(console, snapshot.GetName(), mMachine.GetName());
+        msgCenter().cannotRestoreSnapshot(machine, snapshot.GetName(), mMachine.GetName());
 
     /* Unlock machine finally: */
@@ -688,7 +688,8 @@
         return;
 
-    CConsole console = session.GetConsole();
-    CProgress progress = console.DeleteSnapshot (snapId);
-    if (console.isOk())
+    /* Remove chosen snapshot: */
+    CMachine machine = session.GetMachine();
+    CProgress progress = machine.DeleteSnapshot(snapId);
+    if (machine.isOk())
     {
         /* Show the progress dialog */
@@ -699,5 +700,5 @@
     }
     else
-        msgCenter().cannotRemoveSnapshot(console,  snapshot.GetName(), mMachine.GetName());
+        msgCenter().cannotRemoveSnapshot(machine,  snapshot.GetName(), mMachine.GetName());
 
     session.UnlockMachine();
@@ -829,101 +830,69 @@
     if (fIsValid)
     {
-        /* Get corresponding console object also: */
-        CConsole console = session.GetConsole();
-        /* Remember runtime state: */
-        bool fAtRuntime = mMachine.GetState() == KMachineState_Running;
-        /* Remember paused state: */
-        bool fWasPaused = mMachine.GetState() == KMachineState_Paused ||
-                          mMachine.GetState() == KMachineState_TeleportingPausedVM;
-
-        /* Pause VM if necessary: */
-        if (fIsValid && fAtRuntime && !fWasPaused)
-        {
-            /* Pausing VM: */
-            console.Pause();
-            if (!console.isOk())
+        /* Get corresponding machine object also: */
+        CMachine machine = session.GetMachine();
+
+        /* Create take-snapshot dialog: */
+        QWidget *pDlgParent = windowManager().realParentWindow(this);
+        QPointer<VBoxTakeSnapshotDlg> pDlg = new VBoxTakeSnapshotDlg(pDlgParent, mMachine);
+        windowManager().registerNewParent(pDlg, pDlgParent);
+
+        /* Assign corresponding icon: */
+        pDlg->mLbIcon->setPixmap(vboxGlobal().vmGuestOSTypeIcon(mMachine.GetOSTypeId()));
+
+        /* Search for the max available snapshot index: */
+        int iMaxSnapShotIndex = 0;
+        QString snapShotName = tr("Snapshot %1");
+        QRegExp regExp(QString("^") + snapShotName.arg("([0-9]+)") + QString("$"));
+        QTreeWidgetItemIterator iterator(mTreeWidget);
+        while (*iterator)
+        {
+            QString snapShot = static_cast<SnapshotWgtItem*>(*iterator)->text(0);
+            int pos = regExp.indexIn(snapShot);
+            if (pos != -1)
+                iMaxSnapShotIndex = regExp.cap(1).toInt() > iMaxSnapShotIndex ? regExp.cap(1).toInt() : iMaxSnapShotIndex;
+            ++iterator;
+        }
+        pDlg->mLeName->setText(snapShotName.arg(iMaxSnapShotIndex + 1));
+
+        /* Exec the dialog: */
+        bool fDialogAccepted = pDlg->exec() == QDialog::Accepted;
+
+        /* Is the dialog still valid? */
+        if (pDlg)
+        {
+            /* Acquire variables: */
+            QString strSnapshotName = pDlg->mLeName->text().trimmed();
+            QString strSnapshotDescription = pDlg->mTeDescription->toPlainText();
+
+            /* Destroy dialog early: */
+            delete pDlg;
+
+            /* Was the dialog accepted? */
+            if (fDialogAccepted)
             {
-                msgCenter().cannotPauseMachine(console);
-                fIsValid = false;
-            }
-        }
-
-        if (fIsValid)
-        {
-            /* Create take-snapshot dialog: */
-            QWidget *pDlgParent = windowManager().realParentWindow(this);
-            QPointer<VBoxTakeSnapshotDlg> pDlg = new VBoxTakeSnapshotDlg(pDlgParent, mMachine);
-            windowManager().registerNewParent(pDlg, pDlgParent);
-
-            /* Assign corresponding icon: */
-            pDlg->mLbIcon->setPixmap(vboxGlobal().vmGuestOSTypeIcon(mMachine.GetOSTypeId()));
-
-            /* Search for the max available snapshot index: */
-            int iMaxSnapShotIndex = 0;
-            QString snapShotName = tr("Snapshot %1");
-            QRegExp regExp(QString("^") + snapShotName.arg("([0-9]+)") + QString("$"));
-            QTreeWidgetItemIterator iterator(mTreeWidget);
-            while (*iterator)
-            {
-                QString snapShot = static_cast<SnapshotWgtItem*>(*iterator)->text(0);
-                int pos = regExp.indexIn(snapShot);
-                if (pos != -1)
-                    iMaxSnapShotIndex = regExp.cap(1).toInt() > iMaxSnapShotIndex ? regExp.cap(1).toInt() : iMaxSnapShotIndex;
-                ++iterator;
-            }
-            pDlg->mLeName->setText(snapShotName.arg(iMaxSnapShotIndex + 1));
-
-            /* Exec the dialog: */
-            bool fDialogAccepted = pDlg->exec() == QDialog::Accepted;
-
-            /* Is the dialog still valid? */
-            if (pDlg)
-            {
-                /* Acquire variables: */
-                QString strSnapshotName = pDlg->mLeName->text().trimmed();
-                QString strSnapshotDescription = pDlg->mTeDescription->toPlainText();
-
-                /* Destroy dialog early: */
-                delete pDlg;
-
-                /* Was the dialog accepted? */
-                if (fDialogAccepted)
+                /* Prepare the take-snapshot progress: */
+                CProgress progress = machine.TakeSnapshot(strSnapshotName, strSnapshotDescription, true);
+                if (machine.isOk())
                 {
-                    /* Prepare the take-snapshot progress: */
-                    CProgress progress = console.TakeSnapshot(strSnapshotName, strSnapshotDescription);
-                    if (console.isOk())
+                    /* Show the take-snapshot progress: */
+                    msgCenter().showModalProgressDialog(progress, mMachine.GetName(), ":/progress_snapshot_create_90px.png");
+                    if (!progress.isOk() || progress.GetResultCode() != 0)
                     {
-                        /* Show the take-snapshot progress: */
-                        msgCenter().showModalProgressDialog(progress, mMachine.GetName(), ":/progress_snapshot_create_90px.png");
-                        if (!progress.isOk() || progress.GetResultCode() != 0)
-                        {
-                            msgCenter().cannotTakeSnapshot(progress, mMachine.GetName());
-                            fIsValid = false;
-                        }
-                    }
-                    else
-                    {
-                        msgCenter().cannotTakeSnapshot(console, mMachine.GetName());
+                        msgCenter().cannotTakeSnapshot(progress, mMachine.GetName());
                         fIsValid = false;
                     }
                 }
                 else
+                {
+                    msgCenter().cannotTakeSnapshot(machine, mMachine.GetName());
                     fIsValid = false;
+                }
             }
             else
                 fIsValid = false;
         }
-
-        /* Resume VM if necessary: */
-        if (fIsValid && fAtRuntime && !fWasPaused)
-        {
-            /* Resuming VM: */
-            console.Resume();
-            if (!console.isOk())
-            {
-                msgCenter().cannotResumeMachine(console);
-                fIsValid = false;
-            }
-        }
+        else
+            fIsValid = false;
 
         /* Unlock machine finally: */
Index: /trunk/src/VBox/Frontends/VirtualBox/src/wizards/clonevm/UIWizardCloneVM.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/wizards/clonevm/UIWizardCloneVM.cpp	(revision 55213)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/wizards/clonevm/UIWizardCloneVM.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2011-2013 Oracle Corporation
+ * Copyright (C) 2011-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -79,12 +79,12 @@
             return false;
 
-        /* Prepare console: */
-        CConsole console = session.GetConsole();
+        /* Prepare machine: */
+        CMachine machine = session.GetMachine();
 
         /* Take the snapshot: */
         QString strSnapshotName = tr("Linked Base for %1 and %2").arg(m_machine.GetName()).arg(strName);
-        CProgress progress = console.TakeSnapshot(strSnapshotName, "");
-
-        if (console.isOk())
+        CProgress progress = machine.TakeSnapshot(strSnapshotName, "", true);
+
+        if (machine.isOk())
         {
             /* Show the "Taking Snapshot" progress dialog: */
@@ -99,5 +99,5 @@
         else
         {
-            msgCenter().cannotTakeSnapshot(console, m_machine.GetName(), this);
+            msgCenter().cannotTakeSnapshot(machine, m_machine.GetName(), this);
             return false;
         }
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 55213)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 55214)
@@ -587,5 +587,5 @@
   <enum
     name="MachineState"
-    uuid="ec6c6a9e-113d-4ff4-b44f-0b69f21c97fe"
+    uuid="87f085c3-ca67-4e45-9225-6057f32e9e8e"
     >
     <desc>
@@ -597,5 +597,5 @@
       Below is the basic virtual machine state diagram. It shows how the state
       changes during virtual machine execution. The text in square braces shows
-      a method of the IConsole interface that performs the given state
+      a method of the IConsole or IMachine interface that performs the given state
       transition.
 
@@ -611,5 +611,5 @@
     |     |     +-----------------------------------------+-|-------------------+ +
     |     |     |                                           |                     |
-    |     |     +-- Saving &lt;--------[takeSnapshot()]&lt;-------+---------------------+
+    |     |     +- OnlineSnapshotting &lt;--[takeSnapshot()]&lt;--+---------------------+
     |     |                                                 |                     |
     |     +-------- Saving &lt;--------[saveState()]&lt;----------+---------------------+
@@ -683,5 +683,5 @@
     |                                                                       |
     +-&gt; PoweredOff --+                                                      |
-    |                +--&gt;[takeSnapshot()] -------------------&gt; Saving ------+
+    |                +--&gt;[takeSnapshot()] ------------------&gt; Snapshotting -+
     +-&gt; Aborted -----+
 
@@ -694,11 +694,4 @@
     +---(Saved if restored from an online snapshot, PoweredOff otherwise)---+
       </pre>
-
-      Note that the Saving state is present in both the offline state group and
-      online state group. Currently, the only way to determine what group is
-      assumed in a particular case is to remember the previous machine state: if
-      it was Running or Paused, then Saving is an online state, otherwise it is
-      an offline state. This inconsistency may be removed in one of the future
-      versions of VirtualBox by adding a new state.
 
       <note internal="yes">
@@ -792,5 +785,5 @@
         some of the runtime configuration options are inaccessible. Also, if
         paused while in this state it will transition to
-        @c Saving and it will not be resume the
+        @c OnlineSnapshotting and it will not be resume the
         execution until the snapshot operation has completed.
       </desc>
@@ -810,6 +803,5 @@
     <const name="Saving"                    value="12">
       <desc>
-        Machine is saving its execution state to a file, or an online
-        snapshot of the machine is being taken.
+        Machine is saving its execution state to a file.
       </desc>
     </const>
@@ -824,5 +816,5 @@
         The machine is being teleported to another host or process, but it is
         not running. This is the paused variant of the
-        @c state.
+        @c Teleporting state.
       </desc>
     </const>
@@ -849,10 +841,16 @@
       </desc>
     </const>
-    <const name="RestoringSnapshot"         value="19">
+    <const name="OnlineSnapshotting"        value="19">
+      <desc>
+        Like @c LiveSnapshotting, but the machine was paused when the
+        merging of differencing media was started.
+      </desc>
+    </const>
+    <const name="RestoringSnapshot"         value="20">
       <desc>
         A machine snapshot is being restored; this typically does not take long.
       </desc>
     </const>
-    <const name="DeletingSnapshot"          value="20">
+    <const name="DeletingSnapshot"          value="21">
       <desc>
         A machine snapshot is being deleted; this can take a long time since this
@@ -861,9 +859,14 @@
       </desc>
     </const>
-    <const name="SettingUp"                 value="21">
+    <const name="SettingUp"                 value="22">
       <desc>
         Lengthy setup operation is in progress.
       </desc>
     </const>
+    <const name="Snapshotting"              value="23">
+      <desc>
+        Taking an (offline) snapshot.
+      </desc>
+    </const>
 
     <const name="FirstOnline" value="5" wsmap="suppress"> <!-- Running -->
@@ -872,5 +875,5 @@
       </desc>
     </const>
-    <const name="LastOnline" value="18" wsmap="suppress"> <!-- DeletingSnapshotPaused -->
+    <const name="LastOnline" value="19" wsmap="suppress"> <!-- OnlineSnapshotting -->
       <desc>
         Pseudo-state: last online state (for use in relational expressions).
@@ -883,5 +886,5 @@
       </desc>
     </const>
-    <const name="LastTransient" value="21" wsmap="suppress"> <!-- SettingUp -->
+    <const name="LastTransient" value="23" wsmap="suppress"> <!-- Snapshotting -->
       <desc>
         Pseudo-state: last transient state (for use in relational expressions).
@@ -1074,9 +1077,17 @@
   <enum
     name="LockType"
-    uuid="168a6a8e-12fd-4878-a1f9-38a750a56089"
+    uuid="678aaf14-2815-4c3e-b20a-e86ed0216498"
     >
     <desc>
       Used with <link to="IMachine::lockMachine" />.
     </desc>
+    <const name="Null" value="0">
+      <desc>Placeholder value, do not use when obtaining a lock.</desc>
+    </const>
+    <const name="Shared" value="1">
+      <desc>Request only a shared lock for remote-controlling the machine.
+        Such a lock allows changing certain VM settings which can be safely
+        modified for a running VM.</desc>
+    </const>
     <const name="Write" value="2">
       <desc>Lock the machine for writing. This requests an exclusive lock, i.e.
@@ -1085,9 +1096,4 @@
         which implicitly holds the equivalent of a shared lock during the
         entire VM runtime.</desc>
-    </const>
-    <const name="Shared" value="1">
-      <desc>Request only a shared lock for remote-controlling the machine.
-        Such a lock allows changing certain VM settings which can be safely
-        modified for a running VM.</desc>
     </const>
     <const name="VM" value="3">
@@ -3586,15 +3592,8 @@
   <interface
     name="IInternalMachineControl" extends="$unknown"
-    uuid="1470ff16-d7fa-448e-9c38-0352a36053bf"
+    uuid="f0b3bf6e-c609-4d5e-9fd7-77537a52c31b"
     internal="yes"
     wsmap="suppress"
     >
-    <method name="setRemoveSavedStateFile">
-      <desc>
-        Updates the flag whether the saved state file is removed on a
-        machine state change from Saved to PoweredOff.
-      </desc>
-      <param name="remove" type="boolean" dir="in"/>
-    </method>
 
     <method name="updateState">
@@ -3758,149 +3757,4 @@
     </method>
 
-    <method name="beginSavingState">
-      <desc>
-        Called by the VM process to inform the server it wants to
-        save the current state and stop the VM execution.
-      </desc>
-      <param name="progress" type="IProgress" dir="out">
-        <desc>
-          Progress object created by VBoxSVC to wait until
-          the state is saved.
-        </desc>
-      </param>
-      <param name="stateFilePath" type="wstring" dir="out">
-        <desc>
-          File path the VM process must save the execution state to.
-        </desc>
-      </param>
-    </method>
-
-    <method name="endSavingState">
-      <desc>
-        Called by the VM process to inform the server that saving
-        the state previously requested by #beginSavingState is either
-        successfully finished or there was a failure.
-
-        <result name="VBOX_E_FILE_ERROR">
-          Settings file not accessible.
-        </result>
-        <result name="VBOX_E_XML_ERROR">
-          Could not parse the settings file.
-        </result>
-
-      </desc>
-
-      <param name="result" type="long" dir="in">
-        <desc>@c S_OK to indicate success.
-        </desc>
-      </param>
-      <param name="errMsg" type="wstring" dir="in">
-        <desc>@c human readable error message in case of failure.
-        </desc>
-      </param>
-    </method>
-
-    <method name="adoptSavedState">
-      <desc>
-        Gets called by <link to="IConsole::adoptSavedState"/>.
-        <result name="VBOX_E_FILE_ERROR">
-          Invalid saved state file path.
-        </result>
-      </desc>
-      <param name="savedStateFile" type="wstring" dir="in">
-        <desc>Path to the saved state file to adopt.</desc>
-      </param>
-    </method>
-
-    <method name="beginTakingSnapshot">
-      <desc>
-        Called from the VM process to request from the server to perform the
-        server-side actions of creating a snapshot (creating differencing images
-        and the snapshot object).
-
-        <result name="VBOX_E_FILE_ERROR">
-          Settings file not accessible.
-        </result>
-        <result name="VBOX_E_XML_ERROR">
-          Could not parse the settings file.
-        </result>
-      </desc>
-      <param name="initiator" type="IConsole" dir="in">
-        <desc>The console object that initiated this call.</desc>
-      </param>
-      <param name="name" type="wstring" dir="in">
-        <desc>Snapshot name.</desc>
-      </param>
-      <param name="description" type="wstring" dir="in">
-        <desc>Snapshot description.</desc>
-      </param>
-      <param name="consoleProgress" type="IProgress" dir="in">
-        <desc>
-          Progress object created by the VM process tracking the
-          snapshot's progress. This has the following sub-operations:
-          <ul>
-            <li>setting up (weight 1);</li>
-            <li>one for each medium attachment that needs a differencing image (weight 1 each);</li>
-            <li>another one to copy the VM state (if offline with saved state, weight is VM memory size in MB);</li>
-            <li>another one to save the VM state (if online, weight is VM memory size in MB);</li>
-            <li>finishing up (weight 1)</li>
-          </ul>
-        </desc>
-      </param>
-      <param name="fTakingSnapshotOnline" type="boolean" dir="in">
-        <desc>
-          Whether this is an online snapshot (i.e. the machine is running).
-        </desc>
-      </param>
-      <param name="stateFilePath" type="wstring" dir="out">
-        <desc>
-          File path the VM process must save the execution state to.
-        </desc>
-      </param>
-    </method>
-
-    <method name="endTakingSnapshot">
-      <desc>
-        Called by the VM process to inform the server that the snapshot
-        previously requested by #beginTakingSnapshot is either
-        successfully taken or there was a failure.
-      </desc>
-
-      <param name="success" type="boolean" dir="in">
-        <desc>@c true to indicate success and @c false otherwise</desc>
-      </param>
-    </method>
-
-    <method name="deleteSnapshot">
-      <desc>
-        Gets called by <link to="IConsole::deleteSnapshot"/>,
-        <link to="IConsole::deleteSnapshotAndAllChildren"/> and
-        <link to="IConsole::deleteSnapshotRange"/>.
-        <result name="VBOX_E_INVALID_OBJECT_STATE">
-          Snapshot has more than one child snapshot. Only possible if the
-          delete operation does not delete all children or the range does
-          not meet the linearity condition.
-        </result>
-      </desc>
-      <param name="initiator" type="IConsole" dir="in">
-        <desc>The console object that initiated this call.</desc>
-      </param>
-      <param name="startId" type="uuid" mod="string" dir="in">
-        <desc>UUID of the first snapshot to delete.</desc>
-      </param>
-      <param name="endId" type="uuid" mod="string" dir="in">
-        <desc>UUID of the last snapshot to delete.</desc>
-      </param>
-      <param name="deleteAllChildren" type="boolean" dir="in">
-        <desc>Whether all children should be deleted.</desc>
-      </param>
-      <param name="machineState" type="MachineState" dir="out">
-        <desc>New machine state after this operation is started.</desc>
-      </param>
-      <param name="progress" type="IProgress" dir="return">
-        <desc>Progress object to track the operation completion.</desc>
-      </param>
-    </method>
-
     <method name="finishOnlineMergeMedium">
       <desc>
@@ -3908,22 +3762,4 @@
         All necessary state information is available at the called object.
       </desc>
-    </method>
-
-    <method name="restoreSnapshot">
-      <desc>
-        Gets called by <link to="IConsole::restoreSnapshot"/>.
-      </desc>
-      <param name="initiator" type="IConsole" dir="in">
-        <desc>The console object that initiated this call.</desc>
-      </param>
-      <param name="snapshot" type="ISnapshot" dir="in">
-        <desc>The snapshot to restore the VM state from.</desc>
-      </param>
-      <param name="machineState" type="MachineState" dir="out">
-        <desc>New machine state after this operation is started.</desc>
-      </param>
-      <param name="progress" type="IProgress" dir="return">
-        <desc>Progress object to track the operation completion.</desc>
-      </param>
     </method>
 
@@ -4341,5 +4177,5 @@
   <interface
     name="IMachine" extends="$unknown"
-    uuid="2280b3f8-0c33-4641-8bd5-ccecd1071b49"
+    uuid="bfe5287a-5fbc-4ceb-9f0e-7fb317e78681"
     wsmap="managed"
     wrap-hint-server-addinterfaces="IInternalMachineControl"
@@ -4888,8 +4724,7 @@
         Current snapshot of this machine. This is @c null if the machine
         currently has no snapshots. If it is not @c null, then it was
-        set by one of <link to="IConsole::takeSnapshot" />,
-        <link to="IConsole::deleteSnapshot" />
-        or <link to="IConsole::restoreSnapshot" />, depending on which
-        was called last. See <link to="ISnapshot"/> for details.
+        set by one of <link to="#takeSnapshot" />, <link to="#deleteSnapshot" />
+        or <link to="#restoreSnapshot" />, depending on which was called last.
+       See <link to="ISnapshot"/> for details.
       </desc>
     </attribute>
@@ -4911,9 +4746,8 @@
 
         <ul>
-          <li><link to="IConsole::restoreSnapshot"/>
+          <li><link to="#restoreSnapshot"/>
           </li>
-          <li><link to="IConsole::takeSnapshot"/> (issued on a
-            "powered off" or "saved" machine, for which
-            <link to="#settingsModified"/> returns @c false)
+          <li><link to="#takeSnapshot"/> (issued on a "powered off" or "saved"
+            machine, for which <link to="#settingsModified"/> returns @c false)
           </li>
         </ul>
@@ -7432,468 +7266,4 @@
     </method>
 
-  </interface>
-
-  <interface
-    name="IEmulatedUSB" extends="$unknown"
-    uuid="38cc4dfd-8bb2-4d40-aebe-699eead8c2dd"
-    wsmap="managed"
-    >
-    <desc>
-      Manages emulated USB devices.
-    </desc>
-
-    <method name="webcamAttach">
-      <desc>
-        Attaches the emulated USB webcam to the VM, which will use a host video capture device.
-      </desc>
-      <param name="path" type="wstring" dir="in">
-        <desc>The host path of the capture device to use.</desc>
-      </param>
-      <param name="settings" type="wstring" dir="in">
-        <desc>Optional settings.</desc>
-      </param>
-    </method>
-
-    <method name="webcamDetach">
-      <desc>
-        Detaches the emulated USB webcam from the VM
-      </desc>
-      <param name="path" type="wstring" dir="in">
-        <desc>The host path of the capture device to detach.</desc>
-      </param>
-    </method>
-
-    <attribute name="webcams" type="wstring" safearray="yes" readonly="yes">
-      <desc>Lists attached virtual webcams.</desc>
-    </attribute>
-  </interface>
-
-  <!--
-  // IConsole
-  /////////////////////////////////////////////////////////////////////////
-  -->
-
-  <interface
-    name="IVRDEServerInfo" extends="$unknown"
-    uuid="714434a1-58c3-4aab-9049-7652c5df113b"
-    wsmap="struct"
-    >
-    <desc>
-      Contains information about the remote desktop (VRDE) server capabilities and status.
-      This is used in the <link to="IConsole::VRDEServerInfo" /> attribute.
-    </desc>
-
-    <attribute name="active" type="boolean" readonly="yes">
-      <desc>
-        Whether the remote desktop connection is active.
-      </desc>
-    </attribute>
-
-    <attribute name="port" type="long" readonly="yes">
-      <desc>
-        VRDE server port number. If this property is equal to <tt>0</tt>, then
-        the VRDE server failed to start, usually because there are no free IP
-        ports to bind to. If this property is equal to <tt>-1</tt>, then the VRDE
-        server has not yet been started.
-      </desc>
-    </attribute>
-
-    <attribute name="numberOfClients" type="unsigned long" readonly="yes">
-      <desc>
-        How many times a client connected.
-      </desc>
-    </attribute>
-
-    <attribute name="beginTime" type="long long" readonly="yes">
-      <desc>
-        When the last connection was established, in milliseconds since 1970-01-01 UTC.
-      </desc>
-    </attribute>
-
-    <attribute name="endTime" type="long long" readonly="yes">
-      <desc>
-        When the last connection was terminated or the current time, if
-        connection is still active, in milliseconds since 1970-01-01 UTC.
-      </desc>
-    </attribute>
-
-    <attribute name="bytesSent" type="long long" readonly="yes">
-      <desc>
-        How many bytes were sent in last or current, if still active, connection.
-      </desc>
-    </attribute>
-
-    <attribute name="bytesSentTotal" type="long long" readonly="yes">
-      <desc>
-        How many bytes were sent in all connections.
-      </desc>
-    </attribute>
-
-    <attribute name="bytesReceived" type="long long" readonly="yes">
-      <desc>
-        How many bytes were received in last or current, if still active, connection.
-      </desc>
-    </attribute>
-
-    <attribute name="bytesReceivedTotal" type="long long" readonly="yes">
-      <desc>
-        How many bytes were received in all connections.
-      </desc>
-    </attribute>
-
-    <attribute name="user" type="wstring" readonly="yes">
-      <desc>
-        Login user name supplied by the client.
-      </desc>
-    </attribute>
-
-    <attribute name="domain" type="wstring" readonly="yes">
-      <desc>
-        Login domain name supplied by the client.
-      </desc>
-    </attribute>
-
-    <attribute name="clientName" type="wstring" readonly="yes">
-      <desc>
-        The client name supplied by the client.
-      </desc>
-    </attribute>
-
-    <attribute name="clientIP" type="wstring" readonly="yes">
-      <desc>
-        The IP address of the client.
-      </desc>
-    </attribute>
-
-    <attribute name="clientVersion" type="unsigned long" readonly="yes">
-      <desc>
-        The client software version number.
-      </desc>
-    </attribute>
-
-    <attribute name="encryptionStyle" type="unsigned long" readonly="yes">
-      <desc>
-        Public key exchange method used when connection was established.
-        Values: 0 - RDP4 public key exchange scheme.
-        1 - X509 certificates were sent to client.
-      </desc>
-    </attribute>
-
-  </interface>
-
-  <interface
-    name="IConsole" extends="$unknown"
-    uuid="080505f4-bca9-45aa-ab95-030036b665e6"
-    wsmap="managed"
-    >
-    <desc>
-      The IConsole interface represents an interface to control virtual
-      machine execution.
-
-      A console object gets created when a machine has been locked for a
-      particular session (client process) using <link to="IMachine::lockMachine" />
-      or <link to="IMachine::launchVMProcess"/>. The console object can
-      then be found in the session's <link to="ISession::console" /> attribute.
-
-      Methods of the IConsole interface allow the caller to query the current
-      virtual machine execution state, pause the machine or power it down, save
-      the machine state or take a snapshot, attach and detach removable media
-      and so on.
-
-      <see><link to="ISession"/></see>
-    </desc>
-
-    <attribute name="machine" type="IMachine" readonly="yes">
-      <desc>
-        Machine object for this console session.
-        <note>
-          This is a convenience property, it has the same value as
-          <link to="ISession::machine"/> of the corresponding session
-          object.
-        </note>
-      </desc>
-    </attribute>
-
-    <attribute name="state" type="MachineState" readonly="yes">
-      <desc>
-        Current execution state of the machine.
-        <note>
-          This property always returns the same value as the corresponding
-          property of the IMachine object for this console session.
-          For the process that owns (executes) the VM, this is the
-          preferable way of querying the VM state, because no IPC
-          calls are made.
-        </note>
-      </desc>
-    </attribute>
-
-    <attribute name="guest" type="IGuest" readonly="yes">
-      <desc>Guest object.</desc>
-    </attribute>
-
-    <attribute name="keyboard" type="IKeyboard" readonly="yes">
-      <desc>
-        Virtual keyboard object.
-        <note>
-          If the machine is not running, any attempt to use
-          the returned object will result in an error.
-        </note>
-      </desc>
-    </attribute>
-
-    <attribute name="mouse" type="IMouse" readonly="yes">
-      <desc>
-        Virtual mouse object.
-        <note>
-          If the machine is not running, any attempt to use
-          the returned object will result in an error.
-        </note>
-      </desc>
-    </attribute>
-
-    <attribute name="display" type="IDisplay" readonly="yes">
-      <desc>Virtual display object.
-        <note>
-          If the machine is not running, any attempt to use
-          the returned object will result in an error.
-        </note>
-      </desc>
-    </attribute>
-
-    <attribute name="debugger" type="IMachineDebugger" readonly="yes">
-      <desc>Debugging interface.</desc>
-    </attribute>
-
-    <attribute name="USBDevices" type="IUSBDevice" readonly="yes" safearray="yes">
-      <desc>
-        Collection of USB devices currently attached to the virtual
-        USB controller.
-        <note>
-          The collection is empty if the machine is not running.
-        </note>
-      </desc>
-    </attribute>
-
-    <attribute name="remoteUSBDevices" type="IHostUSBDevice" readonly="yes" safearray="yes">
-      <desc>
-        List of USB devices currently attached to the remote VRDE client.
-        Once a new device is physically attached to the remote host computer,
-        it appears in this list and remains there until detached.
-      </desc>
-    </attribute>
-
-    <attribute name="sharedFolders" type="ISharedFolder" readonly="yes" safearray="yes">
-      <desc>
-        Collection of shared folders for the current session. These folders
-        are called transient shared folders because they are available to the
-        guest OS running inside the associated virtual machine only for the
-        duration of the session (as opposed to
-        <link to="IMachine::sharedFolders"/> which represent permanent shared
-        folders). When the session is closed (e.g. the machine is powered down),
-        these folders are automatically discarded.
-
-        New shared folders are added to the collection using
-        <link to="#createSharedFolder"/>. Existing shared folders can be
-        removed using <link to="#removeSharedFolder"/>.
-      </desc>
-    </attribute>
-
-    <attribute name="VRDEServerInfo" type="IVRDEServerInfo" readonly="yes">
-      <desc>
-        Interface that provides information on Remote Desktop Extension (VRDE) connection.
-      </desc>
-    </attribute>
-
-    <attribute name="eventSource" type="IEventSource" readonly="yes">
-      <desc>
-        Event source for console events.
-      </desc>
-    </attribute>
-
-    <attribute name="attachedPCIDevices" type="IPCIDeviceAttachment" readonly="yes" safearray="yes">
-      <desc>Array of PCI devices attached to this machine.</desc>
-    </attribute>
-
-    <attribute name="useHostClipboard" type="boolean">
-      <desc>
-        Whether the guest clipboard should be connected to the host one or
-        whether it should only be allowed access to the VRDE clipboard. This
-        setting may not affect existing guest clipboard connections which
-        are already connected to the host clipboard.
-      </desc>
-    </attribute>
-
-    <attribute name="emulatedUSB" type="IEmulatedUSB" readonly="yes">
-      <desc>
-        Interface that manages emulated USB devices.
-      </desc>
-    </attribute>
-
-    <method name="powerUp">
-      <desc>
-        Starts the virtual machine execution using the current machine
-        state (that is, its current execution state, current settings and
-        current storage devices).
-
-        <note>
-          This method is only useful for front-ends that want to actually
-          execute virtual machines in their own process (like the VirtualBox
-          or VBoxSDL front-ends). Unless you are intending to write such a
-          front-end, do not call this method. If you simply want to
-          start virtual machine execution using one of the existing front-ends
-          (for example the VirtualBox GUI or headless server), use
-          <link to="IMachine::launchVMProcess"/> instead; these
-          front-ends will power up the machine automatically for you.
-        </note>
-
-        If the machine is powered off or aborted, the execution will
-        start from the beginning (as if the real hardware were just
-        powered on).
-
-        If the machine is in the <link to="MachineState_Saved"/> state,
-        it will continue its execution the point where the state has
-        been saved.
-
-        If the machine <link to="IMachine::teleporterEnabled"/> property is
-        enabled on the machine being powered up, the machine will wait for an
-        incoming teleportation in the <link to="MachineState_TeleportingIn"/>
-        state. The returned progress object will have at least three
-        operations where the last three are defined as: (1) powering up and
-        starting TCP server, (2) waiting for incoming teleportations, and
-        (3) perform teleportation. These operations will be reflected as the
-        last three operations of the progress objected returned by
-        <link to="IMachine::launchVMProcess"/> as well.
-
-        <see><link to="#saveState"/></see>
-
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine already running.
-        </result>
-        <result name="VBOX_E_HOST_ERROR">
-          Host interface does not exist or name not set.
-        </result>
-        <result name="VBOX_E_FILE_ERROR">
-          Invalid saved state file.
-        </result>
-      </desc>
-      <param name="progress" type="IProgress" dir="return">
-        <desc>Progress object to track the operation completion.</desc>
-      </param>
-    </method>
-
-    <method name="powerUpPaused">
-      <desc>
-        Identical to powerUp except that the VM will enter the
-        <link to="MachineState_Paused"/> state, instead of
-        <link to="MachineState_Running"/>.
-
-        <see><link to="#powerUp"/></see>
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine already running.
-        </result>
-        <result name="VBOX_E_HOST_ERROR">
-          Host interface does not exist or name not set.
-        </result>
-        <result name="VBOX_E_FILE_ERROR">
-          Invalid saved state file.
-        </result>
-      </desc>
-      <param name="progress" type="IProgress" dir="return">
-        <desc>Progress object to track the operation completion.</desc>
-      </param>
-    </method>
-
-    <method name="powerDown">
-      <desc>
-        Initiates the power down procedure to stop the virtual machine
-        execution.
-
-        The completion of the power down procedure is tracked using the returned
-        IProgress object. After the operation is complete, the machine will go
-        to the PoweredOff state.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine must be Running, Paused or Stuck to be powered down.
-        </result>
-      </desc>
-      <param name="progress" type="IProgress" dir="return">
-        <desc>Progress object to track the operation completion.</desc>
-      </param>
-    </method>
-
-    <method name="reset">
-      <desc>Resets the virtual machine.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine not in Running state.
-        </result>
-        <result name="VBOX_E_VM_ERROR">
-          Virtual machine error in reset operation.
-        </result>
-      </desc>
-    </method>
-
-    <method name="pause">
-      <desc>Pauses the virtual machine execution.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine not in Running state.
-        </result>
-        <result name="VBOX_E_VM_ERROR">
-          Virtual machine error in suspend operation.
-        </result>
-      </desc>
-    </method>
-
-    <method name="resume">
-      <desc>Resumes the virtual machine execution.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine not in Paused state.
-        </result>
-        <result name="VBOX_E_VM_ERROR">
-          Virtual machine error in resume operation.
-        </result>
-      </desc>
-    </method>
-
-    <method name="powerButton">
-      <desc>Sends the ACPI power button event to the guest.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine not in Running state.
-        </result>
-        <result name="VBOX_E_PDM_ERROR">
-          Controlled power off failed.
-        </result>
-      </desc>
-    </method>
-
-    <method name="sleepButton">
-      <desc>Sends the ACPI sleep button event to the guest.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine not in Running state.
-        </result>
-        <result name="VBOX_E_PDM_ERROR">
-          Sending sleep button event failed.
-        </result>
-      </desc>
-    </method>
-
-    <method name="getPowerButtonHandled">
-      <desc>Checks if the last power button event was handled by guest.
-        <result name="VBOX_E_PDM_ERROR">
-          Checking if the event was handled by the guest OS failed.
-        </result>
-      </desc>
-      <param name="handled" type="boolean" dir="return"/>
-    </method>
-
-    <method name="getGuestEnteredACPIMode">
-      <desc>Checks if the guest entered the ACPI mode G0 (working) or
-        G1 (sleeping). If this method returns @c false, the guest will
-        most likely not respond to external ACPI events.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine not in Running state.
-        </result>
-      </desc>
-      <param name="entered" type="boolean" dir="return"/>
-    </method>
-
     <method name="saveState">
       <desc>
@@ -7914,5 +7284,5 @@
         <note>
           On success, this method implicitly calls
-          <link to="IMachine::saveSettings"/> to save all current machine
+          <link to="#saveSettings"/> to save all current machine
           settings (including runtime changes to the DVD medium, etc.).
           Together with the impossibility to change any VM settings when it is
@@ -7951,5 +7321,5 @@
         The specified saved state file path may be absolute or relative to the
         folder the VM normally saves the state to (usually,
-        <link to="IMachine::snapshotFolder"/>).
+        <link to="#snapshotFolder"/>).
 
         <note>
@@ -7985,5 +7355,5 @@
         re-inserted into a machine using <link to="#adoptSavedState" />.
         The location of the file can be found in the
-        <link to="IMachine::stateFilePath" /> attribute.
+        <link to="#stateFilePath" /> attribute.
         <result name="VBOX_E_INVALID_VM_STATE">
           Virtual machine not in state Saved.
@@ -7992,160 +7362,4 @@
       <param name="fRemoveFile" type="boolean" dir="in" >
         <desc>Whether to also remove the saved state file.</desc>
-      </param>
-    </method>
-
-    <method name="getDeviceActivity">
-      <desc>
-        Gets the current activity type of given devices or device groups.
-        <result name="E_INVALIDARG">
-          Invalid device type.
-        </result>
-      </desc>
-      <param name="type" type="DeviceType" safearray="yes" dir="in"/>
-      <param name="activity" type="DeviceActivity" safearray="yes" dir="return"/>
-    </method>
-
-    <method name="attachUSBDevice">
-      <desc>
-        Attaches a host USB device with the given UUID to the
-        USB controller of the virtual machine.
-
-        The device needs to be in one of the following states:
-        <link to="USBDeviceState_Busy"/>,
-        <link to="USBDeviceState_Available"/> or
-        <link to="USBDeviceState_Held"/>,
-        otherwise an error is immediately returned.
-
-        When the device state is
-        <link to="USBDeviceState_Busy">Busy</link>, an error may also
-        be returned if the host computer refuses to release it for some reason.
-
-        <see><link to="IUSBDeviceFilters::deviceFilters"/>,
-          <link to="USBDeviceState"/></see>
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine state neither Running nor Paused.
-        </result>
-        <result name="VBOX_E_PDM_ERROR">
-          Virtual machine does not have a USB controller.
-        </result>
-      </desc>
-      <param name="id" type="uuid" mod="string" dir="in">
-        <desc>UUID of the host USB device to attach.</desc>
-      </param>
-      <param name="captureFilename" type="wstring" dir="in">
-        <desc>Filename to capture the USB traffic to.</desc>
-      </param>
-    </method>
-
-    <method name="detachUSBDevice">
-      <desc>
-        Detaches an USB device with the given UUID from the USB controller
-        of the virtual machine.
-
-        After this method succeeds, the VirtualBox server re-initiates
-        all USB filters as if the device were just physically attached
-        to the host, but filters of this machine are ignored to avoid
-        a possible automatic re-attachment.
-
-        <see><link to="IUSBDeviceFilters::deviceFilters"/>,
-          <link to="USBDeviceState"/></see>
-
-        <result name="VBOX_E_PDM_ERROR">
-          Virtual machine does not have a USB controller.
-        </result>
-        <result name="E_INVALIDARG">
-          USB device not attached to this virtual machine.
-        </result>
-      </desc>
-      <param name="id" type="uuid" mod="string" dir="in">
-        <desc>UUID of the USB device to detach.</desc>
-      </param>
-      <param name="device" type="IUSBDevice" dir="return">
-        <desc>Detached USB device.</desc>
-      </param>
-    </method>
-
-    <method name="findUSBDeviceByAddress">
-      <desc>
-        Searches for a USB device with the given host address.
-
-        <result name="VBOX_E_OBJECT_NOT_FOUND">
-          Given @c name does not correspond to any USB device.
-        </result>
-
-        <see><link to="IUSBDevice::address"/></see>
-      </desc>
-      <param name="name" type="wstring" dir="in">
-        <desc>
-          Address of the USB device (as assigned by the host) to
-          search for.
-        </desc>
-      </param>
-      <param name="device" type="IUSBDevice" dir="return">
-        <desc>Found USB device object.</desc>
-      </param>
-    </method>
-
-    <method name="findUSBDeviceById">
-      <desc>
-        Searches for a USB device with the given UUID.
-
-        <result name="VBOX_E_OBJECT_NOT_FOUND">
-          Given @c id does not correspond to any USB device.
-        </result>
-
-        <see><link to="IUSBDevice::id"/></see>
-      </desc>
-      <param name="id" type="uuid" mod="string" dir="in">
-        <desc>UUID of the USB device to search for.</desc>
-      </param>
-      <param name="device" type="IUSBDevice" dir="return">
-        <desc>Found USB device object.</desc>
-      </param>
-    </method>
-
-    <method name="createSharedFolder">
-      <desc>
-        Creates a transient new shared folder by associating the given logical
-        name with the given host path, adds it to the collection of shared
-        folders and starts sharing it. Refer to the description of
-        <link to="ISharedFolder"/> to read more about logical names.
-
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine in Saved state or currently changing state.
-        </result>
-        <result name="VBOX_E_FILE_ERROR">
-          Shared folder already exists or not accessible.
-        </result>
-      </desc>
-      <param name="name" type="wstring" dir="in">
-        <desc>Unique logical name of the shared folder.</desc>
-      </param>
-      <param name="hostPath" type="wstring" dir="in">
-        <desc>Full path to the shared folder in the host file system.</desc>
-      </param>
-      <param name="writable" type="boolean" dir="in">
-        <desc>Whether the share is writable or readonly</desc>
-      </param>
-      <param name="automount" type="boolean" dir="in">
-        <desc>Whether the share gets automatically mounted by the guest
-          or not.</desc>
-      </param>
-    </method>
-
-    <method name="removeSharedFolder">
-      <desc>
-        Removes a transient shared folder with the given name previously
-        created by <link to="#createSharedFolder"/> from the collection of
-        shared folders and stops sharing it.
-        <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine in Saved state or currently changing state.
-        </result>
-        <result name="VBOX_E_FILE_ERROR">
-          Shared folder does not exists.
-        </result>
-      </desc>
-      <param name="name" type="wstring" dir="in">
-        <desc>Logical name of the shared folder to remove.</desc>
       </param>
     </method>
@@ -8165,9 +7379,9 @@
 
         The taken snapshot is always based on the
-        <link to="IMachine::currentSnapshot">current snapshot</link>
+        <link to="#currentSnapshot">current snapshot</link>
         of the associated virtual machine and becomes a new current snapshot.
 
         <note>
-          This method implicitly calls <link to="IMachine::saveSettings"/> to
+          This method implicitly calls <link to="#saveSettings"/> to
           save all current machine settings before taking an offline snapshot.
         </note>
@@ -8182,4 +7396,10 @@
       <param name="description" type="wstring" dir="in">
         <desc>Optional description of the snapshot.</desc>
+      </param>
+      <param name="pause" type="boolean" dir="in">
+        <desc>Whether the VM should be paused while taking the snapshot. Only
+          relevant when the VM is running, and distinguishes between online
+          (@c true) and live (@c false) snapshots. When the VM is not running
+          the result is always an offline snapshot.</desc>
       </param>
       <param name="progress" type="IProgress" dir="return">
@@ -8210,5 +7430,5 @@
         If the deleted snapshot is the first or current snapshot, then the
         respective IMachine attributes will be adjusted. Deleting the current
-        snapshot will also implicitly call <link to="IMachine::saveSettings"/>
+        snapshot will also implicitly call <link to="#saveSettings"/>
         to make all current machine settings permanent.
 
@@ -8233,5 +7453,5 @@
         </ul>
 
-        The virtual machine's <link to="IMachine::state">state</link> is
+        The virtual machine's <link to="#state">state</link> is
         changed to "DeletingSnapshot", "DeletingSnapshotOnline" or
         "DeletingSnapshotPaused" while this operation is in progress.
@@ -8366,4 +7586,624 @@
       <param name="progress" type="IProgress" dir="return">
         <desc>Progress object to track the operation completion.</desc>
+      </param>
+    </method>
+
+  </interface>
+
+  <interface
+    name="IEmulatedUSB" extends="$unknown"
+    uuid="38cc4dfd-8bb2-4d40-aebe-699eead8c2dd"
+    wsmap="managed"
+    >
+    <desc>
+      Manages emulated USB devices.
+    </desc>
+
+    <method name="webcamAttach">
+      <desc>
+        Attaches the emulated USB webcam to the VM, which will use a host video capture device.
+      </desc>
+      <param name="path" type="wstring" dir="in">
+        <desc>The host path of the capture device to use.</desc>
+      </param>
+      <param name="settings" type="wstring" dir="in">
+        <desc>Optional settings.</desc>
+      </param>
+    </method>
+
+    <method name="webcamDetach">
+      <desc>
+        Detaches the emulated USB webcam from the VM
+      </desc>
+      <param name="path" type="wstring" dir="in">
+        <desc>The host path of the capture device to detach.</desc>
+      </param>
+    </method>
+
+    <attribute name="webcams" type="wstring" safearray="yes" readonly="yes">
+      <desc>Lists attached virtual webcams.</desc>
+    </attribute>
+  </interface>
+
+  <!--
+  // IConsole
+  /////////////////////////////////////////////////////////////////////////
+  -->
+
+  <interface
+    name="IVRDEServerInfo" extends="$unknown"
+    uuid="714434a1-58c3-4aab-9049-7652c5df113b"
+    wsmap="struct"
+    >
+    <desc>
+      Contains information about the remote desktop (VRDE) server capabilities and status.
+      This is used in the <link to="IConsole::VRDEServerInfo" /> attribute.
+    </desc>
+
+    <attribute name="active" type="boolean" readonly="yes">
+      <desc>
+        Whether the remote desktop connection is active.
+      </desc>
+    </attribute>
+
+    <attribute name="port" type="long" readonly="yes">
+      <desc>
+        VRDE server port number. If this property is equal to <tt>0</tt>, then
+        the VRDE server failed to start, usually because there are no free IP
+        ports to bind to. If this property is equal to <tt>-1</tt>, then the VRDE
+        server has not yet been started.
+      </desc>
+    </attribute>
+
+    <attribute name="numberOfClients" type="unsigned long" readonly="yes">
+      <desc>
+        How many times a client connected.
+      </desc>
+    </attribute>
+
+    <attribute name="beginTime" type="long long" readonly="yes">
+      <desc>
+        When the last connection was established, in milliseconds since 1970-01-01 UTC.
+      </desc>
+    </attribute>
+
+    <attribute name="endTime" type="long long" readonly="yes">
+      <desc>
+        When the last connection was terminated or the current time, if
+        connection is still active, in milliseconds since 1970-01-01 UTC.
+      </desc>
+    </attribute>
+
+    <attribute name="bytesSent" type="long long" readonly="yes">
+      <desc>
+        How many bytes were sent in last or current, if still active, connection.
+      </desc>
+    </attribute>
+
+    <attribute name="bytesSentTotal" type="long long" readonly="yes">
+      <desc>
+        How many bytes were sent in all connections.
+      </desc>
+    </attribute>
+
+    <attribute name="bytesReceived" type="long long" readonly="yes">
+      <desc>
+        How many bytes were received in last or current, if still active, connection.
+      </desc>
+    </attribute>
+
+    <attribute name="bytesReceivedTotal" type="long long" readonly="yes">
+      <desc>
+        How many bytes were received in all connections.
+      </desc>
+    </attribute>
+
+    <attribute name="user" type="wstring" readonly="yes">
+      <desc>
+        Login user name supplied by the client.
+      </desc>
+    </attribute>
+
+    <attribute name="domain" type="wstring" readonly="yes">
+      <desc>
+        Login domain name supplied by the client.
+      </desc>
+    </attribute>
+
+    <attribute name="clientName" type="wstring" readonly="yes">
+      <desc>
+        The client name supplied by the client.
+      </desc>
+    </attribute>
+
+    <attribute name="clientIP" type="wstring" readonly="yes">
+      <desc>
+        The IP address of the client.
+      </desc>
+    </attribute>
+
+    <attribute name="clientVersion" type="unsigned long" readonly="yes">
+      <desc>
+        The client software version number.
+      </desc>
+    </attribute>
+
+    <attribute name="encryptionStyle" type="unsigned long" readonly="yes">
+      <desc>
+        Public key exchange method used when connection was established.
+        Values: 0 - RDP4 public key exchange scheme.
+        1 - X509 certificates were sent to client.
+      </desc>
+    </attribute>
+
+  </interface>
+
+  <interface
+    name="IConsole" extends="$unknown"
+    uuid="650b5f05-8258-4ee9-b518-89c515ca5dd9"
+    wsmap="managed"
+    >
+    <desc>
+      The IConsole interface represents an interface to control virtual
+      machine execution.
+
+      A console object gets created when a machine has been locked for a
+      particular session (client process) using <link to="IMachine::lockMachine" />
+      or <link to="IMachine::launchVMProcess"/>. The console object can
+      then be found in the session's <link to="ISession::console" /> attribute.
+
+      Methods of the IConsole interface allow the caller to query the current
+      virtual machine execution state, pause the machine or power it down, save
+      the machine state or take a snapshot, attach and detach removable media
+      and so on.
+
+      <see><link to="ISession"/></see>
+    </desc>
+
+    <attribute name="machine" type="IMachine" readonly="yes">
+      <desc>
+        Machine object for this console session.
+        <note>
+          This is a convenience property, it has the same value as
+          <link to="ISession::machine"/> of the corresponding session
+          object.
+        </note>
+      </desc>
+    </attribute>
+
+    <attribute name="state" type="MachineState" readonly="yes">
+      <desc>
+        Current execution state of the machine.
+        <note>
+          This property always returns the same value as the corresponding
+          property of the IMachine object for this console session.
+          For the process that owns (executes) the VM, this is the
+          preferable way of querying the VM state, because no IPC
+          calls are made.
+        </note>
+      </desc>
+    </attribute>
+
+    <attribute name="guest" type="IGuest" readonly="yes">
+      <desc>Guest object.</desc>
+    </attribute>
+
+    <attribute name="keyboard" type="IKeyboard" readonly="yes">
+      <desc>
+        Virtual keyboard object.
+        <note>
+          If the machine is not running, any attempt to use
+          the returned object will result in an error.
+        </note>
+      </desc>
+    </attribute>
+
+    <attribute name="mouse" type="IMouse" readonly="yes">
+      <desc>
+        Virtual mouse object.
+        <note>
+          If the machine is not running, any attempt to use
+          the returned object will result in an error.
+        </note>
+      </desc>
+    </attribute>
+
+    <attribute name="display" type="IDisplay" readonly="yes">
+      <desc>Virtual display object.
+        <note>
+          If the machine is not running, any attempt to use
+          the returned object will result in an error.
+        </note>
+      </desc>
+    </attribute>
+
+    <attribute name="debugger" type="IMachineDebugger" readonly="yes">
+      <desc>Debugging interface.</desc>
+    </attribute>
+
+    <attribute name="USBDevices" type="IUSBDevice" readonly="yes" safearray="yes">
+      <desc>
+        Collection of USB devices currently attached to the virtual
+        USB controller.
+        <note>
+          The collection is empty if the machine is not running.
+        </note>
+      </desc>
+    </attribute>
+
+    <attribute name="remoteUSBDevices" type="IHostUSBDevice" readonly="yes" safearray="yes">
+      <desc>
+        List of USB devices currently attached to the remote VRDE client.
+        Once a new device is physically attached to the remote host computer,
+        it appears in this list and remains there until detached.
+      </desc>
+    </attribute>
+
+    <attribute name="sharedFolders" type="ISharedFolder" readonly="yes" safearray="yes">
+      <desc>
+        Collection of shared folders for the current session. These folders
+        are called transient shared folders because they are available to the
+        guest OS running inside the associated virtual machine only for the
+        duration of the session (as opposed to
+        <link to="IMachine::sharedFolders"/> which represent permanent shared
+        folders). When the session is closed (e.g. the machine is powered down),
+        these folders are automatically discarded.
+
+        New shared folders are added to the collection using
+        <link to="#createSharedFolder"/>. Existing shared folders can be
+        removed using <link to="#removeSharedFolder"/>.
+      </desc>
+    </attribute>
+
+    <attribute name="VRDEServerInfo" type="IVRDEServerInfo" readonly="yes">
+      <desc>
+        Interface that provides information on Remote Desktop Extension (VRDE) connection.
+      </desc>
+    </attribute>
+
+    <attribute name="eventSource" type="IEventSource" readonly="yes">
+      <desc>
+        Event source for console events.
+      </desc>
+    </attribute>
+
+    <attribute name="attachedPCIDevices" type="IPCIDeviceAttachment" readonly="yes" safearray="yes">
+      <desc>Array of PCI devices attached to this machine.</desc>
+    </attribute>
+
+    <attribute name="useHostClipboard" type="boolean">
+      <desc>
+        Whether the guest clipboard should be connected to the host one or
+        whether it should only be allowed access to the VRDE clipboard. This
+        setting may not affect existing guest clipboard connections which
+        are already connected to the host clipboard.
+      </desc>
+    </attribute>
+
+    <attribute name="emulatedUSB" type="IEmulatedUSB" readonly="yes">
+      <desc>
+        Interface that manages emulated USB devices.
+      </desc>
+    </attribute>
+
+    <method name="powerUp">
+      <desc>
+        Starts the virtual machine execution using the current machine
+        state (that is, its current execution state, current settings and
+        current storage devices).
+
+        <note>
+          This method is only useful for front-ends that want to actually
+          execute virtual machines in their own process (like the VirtualBox
+          or VBoxSDL front-ends). Unless you are intending to write such a
+          front-end, do not call this method. If you simply want to
+          start virtual machine execution using one of the existing front-ends
+          (for example the VirtualBox GUI or headless server), use
+          <link to="IMachine::launchVMProcess"/> instead; these
+          front-ends will power up the machine automatically for you.
+        </note>
+
+        If the machine is powered off or aborted, the execution will
+        start from the beginning (as if the real hardware were just
+        powered on).
+
+        If the machine is in the <link to="MachineState_Saved"/> state,
+        it will continue its execution the point where the state has
+        been saved.
+
+        If the machine <link to="IMachine::teleporterEnabled"/> property is
+        enabled on the machine being powered up, the machine will wait for an
+        incoming teleportation in the <link to="MachineState_TeleportingIn"/>
+        state. The returned progress object will have at least three
+        operations where the last three are defined as: (1) powering up and
+        starting TCP server, (2) waiting for incoming teleportations, and
+        (3) perform teleportation. These operations will be reflected as the
+        last three operations of the progress objected returned by
+        <link to="IMachine::launchVMProcess"/> as well.
+
+        <see><link to="IMachine::saveState"/></see>
+
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine already running.
+        </result>
+        <result name="VBOX_E_HOST_ERROR">
+          Host interface does not exist or name not set.
+        </result>
+        <result name="VBOX_E_FILE_ERROR">
+          Invalid saved state file.
+        </result>
+      </desc>
+      <param name="progress" type="IProgress" dir="return">
+        <desc>Progress object to track the operation completion.</desc>
+      </param>
+    </method>
+
+    <method name="powerUpPaused">
+      <desc>
+        Identical to powerUp except that the VM will enter the
+        <link to="MachineState_Paused"/> state, instead of
+        <link to="MachineState_Running"/>.
+
+        <see><link to="#powerUp"/></see>
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine already running.
+        </result>
+        <result name="VBOX_E_HOST_ERROR">
+          Host interface does not exist or name not set.
+        </result>
+        <result name="VBOX_E_FILE_ERROR">
+          Invalid saved state file.
+        </result>
+      </desc>
+      <param name="progress" type="IProgress" dir="return">
+        <desc>Progress object to track the operation completion.</desc>
+      </param>
+    </method>
+
+    <method name="powerDown">
+      <desc>
+        Initiates the power down procedure to stop the virtual machine
+        execution.
+
+        The completion of the power down procedure is tracked using the returned
+        IProgress object. After the operation is complete, the machine will go
+        to the PoweredOff state.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine must be Running, Paused or Stuck to be powered down.
+        </result>
+      </desc>
+      <param name="progress" type="IProgress" dir="return">
+        <desc>Progress object to track the operation completion.</desc>
+      </param>
+    </method>
+
+    <method name="reset">
+      <desc>Resets the virtual machine.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine not in Running state.
+        </result>
+        <result name="VBOX_E_VM_ERROR">
+          Virtual machine error in reset operation.
+        </result>
+      </desc>
+    </method>
+
+    <method name="pause">
+      <desc>Pauses the virtual machine execution.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine not in Running state.
+        </result>
+        <result name="VBOX_E_VM_ERROR">
+          Virtual machine error in suspend operation.
+        </result>
+      </desc>
+    </method>
+
+    <method name="resume">
+      <desc>Resumes the virtual machine execution.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine not in Paused state.
+        </result>
+        <result name="VBOX_E_VM_ERROR">
+          Virtual machine error in resume operation.
+        </result>
+      </desc>
+    </method>
+
+    <method name="powerButton">
+      <desc>Sends the ACPI power button event to the guest.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine not in Running state.
+        </result>
+        <result name="VBOX_E_PDM_ERROR">
+          Controlled power off failed.
+        </result>
+      </desc>
+    </method>
+
+    <method name="sleepButton">
+      <desc>Sends the ACPI sleep button event to the guest.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine not in Running state.
+        </result>
+        <result name="VBOX_E_PDM_ERROR">
+          Sending sleep button event failed.
+        </result>
+      </desc>
+    </method>
+
+    <method name="getPowerButtonHandled">
+      <desc>Checks if the last power button event was handled by guest.
+        <result name="VBOX_E_PDM_ERROR">
+          Checking if the event was handled by the guest OS failed.
+        </result>
+      </desc>
+      <param name="handled" type="boolean" dir="return"/>
+    </method>
+
+    <method name="getGuestEnteredACPIMode">
+      <desc>Checks if the guest entered the ACPI mode G0 (working) or
+        G1 (sleeping). If this method returns @c false, the guest will
+        most likely not respond to external ACPI events.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine not in Running state.
+        </result>
+      </desc>
+      <param name="entered" type="boolean" dir="return"/>
+    </method>
+
+    <method name="getDeviceActivity">
+      <desc>
+        Gets the current activity type of given devices or device groups.
+        <result name="E_INVALIDARG">
+          Invalid device type.
+        </result>
+      </desc>
+      <param name="type" type="DeviceType" safearray="yes" dir="in"/>
+      <param name="activity" type="DeviceActivity" safearray="yes" dir="return"/>
+    </method>
+
+    <method name="attachUSBDevice">
+      <desc>
+        Attaches a host USB device with the given UUID to the
+        USB controller of the virtual machine.
+
+        The device needs to be in one of the following states:
+        <link to="USBDeviceState_Busy"/>,
+        <link to="USBDeviceState_Available"/> or
+        <link to="USBDeviceState_Held"/>,
+        otherwise an error is immediately returned.
+
+        When the device state is
+        <link to="USBDeviceState_Busy">Busy</link>, an error may also
+        be returned if the host computer refuses to release it for some reason.
+
+        <see><link to="IUSBDeviceFilters::deviceFilters"/>,
+          <link to="USBDeviceState"/></see>
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine state neither Running nor Paused.
+        </result>
+        <result name="VBOX_E_PDM_ERROR">
+          Virtual machine does not have a USB controller.
+        </result>
+      </desc>
+      <param name="id" type="uuid" mod="string" dir="in">
+        <desc>UUID of the host USB device to attach.</desc>
+      </param>
+      <param name="captureFilename" type="wstring" dir="in">
+        <desc>Filename to capture the USB traffic to.</desc>
+      </param>
+    </method>
+
+    <method name="detachUSBDevice">
+      <desc>
+        Detaches an USB device with the given UUID from the USB controller
+        of the virtual machine.
+
+        After this method succeeds, the VirtualBox server re-initiates
+        all USB filters as if the device were just physically attached
+        to the host, but filters of this machine are ignored to avoid
+        a possible automatic re-attachment.
+
+        <see><link to="IUSBDeviceFilters::deviceFilters"/>,
+          <link to="USBDeviceState"/></see>
+
+        <result name="VBOX_E_PDM_ERROR">
+          Virtual machine does not have a USB controller.
+        </result>
+        <result name="E_INVALIDARG">
+          USB device not attached to this virtual machine.
+        </result>
+      </desc>
+      <param name="id" type="uuid" mod="string" dir="in">
+        <desc>UUID of the USB device to detach.</desc>
+      </param>
+      <param name="device" type="IUSBDevice" dir="return">
+        <desc>Detached USB device.</desc>
+      </param>
+    </method>
+
+    <method name="findUSBDeviceByAddress">
+      <desc>
+        Searches for a USB device with the given host address.
+
+        <result name="VBOX_E_OBJECT_NOT_FOUND">
+          Given @c name does not correspond to any USB device.
+        </result>
+
+        <see><link to="IUSBDevice::address"/></see>
+      </desc>
+      <param name="name" type="wstring" dir="in">
+        <desc>
+          Address of the USB device (as assigned by the host) to
+          search for.
+        </desc>
+      </param>
+      <param name="device" type="IUSBDevice" dir="return">
+        <desc>Found USB device object.</desc>
+      </param>
+    </method>
+
+    <method name="findUSBDeviceById">
+      <desc>
+        Searches for a USB device with the given UUID.
+
+        <result name="VBOX_E_OBJECT_NOT_FOUND">
+          Given @c id does not correspond to any USB device.
+        </result>
+
+        <see><link to="IUSBDevice::id"/></see>
+      </desc>
+      <param name="id" type="uuid" mod="string" dir="in">
+        <desc>UUID of the USB device to search for.</desc>
+      </param>
+      <param name="device" type="IUSBDevice" dir="return">
+        <desc>Found USB device object.</desc>
+      </param>
+    </method>
+
+    <method name="createSharedFolder">
+      <desc>
+        Creates a transient new shared folder by associating the given logical
+        name with the given host path, adds it to the collection of shared
+        folders and starts sharing it. Refer to the description of
+        <link to="ISharedFolder"/> to read more about logical names.
+
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine in Saved state or currently changing state.
+        </result>
+        <result name="VBOX_E_FILE_ERROR">
+          Shared folder already exists or not accessible.
+        </result>
+      </desc>
+      <param name="name" type="wstring" dir="in">
+        <desc>Unique logical name of the shared folder.</desc>
+      </param>
+      <param name="hostPath" type="wstring" dir="in">
+        <desc>Full path to the shared folder in the host file system.</desc>
+      </param>
+      <param name="writable" type="boolean" dir="in">
+        <desc>Whether the share is writable or readonly</desc>
+      </param>
+      <param name="automount" type="boolean" dir="in">
+        <desc>Whether the share gets automatically mounted by the guest
+          or not.</desc>
+      </param>
+    </method>
+
+    <method name="removeSharedFolder">
+      <desc>
+        Removes a transient shared folder with the given name previously
+        created by <link to="#createSharedFolder"/> from the collection of
+        shared folders and stops sharing it.
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Virtual machine in Saved state or currently changing state.
+        </result>
+        <result name="VBOX_E_FILE_ERROR">
+          Shared folder does not exists.
+        </result>
+      </desc>
+      <param name="name" type="wstring" dir="in">
+        <desc>Logical name of the shared folder to remove.</desc>
       </param>
     </method>
@@ -12986,10 +12826,10 @@
 
       The ISnapshot interface has no methods, only attributes; snapshots
-      are controlled through methods of the <link to="IConsole" /> interface
+      are controlled through methods of the <link to="IMachine" /> interface
       which also manage the media associated with the snapshot.
       The following operations exist:
 
       <ul>
-          <li><link to="IConsole::takeSnapshot"/> creates a new snapshot
+          <li><link to="IMachine::takeSnapshot"/> creates a new snapshot
               by creating new, empty differencing images for the machine's
               media and saving the VM settings and (if the VM is running)
@@ -18192,19 +18032,21 @@
       <desc>Host is running low on battery (power management event).</desc>
     </const>
+    <const name="Snapshot"          value="4">
+      <desc>A snapshot of the VM is being taken.</desc>
+    </const>
   </enum>
 
   <interface
     name="IInternalSessionControl" extends="$unknown"
-    uuid="fdb5fa71-eddb-4e06-9844-277d22270fe0"
+    uuid="747e397e-69c8-45a0-88d9-f7f070960718"
     internal="yes"
     wsmap="suppress"
     >
-    <method name="getPID">
+    <attribute name="PID" type="unsigned long" readonly="yes">
       <desc>PID of the process that has created this Session object.
       </desc>
-      <param name="pid" type="unsigned long" dir="return"/>
-    </method>
-
-    <method name="getRemoteConsole">
+    </attribute>
+
+    <attribute name="remoteConsole" type="IConsole" readonly="yes">
       <desc>
         Returns the console object suitable for remote control.
@@ -18218,6 +18060,12 @@
 
       </desc>
-      <param name="console" type="IConsole" dir="return"/>
-    </method>
+    </attribute>
+
+    <attribute name="nominalState" type="MachineState" readonly="yes">
+      <desc>Returns suitable machine state for the VM execution state. Useful
+        for choosing a sensible machine state after a complex operation which
+        failed or otherwise resulted in an unclear situation.
+      </desc>
+    </attribute>
 
 <if target="midl">
@@ -18688,4 +18536,22 @@
     </method>
 
+    <method name="reconfigureMediumAttachments">
+      <desc>
+        Reconfigure all specified medium attachments in one go, making sure
+        the current state corresponds to the specified medium.
+
+        <result name="VBOX_E_INVALID_VM_STATE">
+          Machine session is not open.
+        </result>
+        <result name="VBOX_E_INVALID_OBJECT_STATE">
+          Session type is not direct.
+        </result>
+      </desc>
+      <param name="attachments" type="IMediumAttachment" dir="in" safearray="yes">
+        <desc>Array containing the medium attachments which need to be
+          reconfigured.</desc>
+      </param>
+    </method>
+
     <method name="enableVMMStatistics">
       <desc>
@@ -18751,11 +18617,15 @@
         might behave slightly differently than a normal VM save state.
 
+        This call is fully synchronous, and the caller is expected to have set
+        the machine state appropriately (and has to set the follow-up machine
+        state if this call failed).
+
         <result name="VBOX_E_INVALID_VM_STATE">
-          Virtual machine state neither Running nor Paused.
+          Virtual machine state is not one of the expected values.
         </result>
         <result name="VBOX_E_FILE_ERROR">
           Failed to create directory for saved state file.
         </result>
-        <see><link to="IConsole::saveState"/></see>
+        <see><link to="IMachine::saveState"/></see>
       </desc>
 
@@ -18763,7 +18633,25 @@
         <desc>Specify the best matching reason code please.</desc>
       </param>
-      <param name="progress" type="IProgress" dir="return">
+      <param name="progress" type="IProgress" dir="in">
         <desc>Progress object to track the operation completion.</desc>
       </param>
+      <param name="stateFilePath" type="wstring" dir="in">
+        <desc>File path the VM process must save the execution state to.</desc>
+      </param>
+      <param name="pauseVM" type="boolean" dir="in">
+        <desc>The VM should be paused before saving state. It is automatically
+        unpaused on error in the "vanilla save state" case.</desc>
+      </param>
+      <param name="leftPaused" type="boolean" dir="return">
+        <desc>Returns if the VM was left in paused state, which is necessary
+        in many situations (snapshots, teleportation).</desc>
+      </param>
+    </method>
+
+    <method name="cancelSaveStateWithReason">
+      <desc>
+        Internal method for cancelling a VM save state.
+        <see><link to="IInternalSessionControl::saveStateWithReason"/></see>
+      </desc>
     </method>
 
Index: /trunk/src/VBox/Main/include/ConsoleImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 55213)
+++ /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 55214)
@@ -155,4 +155,5 @@
 
     HRESULT i_updateMachineState(MachineState_T aMachineState);
+    HRESULT i_getNominalState(MachineState_T &aNominalState);
 
     // events from IInternalSessionControl
@@ -188,4 +189,5 @@
                                 ULONG aSourceIdx, ULONG aTargetIdx,
                                 IProgress *aProgress);
+    HRESULT i_reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments);
     int i_hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName);
     VMMDev *i_getVMMDev() { return m_pVMMDev; }
@@ -230,6 +232,7 @@
 
     HRESULT i_pause(Reason_T aReason);
-    HRESULT i_resume(Reason_T aReason);
-    HRESULT i_saveState(Reason_T aReason, IProgress **aProgress);
+    HRESULT i_resume(Reason_T aReason, AutoWriteLock &alock);
+    HRESULT i_saveState(Reason_T aReason, const ComPtr<IProgress> &aProgress, const Utf8Str &aStateFilePath, bool fPauseVM, bool &fLeftPaused);
+    HRESULT i_cancelSaveState();
 
     // callback callers (partly; for some events console callbacks are notified
@@ -318,7 +321,4 @@
     HRESULT getPowerButtonHandled(BOOL *aHandled);
     HRESULT getGuestEnteredACPIMode(BOOL *aEntered);
-    HRESULT saveState(ComPtr<IProgress> &aProgress);
-    HRESULT adoptSavedState(const com::Utf8Str &aSavedStateFile);
-    HRESULT discardSavedState(BOOL aFRemoveFile);
     HRESULT getDeviceActivity(const std::vector<DeviceType_T> &aType,
                               std::vector<DeviceActivity_T> &aActivity);
@@ -335,16 +335,4 @@
                                BOOL aAutomount);
     HRESULT removeSharedFolder(const com::Utf8Str &aName);
-    HRESULT takeSnapshot(const com::Utf8Str &aName,
-                         const com::Utf8Str &aDescription,
-                         ComPtr<IProgress> &aProgress);
-    HRESULT deleteSnapshot(const com::Guid &aId,
-                           ComPtr<IProgress> &aProgress);
-    HRESULT deleteSnapshotAndAllChildren(const com::Guid &aId,
-                                         ComPtr<IProgress> &aProgress);
-    HRESULT deleteSnapshotRange(const com::Guid &aStartId,
-                                const com::Guid &aEndId,
-                                ComPtr<IProgress> &aProgress);
-    HRESULT restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
-                            ComPtr<IProgress> &aProgress);
     HRESULT teleport(const com::Utf8Str &aHostname,
                      ULONG aTcpport,
@@ -751,6 +739,4 @@
     HRESULT i_doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUVM pUVM, bool fSilent);
 
-    static DECLCALLBACK(int)    i_fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser);
-
     static DECLCALLBACK(int)    i_stateProgressCallback(PUVM pUVM, unsigned uPercent, void *pvUser);
 
@@ -766,5 +752,4 @@
 
     static DECLCALLBACK(int)    i_powerUpThread(RTTHREAD Thread, void *pvUser);
-    static DECLCALLBACK(int)    i_saveStateThread(RTTHREAD Thread, void *pvUser);
     static DECLCALLBACK(int)    i_powerDownThread(RTTHREAD Thread, void *pvUser);
 
@@ -997,5 +982,5 @@
      * teleportation operation, will cancel the teleportation / live snapshot
      * operation before starting. */
-    ComObjPtr<Progress> mptrCancelableProgress;
+    ComPtr<IProgress> mptrCancelableProgress;
 
     ComPtr<IEventListener> mVmListener;
Index: /trunk/src/VBox/Main/include/Global.h
===================================================================
--- /trunk/src/VBox/Main/include/Global.h	(revision 55213)
+++ /trunk/src/VBox/Main/include/Global.h	(revision 55214)
@@ -97,32 +97,9 @@
      * dedicated process) or not. Note that some online states are also
      * transitional states (see #IsTransitional()).
-     *
-     * @remarks Saving may actually be an offline state according to the
-     *          documentation (offline snapshot).
      */
     static bool IsOnline(MachineState_T aState)
     {
-#if 0
         return aState >= MachineState_FirstOnline &&
                aState <= MachineState_LastOnline;
-#else
-        switch (aState)
-        {
-            case MachineState_Running:
-            case MachineState_Paused:
-            case MachineState_Teleporting:
-            case MachineState_LiveSnapshotting:
-            case MachineState_Stuck:
-            case MachineState_Starting:
-            case MachineState_Stopping:
-            case MachineState_Saving:
-            case MachineState_Restoring:
-            case MachineState_TeleportingPausedVM:
-            case MachineState_TeleportingIn:
-                return true;
-            default:
-                return false;
-        }
-#endif
     }
 
@@ -136,26 +113,6 @@
     static bool IsTransient(MachineState_T aState)
     {
-#if 0
         return aState >= MachineState_FirstTransient &&
                aState <= MachineState_LastTransient;
-#else
-        switch (aState)
-        {
-            case MachineState_Teleporting:
-            case MachineState_LiveSnapshotting:
-            case MachineState_Starting:
-            case MachineState_Stopping:
-            case MachineState_Saving:
-            case MachineState_Restoring:
-            case MachineState_TeleportingPausedVM:
-            case MachineState_TeleportingIn:
-            case MachineState_RestoringSnapshot:
-            case MachineState_DeletingSnapshot:
-            case MachineState_SettingUp:
-                return true;
-            default:
-                return false;
-        }
-#endif
     }
 
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 55213)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 55214)
@@ -125,4 +125,7 @@
         struct Session
         {
+            /** Type of lock which created this session */
+            LockType_T mLockType;
+
             /** Control of the direct session opened by lockMachine() */
             ComPtr<IInternalSessionControl> mDirectControl;
@@ -597,5 +600,5 @@
     }
 
-
+    static HRESULT i_setErrorStatic(HRESULT aResultCode, const char *pcszMsg, ...);
 
 protected:
@@ -712,7 +715,4 @@
     bool i_isControllerHotplugCapable(StorageControllerType_T enmCtrlType);
 
-    struct DeleteTask;
-    static DECLCALLBACK(int) deleteThread(RTTHREAD Thread, void *pvUser);
-    HRESULT i_deleteTaskWorker(DeleteTask &task);
     Utf8Str i_getExtraData(const Utf8Str &strKey);
 
@@ -778,4 +778,58 @@
 
     uint64_t                        uRegistryNeedsSaving;
+
+    /**
+     * Abstract base class for all Machine or SessionMachine related
+     * asynchronous tasks. This is necessary since RTThreadCreate cannot call
+     * a (non-static) method as its thread function, so instead we have it call
+     * the static Machine::taskHandler, which then calls the handler() method
+     * in here (implemented by the subclasses).
+     */
+    struct Task
+    {
+        Task(Machine *m, Progress *p, const Utf8Str &t)
+            : m_pMachine(m),
+              m_machineCaller(m),
+              m_pProgress(p),
+              m_strTaskName(t),
+              m_machineStateBackup(m->mData->mMachineState) // save the current machine state
+        {}
+
+        HRESULT createThread()
+        {
+            int vrc = RTThreadCreate(NULL,
+                                     taskHandler,
+                                     (void *)this,
+                                     0,
+                                     RTTHREADTYPE_MAIN_WORKER,
+                                     0,
+                                     m_strTaskName.c_str());
+            if (RT_FAILURE(vrc))
+            {
+                HRESULT rc = Machine::i_setErrorStatic(E_FAIL, Machine::tr("Could not create thread \"%s\" (%Rrc)"), m_strTaskName.c_str(), vrc);
+                delete this;
+                return rc;
+            }
+            return S_OK;
+        }
+
+        void modifyBackedUpState(MachineState_T s)
+        {
+            *const_cast<MachineState_T *>(&m_machineStateBackup) = s;
+        }
+
+        virtual void handler() = 0;
+
+        ComObjPtr<Machine>       m_pMachine;
+        AutoCaller                      m_machineCaller;
+        ComObjPtr<Progress>             m_pProgress;
+        Utf8Str                         m_strTaskName;
+        const MachineState_T            m_machineStateBackup;
+    };
+
+    struct DeleteConfigTask;
+    void i_deleteConfigHandler(DeleteConfigTask &task);
+
+    static DECLCALLBACK(int) taskHandler(RTTHREAD thread, void *pvUser);
 
     friend class SessionMachine;
@@ -1131,9 +1185,24 @@
                     const std::vector<CloneOptions_T> &aOptions,
                     ComPtr<IProgress> &aProgress);
+    HRESULT saveState(ComPtr<IProgress> &aProgress);
+    HRESULT adoptSavedState(const com::Utf8Str &aSavedStateFile);
+    HRESULT discardSavedState(BOOL aFRemoveFile);
+    HRESULT takeSnapshot(const com::Utf8Str &aName,
+                         const com::Utf8Str &aDescription,
+                         BOOL aPause,
+                         ComPtr<IProgress> &aProgress);
+    HRESULT deleteSnapshot(const com::Guid &aId,
+                           ComPtr<IProgress> &aProgress);
+    HRESULT deleteSnapshotAndAllChildren(const com::Guid &aId,
+                                         ComPtr<IProgress> &aProgress);
+    HRESULT deleteSnapshotRange(const com::Guid &aStartId,
+                                const com::Guid &aEndId,
+                                ComPtr<IProgress> &aProgress);
+    HRESULT restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
+                            ComPtr<IProgress> &aProgress);
 
     // wrapped IInternalMachineControl properties
 
     // wrapped IInternalMachineControl methods
-    HRESULT setRemoveSavedStateFile(BOOL aRemove);
     HRESULT updateState(MachineState_T aState);
     HRESULT beginPowerUp(const ComPtr<IProgress> &aProgress);
@@ -1145,5 +1214,6 @@
                                 BOOL *aMatched,
                                 ULONG *aMaskedInterfaces);
-    HRESULT captureUSBDevice(const com::Guid &aId, const com::Utf8Str &aCaptureFilename);
+    HRESULT captureUSBDevice(const com::Guid &aId,
+                             const com::Utf8Str &aCaptureFilename);
     HRESULT detachUSBDevice(const com::Guid &aId,
                             BOOL aDone);
@@ -1152,27 +1222,5 @@
     HRESULT onSessionEnd(const ComPtr<ISession> &aSession,
                          ComPtr<IProgress> &aProgress);
-    HRESULT beginSavingState(ComPtr<IProgress> &aProgress,
-                             com::Utf8Str &aStateFilePath);
-    HRESULT endSavingState(LONG aResult,
-                           const com::Utf8Str &aErrMsg);
-    HRESULT adoptSavedState(const com::Utf8Str &aSavedStateFile);
-    HRESULT beginTakingSnapshot(const ComPtr<IConsole> &aInitiator,
-                                const com::Utf8Str &aName,
-                                const com::Utf8Str &aDescription,
-                                const ComPtr<IProgress> &aConsoleProgress,
-                                BOOL aFTakingSnapshotOnline,
-                                com::Utf8Str &aStateFilePath);
-    HRESULT endTakingSnapshot(BOOL aSuccess);
-    HRESULT deleteSnapshot(const ComPtr<IConsole> &aInitiator,
-                           const com::Guid &aStartId,
-                           const com::Guid &aEndId,
-                           BOOL aDeleteAllChildren,
-                           MachineState_T *aMachineState,
-                           ComPtr<IProgress> &aProgress);
     HRESULT finishOnlineMergeMedium();
-    HRESULT restoreSnapshot(const ComPtr<IConsole> &aInitiator,
-                            const ComPtr<ISnapshot> &aSnapshot,
-                            MachineState_T *aMachineState,
-                            ComPtr<IProgress> &aProgress);
     HRESULT pullGuestProperties(std::vector<com::Utf8Str> &aNames,
                                 std::vector<com::Utf8Str> &aValues,
@@ -1203,8 +1251,4 @@
                                ULONG aVmNetRx,
                                ULONG aVmNetTx);
-
-
-
-
 };
 
@@ -1302,4 +1346,6 @@
     HRESULT i_unlockMedia();
 
+    HRESULT i_saveStateWithReason(Reason_T aReason, ComPtr<IProgress> &aProgress);
+
 private:
 
@@ -1324,27 +1370,5 @@
     HRESULT onSessionEnd(const ComPtr<ISession> &aSession,
                          ComPtr<IProgress> &aProgress);
-    HRESULT beginSavingState(ComPtr<IProgress> &aProgress,
-                             com::Utf8Str &aStateFilePath);
-    HRESULT endSavingState(LONG aResult,
-                           const com::Utf8Str &aErrMsg);
-    HRESULT adoptSavedState(const com::Utf8Str &aSavedStateFile);
-    HRESULT beginTakingSnapshot(const ComPtr<IConsole> &aInitiator,
-                                const com::Utf8Str &aName,
-                                const com::Utf8Str &aDescription,
-                                const ComPtr<IProgress> &aConsoleProgress,
-                                BOOL aFTakingSnapshotOnline,
-                                com::Utf8Str &aStateFilePath);
-    HRESULT endTakingSnapshot(BOOL aSuccess);
-    HRESULT deleteSnapshot(const ComPtr<IConsole> &aInitiator,
-                           const com::Guid &aStartId,
-                           const com::Guid &aEndId,
-                           BOOL aDeleteAllChildren,
-                           MachineState_T *aMachineState,
-                           ComPtr<IProgress> &aProgress);
     HRESULT finishOnlineMergeMedium();
-    HRESULT restoreSnapshot(const ComPtr<IConsole> &aInitiator,
-                            const ComPtr<ISnapshot> &aSnapshot,
-                            MachineState_T *aMachineState,
-                            ComPtr<IProgress> &aProgress);
     HRESULT pullGuestProperties(std::vector<com::Utf8Str> &aNames,
                                 std::vector<com::Utf8Str> &aValues,
@@ -1380,5 +1404,6 @@
     {
         ConsoleTaskData()
-            : mLastState(MachineState_Null), mDeleteSnapshotInfo(NULL)
+            : mLastState(MachineState_Null),
+              mDeleteSnapshotInfo(NULL)
         { }
 
@@ -1386,24 +1411,48 @@
         ComObjPtr<Progress> mProgress;
 
-        // used when taking snapshot
-        ComObjPtr<Snapshot> mSnapshot;
-
-        // used when deleting online snapshot
+        // used when deleting online snaphshot
         void *mDeleteSnapshotInfo;
-
-        // used when saving state (either as part of a snapshot or separate)
-        Utf8Str strStateFilePath;
     };
 
+    struct SaveStateTask;
     struct SnapshotTask;
+    struct TakeSnapshotTask;
     struct DeleteSnapshotTask;
     struct RestoreSnapshotTask;
 
+    friend struct TakeSnapshotTask;
     friend struct DeleteSnapshotTask;
     friend struct RestoreSnapshotTask;
 
-    HRESULT i_endSavingState(HRESULT aRC, const Utf8Str &aErrMsg);
+    void i_saveStateHandler(SaveStateTask &aTask);
+
+    // Override some functionality for SessionMachine, this is where the
+    // real action happens (the Machine methods are just dummies).
+    HRESULT saveState(ComPtr<IProgress> &aProgress);
+    HRESULT adoptSavedState(const com::Utf8Str &aSavedStateFile);
+    HRESULT discardSavedState(BOOL aFRemoveFile);
+    HRESULT takeSnapshot(const com::Utf8Str &aName,
+                         const com::Utf8Str &aDescription,
+                         BOOL aPause,
+                         ComPtr<IProgress> &aProgress);
+    HRESULT deleteSnapshot(const com::Guid &aId,
+                           ComPtr<IProgress> &aProgress);
+    HRESULT deleteSnapshotAndAllChildren(const com::Guid &aId,
+                                         ComPtr<IProgress> &aProgress);
+    HRESULT deleteSnapshotRange(const com::Guid &aStartId,
+                                const com::Guid &aEndId,
+                                ComPtr<IProgress> &aProgress);
+    HRESULT restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
+                            ComPtr<IProgress> &aProgress);
+
     void i_releaseSavedStateFile(const Utf8Str &strSavedStateFile, Snapshot *pSnapshotToIgnore);
 
+    void i_takeSnapshotHandler(TakeSnapshotTask &aTask);
+    static void i_takeSnapshotProgressCancelCallback(void *pvUser);
+    HRESULT i_finishTakingSnapshot(TakeSnapshotTask &aTask, AutoWriteLock &alock, bool aSuccess);
+    HRESULT i_deleteSnapshot(const com::Guid &aStartId,
+                             const com::Guid &aEndId,
+                             BOOL aDeleteAllChildren,
+                             ComPtr<IProgress> &aProgress);
     void i_deleteSnapshotHandler(DeleteSnapshotTask &aTask);
     void i_restoreSnapshotHandler(RestoreSnapshotTask &aTask);
@@ -1451,6 +1500,4 @@
 
     int miNATNetworksStarted;
-
-    static DECLCALLBACK(int) taskHandler(RTTHREAD thread, void *pvUser);
 };
 
Index: /trunk/src/VBox/Main/include/SessionImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/SessionImpl.h	(revision 55213)
+++ /trunk/src/VBox/Main/include/SessionImpl.h	(revision 55214)
@@ -53,5 +53,5 @@
 private:
 
-    // Wrapped Isession properties
+    // Wrapped ISession properties
     HRESULT getState(SessionState_T *aState);
     HRESULT getType(SessionType_T *aType);
@@ -59,8 +59,13 @@
     HRESULT getConsole(ComPtr<IConsole> &aConsole);
 
-    // Wrapped Isession methods
+    // Wrapped ISession methods
     HRESULT unlockMachine();
+
+    // Wrapped IInternalSessionControl properties
     HRESULT getPID(ULONG *aPid);
-    HRESULT getRemoteConsole(ComPtr<IConsole> &aConsole);
+    HRESULT getRemoteConsole(ComPtr<IConsole> &aRemoteConsole);
+    HRESULT getNominalState(MachineState_T *aNominalState);
+
+    // Wrapped IInternalSessionControl methods
 #ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
     HRESULT assignMachine(const ComPtr<IMachine> &aMachine,
@@ -121,10 +126,17 @@
                               ULONG aTargetIdx,
                               const ComPtr<IProgress> &aProgress);
+    HRESULT reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments);
     HRESULT enableVMMStatistics(BOOL aEnable);
     HRESULT pauseWithReason(Reason_T aReason);
     HRESULT resumeWithReason(Reason_T aReason);
     HRESULT saveStateWithReason(Reason_T aReason,
-                                ComPtr<IProgress> &aProgress);
-    HRESULT unlockMachine(bool aFinalRelease, bool aFromServer);
+                                const ComPtr<IProgress> &aProgress,
+                                const Utf8Str &aStateFilePath,
+                                BOOL aPauseVM,
+                                BOOL *aLeftPaused);
+    HRESULT cancelSaveStateWithReason();
+
+
+    HRESULT i_unlockMachine(bool aFinalRelease, bool aFromServer);
 
     SessionState_T mState;
Index: /trunk/src/VBox/Main/src-all/Global.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/Global.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-all/Global.cpp	(revision 55214)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2008-2013 Oracle Corporation
+ * Copyright (C) 2008-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -448,7 +448,9 @@
         case MachineState_DeletingSnapshotOnline: return "DeletingSnapshotOnline";
         case MachineState_DeletingSnapshotPaused: return "DeletingSnapshotPaused";
+        case MachineState_OnlineSnapshotting:   return "OnlineSnapshotting";
         case MachineState_RestoringSnapshot:    return "RestoringSnapshot";
         case MachineState_DeletingSnapshot:     return "DeletingSnapshot";
         case MachineState_SettingUp:            return "SettingUp";
+        case MachineState_Snapshotting:         return "Snapshotting";
         default:
         {
@@ -513,4 +515,5 @@
         case Reason_HostResume:       return "host resume";
         case Reason_HostBatteryLow:   return "host battery low";
+        case Reason_Snapshot:         return "snapshot";
         default:
         {
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 55214)
@@ -164,5 +164,4 @@
           mProgress(aProgress),
           mServerProgress(aServerProgress),
-          mpUVM(NULL),
           mRC(E_FAIL),
           mpSafeVMPtr(NULL)
@@ -175,7 +174,5 @@
         {
             mpSafeVMPtr = new Console::SafeVMPtr(aConsole);
-            if (mpSafeVMPtr->isOk())
-                mpUVM = mpSafeVMPtr->rawUVM();
-            else
+            if (!mpSafeVMPtr->isOk())
                 mRC = mpSafeVMPtr->rc();
         }
@@ -205,5 +202,4 @@
     Utf8Str                     mErrorMsg;
     const ComPtr<IProgress>     mServerProgress;
-    PUVM                        mpUVM;
 
 private:
@@ -212,24 +208,4 @@
 };
 
-struct VMTakeSnapshotTask : public VMTask
-{
-    VMTakeSnapshotTask(Console *aConsole,
-                       Progress *aProgress,
-                       IN_BSTR aName,
-                       IN_BSTR aDescription)
-        : VMTask(aConsole, aProgress, NULL /* aServerProgress */,
-                 false /* aUsesVMPtr */),
-          bstrName(aName),
-          bstrDescription(aDescription),
-          lastMachineState(MachineState_Null)
-    {}
-
-    Bstr                    bstrName,
-                            bstrDescription;
-    Bstr                    bstrSavedStateFile;         // received from BeginTakeSnapshot()
-    MachineState_T          lastMachineState;
-    bool                    fTakingSnapshotOnline;
-    ULONG                   ulMemSize;
-};
 
 struct VMPowerUpTask : public VMTask
@@ -264,25 +240,4 @@
                  true /* aUsesVMPtr */)
     {}
-};
-
-struct VMSaveTask : public VMTask
-{
-    VMSaveTask(Console *aConsole,
-               const ComPtr<IProgress> &aServerProgress,
-               const Utf8Str &aSavedStateFile,
-               MachineState_T aMachineStateBefore,
-               Reason_T aReason)
-        : VMTask(aConsole, NULL /* aProgress */, aServerProgress,
-                 true /* aUsesVMPtr */),
-          mSavedStateFile(aSavedStateFile),
-          mMachineStateBefore(aMachineStateBefore),
-          mReason(aReason)
-    {}
-
-    Utf8Str mSavedStateFile;
-    /* The local machine state we had before. Required if something fails */
-    MachineState_T mMachineStateBefore;
-    /* The reason for saving state */
-    Reason_T mReason;
 };
 
@@ -597,12 +552,4 @@
             meAttachmentType[slot] = NetworkAttachmentType_Null;
 
-        // VirtualBox 4.0: We no longer initialize the VMMDev instance here,
-        // which starts the HGCM thread. Instead, this is now done in the
-        // power-up thread when a VM is actually being powered up to avoid
-        // having HGCM threads all over the place every time a session is
-        // opened, even if that session will not run a VM.
-        //     unconst(m_pVMMDev) = new VMMDev(this);
-        //     AssertReturn(mVMMDev, E_FAIL);
-
 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
         unconst(mAudioVRDE) = new AudioVRDE(this);
@@ -2106,7 +2053,5 @@
 HRESULT Console::powerUp(ComPtr<IProgress> &aProgress)
 {
-    ComObjPtr<IProgress> pProgress;
-    i_powerUp(pProgress.asOutParam(), false /* aPaused */);
-    pProgress.queryInterfaceTo(aProgress.asOutParam());
+    i_powerUp(aProgress.asOutParam(), false /* aPaused */);
     return S_OK;
 }
@@ -2114,7 +2059,5 @@
 HRESULT Console::powerUpPaused(ComPtr<IProgress> &aProgress)
 {
-    ComObjPtr<IProgress> pProgress;
-    i_powerUp(pProgress.asOutParam(), true /* aPaused */);
-    pProgress.queryInterfaceTo(aProgress.asOutParam());
+    i_powerUp(aProgress.asOutParam(), true /* aPaused */);
     return S_OK;
 }
@@ -2133,4 +2076,14 @@
         case MachineState_Stuck:
             break;
+
+        /* Try cancel the save state. */
+        case MachineState_Saving:
+            if (!mptrCancelableProgress.isNull())
+            {
+                HRESULT hrc = mptrCancelableProgress->Cancel();
+                if (SUCCEEDED(hrc))
+                    break;
+            }
+            return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point during a save state"));
 
         /* Try cancel the teleportation. */
@@ -2145,4 +2098,14 @@
             return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point in a teleportation"));
 
+        /* Try cancel the online snapshot. */
+        case MachineState_OnlineSnapshotting:
+            if (!mptrCancelableProgress.isNull())
+            {
+                HRESULT hrc = mptrCancelableProgress->Cancel();
+                if (SUCCEEDED(hrc))
+                    break;
+            }
+            return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point in an online snapshot"));
+
         /* Try cancel the live snapshot. */
         case MachineState_LiveSnapshotting:
@@ -2539,5 +2502,12 @@
     LogFlowThisFuncEnter();
 
-    HRESULT rc = i_resume(Reason_Unspecified);
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mMachineState != MachineState_Paused)
+        return setError(VBOX_E_INVALID_VM_STATE,
+                        tr("Cannot resume the machine as it is not paused (machine state: %s)"),
+                        Global::stringifyMachineState(mMachineState));
+
+    HRESULT rc = i_resume(Reason_Unspecified, alock);
 
     LogFlowThisFunc(("rc=%Rhrc\n", rc));
@@ -2720,53 +2690,4 @@
     LogFlowThisFunc(("rc=%Rhrc\n", rc));
     LogFlowThisFuncLeave();
-    return rc;
-}
-
-HRESULT Console::saveState(ComPtr<IProgress> &aProgress)
-{
-    LogFlowThisFuncEnter();
-    ComObjPtr<IProgress> pProgress;
-
-    HRESULT rc = i_saveState(Reason_Unspecified, pProgress.asOutParam());
-    pProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    LogFlowThisFunc(("rc=%Rhrc\n", rc));
-    LogFlowThisFuncLeave();
-    return rc;
-}
-
-HRESULT Console::adoptSavedState(const com::Utf8Str &aSavedStateFile)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (   mMachineState != MachineState_PoweredOff
-        && mMachineState != MachineState_Teleported
-        && mMachineState != MachineState_Aborted
-       )
-        return setError(VBOX_E_INVALID_VM_STATE,
-            tr("Cannot adopt the saved machine state as the machine is not in Powered Off, Teleported or Aborted state (machine state: %s)"),
-            Global::stringifyMachineState(mMachineState));
-
-    return mControl->AdoptSavedState(Bstr(aSavedStateFile.c_str()).raw());
-}
-
-HRESULT Console::discardSavedState(BOOL aFRemoveFile)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (mMachineState != MachineState_Saved)
-        return setError(VBOX_E_INVALID_VM_STATE,
-            tr("Cannot delete the machine state as the machine is not in the saved state (machine state: %s)"),
-            Global::stringifyMachineState(mMachineState));
-
-    HRESULT rc = mControl->SetRemoveSavedStateFile(aFRemoveFile);
-    if (FAILED(rc)) return rc;
-
-    /*
-     * Saved -> PoweredOff transition will be detected in the SessionMachine
-     * and properly handled.
-     */
-    rc = i_setMachineState(MachineState_PoweredOff);
-
     return rc;
 }
@@ -3155,210 +3076,4 @@
 
     return rc;
-}
-
-HRESULT Console::takeSnapshot(const com::Utf8Str &aName,
-                              const com::Utf8Str &aDescription,
-                              ComPtr<IProgress> &aProgress)
-{
-    LogFlowThisFuncEnter();
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-    LogFlowThisFunc(("aName='%s' mMachineState=%d\n", aName.c_str(), mMachineState));
-
-    if (Global::IsTransient(mMachineState))
-        return setError(VBOX_E_INVALID_VM_STATE,
-                        tr("Cannot take a snapshot of the machine while it is changing the state (machine state: %s)"),
-                        Global::stringifyMachineState(mMachineState));
-
-    HRESULT rc = S_OK;
-
-    /* prepare the progress object:
-       a) count the no. of hard disk attachments to get a matching no. of progress sub-operations */
-    ULONG cOperations = 2;              // always at least setting up + finishing up
-    ULONG ulTotalOperationsWeight = 2;  // one each for setting up + finishing up
-    SafeIfaceArray<IMediumAttachment> aMediumAttachments;
-    rc = mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aMediumAttachments));
-    if (FAILED(rc))
-        return setError(rc, tr("Cannot get medium attachments of the machine"));
-
-    ULONG ulMemSize;
-    rc = mMachine->COMGETTER(MemorySize)(&ulMemSize);
-    if (FAILED(rc))
-        return rc;
-
-    for (size_t i = 0;
-         i < aMediumAttachments.size();
-         ++i)
-    {
-        DeviceType_T type;
-        rc = aMediumAttachments[i]->COMGETTER(Type)(&type);
-        if (FAILED(rc))
-            return rc;
-
-        if (type == DeviceType_HardDisk)
-        {
-            ++cOperations;
-
-            // assume that creating a diff image takes as long as saving a 1MB state
-            // (note, the same value must be used in SessionMachine::BeginTakingSnapshot() on the server!)
-            ulTotalOperationsWeight += 1;
-        }
-    }
-
-    // b) one extra sub-operations for online snapshots OR offline snapshots that have a saved state (needs to be copied)
-    bool const fTakingSnapshotOnline = Global::IsOnline(mMachineState);
-
-    LogFlowFunc(("fTakingSnapshotOnline = %d, mMachineState = %d\n", fTakingSnapshotOnline, mMachineState));
-
-    if (fTakingSnapshotOnline)
-    {
-        ++cOperations;
-        ulTotalOperationsWeight += ulMemSize;
-    }
-
-    // finally, create the progress object
-    ComObjPtr<Progress> pProgress;
-    pProgress.createObject();
-    rc = pProgress->init(static_cast<IConsole *>(this),
-                         Bstr(tr("Taking a snapshot of the virtual machine")).raw(),
-                            (mMachineState >= MachineState_FirstOnline)
-                         && (mMachineState <= MachineState_LastOnline) /* aCancelable */,
-                         cOperations,
-                         ulTotalOperationsWeight,
-                         Bstr(tr("Setting up snapshot operation")).raw(),      // first sub-op description
-                         1);        // ulFirstOperationWeight
-
-    if (FAILED(rc))
-        return rc;
-
-    VMTakeSnapshotTask *pTask;
-    if (!(pTask = new VMTakeSnapshotTask(this, pProgress, Bstr(aName).raw(), Bstr(aDescription).raw())))
-        return E_OUTOFMEMORY;
-
-    Assert(pTask->mProgress);
-
-    try
-    {
-        mptrCancelableProgress = pProgress;
-
-        /*
-         * If we fail here it means a PowerDown() call happened on another
-         * thread while we were doing Pause() (which releases the Console lock).
-         * We assign PowerDown() a higher precedence than TakeSnapshot(),
-         * therefore just return the error to the caller.
-         */
-        rc = pTask->rc();
-        if (FAILED(rc)) throw rc;
-
-        pTask->ulMemSize = ulMemSize;
-
-        /* memorize the current machine state */
-        pTask->lastMachineState = mMachineState;
-        pTask->fTakingSnapshotOnline = fTakingSnapshotOnline;
-
-        int vrc = RTThreadCreate(NULL,
-                                 Console::i_fntTakeSnapshotWorker,
-                                 (void *)pTask,
-                                 0,
-                                 RTTHREADTYPE_MAIN_WORKER,
-                                 0,
-                                 "TakeSnap");
-        if (FAILED(vrc))
-            throw setError(E_FAIL,
-                           tr("Could not create VMTakeSnap thread (%Rrc)"),
-                           vrc);
-
-        pTask->mProgress.queryInterfaceTo(aProgress.asOutParam());
-    }
-    catch (HRESULT erc)
-    {
-        delete pTask;
-        rc = erc;
-        mptrCancelableProgress.setNull();
-    }
-
-    LogFlowThisFunc(("rc=%Rhrc\n", rc));
-    LogFlowThisFuncLeave();
-    return rc;
-}
-
-HRESULT Console::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (Global::IsTransient(mMachineState))
-        return setError(VBOX_E_INVALID_VM_STATE,
-                        tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
-                        Global::stringifyMachineState(mMachineState));
-    ComObjPtr<IProgress> iProgress;
-    MachineState_T machineState = MachineState_Null;
-    HRESULT rc = mControl->DeleteSnapshot((IConsole *)this, Bstr(aId.toString()).raw(), Bstr(aId.toString()).raw(),
-                                          FALSE /* fDeleteAllChildren */, &machineState, iProgress.asOutParam());
-    if (FAILED(rc)) return rc;
-    iProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    i_setMachineStateLocally(machineState);
-    return S_OK;
-}
-
-HRESULT Console::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress)
-
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (Global::IsTransient(mMachineState))
-        return setError(VBOX_E_INVALID_VM_STATE,
-                        tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
-                        Global::stringifyMachineState(mMachineState));
-
-    ComObjPtr<IProgress> iProgress;
-    MachineState_T machineState = MachineState_Null;
-    HRESULT rc = mControl->DeleteSnapshot((IConsole *)this, Bstr(aId.toString()).raw(), Bstr(aId.toString()).raw(),
-                                          TRUE /* fDeleteAllChildren */, &machineState, iProgress.asOutParam());
-    if (FAILED(rc)) return rc;
-    iProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    i_setMachineStateLocally(machineState);
-    return S_OK;
-}
-
-HRESULT Console::deleteSnapshotRange(const com::Guid &aStartId, const com::Guid &aEndId, ComPtr<IProgress> &aProgress)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (Global::IsTransient(mMachineState))
-        return setError(VBOX_E_INVALID_VM_STATE,
-                        tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
-                        Global::stringifyMachineState(mMachineState));
-
-    ComObjPtr<IProgress> iProgress;
-    MachineState_T machineState = MachineState_Null;
-    HRESULT rc = mControl->DeleteSnapshot((IConsole *)this, Bstr(aStartId.toString()).raw(), Bstr(aEndId.toString()).raw(),
-                                          FALSE /* fDeleteAllChildren */, &machineState, iProgress.asOutParam());
-    if (FAILED(rc)) return rc;
-    iProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    i_setMachineStateLocally(machineState);
-    return S_OK;
-}
-
-HRESULT Console::restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot, ComPtr<IProgress> &aProgress)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (Global::IsOnlineOrTransient(mMachineState))
-        return setError(VBOX_E_INVALID_VM_STATE,
-                        tr("Cannot delete the current state of the running machine (machine state: %s)"),
-                        Global::stringifyMachineState(mMachineState));
-
-    ISnapshot* iSnapshot = aSnapshot;
-    ComObjPtr<IProgress> iProgress;
-    MachineState_T machineState = MachineState_Null;
-    HRESULT rc = mControl->RestoreSnapshot((IConsole*)this, iSnapshot, &machineState, iProgress.asOutParam());
-    if (FAILED(rc)) return rc;
-    iProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    i_setMachineStateLocally(machineState);
-    return S_OK;
 }
 
@@ -3645,5 +3360,5 @@
                                     getStaticComponentName(),
                                     Utf8StrFmt("Invalid state '%s' for changing medium",
-                                        VMR3GetStateName(enmVMState)),
+                                               VMR3GetStateName(enmVMState)),
                                     false /*aWarning*/,
                                     true /*aLogIt*/);
@@ -6219,5 +5934,5 @@
 
     /* We will need to release the lock before doing the actual merge */
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
     /* paranoia - we don't want merges to happen while teleporting etc. */
@@ -6295,18 +6010,13 @@
     AssertComRCReturnRC(rc);
 
+    Assert(mMachineState == MachineState_DeletingSnapshotOnline);
+
+    /* Pause the VM, as it might have pending IO on this drive */
+    bool fResume = false;
+    rc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), &alock, &fResume);
+    if (FAILED(rc))
+        return rc;
+
     alock.release();
-
-    /* Pause the VM, as it might have pending IO on this drive */
-    VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM());
-    if (mMachineState == MachineState_DeletingSnapshotOnline)
-    {
-        LogFlowFunc(("Suspending the VM...\n"));
-        /* disable the callback to prevent Console-level state change */
-        mVMStateChangeCallbackDisabled = true;
-        int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG);
-        mVMStateChangeCallbackDisabled = false;
-        AssertRCReturn(vrc2, E_FAIL);
-    }
-
     vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
                            (PFNRT)i_reconfigureMediumAttachment, 13,
@@ -6316,18 +6026,6 @@
     /* error handling is after resuming the VM */
 
-    if (mMachineState == MachineState_DeletingSnapshotOnline)
-    {
-        LogFlowFunc(("Resuming the VM...\n"));
-        /* disable the callback to prevent Console-level state change */
-        mVMStateChangeCallbackDisabled = true;
-        int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG);
-        mVMStateChangeCallbackDisabled = false;
-        if (RT_FAILURE(vrc2))
-        {
-            /* too bad, we failed. try to sync the console state with the VMM state */
-            AssertLogRelRC(vrc2);
-            i_vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this);
-        }
-    }
+    if (fResume)
+        i_resumeAfterConfigChange(ptrVM.rawUVM());
 
     if (RT_FAILURE(vrc))
@@ -6356,15 +6054,10 @@
         return setError(E_FAIL, tr("Failed to perform an online medium merge (%Rrc)"), vrc);
 
+    alock.acquire();
     /* Pause the VM, as it might have pending IO on this drive */
-    enmVMState = VMR3GetStateU(ptrVM.rawUVM());
-    if (mMachineState == MachineState_DeletingSnapshotOnline)
-    {
-        LogFlowFunc(("Suspending the VM...\n"));
-        /* disable the callback to prevent Console-level state change */
-        mVMStateChangeCallbackDisabled = true;
-        int vrc2 = VMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_RECONFIG);
-        mVMStateChangeCallbackDisabled = false;
-        AssertRCReturn(vrc2, E_FAIL);
-    }
+    rc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), &alock, &fResume);
+    if (FAILED(rc))
+        return rc;
+    alock.release();
 
     /* Update medium chain and state now, so that the VM can continue. */
@@ -6378,18 +6071,6 @@
     /* error handling is after resuming the VM */
 
-    if (mMachineState == MachineState_DeletingSnapshotOnline)
-    {
-        LogFlowFunc(("Resuming the VM...\n"));
-        /* disable the callback to prevent Console-level state change */
-        mVMStateChangeCallbackDisabled = true;
-        int vrc2 = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG);
-        mVMStateChangeCallbackDisabled = false;
-        AssertRC(vrc2);
-        if (RT_FAILURE(vrc2))
-        {
-            /* too bad, we failed. try to sync the console state with the VMM state */
-            i_vmstateChangeCallback(ptrVM.rawUVM(), VMSTATE_SUSPENDED, enmVMState, this);
-        }
-    }
+    if (fResume)
+        i_resumeAfterConfigChange(ptrVM.rawUVM());
 
     if (RT_FAILURE(vrc))
@@ -6397,4 +6078,79 @@
     if (FAILED(rc))
         return rc;
+
+    return rc;
+}
+
+HRESULT Console::i_reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments)
+{
+    HRESULT rc = S_OK;
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /* get the VM handle. */
+    SafeVMPtr ptrVM(this);
+    if (!ptrVM.isOk())
+        return ptrVM.rc();
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    for (size_t i = 0; i < aAttachments.size(); ++i)
+    {
+        ComPtr<IStorageController> pStorageController;
+        Bstr controllerName;
+        ULONG lInstance;
+        StorageControllerType_T enmController;
+        StorageBus_T enmBus;
+        BOOL fUseHostIOCache;
+
+        /*
+         * We could pass the objects, but then EMT would have to do lots of
+         * IPC (to VBoxSVC) which takes a significant amount of time.
+         * Better query needed values here and pass them.
+         */
+        rc = aAttachments[i]->COMGETTER(Controller)(controllerName.asOutParam());
+        if (FAILED(rc))
+            throw rc;
+
+        rc = mMachine->GetStorageControllerByName(controllerName.raw(),
+                                                  pStorageController.asOutParam());
+        if (FAILED(rc))
+            throw rc;
+
+        rc = pStorageController->COMGETTER(ControllerType)(&enmController);
+        if (FAILED(rc))
+            throw rc;
+        rc = pStorageController->COMGETTER(Instance)(&lInstance);
+        if (FAILED(rc))
+            throw rc;
+        rc = pStorageController->COMGETTER(Bus)(&enmBus);
+        if (FAILED(rc))
+            throw rc;
+        rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
+        if (FAILED(rc))
+            throw rc;
+
+        const char *pcszDevice = i_convertControllerTypeToDev(enmController);
+
+        BOOL fBuiltinIOCache;
+        rc = mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);
+        if (FAILED(rc))
+            throw rc;
+
+        alock.release();
+
+        int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
+                                   (PFNRT)i_reconfigureMediumAttachment, 13,
+                                   this, ptrVM.rawUVM(), pcszDevice, lInstance, enmBus, fUseHostIOCache,
+                                   fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */,
+                                   0 /* uMergeTarget */, aAttachments[i], mMachineState, &rc);
+        if (RT_FAILURE(vrc))
+            throw setError(E_FAIL, tr("%Rrc"), vrc);
+        if (FAILED(rc))
+            throw rc;
+
+        alock.acquire();
+    }
 
     return rc;
@@ -6450,5 +6206,5 @@
         case MachineState_Paused:
         case MachineState_TeleportingPausedVM:
-        case MachineState_Saving:
+        case MachineState_OnlineSnapshotting:
 
         /* Remove any keys which are supposed to be removed on a suspend. */
@@ -6502,5 +6258,5 @@
  * a specific reason.
  */
-HRESULT Console::i_resume(Reason_T aReason)
+HRESULT Console::i_resume(Reason_T aReason, AutoWriteLock &alock)
 {
     LogFlowThisFuncEnter();
@@ -6508,11 +6264,4 @@
     AutoCaller autoCaller(this);
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (mMachineState != MachineState_Paused)
-        return setError(VBOX_E_INVALID_VM_STATE,
-                        tr("Cannot resume the machine as it is not paused (machine state: %s)"),
-                        Global::stringifyMachineState(mMachineState));
 
     /* get the VM handle. */
@@ -6544,5 +6293,13 @@
         if (aReason == Reason_HostResume)
             enmReason = VMRESUMEREASON_HOST_RESUME;
+        else if (aReason == Reason_Snapshot)
+            enmReason = VMRESUMEREASON_STATE_SAVED;
+
+        // for snapshots: no state change callback, VBoxSVC does everything
+        if (aReason == Reason_Snapshot)
+            mVMStateChangeCallbackDisabled = true;
         vrc = VMR3Resume(ptrVM.rawUVM(), enmReason);
+        if (aReason == Reason_Snapshot)
+            mVMStateChangeCallbackDisabled = false;
     }
 
@@ -6558,12 +6315,20 @@
 
 /**
- * Worker for Console::SaveState and internal entry point for saving state of
- * a VM for a specific reason.
- */
-HRESULT Console::i_saveState(Reason_T aReason, IProgress **aProgress)
+ * Internal entry point for saving state of a VM for a specific reason. This
+ * method is completely synchronous.
+ *
+ * The machine state is already set appropriately. It is only changed when
+ * saving state actually paused the VM (happens with live snapshots and
+ * teleportation), and in this case reflects the now paused variant.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT Console::i_saveState(Reason_T aReason, const ComPtr<IProgress> &aProgress, const Utf8Str &aStateFilePath, bool aPauseVM, bool &aLeftPaused)
 {
     LogFlowThisFuncEnter();
-
-    CheckComArgOutPointerValid(aProgress);
+    aLeftPaused = false;
+
+    AssertReturn(!aProgress.isNull(), E_INVALIDARG);
+    AssertReturn(!aStateFilePath.isEmpty(), E_INVALIDARG);
 
     AutoCaller autoCaller(this);
@@ -6573,6 +6338,9 @@
 
     LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
-    if (   mMachineState != MachineState_Running
-        && mMachineState != MachineState_Paused)
+    if (   mMachineState != MachineState_Saving
+        && mMachineState != MachineState_LiveSnapshotting
+        && mMachineState != MachineState_OnlineSnapshotting
+        && mMachineState != MachineState_Teleporting
+        && mMachineState != MachineState_TeleportingPausedVM)
     {
         return setError(VBOX_E_INVALID_VM_STATE,
@@ -6580,4 +6348,5 @@
             Global::stringifyMachineState(mMachineState));
     }
+    bool fContinueAfterwards = mMachineState != MachineState_Saving;
 
     Bstr strDisableSaveState;
@@ -6590,14 +6359,26 @@
         LogRel(("Saving state of VM, reason \"%s\"\n", Global::stringifyReason(aReason)));
 
-    /* memorize the current machine state */
-    MachineState_T lastMachineState = mMachineState;
-
-    if (mMachineState == MachineState_Running)
-    {
-        /* get the VM handle. */
-        SafeVMPtr ptrVM(this);
-        if (!ptrVM.isOk())
-            return ptrVM.rc();
-
+    /* ensure the directory for the saved state file exists */
+    {
+        Utf8Str dir = aStateFilePath;
+        dir.stripFilename();
+        if (!RTDirExists(dir.c_str()))
+        {
+            int vrc = RTDirCreateFullPath(dir.c_str(), 0700);
+            if (RT_FAILURE(vrc))
+                return setError(VBOX_E_FILE_ERROR,
+                                tr("Could not create a directory '%s' to save the state to (%Rrc)"),
+                                dir.c_str(), vrc);
+        }
+    }
+
+    /* Get the VM handle early, we need it in several places. */
+    SafeVMPtr ptrVM(this);
+    if (!ptrVM.isOk())
+        return ptrVM.rc();
+
+    bool fPaused = false;
+    if (aPauseVM)
+    {
         /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
         alock.release();
@@ -6610,121 +6391,82 @@
         alock.acquire();
 
-        HRESULT hrc = S_OK;
         if (RT_FAILURE(vrc))
-            hrc = setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc);
-        if (FAILED(hrc))
-            return hrc;
-    }
-
-    HRESULT rc = S_OK;
-    bool fBeganSavingState = false;
-    bool fTaskCreationFailed = false;
-
-    do
-    {
-        ComPtr<IProgress> pProgress;
-        Bstr stateFilePath;
-
+            return setError(VBOX_E_VM_ERROR, tr("Could not suspend the machine execution (%Rrc)"), vrc);
+        fPaused = true;
+    }
+
+    LogFlowFunc(("Saving the state to '%s'...\n", aStateFilePath.c_str()));
+
+    mptrCancelableProgress = aProgress;
+    alock.release();
+    int vrc = VMR3Save(ptrVM.rawUVM(),
+                       aStateFilePath.c_str(),
+                       fContinueAfterwards,
+                       Console::i_stateProgressCallback,
+                       static_cast<IProgress *>(aProgress),
+                       &aLeftPaused);
+    alock.acquire();
+    mptrCancelableProgress.setNull();
+    if (RT_FAILURE(vrc))
+    {
+        if (fPaused)
+        {
+            alock.release();
+            VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED);
+            alock.acquire();
+        }
+        return setError(E_FAIL, tr("Failed to save the machine state to '%s' (%Rrc)"),
+                        aStateFilePath.c_str(), vrc);
+    }
+    Assert(fContinueAfterwards || !aLeftPaused);
+
+    if (!fContinueAfterwards)
+    {
         /*
-         * request a saved state file path from the server
-         * (this will set the machine state to Saving on the server to block
-         * others from accessing this machine)
+         * The machine has been successfully saved, so power it down
+         * (vmstateChangeCallback() will set state to Saved on success).
+         * Note: we release the VM caller, otherwise it will deadlock.
          */
-        rc = mControl->BeginSavingState(pProgress.asOutParam(),
-                                        stateFilePath.asOutParam());
-        if (FAILED(rc))
-            break;
-
-        fBeganSavingState = true;
-
-        /* sync the state with the server */
-        i_setMachineStateLocally(MachineState_Saving);
-
-        /* ensure the directory for the saved state file exists */
-        {
-            Utf8Str dir = stateFilePath;
-            dir.stripFilename();
-            if (!RTDirExists(dir.c_str()))
-            {
-                int vrc = RTDirCreateFullPath(dir.c_str(), 0700);
-                if (RT_FAILURE(vrc))
-                {
-                    rc = setError(VBOX_E_FILE_ERROR,
-                        tr("Could not create a directory '%s' to save the state to (%Rrc)"),
-                        dir.c_str(), vrc);
-                    break;
-                }
-            }
-        }
-
-        /* Create a task object early to ensure mpUVM protection is successful. */
-        std::auto_ptr<VMSaveTask> task(new VMSaveTask(this, pProgress,
-                                                      stateFilePath,
-                                                      lastMachineState,
-                                                      aReason));
-        rc = task->rc();
-        /*
-         * If we fail here it means a PowerDown() call happened on another
-         * thread while we were doing Pause() (which releases the Console lock).
-         * We assign PowerDown() a higher precedence than SaveState(),
-         * therefore just return the error to the caller.
-         */
-        if (FAILED(rc))
-        {
-            fTaskCreationFailed = true;
-            break;
-        }
-
-        /* create a thread to wait until the VM state is saved */
-        int vrc = RTThreadCreate(NULL, Console::i_saveStateThread, (void *)task.get(),
-                                 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave");
-        if (RT_FAILURE(vrc))
-        {
-            rc = setError(E_FAIL, "Could not create VMSave thread (%Rrc)", vrc);
-            break;
-        }
-
-        /* task is now owned by saveStateThread(), so release it */
-        task.release();
-
-        /* return the progress to the caller */
-        pProgress.queryInterfaceTo(aProgress);
-    } while (0);
-
-    if (FAILED(rc) && !fTaskCreationFailed)
-    {
-        /* preserve existing error info */
-        ErrorInfoKeeper eik;
-
-        if (fBeganSavingState)
-        {
-            /*
-             * cancel the requested save state procedure.
-             * This will reset the machine state to the state it had right
-             * before calling mControl->BeginSavingState().
-             */
-            mControl->EndSavingState(eik.getResultCode(), eik.getText().raw());
-        }
-
-        if (lastMachineState == MachineState_Running)
-        {
-            /* restore the paused state if appropriate */
-            i_setMachineStateLocally(MachineState_Paused);
-            /* restore the running state if appropriate */
-            SafeVMPtr ptrVM(this);
-            if (ptrVM.isOk())
-            {
-                alock.release();
-                VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED);
-                alock.acquire();
-            }
-        }
-        else
-            i_setMachineStateLocally(lastMachineState);
-    }
-
-    LogFlowThisFunc(("rc=%Rhrc\n", rc));
-    LogFlowThisFuncLeave();
-    return rc;
+        ptrVM.release();
+        alock.release();
+        autoCaller.release();
+        HRESULT rc = i_powerDown();
+        AssertComRC(rc);
+        autoCaller.add();
+        alock.acquire();
+    }
+    else
+    {
+        if (fPaused)
+            aLeftPaused = true;
+    }
+
+    LogFlowFuncLeave();
+    return S_OK;
+}
+
+/**
+ * Internal entry point for cancelling a VM save state.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT Console::i_cancelSaveState()
+{
+    LogFlowThisFuncEnter();
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /* Get the VM handle. */
+    SafeVMPtr ptrVM(this);
+    if (!ptrVM.isOk())
+        return ptrVM.rc();
+
+    SSMR3Cancel(ptrVM.rawUVM());
+
+    LogFlowFuncLeave();
+    return S_OK;
 }
 
@@ -6745,12 +6487,96 @@
 
     AssertReturn(   mMachineState == MachineState_Saving
+                 || mMachineState == MachineState_OnlineSnapshotting
                  || mMachineState == MachineState_LiveSnapshotting
-                 || mMachineState == MachineState_RestoringSnapshot
-                 || mMachineState == MachineState_DeletingSnapshot
                  || mMachineState == MachineState_DeletingSnapshotOnline
                  || mMachineState == MachineState_DeletingSnapshotPaused
+                 || aMachineState == MachineState_Saving
+                 || aMachineState == MachineState_OnlineSnapshotting
+                 || aMachineState == MachineState_LiveSnapshotting
+                 || aMachineState == MachineState_DeletingSnapshotOnline
+                 || aMachineState == MachineState_DeletingSnapshotPaused
                  , E_FAIL);
 
     return i_setMachineStateLocally(aMachineState);
+}
+
+/**
+ * Gets called by Session::COMGETTER(NominalState)()
+ * (IInternalSessionControl::getNominalState()).
+ *
+ * @note Locks this object for reading.
+ */
+HRESULT Console::i_getNominalState(MachineState_T &aNominalState)
+{
+    LogFlowThisFuncEnter();
+
+    AutoCaller autoCaller(this);
+    AssertComRCReturnRC(autoCaller.rc());
+
+    /* Get the VM handle. */
+    SafeVMPtr ptrVM(this);
+    if (!ptrVM.isOk())
+        return ptrVM.rc();
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    MachineState_T enmMachineState = MachineState_Null;
+    VMSTATE enmVMState = VMR3GetStateU(ptrVM.rawUVM());
+    switch (enmVMState)
+    {
+        case VMSTATE_CREATING:
+        case VMSTATE_CREATED:
+        case VMSTATE_POWERING_ON:
+            enmMachineState = MachineState_Starting;
+            break;
+        case VMSTATE_LOADING:
+            enmMachineState = MachineState_Restoring;
+            break;
+        case VMSTATE_RESUMING:
+        case VMSTATE_SUSPENDING:
+        case VMSTATE_SUSPENDING_LS:
+        case VMSTATE_SUSPENDING_EXT_LS:
+        case VMSTATE_SUSPENDED:
+        case VMSTATE_SUSPENDED_LS:
+        case VMSTATE_SUSPENDED_EXT_LS:
+            enmMachineState = MachineState_Paused;
+            break;
+        case VMSTATE_RUNNING:
+        case VMSTATE_RUNNING_LS:
+        case VMSTATE_RUNNING_FT:
+        case VMSTATE_RESETTING:
+        case VMSTATE_RESETTING_LS:
+        case VMSTATE_DEBUGGING:
+        case VMSTATE_DEBUGGING_LS:
+            enmMachineState = MachineState_Running;
+            break;
+        case VMSTATE_SAVING:
+            enmMachineState = MachineState_Saving;
+            break;
+        case VMSTATE_POWERING_OFF:
+        case VMSTATE_POWERING_OFF_LS:
+        case VMSTATE_DESTROYING:
+            enmMachineState = MachineState_Stopping;
+            break;
+        case VMSTATE_OFF:
+        case VMSTATE_OFF_LS:
+        case VMSTATE_FATAL_ERROR:
+        case VMSTATE_FATAL_ERROR_LS:
+        case VMSTATE_LOAD_FAILURE:
+        case VMSTATE_TERMINATED:
+            enmMachineState = MachineState_PoweredOff;
+            break;
+        case VMSTATE_GURU_MEDITATION:
+        case VMSTATE_GURU_MEDITATION_LS:
+            enmMachineState = MachineState_Stuck;
+            break;
+        default:
+            AssertMsgFailed(("%s\n", VMR3GetStateName(enmVMState)));
+            enmMachineState = MachineState_PoweredOff;
+    }
+    aNominalState = enmMachineState;
+
+    LogFlowFuncLeave();
+    return S_OK;
 }
 
@@ -7160,5 +6986,4 @@
     try
     {
-
         if (Global::IsOnlineOrTransient(mMachineState))
             throw setError(VBOX_E_INVALID_VM_STATE,
@@ -7273,6 +7098,6 @@
         }
 
-        /* Setup task object and thread to carry out the operaton
-         * Asycnhronously */
+        /* Setup task object and thread to carry out the operation
+         * asynchronously */
         std::auto_ptr<VMPowerUpTask> task(new VMPowerUpTask(this, pPowerupProgress));
         ComAssertComRCRetRC(task->rc());
@@ -7892,5 +7717,5 @@
  */
 HRESULT Console::i_setMachineState(MachineState_T aMachineState,
-                                 bool aUpdateServer /* = true */)
+                                   bool aUpdateServer /* = true */)
 {
     AutoCaller autoCaller(this);
@@ -7905,4 +7730,5 @@
         LogThisFunc(("machineState=%s -> %s aUpdateServer=%RTbool\n",
                      Global::stringifyMachineState(mMachineState), Global::stringifyMachineState(aMachineState), aUpdateServer));
+        LogRel(("Console: machine state changed to %s\n", Global::stringifyMachineState(aMachineState)));
         mMachineState = aMachineState;
 
@@ -8515,5 +8341,5 @@
 
                 case MachineState_LiveSnapshotting:
-                    that->i_setMachineState(MachineState_Saving);
+                    that->i_setMachineState(MachineState_OnlineSnapshotting);
                     break;
 
@@ -8524,9 +8350,8 @@
                 case MachineState_TeleportingIn:
                 case MachineState_FaultTolerantSyncing:
+                case MachineState_OnlineSnapshotting:
                     /* The worker thread handles the transition. */
                     break;
 
-                default:
-                    AssertMsgFailed(("%s\n", Global::stringifyMachineState(that->mMachineState)));
                 case MachineState_Running:
                     that->i_setMachineState(MachineState_Paused);
@@ -8536,4 +8361,7 @@
                     /* Nothing to do. */
                     break;
+
+                default:
+                    AssertMsgFailed(("%s\n", Global::stringifyMachineState(that->mMachineState)));
             }
             break;
@@ -8553,5 +8381,5 @@
 
                 case MachineState_LiveSnapshotting:
-                    that->i_setMachineState(MachineState_Saving);
+                    that->i_setMachineState(MachineState_OnlineSnapshotting);
                     break;
 
@@ -9613,6 +9441,5 @@
         // Create the VMM device object, which starts the HGCM thread; do this only
         // once for the console, for the pathological case that the same console
-        // object is used to power up a VM twice. VirtualBox 4.0: we now do that
-        // here instead of the Console constructor (see Console::init())
+        // object is used to power up a VM twice.
         if (!pConsole->m_pVMMDev)
         {
@@ -10102,408 +9929,4 @@
 
 /**
- * Progress cancelation callback employed by Console::fntTakeSnapshotWorker.
- */
-static void takesnapshotProgressCancelCallback(void *pvUser)
-{
-    PUVM pUVM = (PUVM)pvUser;
-    SSMR3Cancel(pUVM);
-}
-
-/**
- * Worker thread created by Console::TakeSnapshot.
- * @param Thread The current thread (ignored).
- * @param pvUser The task.
- * @return VINF_SUCCESS (ignored).
- */
-/*static*/
-DECLCALLBACK(int) Console::i_fntTakeSnapshotWorker(RTTHREAD Thread, void *pvUser)
-{
-    VMTakeSnapshotTask *pTask = (VMTakeSnapshotTask*)pvUser;
-
-    // taking a snapshot consists of the following:
-
-    // 1) creating a diff image for each virtual hard disk, into which write operations go after
-    //    the snapshot has been created (done in VBoxSVC, in SessionMachine::BeginTakingSnapshot)
-    // 2) creating a Snapshot object with the state of the machine (hardware + storage,
-    //    done in VBoxSVC, also in SessionMachine::BeginTakingSnapshot)
-    // 3) saving the state of the virtual machine (here, in the VM process, if the machine is online)
-
-    Console    *that                 = pTask->mConsole;
-    bool        fBeganTakingSnapshot = false;
-    bool        fSuspenededBySave    = false;
-
-    AutoCaller autoCaller(that);
-    if (FAILED(autoCaller.rc()))
-    {
-        that->mptrCancelableProgress.setNull();
-        return autoCaller.rc();
-    }
-
-    AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
-
-    HRESULT rc = S_OK;
-
-    try
-    {
-        /* STEP 1 + 2:
-         * request creating the diff images on the server and create the snapshot object
-         * (this will set the machine state to Saving on the server to block
-         * others from accessing this machine)
-         */
-        rc = that->mControl->BeginTakingSnapshot(that,
-                                                 pTask->bstrName.raw(),
-                                                 pTask->bstrDescription.raw(),
-                                                 pTask->mProgress,
-                                                 pTask->fTakingSnapshotOnline,
-                                                 pTask->bstrSavedStateFile.asOutParam());
-        if (FAILED(rc))
-            throw rc;
-
-        fBeganTakingSnapshot = true;
-
-        /* Check sanity: for offline snapshots there must not be a saved state
-         * file name. All other combinations are valid (even though online
-         * snapshots without saved state file seems inconsistent - there are
-         * some exotic use cases, which need to be explicitly enabled, see the
-         * code of SessionMachine::BeginTakingSnapshot. */
-        if (   !pTask->fTakingSnapshotOnline
-            && !pTask->bstrSavedStateFile.isEmpty())
-            throw i_setErrorStatic(E_FAIL, "Invalid state of saved state file");
-
-        /* sync the state with the server */
-        if (pTask->lastMachineState == MachineState_Running)
-            that->i_setMachineStateLocally(MachineState_LiveSnapshotting);
-        else
-            that->i_setMachineStateLocally(MachineState_Saving);
-
-        // STEP 3: save the VM state (if online)
-        if (pTask->fTakingSnapshotOnline)
-        {
-            int vrc;
-            SafeVMPtr ptrVM(that);
-            if (!ptrVM.isOk())
-                throw ptrVM.rc();
-
-            pTask->mProgress->SetNextOperation(Bstr(tr("Saving the machine state")).raw(),
-                                               pTask->ulMemSize);       // operation weight, same as computed
-                                                                        // when setting up progress object
-            if (!pTask->bstrSavedStateFile.isEmpty())
-            {
-                Utf8Str strSavedStateFile(pTask->bstrSavedStateFile);
-
-                pTask->mProgress->i_setCancelCallback(takesnapshotProgressCancelCallback, ptrVM.rawUVM());
-
-                alock.release();
-                LogFlowFunc(("VMR3Save...\n"));
-                vrc = VMR3Save(ptrVM.rawUVM(),
-                               strSavedStateFile.c_str(),
-                               true /*fContinueAfterwards*/,
-                               Console::i_stateProgressCallback,
-                               static_cast<IProgress *>(pTask->mProgress),
-                               &fSuspenededBySave);
-                alock.acquire();
-                if (RT_FAILURE(vrc))
-                    throw i_setErrorStatic(E_FAIL,
-                                         tr("Failed to save the machine state to '%s' (%Rrc)"),
-                                         strSavedStateFile.c_str(), vrc);
-
-                pTask->mProgress->i_setCancelCallback(NULL, NULL);
-            }
-            else
-                LogRel(("Console: skipped saving state as part of online snapshot\n"));
-
-            if (!pTask->mProgress->i_notifyPointOfNoReturn())
-                throw i_setErrorStatic(E_FAIL, tr("Canceled"));
-            that->mptrCancelableProgress.setNull();
-
-            // STEP 4: reattach hard disks
-            LogFlowFunc(("Reattaching new differencing hard disks...\n"));
-
-            pTask->mProgress->SetNextOperation(Bstr(tr("Reconfiguring medium attachments")).raw(),
-                                               1);       // operation weight, same as computed when setting up progress object
-
-            com::SafeIfaceArray<IMediumAttachment> atts;
-            rc = that->mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(atts));
-            if (FAILED(rc))
-                throw rc;
-
-            for (size_t i = 0;
-                i < atts.size();
-                ++i)
-            {
-                ComPtr<IStorageController> pStorageController;
-                Bstr controllerName;
-                ULONG lInstance;
-                StorageControllerType_T enmController;
-                StorageBus_T enmBus;
-                BOOL fUseHostIOCache;
-
-                /*
-                * We can't pass a storage controller object directly
-                * (g++ complains about not being able to pass non POD types through '...')
-                * so we have to query needed values here and pass them.
-                */
-                rc = atts[i]->COMGETTER(Controller)(controllerName.asOutParam());
-                if (FAILED(rc))
-                    throw rc;
-
-                rc = that->mMachine->GetStorageControllerByName(controllerName.raw(),
-                                                                pStorageController.asOutParam());
-                if (FAILED(rc))
-                    throw rc;
-
-                rc = pStorageController->COMGETTER(ControllerType)(&enmController);
-                if (FAILED(rc))
-                    throw rc;
-                rc = pStorageController->COMGETTER(Instance)(&lInstance);
-                if (FAILED(rc))
-                    throw rc;
-                rc = pStorageController->COMGETTER(Bus)(&enmBus);
-                if (FAILED(rc))
-                    throw rc;
-                rc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
-                if (FAILED(rc))
-                    throw rc;
-
-                const char *pcszDevice = Console::i_convertControllerTypeToDev(enmController);
-
-                BOOL fBuiltinIOCache;
-                rc = that->mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);
-                if (FAILED(rc))
-                    throw rc;
-
-                alock.release();
-                vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
-                                       (PFNRT)i_reconfigureMediumAttachment, 13,
-                                       that, ptrVM.rawUVM(), pcszDevice, lInstance, enmBus, fUseHostIOCache,
-                                       fBuiltinIOCache, false /* fSetupMerge */, 0 /* uMergeSource */,
-                                       0 /* uMergeTarget */, atts[i], that->mMachineState, &rc);
-                alock.acquire();
-                if (RT_FAILURE(vrc))
-                    throw i_setErrorStatic(E_FAIL, Console::tr("%Rrc"), vrc);
-                if (FAILED(rc))
-                    throw rc;
-            }
-        }
-
-        /*
-         * finalize the requested snapshot object.
-         * This will reset the machine state to the state it had right
-         * before calling mControl->BeginTakingSnapshot().
-         */
-        rc = that->mControl->EndTakingSnapshot(TRUE /*aSuccess*/);
-        // do not throw rc here because we can't call EndTakingSnapshot() twice
-        LogFlowFunc(("EndTakingSnapshot -> %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(that->mMachineState)));
-    }
-    catch (HRESULT rcThrown)
-    {
-        /* preserve existing error info */
-        ErrorInfoKeeper eik;
-
-        if (fBeganTakingSnapshot)
-            that->mControl->EndTakingSnapshot(FALSE /*aSuccess*/);
-
-        rc = rcThrown;
-        LogFunc(("Caught %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(that->mMachineState)));
-    }
-    Assert(alock.isWriteLockOnCurrentThread());
-
-    if (FAILED(rc)) /* Must come before calling setMachineState. */
-        pTask->mProgress->i_notifyComplete(rc);
-
-    /*
-     * Fix up the machine state.
-     *
-     * For live snapshots we do all the work, for the two other variations we
-     * just update the local copy.
-     */
-    MachineState_T enmMachineState;
-    that->mMachine->COMGETTER(State)(&enmMachineState);
-    if (   that->mMachineState == MachineState_LiveSnapshotting
-        || that->mMachineState == MachineState_Saving)
-    {
-
-        if (!pTask->fTakingSnapshotOnline)
-            that->i_setMachineStateLocally(pTask->lastMachineState);
-        else if (SUCCEEDED(rc))
-        {
-            Assert(   pTask->lastMachineState == MachineState_Running
-                   || pTask->lastMachineState == MachineState_Paused);
-            Assert(that->mMachineState == MachineState_Saving);
-            if (pTask->lastMachineState == MachineState_Running)
-            {
-                LogFlowFunc(("VMR3Resume...\n"));
-                SafeVMPtr ptrVM(that);
-                alock.release();
-                int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED);
-                alock.acquire();
-                if (RT_FAILURE(vrc))
-                {
-                    rc = i_setErrorStatic(VBOX_E_VM_ERROR, tr("Could not resume the machine execution (%Rrc)"), vrc);
-                    pTask->mProgress->i_notifyComplete(rc);
-                    if (that->mMachineState == MachineState_Saving)
-                        that->i_setMachineStateLocally(MachineState_Paused);
-                }
-            }
-            else
-                that->i_setMachineStateLocally(MachineState_Paused);
-        }
-        else
-        {
-            /** @todo this could probably be made more generic and reused elsewhere. */
-            /* paranoid cleanup on for a failed online snapshot. */
-            VMSTATE enmVMState = VMR3GetStateU(that->mpUVM);
-            switch (enmVMState)
-            {
-                case VMSTATE_RUNNING:
-                case VMSTATE_RUNNING_LS:
-                case VMSTATE_DEBUGGING:
-                case VMSTATE_DEBUGGING_LS:
-                case VMSTATE_POWERING_OFF:
-                case VMSTATE_POWERING_OFF_LS:
-                case VMSTATE_RESETTING:
-                case VMSTATE_RESETTING_LS:
-                    Assert(!fSuspenededBySave);
-                    that->i_setMachineState(MachineState_Running);
-                    break;
-
-                case VMSTATE_GURU_MEDITATION:
-                case VMSTATE_GURU_MEDITATION_LS:
-                    that->i_setMachineState(MachineState_Stuck);
-                    break;
-
-                case VMSTATE_FATAL_ERROR:
-                case VMSTATE_FATAL_ERROR_LS:
-                    if (pTask->lastMachineState == MachineState_Paused)
-                        that->i_setMachineStateLocally(pTask->lastMachineState);
-                    else
-                        that->i_setMachineState(MachineState_Paused);
-                    break;
-
-                default:
-                    AssertMsgFailed(("%s\n", VMR3GetStateName(enmVMState)));
-                case VMSTATE_SUSPENDED:
-                case VMSTATE_SUSPENDED_LS:
-                case VMSTATE_SUSPENDING:
-                case VMSTATE_SUSPENDING_LS:
-                case VMSTATE_SUSPENDING_EXT_LS:
-                    if (fSuspenededBySave)
-                    {
-                        Assert(pTask->lastMachineState == MachineState_Running);
-                        LogFlowFunc(("VMR3Resume (on failure)...\n"));
-                        SafeVMPtr ptrVM(that);
-                        alock.release();
-                        int vrc = VMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_SAVED); AssertLogRelRC(vrc);
-                        alock.acquire();
-                        if (RT_FAILURE(vrc))
-                            that->i_setMachineState(MachineState_Paused);
-                    }
-                    else if (pTask->lastMachineState == MachineState_Paused)
-                        that->i_setMachineStateLocally(pTask->lastMachineState);
-                    else
-                        that->i_setMachineState(MachineState_Paused);
-                    break;
-            }
-
-        }
-    }
-    /*else: somebody else has change the state... Leave it. */
-
-    /* check the remote state to see that we got it right. */
-    that->mMachine->COMGETTER(State)(&enmMachineState);
-    AssertLogRelMsg(that->mMachineState == enmMachineState,
-                    ("mMachineState=%s enmMachineState=%s\n", Global::stringifyMachineState(that->mMachineState),
-                     Global::stringifyMachineState(enmMachineState) ));
-
-
-    if (SUCCEEDED(rc)) /* The failure cases are handled above. */
-        pTask->mProgress->i_notifyComplete(rc);
-
-    delete pTask;
-
-    LogFlowFuncLeave();
-    return VINF_SUCCESS;
-}
-
-/**
- * Thread for executing the saved state operation.
- *
- * @param   Thread      The thread handle.
- * @param   pvUser      Pointer to a VMSaveTask structure.
- * @return  VINF_SUCCESS (ignored).
- *
- * @note Locks the Console object for writing.
- */
-/*static*/
-DECLCALLBACK(int) Console::i_saveStateThread(RTTHREAD Thread, void *pvUser)
-{
-    LogFlowFuncEnter();
-
-    std::auto_ptr<VMSaveTask> task(static_cast<VMSaveTask*>(pvUser));
-    AssertReturn(task.get(), VERR_INVALID_PARAMETER);
-
-    Assert(task->mSavedStateFile.length());
-    Assert(task->mProgress.isNull());
-    Assert(!task->mServerProgress.isNull());
-
-    const ComObjPtr<Console> &that = task->mConsole;
-    Utf8Str errMsg;
-    HRESULT rc = S_OK;
-
-    LogFlowFunc(("Saving the state to '%s'...\n", task->mSavedStateFile.c_str()));
-
-    bool fSuspenededBySave;
-    int vrc = VMR3Save(task->mpUVM,
-                       task->mSavedStateFile.c_str(),
-                       false, /*fContinueAfterwards*/
-                       Console::i_stateProgressCallback,
-                       static_cast<IProgress *>(task->mServerProgress),
-                       &fSuspenededBySave);
-    if (RT_FAILURE(vrc))
-    {
-        errMsg = Utf8StrFmt(Console::tr("Failed to save the machine state to '%s' (%Rrc)"),
-                            task->mSavedStateFile.c_str(), vrc);
-        rc = E_FAIL;
-    }
-    Assert(!fSuspenededBySave);
-
-    /* lock the console once we're going to access it */
-    AutoWriteLock thatLock(that COMMA_LOCKVAL_SRC_POS);
-
-    /* synchronize the state with the server */
-    if (SUCCEEDED(rc))
-    {
-        /*
-         * The machine has been successfully saved, so power it down
-         * (vmstateChangeCallback() will set state to Saved on success).
-         * Note: we release the task's VM caller, otherwise it will
-         * deadlock.
-         */
-        task->releaseVMCaller();
-        thatLock.release();
-        rc = that->i_powerDown();
-        thatLock.acquire();
-    }
-
-    /*
-     * If we failed, reset the local machine state.
-     */
-    if (FAILED(rc))
-        that->i_setMachineStateLocally(task->mMachineStateBefore);
-
-    /*
-     * Finalize the requested save state procedure. In case of failure it will
-     * reset the machine state to the state it had right before calling
-     * mControl->BeginSavingState(). This must be the last thing because it
-     * will set the progress to completed, and that means that the frontend
-     * can immediately uninit the associated console object.
-     */
-    that->mControl->EndSavingState(rc, Bstr(errMsg).raw());
-
-    LogFlowFuncLeave();
-    return VINF_SUCCESS;
-}
-
-/**
  * Thread for powering down the Console.
  *
@@ -10560,7 +9983,10 @@
     /*
      * For now, just call SaveState.  We should probably try notify the GUI so
-     * it can pop up a progress object and stuff.
+     * it can pop up a progress object and stuff. The progress object created
+     * by the call isn't returned to anyone and thus gets updated without
+     * anyone noticing it.
      */
-    HRESULT hrc = pConsole->SaveState(NULL);
+    ComPtr<IProgress> pProgress;
+    HRESULT hrc = pConsole->mMachine->SaveState(pProgress.asOutParam());
     return SUCCEEDED(hrc) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc);
 }
Index: /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2010-2014 Oracle Corporation
+ * Copyright (C) 2010-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -997,5 +997,5 @@
         {
             ptrProgress.queryInterfaceTo(aProgress.asOutParam());
-            mptrCancelableProgress = ptrProgress;
+            mptrCancelableProgress = aProgress;
         }
         else
Index: /trunk/src/VBox/Main/src-client/SessionImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/SessionImpl.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-client/SessionImpl.cpp	(revision 55214)
@@ -123,5 +123,5 @@
                mState == SessionState_Spawning);
 
-        HRESULT rc = unlockMachine(true /* aFinalRelease */, false /* aFromServer */);
+        HRESULT rc = i_unlockMachine(true /* aFinalRelease */, false /* aFromServer */);
         AssertComRC(rc);
     }
@@ -167,14 +167,13 @@
     if (FAILED(rc))
     {
-        /** @todo VBox 3.3: replace E_FAIL with rc here. */
 #ifndef VBOX_COM_INPROC_API_CLIENT
         if (mConsole)
-            setError(E_FAIL, tr("Failed to query the session machine (%Rhrc)"), rc);
+            setError(rc, tr("Failed to query the session machine"));
         else
 #endif
         if (FAILED_DEAD_INTERFACE(rc))
-            setError(E_FAIL, tr("Peer process crashed"));
+            setError(rc, tr("Peer process crashed"));
         else
-            setError(E_FAIL, tr("Failed to query the remote session machine (%Rhrc)"), rc);
+            setError(rc, tr("Failed to query the remote session machine"));
     }
 
@@ -198,14 +197,13 @@
     if (FAILED(rc))
     {
-        /** @todo VBox 3.3: replace E_FAIL with rc here. */
 #ifndef VBOX_COM_INPROC_API_CLIENT
         if (mConsole)
-            setError(E_FAIL, tr("Failed to query the console (%Rhrc)"), rc);
+            setError(rc, tr("Failed to query the console"));
         else
 #endif
         if (FAILED_DEAD_INTERFACE(rc))
-            setError(E_FAIL, tr("Peer process crashed"));
+            setError(rc, tr("Peer process crashed"));
         else
-            setError(E_FAIL, tr("Failed to query the remote console (%Rhrc)"), rc);
+            setError(rc, tr("Failed to query the remote console"));
     }
 
@@ -224,5 +222,5 @@
     CHECK_OPEN();
 
-    return unlockMachine(false /* aFinalRelease */, false /* aFromServer */);
+    return i_unlockMachine(false /* aFinalRelease */, false /* aFromServer */);
 }
 
@@ -265,4 +263,19 @@
     return VBOX_E_INVALID_OBJECT_STATE;
 #endif /* VBOX_COM_INPROC_API_CLIENT */
+}
+
+HRESULT Session::getNominalState(MachineState_T *aNominalState)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+    return mConsole->i_getNominalState(*aNominalState);
+#else
+    AssertFailed();
+    return E_NOTIMPL;
+#endif
 }
 
@@ -300,12 +313,19 @@
     AssertReturn(!!mControl, E_FAIL);
 
-#ifndef VBOX_COM_INPROC_API_CLIENT
-    HRESULT rc = mConsole.createObject();
-    AssertComRCReturn(rc, rc);
-
-    rc = mConsole->init(aMachine, mControl, aLockType);
-    AssertComRCReturn(rc, rc);
-#else
     HRESULT rc = S_OK;
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    if (aLockType == LockType_VM)
+    {
+        /* This is what is special about VM processes: they have a Console
+         * object which is the root of all VM related activity. */
+        rc = mConsole.createObject();
+        AssertComRCReturn(rc, rc);
+
+        rc = mConsole->init(aMachine, mControl, aLockType);
+        AssertComRCReturn(rc, rc);
+    }
+    else
+        mRemoteMachine = aMachine;
+#else
     mRemoteMachine = aMachine;
 #endif
@@ -369,5 +389,5 @@
 
 {
-    AssertReturn(aMachine && aConsole, E_INVALIDARG);
+    AssertReturn(aMachine, E_INVALIDARG);
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -496,5 +516,5 @@
 
         /* close ourselves */
-        rc = unlockMachine(false /* aFinalRelease */, true /* aFromServer */);
+        rc = i_unlockMachine(false /* aFinalRelease */, true /* aFromServer */);
     }
     else if (getObjectState().getState() == ObjectState::InUninit)
@@ -721,4 +741,5 @@
 #ifndef VBOX_COM_INPROC_API_CLIENT
     AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
 
     return mConsole->i_onDnDModeChange(aDndMode);
@@ -911,15 +932,15 @@
 }
 
-HRESULT Session::enableVMMStatistics(BOOL aEnable)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
-    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
-#ifndef VBOX_COM_INPROC_API_CLIENT
-    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
-
-    mConsole->i_enableVMMStatistics(aEnable);
-
-    return S_OK;
+HRESULT Session::reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments)
+{
+    if (mState != SessionState_Locked)
+        return setError(VBOX_E_INVALID_VM_STATE,
+                        tr("Machine is not locked by session (session state: %s)."),
+                        Global::stringifySessionState(mState));
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+    return mConsole->i_reconfigureMediumAttachments(aAttachments);
 #else
     AssertFailed();
@@ -928,13 +949,15 @@
 }
 
-HRESULT Session::pauseWithReason(Reason_T aReason)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
-    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
-#ifndef VBOX_COM_INPROC_API_CLIENT
-    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
-
-    return mConsole->i_pause(aReason);
+HRESULT Session::enableVMMStatistics(BOOL aEnable)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+    mConsole->i_enableVMMStatistics(aEnable);
+
+    return S_OK;
 #else
     AssertFailed();
@@ -943,13 +966,13 @@
 }
 
-HRESULT Session::resumeWithReason(Reason_T aReason)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
-    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
-#ifndef VBOX_COM_INPROC_API_CLIENT
-    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
-
-    return mConsole->i_resume(aReason);
+HRESULT Session::pauseWithReason(Reason_T aReason)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+    return mConsole->i_pause(aReason);
 #else
     AssertFailed();
@@ -958,13 +981,48 @@
 }
 
-HRESULT Session::saveStateWithReason(Reason_T aReason, ComPtr<IProgress> &aProgress)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
-    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
-#ifndef VBOX_COM_INPROC_API_CLIENT
-    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
-
-    return mConsole->i_saveState(aReason, aProgress.asOutParam());
+HRESULT Session::resumeWithReason(Reason_T aReason)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+    AutoWriteLock dummyLock(mConsole COMMA_LOCKVAL_SRC_POS);
+    return mConsole->i_resume(aReason, dummyLock);
+#else
+    AssertFailed();
+    return E_NOTIMPL;
+#endif
+}
+
+HRESULT Session::saveStateWithReason(Reason_T aReason, const ComPtr<IProgress> &aProgress, const Utf8Str &aStateFilePath, BOOL aPauseVM, BOOL *aLeftPaused)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+    bool fLeftPaused = false;
+    HRESULT rc = mConsole->i_saveState(aReason, aProgress, aStateFilePath, !!aPauseVM, fLeftPaused);
+    if (aLeftPaused)
+        *aLeftPaused = fLeftPaused;
+    return rc;
+#else
+    AssertFailed();
+    return E_NOTIMPL;
+#endif
+}
+
+HRESULT Session::cancelSaveStateWithReason()
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+    AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+#ifndef VBOX_COM_INPROC_API_CLIENT
+    AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+    return mConsole->i_cancelSaveState();
 #else
     AssertFailed();
@@ -985,5 +1043,5 @@
  *  @note Locks this object for writing.
  */
-HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer)
+HRESULT Session::i_unlockMachine(bool aFinalRelease, bool aFromServer)
 {
     LogFlowThisFuncEnter();
Index: /trunk/src/VBox/Main/src-server/HostPower.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/HostPower.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-server/HostPower.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -139,10 +139,9 @@
 
             /* save running VMs */
-            SessionMachinesList::const_iterator it2 = machines.begin();
-            for (VirtualBox::InternalControlList::const_iterator it = controls.begin();
-                 it != controls.end() && it2 != machines.end();
-                 ++it, ++it2)
+            for (SessionMachinesList::const_iterator it = machines.begin();
+                 it != machines.end();
+                 ++it)
             {
-                ComPtr<SessionMachine> pMachine = *it2;
+                ComPtr<SessionMachine> pMachine = *it;
                 rc = pMachine->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(),
                                             value.asOutParam());
@@ -160,10 +159,9 @@
                 if (fGlobal + fPerVM >= 0)
                 {
-                    ComPtr<IInternalSessionControl> pControl = *it;
                     ComPtr<IProgress> progress;
 
-                    /* note that SaveStateWithReason() will simply return a failure
-                     * if the VM is in an inappropriate state */
-                    rc = pControl->SaveStateWithReason(Reason_HostBatteryLow, progress.asOutParam());
+                    /* SessionMachine::i_saveStateWithReason() will return
+                     * a failure if the VM is in an inappropriate state */
+                    rc = pMachine->i_saveStateWithReason(Reason_HostBatteryLow, progress);
                     if (FAILED(rc))
                     {
Index: /trunk/src/VBox/Main/src-server/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 55214)
@@ -131,4 +131,5 @@
 
     mSession.mPID              = NIL_RTPROCESS;
+    mSession.mLockType         = LockType_Null;
     mSession.mState            = SessionState_Unlocked;
 }
@@ -2694,4 +2695,5 @@
 
     *aState = mData->mMachineState;
+    Assert(mData->mMachineState != MachineState_Null);
 
     return S_OK;
@@ -3248,4 +3250,5 @@
 
         // copy pointers to W (the write-locking session) before leaving lock (these must not be NULL)
+        ComAssertRet(mData->mSession.mLockType == LockType_Write || mData->mSession.mLockType == LockType_VM, E_FAIL);
         ComPtr<IInternalSessionControl> pSessionW = mData->mSession.mDirectControl;
         ComAssertRet(!pSessionW.isNull(), E_FAIL);
@@ -3263,13 +3266,15 @@
         // get the console of the session holding the write lock (this is a remote call)
         ComPtr<IConsole> pConsoleW;
-        LogFlowThisFunc(("Calling GetRemoteConsole()...\n"));
-        rc = pSessionW->GetRemoteConsole(pConsoleW.asOutParam());
-        LogFlowThisFunc(("GetRemoteConsole() returned %08X\n", rc));
-        if (FAILED(rc))
-            // the failure may occur w/o any error info (from RPC), so provide one
-            return setError(VBOX_E_VM_ERROR,
-                            tr("Failed to get a console object from the direct session (%Rhrc)"), rc);
-
-        ComAssertRet(!pConsoleW.isNull(), E_FAIL);
+        if (mData->mSession.mLockType == LockType_VM)
+        {
+            LogFlowThisFunc(("Calling GetRemoteConsole()...\n"));
+            rc = pSessionW->COMGETTER(RemoteConsole)(pConsoleW.asOutParam());
+            LogFlowThisFunc(("GetRemoteConsole() returned %08X\n", rc));
+            if (FAILED(rc))
+                // the failure may occur w/o any error info (from RPC), so provide one
+                return setError(VBOX_E_VM_ERROR,
+                                tr("Failed to get a console object from the direct session (%Rhrc)"), rc);
+            ComAssertRet(!pConsoleW.isNull(), E_FAIL);
+        }
 
         // share the session machine and W's console with the caller's session
@@ -3315,5 +3320,5 @@
         RTPROCESS pid = NIL_RTPROCESS;
         AssertCompile(sizeof(ULONG) == sizeof(RTPROCESS));
-        pSessionControl->GetPID((ULONG*)&pid);
+        pSessionControl->COMGETTER(PID)((ULONG*)&pid);
         Assert(pid != NIL_RTPROCESS);
 
@@ -3432,5 +3437,5 @@
                 /* get the console from the direct session */
                 ComPtr<IConsole> console;
-                rc = pSessionControl->GetRemoteConsole(console.asOutParam());
+                rc = pSessionControl->COMGETTER(RemoteConsole)(console.asOutParam());
                 ComAssertComRC(rc);
 
@@ -3505,4 +3510,5 @@
         if (SUCCEEDED(rc))
         {
+            mData->mSession.mLockType = aLockType;
             /* memorize the direct session control and cache IUnknown for it */
             mData->mSession.mDirectControl = pSessionControl;
@@ -3525,5 +3531,4 @@
         if (FAILED(rc))
             sessionMachine->uninit();
-
     }
 
@@ -5172,114 +5177,54 @@
 }
 
-struct Machine::DeleteTask
-{
-    ComObjPtr<Machine>          pMachine;
-    RTCList<ComPtr<IMedium> >   llMediums;
-    StringsList                 llFilesToDelete;
-    ComObjPtr<Progress>         pProgress;
+/**
+ * Task record for deleting a machine config.
+ */
+struct Machine::DeleteConfigTask
+    : public Machine::Task
+{
+    DeleteConfigTask(Machine *m,
+                     Progress *p,
+                     const Utf8Str &t,
+                     const RTCList<ComPtr<IMedium> > &llMediums,
+                     const StringsList &llFilesToDelete)
+        : Task(m, p, t),
+          m_llMediums(llMediums),
+          m_llFilesToDelete(llFilesToDelete)
+    {}
+
+    void handler()
+    {
+        m_pMachine->i_deleteConfigHandler(*this);
+    }
+
+    RTCList<ComPtr<IMedium> >   m_llMediums;
+    StringsList                 m_llFilesToDelete;
 };
 
-HRESULT Machine::deleteConfig(const std::vector<ComPtr<IMedium> > &aMedia, ComPtr<IProgress> &aProgress)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    HRESULT rc = i_checkStateDependency(MutableStateDep);
-    if (FAILED(rc)) return rc;
-
-    if (mData->mRegistered)
-        return setError(VBOX_E_INVALID_VM_STATE,
-                        tr("Cannot delete settings of a registered machine"));
-
-    DeleteTask *pTask = new DeleteTask;
-    pTask->pMachine = this;
-
-    // collect files to delete
-    pTask->llFilesToDelete = mData->llFilesToDelete;            // saved states pushed here by Unregister()
-
-    for (size_t i = 0; i < aMedia.size(); ++i)
-    {
-        IMedium *pIMedium(aMedia[i]);
-        ComObjPtr<Medium> pMedium = static_cast<Medium*>(pIMedium);
-        if (pMedium.isNull())
-            return setError(E_INVALIDARG, "The given medium pointer with index %d is invalid", i);
-        SafeArray<BSTR> ids;
-        rc = pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids));
-        if (FAILED(rc)) return rc;
-        /* At this point the medium should not have any back references
-         * anymore. If it has it is attached to another VM and *must* not
-         * deleted. */
-        if (ids.size() < 1)
-            pTask->llMediums.append(pMedium);
-    }
-    if (mData->pMachineConfigFile->fileExists())
-        pTask->llFilesToDelete.push_back(mData->m_strConfigFileFull);
-
-    pTask->pProgress.createObject();
-    pTask->pProgress->init(i_getVirtualBox(),
-                           static_cast<IMachine*>(this) /* aInitiator */,
-                           Bstr(tr("Deleting files")).raw(),
-                           true /* fCancellable */,
-                           (ULONG)(pTask->llFilesToDelete.size() + pTask->llMediums.size() + 1),   // cOperations
-                           BstrFmt(tr("Deleting '%s'"), pTask->llFilesToDelete.front().c_str()).raw());
-
-    int vrc = RTThreadCreate(NULL,
-                             Machine::deleteThread,
-                             (void*)pTask,
-                             0,
-                             RTTHREADTYPE_MAIN_WORKER,
-                             0,
-                             "MachineDelete");
-
-    pTask->pProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    if (RT_FAILURE(vrc))
-    {
-        delete pTask;
-        return setError(E_FAIL, "Could not create MachineDelete thread (%Rrc)", vrc);
-    }
-
-    LogFlowFuncLeave();
-
-    return S_OK;
-}
-
 /**
- * Static task wrapper passed to RTThreadCreate() in Machine::Delete() which then
- * calls Machine::deleteTaskWorker() on the actual machine object.
- * @param Thread
- * @param pvUser
- * @return
- */
-/*static*/
-DECLCALLBACK(int) Machine::deleteThread(RTTHREAD Thread, void *pvUser)
-{
-    LogFlowFuncEnter();
-
-    DeleteTask *pTask = (DeleteTask*)pvUser;
-    Assert(pTask);
-    Assert(pTask->pMachine);
-    Assert(pTask->pProgress);
-
-    HRESULT rc = pTask->pMachine->i_deleteTaskWorker(*pTask);
-    pTask->pProgress->i_notifyComplete(rc);
-
-    delete pTask;
-
-    LogFlowFuncLeave();
-
-    NOREF(Thread);
-
-    return VINF_SUCCESS;
-}
-
-/**
- * Task thread implementation for Machine::Delete(), called from Machine::deleteThread().
+ * Task thread implementation for SessionMachine::DeleteConfig(), called from
+ * SessionMachine::taskHandler().
+ *
+ * @note Locks this object for writing.
+ *
  * @param task
  * @return
  */
-HRESULT Machine::i_deleteTaskWorker(DeleteTask &task)
-{
+void Machine::i_deleteConfigHandler(DeleteConfigTask &task)
+{
+    LogFlowThisFuncEnter();
+
     AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+    LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
+    if (FAILED(autoCaller.rc()))
+    {
+        /* we might have been uninitialized because the session was accidentally
+         * closed by the client, so don't assert */
+        HRESULT rc = setError(E_FAIL,
+                              tr("The session has been accidentally closed"));
+        task.m_pProgress->i_notifyComplete(rc);
+        LogFlowThisFuncLeave();
+        return;
+    }
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
@@ -5303,12 +5248,12 @@
         i_setMachineState(MachineState_SettingUp);
         alock.release();
-        for (size_t i = 0; i < task.llMediums.size(); ++i)
-        {
-            ComObjPtr<Medium> pMedium = (Medium*)(IMedium*)task.llMediums.at(i);
+        for (size_t i = 0; i < task.m_llMediums.size(); ++i)
+        {
+            ComObjPtr<Medium> pMedium = (Medium*)(IMedium*)(task.m_llMediums.at(i));
             {
                 AutoCaller mac(pMedium);
                 if (FAILED(mac.rc())) throw mac.rc();
                 Utf8Str strLocation = pMedium->i_getLocationFull();
-                rc = task.pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), strLocation.c_str()).raw(), 1);
+                rc = task.m_pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), strLocation.c_str()).raw(), 1);
                 if (FAILED(rc)) throw rc;
                 LogFunc(("Deleting file %s\n", strLocation.c_str()));
@@ -5319,5 +5264,5 @@
                 rc = pMedium->DeleteStorage(pProgress2.asOutParam());
                 if (FAILED(rc)) throw rc;
-                rc = task.pProgress->WaitForAsyncProgressCompletion(pProgress2);
+                rc = task.m_pProgress->WaitForAsyncProgressCompletion(pProgress2);
                 if (FAILED(rc)) throw rc;
                 /* Check the result of the asynchronous process. */
@@ -5347,6 +5292,6 @@
         // medium storage files from the IMedium list passed in, and the
         // machine XML file)
-        StringsList::const_iterator it = task.llFilesToDelete.begin();
-        while (it != task.llFilesToDelete.end())
+        StringsList::const_iterator it = task.m_llFilesToDelete.begin();
+        while (it != task.m_llFilesToDelete.end())
         {
             const Utf8Str &strFile = *it;
@@ -5358,12 +5303,12 @@
 
             ++it;
-            if (it == task.llFilesToDelete.end())
+            if (it == task.m_llFilesToDelete.end())
             {
-                rc = task.pProgress->SetNextOperation(Bstr(tr("Cleaning up machine directory")).raw(), 1);
+                rc = task.m_pProgress->SetNextOperation(Bstr(tr("Cleaning up machine directory")).raw(), 1);
                 if (FAILED(rc)) throw rc;
                 break;
             }
 
-            rc = task.pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), it->c_str()).raw(), 1);
+            rc = task.m_pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), it->c_str()).raw(), 1);
             if (FAILED(rc)) throw rc;
         }
@@ -5438,5 +5383,65 @@
     catch (HRESULT aRC) { rc = aRC; }
 
-    return rc;
+    task.m_pProgress->i_notifyComplete(rc);
+
+    LogFlowThisFuncLeave();
+}
+
+HRESULT Machine::deleteConfig(const std::vector<ComPtr<IMedium> > &aMedia, ComPtr<IProgress> &aProgress)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    HRESULT rc = i_checkStateDependency(MutableStateDep);
+    if (FAILED(rc)) return rc;
+
+    if (mData->mRegistered)
+        return setError(VBOX_E_INVALID_VM_STATE,
+                        tr("Cannot delete settings of a registered machine"));
+
+    // collect files to delete
+    StringsList llFilesToDelete(mData->llFilesToDelete);    // saved states pushed here by Unregister()
+    if (mData->pMachineConfigFile->fileExists())
+        llFilesToDelete.push_back(mData->m_strConfigFileFull);
+
+    RTCList<ComPtr<IMedium> > llMediums;
+    for (size_t i = 0; i < aMedia.size(); ++i)
+    {
+        IMedium *pIMedium(aMedia[i]);
+        ComObjPtr<Medium> pMedium = static_cast<Medium*>(pIMedium);
+        if (pMedium.isNull())
+            return setError(E_INVALIDARG, "The given medium pointer with index %d is invalid", i);
+        SafeArray<BSTR> ids;
+        rc = pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids));
+        if (FAILED(rc)) return rc;
+        /* At this point the medium should not have any back references
+         * anymore. If it has it is attached to another VM and *must* not
+         * deleted. */
+        if (ids.size() < 1)
+            llMediums.append(pMedium);
+    }
+
+    ComObjPtr<Progress> pProgress;
+    pProgress.createObject();
+    rc = pProgress->init(i_getVirtualBox(),
+                         static_cast<IMachine*>(this) /* aInitiator */,
+                         Bstr(tr("Deleting files")).raw(),
+                         true /* fCancellable */,
+                         (ULONG)(llFilesToDelete.size() + llMediums.size() + 1),   // cOperations
+                         BstrFmt(tr("Deleting '%s'"), llFilesToDelete.front().c_str()).raw());
+    if (FAILED(rc))
+        return rc;
+
+    /* create and start the task on a separate thread (note that it will not
+     * start working until we release alock) */
+    DeleteConfigTask *pTask = new DeleteConfigTask(this, pProgress, "DeleteVM", llMediums, llFilesToDelete);
+    rc = pTask->createThread();
+    if (FAILED(rc))
+        return rc;
+
+    pProgress.queryInterfaceTo(aProgress.asOutParam());
+
+    LogFlowFuncLeave();
+
+    return S_OK;
 }
 
@@ -5534,5 +5539,6 @@
                             Global::stringifySessionState(mData->mSession.mState));
 
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -5556,5 +5562,6 @@
                             Global::stringifySessionState(mData->mSession.mState));
 
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -5609,12 +5616,11 @@
 
     ComPtr<IInternalSessionControl> directControl;
-    directControl = mData->mSession.mDirectControl;
-
-    /* fail if we were called after #OnSessionEnd() is called.  This is a
-     * silly race condition. */
-
-    /** @todo This code is bothering API clients (like python script clients) with
-     *        the AccessGuestProperty call, creating unncessary IPC.  Need to
-     *        have a way of figuring out which kind of direct session it is... */
+    {
+        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
+    }
+
+    /* ignore calls made after #OnSessionEnd() is called */
     if (!directControl)
         rc = E_ACCESSDENIED;
@@ -5769,5 +5775,10 @@
     try
     {
-        ComPtr<IInternalSessionControl> directControl = mData->mSession.mDirectControl;
+        ComPtr<IInternalSessionControl> directControl;
+        {
+            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+            if (mData->mSession.mLockType == LockType_VM)
+                directControl = mData->mSession.mDirectControl;
+        }
 
         BSTR dummy = NULL; /* will not be changed (setter) */
@@ -5896,6 +5907,9 @@
     HRESULT rc;
     ComPtr<IInternalSessionControl> directControl;
-    directControl = mData->mSession.mDirectControl;
-
+    {
+        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
+    }
 
     com::SafeArray<BSTR> bNames;
@@ -7086,4 +7100,40 @@
     return rc;
 
+}
+
+HRESULT Machine::saveState(ComPtr<IProgress> &aProgress)
+{
+    NOREF(aProgress);
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    // This check should always fail.
+    HRESULT rc = i_checkStateDependency(MutableStateDep);
+    if (FAILED(rc)) return rc;
+
+    AssertFailedReturn(E_NOTIMPL);
+}
+
+HRESULT Machine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
+{
+    NOREF(aSavedStateFile);
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    // This check should always fail.
+    HRESULT rc = i_checkStateDependency(MutableStateDep);
+    if (FAILED(rc)) return rc;
+
+    AssertFailedReturn(E_NOTIMPL);
+}
+
+HRESULT Machine::discardSavedState(BOOL aFRemoveFile)
+{
+    NOREF(aFRemoveFile);
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    // This check should always fail.
+    HRESULT rc = i_checkStateDependency(MutableStateDep);
+    if (FAILED(rc)) return rc;
+
+    AssertFailedReturn(E_NOTIMPL);
 }
 
@@ -7718,5 +7768,6 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    if (    mData->mSession.mState == SessionState_Locked
+    if (    (   mData->mSession.mState == SessionState_Locked
+             && mData->mSession.mLockType == LockType_VM)
          || (aAllowClosing && mData->mSession.mState == SessionState_Unlocking)
        )
@@ -8419,4 +8470,5 @@
     LogFlowThisFuncEnter();
     LogFlowThisFunc(("aMachineState=%s\n", Global::stringifyMachineState(aMachineState) ));
+    Assert(aMachineState != MachineState_Null);
 
     AutoCaller autoCaller(this);
@@ -10581,5 +10633,6 @@
 
     /* must be in a protective state because we release the lock below */
-    AssertReturn(   mData->mMachineState == MachineState_Saving
+    AssertReturn(   mData->mMachineState == MachineState_Snapshotting
+                 || mData->mMachineState == MachineState_OnlineSnapshotting
                  || mData->mMachineState == MachineState_LiveSnapshotting
                  || mData->mMachineState == MachineState_RestoringSnapshot
@@ -10670,5 +10723,5 @@
                 /* copy the attachment as is */
 
-                /** @todo the progress object created in Console::TakeSnaphot
+                /** @todo the progress object created in SessionMachine::TakeSnaphot
                  * only expects operations for hard disks. Later other
                  * device types need to show up in the progress as well. */
@@ -10832,5 +10885,6 @@
     /* will release the lock before the potentially lengthy operation,
      * so protect with the special state (unless already protected) */
-    if (   oldState != MachineState_Saving
+    if (   oldState != MachineState_Snapshotting
+        && oldState != MachineState_OnlineSnapshotting
         && oldState != MachineState_LiveSnapshotting
         && oldState != MachineState_RestoringSnapshot
@@ -10969,4 +11023,8 @@
                 mrc = rc;
             }
+            // Clear the list of deleted implicit attachments now, while not
+            // holding the lock, as it will ultimately trigger Medium::uninit()
+            // calls which assume that the media tree lock isn't held.
+            implicitAtts.clear();
 
             alock.acquire();
@@ -12490,27 +12548,4 @@
     }
 
-    Assert(    mConsoleTaskData.strStateFilePath.isEmpty()
-            || !mConsoleTaskData.mSnapshot);
-    if (!mConsoleTaskData.strStateFilePath.isEmpty())
-    {
-        LogWarningThisFunc(("canceling failed save state request!\n"));
-        endSavingState(E_FAIL, tr("Machine terminated with pending save state!"));
-    }
-    else if (!mConsoleTaskData.mSnapshot.isNull())
-    {
-        LogWarningThisFunc(("canceling untaken snapshot!\n"));
-
-        /* delete all differencing hard disks created (this will also attach
-         * their parents back by rolling back mMediaData) */
-        i_rollbackMedia();
-
-        // delete the saved state file (it might have been already created)
-        // AFTER killing the snapshot so that releaseSavedStateFile() won't
-        // think it's still in use
-        Utf8Str strStateFile = mConsoleTaskData.mSnapshot->i_getStateFilePath();
-        mConsoleTaskData.mSnapshot->uninit();
-        i_releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );
-    }
-
     mData->mSession.mPID = NIL_RTPROCESS;
 
@@ -12613,4 +12648,5 @@
 
     /* reset the rest of session data */
+    mData->mSession.mLockType = LockType_Null;
     mData->mSession.mMachine.setNull();
     mData->mSession.mState = SessionState_Unlocked;
@@ -12698,15 +12734,220 @@
 }
 
+////////////////////////////////////////////////////////////////////////////////
+//
+// SessionMachine task records
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Task record for saving the machine state.
+ */
+struct SessionMachine::SaveStateTask
+    : public Machine::Task
+{
+    SaveStateTask(SessionMachine *m,
+                  Progress *p,
+                  const Utf8Str &t,
+                  Reason_T enmReason,
+                  const Utf8Str &strStateFilePath)
+        : Task(m, p, t),
+          m_enmReason(enmReason),
+          m_strStateFilePath(strStateFilePath)
+    {}
+
+    void handler()
+    {
+        ((SessionMachine *)(Machine *)m_pMachine)->i_saveStateHandler(*this);
+    }
+
+    Reason_T m_enmReason;
+    Utf8Str m_strStateFilePath;
+};
+
+/**
+ * Task thread implementation for SessionMachine::SaveState(), called from
+ * SessionMachine::taskHandler().
+ *
+ * @note Locks this object for writing.
+ *
+ * @param task
+ * @return
+ */
+void SessionMachine::i_saveStateHandler(SaveStateTask &task)
+{
+    LogFlowThisFuncEnter();
+
+    AutoCaller autoCaller(this);
+    LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
+    if (FAILED(autoCaller.rc()))
+    {
+        /* we might have been uninitialized because the session was accidentally
+         * closed by the client, so don't assert */
+        HRESULT rc = setError(E_FAIL,
+                              tr("The session has been accidentally closed"));
+        task.m_pProgress->i_notifyComplete(rc);
+        LogFlowThisFuncLeave();
+        return;
+    }
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        ComPtr<IInternalSessionControl> directControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
+        if (directControl.isNull())
+            throw setError(VBOX_E_INVALID_VM_STATE,
+                           tr("Trying to save state without a running VM"));
+        alock.release();
+        BOOL fSuspendedBySave;
+        rc = directControl->SaveStateWithReason(task.m_enmReason, task.m_pProgress, Bstr(task.m_strStateFilePath).raw(), task.m_machineStateBackup != MachineState_Paused, &fSuspendedBySave);
+        Assert(!fSuspendedBySave);
+        alock.acquire();
+
+        AssertStmt(   (SUCCEEDED(rc) && mData->mMachineState == MachineState_Saved)
+                   || (FAILED(rc) && mData->mMachineState == MachineState_Saving),
+                   throw E_FAIL);
+
+        if (SUCCEEDED(rc))
+        {
+            mSSData->strStateFilePath = task.m_strStateFilePath;
+
+            /* save all VM settings */
+            rc = i_saveSettings(NULL);
+                    // no need to check whether VirtualBox.xml needs saving also since
+                    // we can't have a name change pending at this point
+        }
+        else
+        {
+            // On failure, set the state to the state we had at the beginning.
+            i_setMachineState(task.m_machineStateBackup);
+            i_updateMachineStateOnClient();
+
+            // Delete the saved state file (might have been already created).
+            // No need to check whether this is shared with a snapshot here
+            // because we certainly created a fresh saved state file here.
+            RTFileDelete(task.m_strStateFilePath.c_str());
+        }
+    }
+    catch (HRESULT aRC) { rc = aRC; }
+
+    task.m_pProgress->i_notifyComplete(rc);
+
+    LogFlowThisFuncLeave();
+}
+
 /**
  *  @note Locks this object for writing.
  */
-HRESULT SessionMachine::setRemoveSavedStateFile(BOOL aRemove)
+HRESULT SessionMachine::saveState(ComPtr<IProgress> &aProgress)
+{
+    return i_saveStateWithReason(Reason_Unspecified, aProgress);
+}
+
+HRESULT SessionMachine::i_saveStateWithReason(Reason_T aReason, ComPtr<IProgress> &aProgress)
 {
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    mRemoveSavedState = RT_BOOL(aRemove);
-
-    return S_OK;
-}
+    HRESULT rc = i_checkStateDependency(MutableOrRunningStateDep);
+    if (FAILED(rc)) return rc;
+
+    if (   mData->mMachineState != MachineState_Running
+        && mData->mMachineState != MachineState_Paused
+       )
+        return setError(VBOX_E_INVALID_VM_STATE,
+            tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"),
+            Global::stringifyMachineState(mData->mMachineState));
+
+    ComObjPtr<Progress> pProgress;
+    pProgress.createObject();
+    rc = pProgress->init(i_getVirtualBox(),
+                         static_cast<IMachine *>(this) /* aInitiator */,
+                         Bstr(tr("Saving the execution state of the virtual machine")).raw(),
+                         FALSE /* aCancelable */);
+    if (FAILED(rc))
+        return rc;
+
+    Utf8Str strStateFilePath;
+    i_composeSavedStateFilename(strStateFilePath);
+
+    /* create and start the task on a separate thread (note that it will not
+     * start working until we release alock) */
+    SaveStateTask *pTask = new SaveStateTask(this, pProgress, "SaveState", aReason, strStateFilePath);
+    rc = pTask->createThread();
+    if (FAILED(rc))
+        return rc;
+
+    /* set the state to Saving (expected by Session::SaveStateWithReason()) */
+    i_setMachineState(MachineState_Saving);
+    i_updateMachineStateOnClient();
+
+    pProgress.queryInterfaceTo(aProgress.asOutParam());
+
+    return S_OK;
+}
+
+/**
+ *  @note Locks this object for writing.
+ */
+HRESULT SessionMachine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    HRESULT rc = i_checkStateDependency(MutableStateDep);
+    if (FAILED(rc)) return rc;
+
+    if (   mData->mMachineState != MachineState_PoweredOff
+        && mData->mMachineState != MachineState_Teleported
+        && mData->mMachineState != MachineState_Aborted
+       )
+        return setError(VBOX_E_INVALID_VM_STATE,
+            tr("Cannot adopt the saved machine state as the machine is not in Powered Off, Teleported or Aborted state (machine state: %s)"),
+            Global::stringifyMachineState(mData->mMachineState));
+
+    com::Utf8Str stateFilePathFull;
+    int vrc = i_calculateFullPath(aSavedStateFile, stateFilePathFull);
+    if (RT_FAILURE(vrc))
+        return setError(VBOX_E_FILE_ERROR,
+                        tr("Invalid saved state file path '%s' (%Rrc)"),
+                        aSavedStateFile.c_str(),
+                        vrc);
+
+    mSSData->strStateFilePath = stateFilePathFull;
+
+    /* The below i_setMachineState() will detect the state transition and will
+     * update the settings file */
+
+    return i_setMachineState(MachineState_Saved);
+}
+
+/**
+ *  @note Locks this object for writing.
+ */
+HRESULT SessionMachine::discardSavedState(BOOL aFRemoveFile)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    HRESULT rc = i_checkStateDependency(MutableStateDep);
+    if (FAILED(rc)) return rc;
+
+    if (mData->mMachineState != MachineState_Saved)
+        return setError(VBOX_E_INVALID_VM_STATE,
+            tr("Cannot delete the machine state as the machine is not in the saved state (machine state: %s)"),
+            Global::stringifyMachineState(mData->mMachineState));
+
+    mRemoveSavedState = RT_BOOL(aFRemoveFile);
+
+    /*
+     * Saved -> PoweredOff transition will be detected in the SessionMachine
+     * and properly handled.
+     */
+    rc = i_setMachineState(MachineState_PoweredOff);
+    return rc;
+}
+
 
 /**
@@ -13087,103 +13328,4 @@
 }
 
-/**
- *  @note Locks this object for writing.
- */
-HRESULT SessionMachine::beginSavingState(ComPtr<IProgress> &aProgress,
-                                         com::Utf8Str &aStateFilePath)
-{
-    LogFlowThisFuncEnter();
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    AssertReturn(    mData->mMachineState == MachineState_Paused
-                  && mConsoleTaskData.mLastState == MachineState_Null
-                  && mConsoleTaskData.strStateFilePath.isEmpty(),
-                 E_FAIL);
-
-    /* create a progress object to track operation completion */
-    ComObjPtr<Progress> pProgress;
-    pProgress.createObject();
-    pProgress->init(i_getVirtualBox(),
-                    static_cast<IMachine *>(this) /* aInitiator */,
-                    Bstr(tr("Saving the execution state of the virtual machine")).raw(),
-                    FALSE /* aCancelable */);
-
-    /* stateFilePath is null when the machine is not running */
-    if (mData->mMachineState == MachineState_Paused)
-        i_composeSavedStateFilename(aStateFilePath);
-
-    /* fill in the console task data */
-    mConsoleTaskData.mLastState = mData->mMachineState;
-    mConsoleTaskData.strStateFilePath = aStateFilePath;
-    mConsoleTaskData.mProgress = pProgress;
-
-    /* set the state to Saving (this is expected by Console::SaveState()) */
-    i_setMachineState(MachineState_Saving);
-
-    pProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    return S_OK;
-}
-
-/**
- *  @note Locks mParent + this object for writing.
- */
-HRESULT SessionMachine::endSavingState(LONG aResult,
-                                       const com::Utf8Str &aErrMsg)
-{
-    LogFlowThisFunc(("\n"));
-
-    /* endSavingState() need mParent lock */
-    AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
-
-    AssertReturn(    (   (SUCCEEDED(aResult) && mData->mMachineState == MachineState_Saved)
-                      || (FAILED(aResult) && mData->mMachineState == MachineState_Saving))
-                  && mConsoleTaskData.mLastState != MachineState_Null
-                  && !mConsoleTaskData.strStateFilePath.isEmpty(),
-                 E_FAIL);
-
-    /*
-     * On failure, set the state to the state we had when BeginSavingState()
-     * was called (this is expected by Console::SaveState() and the associated
-     * task). On success the VM process already changed the state to
-     * MachineState_Saved, so no need to do anything.
-     */
-    if (FAILED(aResult))
-        i_setMachineState(mConsoleTaskData.mLastState);
-
-    return i_endSavingState(aResult, aErrMsg);
-}
-
-/**
- *  @note Locks this object for writing.
- */
-HRESULT SessionMachine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
-{
-    LogFlowThisFunc(("\n"));
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    AssertReturn(   mData->mMachineState == MachineState_PoweredOff
-                 || mData->mMachineState == MachineState_Teleported
-                 || mData->mMachineState == MachineState_Aborted
-                 , E_FAIL); /** @todo setError. */
-
-    com::Utf8Str stateFilePathFull;
-    int vrc = i_calculateFullPath(aSavedStateFile, stateFilePathFull);
-    if (RT_FAILURE(vrc))
-        return setError(VBOX_E_FILE_ERROR,
-                        tr("Invalid saved state file path '%s' (%Rrc)"),
-                        aSavedStateFile.c_str(),
-                        vrc);
-
-    mSSData->strStateFilePath = stateFilePathFull;
-
-    /* The below i_setMachineState() will detect the state transition and will
-     * update the settings file */
-
-    return i_setMachineState(MachineState_Saved);
-}
-
 HRESULT SessionMachine::pullGuestProperties(std::vector<com::Utf8Str> &aNames,
                                             std::vector<com::Utf8Str> &aValues,
@@ -13263,4 +13405,5 @@
             case MachineState_Teleporting:
             case MachineState_TeleportingPausedVM:
+            case MachineState_OnlineSnapshotting:
             case MachineState_LiveSnapshotting:
             case MachineState_DeletingSnapshotOnline:
@@ -13536,5 +13679,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13561,5 +13705,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13589,5 +13734,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13612,5 +13758,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13635,5 +13782,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13658,5 +13806,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13681,5 +13830,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13701,5 +13851,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13724,5 +13875,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13747,5 +13899,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13770,5 +13923,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13793,5 +13947,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13816,5 +13971,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13839,5 +13995,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13862,5 +14019,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13885,5 +14043,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13951,5 +14110,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -13983,5 +14143,6 @@
     {
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
     }
 
@@ -14000,66 +14161,4 @@
 // protected methods
 /////////////////////////////////////////////////////////////////////////////
-
-/**
- *  Helper method to finalize saving the state.
- *
- *  @note Must be called from under this object's lock.
- *
- *  @param aRc      S_OK if the snapshot has been taken successfully
- *  @param aErrMsg  human readable error message for failure
- *
- *  @note Locks mParent + this objects for writing.
- */
-HRESULT SessionMachine::i_endSavingState(HRESULT aRc, const Utf8Str &aErrMsg)
-{
-    LogFlowThisFuncEnter();
-
-    AutoCaller autoCaller(this);
-    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    HRESULT rc = S_OK;
-
-    if (SUCCEEDED(aRc))
-    {
-        mSSData->strStateFilePath = mConsoleTaskData.strStateFilePath;
-
-        /* save all VM settings */
-        rc = i_saveSettings(NULL);
-                // no need to check whether VirtualBox.xml needs saving also since
-                // we can't have a name change pending at this point
-    }
-    else
-    {
-        // delete the saved state file (it might have been already created);
-        // we need not check whether this is shared with a snapshot here because
-        // we certainly created this saved state file here anew
-        RTFileDelete(mConsoleTaskData.strStateFilePath.c_str());
-    }
-
-    /* notify the progress object about operation completion */
-    Assert(mConsoleTaskData.mProgress);
-    if (SUCCEEDED(aRc))
-        mConsoleTaskData.mProgress->i_notifyComplete(S_OK);
-    else
-    {
-        if (aErrMsg.length())
-            mConsoleTaskData.mProgress->i_notifyComplete(aRc,
-                                                         COM_IIDOF(ISession),
-                                                         getComponentName(),
-                                                         aErrMsg.c_str());
-        else
-            mConsoleTaskData.mProgress->i_notifyComplete(aRc);
-    }
-
-    /* clear out the temporary saved state data */
-    mConsoleTaskData.mLastState = MachineState_Null;
-    mConsoleTaskData.strStateFilePath.setNull();
-    mConsoleTaskData.mProgress.setNull();
-
-    LogFlowThisFuncLeave();
-    return rc;
-}
 
 /**
@@ -14259,4 +14358,5 @@
                  || oldMachineState == MachineState_Paused
                  || oldMachineState == MachineState_Teleporting
+                 || oldMachineState == MachineState_OnlineSnapshotting
                  || oldMachineState == MachineState_LiveSnapshotting
                  || oldMachineState == MachineState_Stuck
@@ -14273,9 +14373,4 @@
                  || aMachineState == MachineState_Aborted
                 )
-             /* ignore PoweredOff->Saving->PoweredOff transition when taking a
-              * snapshot */
-             && (   mConsoleTaskData.mSnapshot.isNull()
-                 || mConsoleTaskData.mLastState >= MachineState_Running /** @todo Live Migration: clean up (lazy bird) */
-                )
             )
     {
@@ -14310,5 +14405,5 @@
     {
         /*
-         *  delete the saved state after Console::ForgetSavedState() is called
+         *  delete the saved state after SessionMachine::ForgetSavedState() is called
          *  or if the VM process (owning a direct VM session) crashed while the
          *  VM was Saved
@@ -14456,5 +14551,6 @@
         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
         AssertReturn(!!mData, E_FAIL);
-        directControl = mData->mSession.mDirectControl;
+        if (mData->mSession.mLockType == LockType_VM)
+            directControl = mData->mSession.mDirectControl;
 
         /* directControl may be already set to NULL here in #OnSessionEnd()
@@ -14469,16 +14565,47 @@
         if (mData->mSession.mState == SessionState_Unlocking)
             return S_OK;
-
-        AssertReturn(!directControl.isNull(), E_FAIL);
-    }
+    }
+
+    /* ignore notifications sent after #OnSessionEnd() is called */
+    if (!directControl)
+        return S_OK;
 
     return directControl->UpdateMachineState(mData->mMachineState);
 }
 
-HRESULT Machine::setRemoveSavedStateFile(BOOL aRemove)
-{
-    NOREF(aRemove);
-    ReturnComNotImplemented();
-}
+
+/**
+ * Static Machine method that can get passed to RTThreadCreate to
+ * have a thread started for a Task. See Machine::Task.
+ */
+/* static */ DECLCALLBACK(int) Machine::taskHandler(RTTHREAD /* thread */, void *pvUser)
+{
+    AssertReturn(pvUser, VERR_INVALID_POINTER);
+
+    Task *pTask = static_cast<Task *>(pvUser);
+    pTask->handler();
+    /** @todo r=klaus it would be safer to update the progress object here,
+     * as it avoids possible races due to scoping issues/tricks in the handler */
+    // it's our responsibility to delete the task
+    delete pTask;
+
+    return 0;
+}
+
+/*static*/
+HRESULT Machine::i_setErrorStatic(HRESULT aResultCode, const char *pcszMsg, ...)
+{
+    va_list args;
+    va_start(args, pcszMsg);
+    HRESULT rc = setErrorInternal(aResultCode,
+                                  getStaticClassIID(),
+                                  getStaticComponentName(),
+                                  Utf8Str(pcszMsg, args),
+                                  false /* aWarning */,
+                                  true /* aLogIt */);
+    va_end(args);
+    return rc;
+}
+
 
 HRESULT Machine::updateState(MachineState_T aState)
@@ -14558,78 +14685,6 @@
 }
 
-HRESULT Machine::beginSavingState(ComPtr<IProgress> &aProgress,
-                                  com::Utf8Str &aStateFilePath)
-{
-    NOREF(aProgress);
-    NOREF(aStateFilePath);
-    ReturnComNotImplemented();
-}
-
-HRESULT Machine::endSavingState(LONG aResult,
-                                const com::Utf8Str &aErrMsg)
-{
-    NOREF(aResult);
-    NOREF(aErrMsg);
-    ReturnComNotImplemented();
-}
-
-HRESULT Machine::adoptSavedState(const com::Utf8Str &aSavedStateFile)
-{
-    NOREF(aSavedStateFile);
-    ReturnComNotImplemented();
-}
-
-HRESULT Machine::beginTakingSnapshot(const ComPtr<IConsole> &aInitiator,
-                                     const com::Utf8Str &aName,
-                                     const com::Utf8Str &aDescription,
-                                     const ComPtr<IProgress> &aConsoleProgress,
-                                     BOOL aFTakingSnapshotOnline,
-                                     com::Utf8Str &aStateFilePath)
-{
-    NOREF(aInitiator);
-    NOREF(aName);
-    NOREF(aDescription);
-    NOREF(aConsoleProgress);
-    NOREF(aFTakingSnapshotOnline);
-    NOREF(aStateFilePath);
-    ReturnComNotImplemented();
-}
-
-HRESULT Machine::endTakingSnapshot(BOOL aSuccess)
-{
-    NOREF(aSuccess);
-    ReturnComNotImplemented();
-}
-
-HRESULT Machine::deleteSnapshot(const ComPtr<IConsole> &aInitiator,
-                                const com::Guid &aStartId,
-                                const com::Guid &aEndId,
-                                BOOL aDeleteAllChildren,
-                                MachineState_T *aMachineState,
-                                ComPtr<IProgress> &aProgress)
-{
-    NOREF(aInitiator);
-    NOREF(aStartId);
-    NOREF(aEndId);
-    NOREF(aDeleteAllChildren);
-    NOREF(aMachineState);
-    NOREF(aProgress);
-    ReturnComNotImplemented();
-}
-
 HRESULT Machine::finishOnlineMergeMedium()
 {
-    ReturnComNotImplemented();
-}
-
-HRESULT Machine::restoreSnapshot(const ComPtr<IConsole> &aInitiator,
-                                 const ComPtr<ISnapshot> &aSnapshot,
-                                 MachineState_T *aMachineState,
-                                 ComPtr<IProgress> &aProgress)
-{
-    NOREF(aInitiator);
-    NOREF(aSnapshot);
-    NOREF(aMachineState);
-    NOREF(aProgress);
     ReturnComNotImplemented();
 }
Index: /trunk/src/VBox/Main/src-server/Performance.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/Performance.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-server/Performance.cpp	(revision 55214)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2008-2014 Oracle Corporation
+ * Copyright (C) 2008-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -311,5 +311,5 @@
 
         /* get the associated console; this is a remote call (!) */
-        ret = directControl->GetRemoteConsole(mConsole.asOutParam());
+        ret = directControl->COMGETTER(RemoteConsole)(mConsole.asOutParam());
         if (ret != S_OK)
             return ret;
Index: /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp	(revision 55213)
+++ /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp	(revision 55214)
@@ -412,5 +412,5 @@
 }
 
-HRESULT Snapshot::getChildrenCount(ULONG* count)
+HRESULT Snapshot::getChildrenCount(ULONG *count)
 {
     *count = i_getChildrenCount();
@@ -1305,36 +1305,60 @@
 
 /**
- * Abstract base class for SessionMachine::RestoreSnapshotTask and
- * SessionMachine::DeleteSnapshotTask. This is necessary since
- * RTThreadCreate cannot call a method as its thread function, so
- * instead we have it call the static SessionMachine::taskHandler,
- * which can then call the handler() method in here (implemented
- * by the children).
+ * Still abstract base class for SessionMachine::TakeSnapshotTask,
+ * SessionMachine::RestoreSnapshotTask and SessionMachine::DeleteSnapshotTask.
  */
 struct SessionMachine::SnapshotTask
+    : public SessionMachine::Task
 {
     SnapshotTask(SessionMachine *m,
                  Progress *p,
+                 const Utf8Str &t,
                  Snapshot *s)
-        : pMachine(m),
-          pProgress(p),
-          machineStateBackup(m->mData->mMachineState), // save the current machine state
-          pSnapshot(s)
+        : Task(m, p, t),
+          m_pSnapshot(s)
     {}
 
-    void modifyBackedUpState(MachineState_T s)
-    {
-        *const_cast<MachineState_T*>(&machineStateBackup) = s;
-    }
-
-    virtual void handler() = 0;
-
-    ComObjPtr<SessionMachine>       pMachine;
-    ComObjPtr<Progress>             pProgress;
-    const MachineState_T            machineStateBackup;
-    ComObjPtr<Snapshot>             pSnapshot;
+    ComObjPtr<Snapshot> m_pSnapshot;
 };
 
-/** Restore snapshot state task */
+/** Take snapshot task */
+struct SessionMachine::TakeSnapshotTask
+    : public SessionMachine::SnapshotTask
+{
+    TakeSnapshotTask(SessionMachine *m,
+                     Progress *p,
+                     const Utf8Str &t,
+                     Snapshot *s,
+                     const Utf8Str &strName,
+                     const Utf8Str &strDescription,
+                     bool fPause,
+                     uint32_t uMemSize,
+                     bool fTakingSnapshotOnline)
+        : SnapshotTask(m, p, t, s),
+          m_strName(strName),
+          m_strDescription(strDescription),
+          m_fPause(fPause),
+          m_uMemSize(uMemSize),
+          m_fTakingSnapshotOnline(fTakingSnapshotOnline)
+    {
+        if (fTakingSnapshotOnline)
+            m_pDirectControl = m->mData->mSession.mDirectControl;
+    }
+
+    void handler()
+    {
+        ((SessionMachine *)(Machine *)m_pMachine)->i_takeSnapshotHandler(*this);
+    }
+
+    Utf8Str m_strName;
+    Utf8Str m_strDescription;
+    Utf8Str m_strStateFilePath;
+    ComPtr<IInternalSessionControl> m_pDirectControl;
+    bool m_fPause;
+    uint32_t m_uMemSize;
+    bool m_fTakingSnapshotOnline;
+};
+
+/** Restore snapshot task */
 struct SessionMachine::RestoreSnapshotTask
     : public SessionMachine::SnapshotTask
@@ -1342,11 +1366,12 @@
     RestoreSnapshotTask(SessionMachine *m,
                         Progress *p,
+                        const Utf8Str &t,
                         Snapshot *s)
-        : SnapshotTask(m, p, s)
+        : SnapshotTask(m, p, t, s)
     {}
 
     void handler()
     {
-        pMachine->i_restoreSnapshotHandler(*this);
+        ((SessionMachine *)(Machine *)m_pMachine)->i_restoreSnapshotHandler(*this);
     }
 };
@@ -1358,7 +1383,8 @@
     DeleteSnapshotTask(SessionMachine *m,
                        Progress *p,
+                       const Utf8Str &t,
                        bool fDeleteOnline,
                        Snapshot *s)
-        : SnapshotTask(m, p, s),
+        : SnapshotTask(m, p, t, s),
           m_fDeleteOnline(fDeleteOnline)
     {}
@@ -1366,5 +1392,5 @@
     void handler()
     {
-        pMachine->i_deleteSnapshotHandler(*this);
+        ((SessionMachine *)(Machine *)m_pMachine)->i_deleteSnapshotHandler(*this);
     }
 
@@ -1372,214 +1398,424 @@
 };
 
-/**
- * Static SessionMachine method that can get passed to RTThreadCreate to
- * have a thread started for a SnapshotTask. See SnapshotTask above.
- *
- * This calls either RestoreSnapshotTask::handler() or DeleteSnapshotTask::handler().
- */
-
-/* static */ DECLCALLBACK(int) SessionMachine::taskHandler(RTTHREAD /* thread */, void *pvUser)
-{
-    AssertReturn(pvUser, VERR_INVALID_POINTER);
-
-    SnapshotTask *task = static_cast<SnapshotTask*>(pvUser);
-    task->handler();
-
-    // it's our responsibility to delete the task
-    delete task;
-
-    return 0;
-}
 
 ////////////////////////////////////////////////////////////////////////////////
 //
-// TakeSnapshot methods (SessionMachine and related tasks)
+// TakeSnapshot methods (Machine and related tasks)
 //
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
- * Implementation for IInternalMachineControl::beginTakingSnapshot().
- *
- * Gets called indirectly from Console::TakeSnapshot, which creates a
- * progress object in the client and then starts a thread
- * (Console::fntTakeSnapshotWorker) which then calls this.
- *
- * In other words, the asynchronous work for taking snapshots takes place
- * on the _client_ (in the Console). This is different from restoring
- * or deleting snapshots, which start threads on the server.
- *
- * This does the server-side work of taking a snapshot: it creates differencing
- * images for all hard disks attached to the machine and then creates a
- * Snapshot object with a corresponding SnapshotMachine to save the VM settings.
- *
- * The client's fntTakeSnapshotWorker() blocks while this takes place.
- * After this returns successfully, fntTakeSnapshotWorker() will begin
- * saving the machine state to the snapshot object and reconfigure the
- * hard disks.
- *
- * When the console is done, it calls SessionMachine::EndTakingSnapshot().
- *
- * @note Locks mParent + this object for writing.
- *
- * @param aInitiator in: The console on which Console::TakeSnapshot was called.
- * @param aName  in: The name for the new snapshot.
- * @param aDescription  in: A description for the new snapshot.
- * @param aConsoleProgress  in: The console's (client's) progress object.
- * @param fTakingSnapshotOnline  in: True if an online snapshot is being taken (i.e. machine is running).
- * @param aStateFilePath out: name of file in snapshots folder to which the console should write the VM state.
+HRESULT Machine::takeSnapshot(const com::Utf8Str &aName,
+                              const com::Utf8Str &aDescription,
+                              BOOL fPause,
+                              ComPtr<IProgress> &aProgress)
+{
+    NOREF(aName);
+    NOREF(aDescription);
+    NOREF(fPause);
+    NOREF(aProgress);
+    ReturnComNotImplemented();
+}
+
+HRESULT SessionMachine::takeSnapshot(const com::Utf8Str &aName,
+                                     const com::Utf8Str &aDescription,
+                                     BOOL fPause,
+                                     ComPtr<IProgress> &aProgress)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    LogFlowThisFunc(("aName='%s' mMachineState=%d\n", aName.c_str(), mData->mMachineState));
+
+    if (Global::IsTransient(mData->mMachineState))
+        return setError(VBOX_E_INVALID_VM_STATE,
+                        tr("Cannot take a snapshot of the machine while it is changing the state (machine state: %s)"),
+                        Global::stringifyMachineState(mData->mMachineState));
+
+    HRESULT rc = S_OK;
+
+    // prepare the progress object:
+    // a) count the no. of hard disk attachments to get a matching no. of progress sub-operations
+    ULONG cOperations = 2;              // always at least setting up + finishing up
+    ULONG ulTotalOperationsWeight = 2;  // one each for setting up + finishing up
+
+    for (MediaData::AttachmentList::iterator it = mMediaData->mAttachments.begin();
+         it != mMediaData->mAttachments.end();
+         ++it)
+    {
+        const ComObjPtr<MediumAttachment> pAtt(*it);
+        AutoReadLock attlock(pAtt COMMA_LOCKVAL_SRC_POS);
+        AutoCaller attCaller(pAtt);
+        if (pAtt->i_getType() == DeviceType_HardDisk)
+        {
+            ++cOperations;
+
+            // assume that creating a diff image takes as long as saving a 1MB state
+            ulTotalOperationsWeight += 1;
+        }
+    }
+
+    // b) one extra sub-operations for online snapshots OR offline snapshots that have a saved state (needs to be copied)
+    const bool fTakingSnapshotOnline = Global::IsOnline(mData->mMachineState);
+    LogFlowThisFunc(("fTakingSnapshotOnline = %d\n", fTakingSnapshotOnline));
+    if (fTakingSnapshotOnline)
+    {
+        ++cOperations;
+        ulTotalOperationsWeight += mHWData->mMemorySize;
+    }
+
+    // finally, create the progress object
+    ComObjPtr<Progress> pProgress;
+    pProgress.createObject();
+    rc = pProgress->init(mParent,
+                         static_cast<IMachine *>(this),
+                         Bstr(tr("Taking a snapshot of the virtual machine")).raw(),
+                         fTakingSnapshotOnline /* aCancelable */,
+                         cOperations,
+                         ulTotalOperationsWeight,
+                         Bstr(tr("Setting up snapshot operation")).raw(),      // first sub-op description
+                         1);        // ulFirstOperationWeight
+    if (FAILED(rc))
+        return rc;
+
+    /* create and start the task on a separate thread (note that it will not
+     * start working until we release alock) */
+    TakeSnapshotTask *pTask = new TakeSnapshotTask(this,
+                                                   pProgress,
+                                                   "TakeSnap",
+                                                   NULL /* pSnapshot */,
+                                                   aName,
+                                                   aDescription,
+                                                   !!fPause,
+                                                   mHWData->mMemorySize,
+                                                   fTakingSnapshotOnline);
+    rc = pTask->createThread();
+    if (FAILED(rc))
+        return rc;
+
+    /* set the proper machine state (note: after creating a Task instance) */
+    if (fTakingSnapshotOnline)
+    {
+        if (pTask->m_machineStateBackup != MachineState_Paused && !fPause)
+            i_setMachineState(MachineState_LiveSnapshotting);
+        else
+            i_setMachineState(MachineState_OnlineSnapshotting);
+        i_updateMachineStateOnClient();
+    }
+    else
+        i_setMachineState(MachineState_Snapshotting);
+
+    pTask->m_pProgress.queryInterfaceTo(aProgress.asOutParam());
+
+    return rc;
+}
+
+/**
+ * Task thread implementation for SessionMachine::TakeSnapshot(), called from
+ * SessionMachine::taskHandler().
+ *
+ * @note Locks this object for writing.
+ *
+ * @param task
  * @return
  */
-HRESULT SessionMachine::beginTakingSnapshot(const ComPtr<IConsole> &aInitiator,
-                                            const com::Utf8Str &aName,
-                                            const com::Utf8Str &aDescription,
-                                            const ComPtr<IProgress> &aConsoleProgress,
-                                            BOOL  aFTakingSnapshotOnline,
-                                            com::Utf8Str &aStateFilePath)
-{
-    NOREF(aInitiator);
+void SessionMachine::i_takeSnapshotHandler(TakeSnapshotTask &task)
+{
     LogFlowThisFuncEnter();
 
-    LogFlowThisFunc(("aName='%s' aFTakingSnapshotOnline=%RTbool\n", aName.c_str(), aFTakingSnapshotOnline));
+    // Taking a snapshot consists of the following:
+    // 1) creating a Snapshot object with the current state of the machine
+    //    (hardware + storage)
+    // 2) creating a diff image for each virtual hard disk, into which write
+    //    operations go after the snapshot has been created
+    // 3) if the machine is online: saving the state of the virtual machine
+    //    (in the VM process)
+    // 4) reattach the hard disks
+    // 5) update the various snapshot/machine objects, save settings
+
+    HRESULT rc = S_OK;
+    AutoCaller autoCaller(this);
+    LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
+    if (FAILED(autoCaller.rc()))
+    {
+        /* we might have been uninitialized because the session was accidentally
+         * closed by the client, so don't assert */
+        rc = setError(E_FAIL,
+                      tr("The session has been accidentally closed"));
+        task.m_pProgress->i_notifyComplete(rc);
+        LogFlowThisFuncLeave();
+        return;
+    }
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    AssertReturn(    !Global::IsOnlineOrTransient(mData->mMachineState)
-                  || mData->mMachineState == MachineState_Running
-                  || mData->mMachineState == MachineState_Paused, E_FAIL);
-    AssertReturn(mConsoleTaskData.mLastState == MachineState_Null, E_FAIL);
-    AssertReturn(mConsoleTaskData.mSnapshot.isNull(), E_FAIL);
-
-    if (   mData->mCurrentSnapshot
-        && mData->mCurrentSnapshot->i_getDepth() >= SETTINGS_SNAPSHOT_DEPTH_MAX)
-    {
-
-        return setError(VBOX_E_INVALID_OBJECT_STATE,
-                        tr("Cannot take another snapshot for machine '%s', because it exceeds the maximum snapshot depth limit. Please delete some earlier snapshot which you no longer need"),
-                        mUserData->s.strName.c_str());
-    }
-
-    if (    !aFTakingSnapshotOnline
-         && mData->mMachineState != MachineState_Saved
-       )
-    {
-        /* save all current settings to ensure current changes are committed and
-         * hard disks are fixed up */
-        HRESULT rc = i_saveSettings(NULL);
+    bool fBeganTakingSnapshot = false;
+    BOOL fSuspendedBySave     = FALSE;
+
+    try
+    {
+        // @todo: at this point we have to be in the right state!!!!
+        AssertStmt(   !Global::IsOnlineOrTransient(mData->mMachineState)
+                   || mData->mMachineState == MachineState_Snapshotting
+                   || mData->mMachineState == MachineState_OnlineSnapshotting
+                   || mData->mMachineState == MachineState_LiveSnapshotting, throw E_FAIL);
+        AssertStmt(task.m_machineStateBackup != mData->mMachineState, throw E_FAIL);
+        AssertStmt(task.m_pSnapshot.isNull(), throw E_FAIL);
+
+        if (   mData->mCurrentSnapshot
+            && mData->mCurrentSnapshot->i_getDepth() >= SETTINGS_SNAPSHOT_DEPTH_MAX)
+        {
+            throw setError(VBOX_E_INVALID_OBJECT_STATE,
+                           tr("Cannot take another snapshot for machine '%s', because it exceeds the maximum snapshot depth limit. Please delete some earlier snapshot which you no longer need"),
+                           mUserData->s.strName.c_str());
+        }
+
+        if (    !task.m_fTakingSnapshotOnline
+             && mData->mMachineState != MachineState_Saved)
+        {
+            /* save settings to ensure current changes are committed and
+             * hard disks are fixed up */
+            rc = i_saveSettings(NULL);
                 // no need to check for whether VirtualBox.xml needs changing since
                 // we can't have a machine XML rename pending at this point
-        if (FAILED(rc)) return rc;
-    }
-
-    /* create an ID for the snapshot */
-    Guid snapshotId;
-    snapshotId.create();
-
-    /* stateFilePath is null when the machine is not online nor saved */
-    if (aFTakingSnapshotOnline)
-    {
-        Bstr value;
-        HRESULT rc = GetExtraData(Bstr("VBoxInternal2/ForceTakeSnapshotWithoutState").raw(),
-                                  value.asOutParam());
-        if (FAILED(rc) || value != "1")
-            // creating a new online snapshot: we need a fresh saved state file
-            i_composeSavedStateFilename(aStateFilePath);
-    }
-    else if (mData->mMachineState == MachineState_Saved)
-        // taking an online snapshot from machine in "saved" state: then use existing state file
-        aStateFilePath = mSSData->strStateFilePath;
-
-    if (aStateFilePath.isNotEmpty())
-    {
-        // ensure the directory for the saved state file exists
-        HRESULT rc = VirtualBox::i_ensureFilePathExists(aStateFilePath, true /* fCreate */);
-        if (FAILED(rc)) return rc;
-    }
-
-    /* create a snapshot machine object */
-    ComObjPtr<SnapshotMachine> snapshotMachine;
-    snapshotMachine.createObject();
-    HRESULT rc = snapshotMachine->init(this, snapshotId.ref(), aStateFilePath);
-    AssertComRCReturn(rc, rc);
-
-    /* create a snapshot object */
-    RTTIMESPEC time;
-    ComObjPtr<Snapshot> pSnapshot;
-    pSnapshot.createObject();
-    rc = pSnapshot->init(mParent,
-                         snapshotId,
-                         aName,
-                         aDescription,
-                         *RTTimeNow(&time),
-                         snapshotMachine,
-                         mData->mCurrentSnapshot);
-    AssertComRCReturnRC(rc);
-
-    /* fill in the snapshot data */
-    mConsoleTaskData.mLastState = mData->mMachineState;
-    mConsoleTaskData.mSnapshot = pSnapshot;
-
-    /// @todo in the long run the progress object should be moved to
-    // VBoxSVC to avoid trouble with monitoring the progress object state
-    // when the process where it lives is terminating shortly after the
-    // operation completed.
-
-    try
-    {
+            if (FAILED(rc))
+                throw rc;
+        }
+
+        /* task.m_strStateFilePath is "" when the machine is offline or saved */
+        if (task.m_fTakingSnapshotOnline)
+        {
+            Bstr value;
+            HRESULT rc = GetExtraData(Bstr("VBoxInternal2/ForceTakeSnapshotWithoutState").raw(),
+                                      value.asOutParam());
+            if (FAILED(rc) || value != "1")
+                // creating a new online snapshot: we need a fresh saved state file
+                i_composeSavedStateFilename(task.m_strStateFilePath);
+        }
+        else if (mData->mMachineState == MachineState_Saved)
+            // taking an offline snapshot from machine in "saved" state: use existing state file
+            task.m_strStateFilePath = mSSData->strStateFilePath;
+
+        if (task.m_strStateFilePath.isNotEmpty())
+        {
+            // ensure the directory for the saved state file exists
+            rc = VirtualBox::i_ensureFilePathExists(task.m_strStateFilePath, true /* fCreate */);
+            if (FAILED(rc))
+                throw rc;
+        }
+
+        /* STEP 1: create the snapshot object */
+
+        /* create an ID for the snapshot */
+        Guid snapshotId;
+        snapshotId.create();
+
+        /* create a snapshot machine object */
+        ComObjPtr<SnapshotMachine> pSnapshotMachine;
+        pSnapshotMachine.createObject();
+        rc = pSnapshotMachine->init(this, snapshotId.ref(), task.m_strStateFilePath);
+        AssertComRCThrowRC(rc);
+
+        /* create a snapshot object */
+        RTTIMESPEC time;
+        RTTimeNow(&time);
+        task.m_pSnapshot.createObject();
+        rc = task.m_pSnapshot->init(mParent,
+                                    snapshotId,
+                                    task.m_strName,
+                                    task.m_strDescription,
+                                    time,
+                                    pSnapshotMachine,
+                                    mData->mCurrentSnapshot);
+        AssertComRCThrowRC(rc);
+
+        /* STEP 2: create the diff images */
         LogFlowThisFunc(("Creating differencing hard disks (online=%d)...\n",
-                         aFTakingSnapshotOnline));
-
-        // backup the media data so we can recover if things goes wrong along the day;
-        // the matching commit() is in fixupMedia() during endSnapshot()
+                         task.m_fTakingSnapshotOnline));
+
+        // Backup the media data so we can recover if something goes wrong.
+        // The matching commit() is in fixupMedia() during SessionMachine::i_finishTakingSnapshot()
         i_setModified(IsModified_Storage);
         mMediaData.backup();
 
-        /* Console::fntTakeSnapshotWorker and friends expects this. */
-        if (mConsoleTaskData.mLastState == MachineState_Running)
-            i_setMachineState(MachineState_LiveSnapshotting);
-        else
-            i_setMachineState(MachineState_Saving); /** @todo Confusing! Saving is used for both online and offline snapshots. */
-
         alock.release();
         /* create new differencing hard disks and attach them to this machine */
-        rc = i_createImplicitDiffs(aConsoleProgress,
-                                   1,            // operation weight; must be the same as in Console::TakeSnapshot()
-                                   !!aFTakingSnapshotOnline);
+        rc = i_createImplicitDiffs(task.m_pProgress,
+                                   1,            // operation weight; must be the same as in Machine::TakeSnapshot()
+                                   task.m_fTakingSnapshotOnline);
         if (FAILED(rc))
             throw rc;
+        alock.acquire();
 
         // MUST NOT save the settings or the media registry here, because
         // this causes trouble with rolling back settings if the user cancels
         // taking the snapshot after the diff images have been created.
-    }
-    catch (HRESULT hrc)
-    {
-        LogThisFunc(("Caught %Rhrc [%s]\n", hrc, Global::stringifyMachineState(mData->mMachineState) ));
-        if (    mConsoleTaskData.mLastState != mData->mMachineState
-             && (   mConsoleTaskData.mLastState == MachineState_Running
-                  ? mData->mMachineState == MachineState_LiveSnapshotting
-                  : mData->mMachineState == MachineState_Saving)
-           )
-               i_setMachineState(mConsoleTaskData.mLastState);
-
-        pSnapshot->uninit();
-        pSnapshot.setNull();
-        mConsoleTaskData.mLastState = MachineState_Null;
-        mConsoleTaskData.mSnapshot.setNull();
-
-        rc = hrc;
-
-        // @todo r=dj what with the implicit diff that we created above? this is never cleaned up
-    }
-
-    if (!(aFTakingSnapshotOnline && SUCCEEDED(rc)))
-        aStateFilePath = "";
-
-    LogFlowThisFunc(("LEAVE - %Rhrc [%s]\n", rc, Global::stringifyMachineState(mData->mMachineState) ));
-    return rc;
-}
-
-/**
- * Implementation for IInternalMachineControl::endTakingSnapshot().
- *
+
+        fBeganTakingSnapshot = true;
+
+        /* Check sanity: for offline snapshots there must not be a saved state
+         * file name. All other combinations are valid (though online snapshots
+         * without saved state file seems inconsistent - there are exotic use
+         * cases, which need to be explicitly enabled, see the code above. */
+        if (   !task.m_fTakingSnapshotOnline
+            && !task.m_strStateFilePath.isEmpty())
+            throw setError(E_FAIL, "Invalid state of saved state file");
+
+        // STEP 3: save the VM state (if online)
+        if (task.m_fTakingSnapshotOnline)
+        {
+            task.m_pProgress->SetNextOperation(Bstr(tr("Saving the machine state")).raw(),
+                                               mHWData->mMemorySize);   // operation weight, same as computed
+                                                                        // when setting up progress object
+
+            if (task.m_strStateFilePath.isNotEmpty())
+            {
+                alock.release();
+                task.m_pProgress->i_setCancelCallback(i_takeSnapshotProgressCancelCallback, &task);
+                rc = task.m_pDirectControl->SaveStateWithReason(Reason_Snapshot,
+                                                                task.m_pProgress,
+                                                                Bstr(task.m_strStateFilePath).raw(),
+                                                                task.m_fPause,
+                                                                &fSuspendedBySave);
+                task.m_pProgress->i_setCancelCallback(NULL, NULL);
+                alock.acquire();
+                if (FAILED(rc))
+                    throw rc;
+            }
+            else
+                LogRel(("Machine: skipped saving state as part of online snapshot\n"));
+
+            if (!task.m_pProgress->i_notifyPointOfNoReturn())
+                throw setError(E_FAIL, tr("Canceled"));
+
+            // STEP 4: reattach hard disks
+            LogFlowThisFunc(("Reattaching new differencing hard disks...\n"));
+
+            task.m_pProgress->SetNextOperation(Bstr(tr("Reconfiguring medium attachments")).raw(),
+                                               1);       // operation weight, same as computed when setting up progress object
+
+            com::SafeIfaceArray<IMediumAttachment> atts;
+            rc = COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(atts));
+            if (FAILED(rc))
+                throw rc;
+
+            alock.release();
+            rc = task.m_pDirectControl->ReconfigureMediumAttachments(ComSafeArrayAsInParam(atts));
+            alock.acquire();
+            if (FAILED(rc))
+                throw rc;
+        }
+
+        /*
+         * Finalize the requested snapshot object. This will reset the
+         * machine state to the state it had at the beginning.
+         */
+        rc = i_finishTakingSnapshot(task, alock, true /*aSuccess*/);
+        // do not throw rc here because we can't call i_finishTakingSnapshot() twice
+        LogFlowThisFunc(("i_finishTakingSnapshot -> %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(mData->mMachineState)));
+    }
+    catch (HRESULT rcThrown)
+    {
+        rc = rcThrown;
+        LogThisFunc(("Caught %Rhrc [mMachineState=%s]\n", rc, Global::stringifyMachineState(mData->mMachineState)));
+
+        // @todo r=klaus check that the implicit diffs created above are cleaned up im the relevant error cases
+
+        /* preserve existing error info */
+        ErrorInfoKeeper eik;
+
+        if (fBeganTakingSnapshot)
+            i_finishTakingSnapshot(task, alock, false /*aSuccess*/);
+
+        // have to postpone this to the end as i_finishTakingSnapshot() needs
+        // it for various cleanup steps
+        task.m_pSnapshot->uninit();
+        task.m_pSnapshot.setNull();
+    }
+    Assert(alock.isWriteLockOnCurrentThread());
+
+    {
+        // Keep all error information over the cleanup steps
+        ErrorInfoKeeper eik;
+
+        /*
+         * Fix up the machine state.
+         *
+         * For offline snapshots we just update the local copy, for the other
+         * variants do the entire work. This ensures that the state is in sync
+         * with the VM process (in particular the VM execution state).
+         */
+        bool fNeedClientMachineStateUpdate = false;
+        if (   mData->mMachineState == MachineState_LiveSnapshotting
+            || mData->mMachineState == MachineState_OnlineSnapshotting
+            || mData->mMachineState == MachineState_Snapshotting)
+        {
+            if (!task.m_fTakingSnapshotOnline)
+                i_setMachineState(task.m_machineStateBackup);
+            else
+            {
+                MachineState_T enmMachineState = MachineState_Null;
+                HRESULT rc2 = task.m_pDirectControl->COMGETTER(NominalState)(&enmMachineState);
+                if (FAILED(rc2) || enmMachineState == MachineState_Null)
+                {
+                    AssertMsgFailed(("state=%s\n", Global::stringifyMachineState(enmMachineState)));
+                    // pure nonsense, try to continue somehow
+                    enmMachineState = MachineState_Aborted;
+                }
+                if (enmMachineState == MachineState_Paused)
+                {
+                    if (fSuspendedBySave)
+                    {
+                        alock.release();
+                        rc2 = task.m_pDirectControl->ResumeWithReason(Reason_Snapshot);
+                        alock.acquire();
+                        if (SUCCEEDED(rc2))
+                            enmMachineState = task.m_machineStateBackup;
+                    }
+                    else
+                        enmMachineState = task.m_machineStateBackup;
+                }
+                if (enmMachineState != mData->mMachineState)
+                {
+                    fNeedClientMachineStateUpdate = true;
+                    i_setMachineState(enmMachineState);
+                }
+            }
+        }
+
+        /* check the remote state to see that we got it right. */
+        MachineState_T enmMachineState = MachineState_Null;
+        if (!task.m_pDirectControl.isNull())
+        {
+            ComPtr<IConsole> pConsole;
+            task.m_pDirectControl->COMGETTER(RemoteConsole)(pConsole.asOutParam());
+            if (!pConsole.isNull())
+                pConsole->COMGETTER(State)(&enmMachineState);
+        }
+        LogFlowThisFunc(("local mMachineState=%s remote mMachineState=%s\n",
+                         Global::stringifyMachineState(mData->mMachineState),
+                         Global::stringifyMachineState(enmMachineState)));
+
+        if (fNeedClientMachineStateUpdate)
+            i_updateMachineStateOnClient();
+    }
+
+    task.m_pProgress->i_notifyComplete(rc);
+
+    LogFlowThisFuncLeave();
+}
+
+
+/**
+ * Progress cancelation callback employed by SessionMachine::i_takeSnapshotHandler.
+ */
+/*static*/
+void SessionMachine::i_takeSnapshotProgressCancelCallback(void *pvUser)
+{
+    TakeSnapshotTask *pTask = (TakeSnapshotTask *)pvUser;
+    AssertPtrReturnVoid(pTask);
+    AssertReturnVoid(!pTask->m_pDirectControl.isNull());
+    pTask->m_pDirectControl->CancelSaveStateWithReason();
+}
+
+
+/**
  * Called by the Console when it's done saving the VM state into the snapshot
  * (if online) and reconfiguring the hard disks. See BeginTakingSnapshot() above.
@@ -1593,33 +1829,19 @@
  * @return
  */
-HRESULT SessionMachine::endTakingSnapshot(BOOL aSuccess)
+HRESULT SessionMachine::i_finishTakingSnapshot(TakeSnapshotTask &task, AutoWriteLock &alock, bool aSuccess)
 {
     LogFlowThisFunc(("\n"));
 
-    AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
+    Assert(alock.isWriteLockOnCurrentThread());
 
     AssertReturn(   !aSuccess
-                 || (    (    mData->mMachineState == MachineState_Saving
-                           || mData->mMachineState == MachineState_LiveSnapshotting)
-                      && mConsoleTaskData.mLastState != MachineState_Null
-                      && !mConsoleTaskData.mSnapshot.isNull()
-                    )
-                 , E_FAIL);
-
-    /*
-     * Restore the state we had when BeginTakingSnapshot() was called,
-     * Console::fntTakeSnapshotWorker restores its local copy when we return.
-     * If the state was Running, then let Console::fntTakeSnapshotWorker do it
-     * all to avoid races.
-     */
-    if (    mData->mMachineState != mConsoleTaskData.mLastState
-         && mConsoleTaskData.mLastState != MachineState_Running
-       )
-           i_setMachineState(mConsoleTaskData.mLastState);
+                 || mData->mMachineState == MachineState_Snapshotting
+                 || mData->mMachineState == MachineState_OnlineSnapshotting
+                 || mData->mMachineState == MachineState_LiveSnapshotting, E_FAIL);
 
     ComObjPtr<Snapshot> pOldFirstSnap = mData->mFirstSnapshot;
     ComObjPtr<Snapshot> pOldCurrentSnap = mData->mCurrentSnapshot;
 
-    bool fOnline = Global::IsOnline(mConsoleTaskData.mLastState);
+    bool fOnline = Global::IsOnline(task.m_machineStateBackup);
 
     HRESULT rc = S_OK;
@@ -1628,5 +1850,5 @@
     {
         // new snapshot becomes the current one
-        mData->mCurrentSnapshot = mConsoleTaskData.mSnapshot;
+        mData->mCurrentSnapshot = task.m_pSnapshot;
 
         /* memorize the first snapshot if necessary */
@@ -1651,6 +1873,6 @@
         /* inform callbacks */
         mParent->i_onSnapshotTaken(mData->mUuid,
-                                   mConsoleTaskData.mSnapshot->i_getId());
-        machineLock.release();
+                                   task.m_pSnapshot->i_getId());
+        alock.release();
     }
     else
@@ -1658,5 +1880,5 @@
         /* delete all differencing hard disks created (this will also attach
          * their parents back by rolling back mMediaData) */
-        machineLock.release();
+        alock.release();
 
         i_rollbackMedia();
@@ -1670,20 +1892,20 @@
             // snapshot means that a new saved state file was created, which we must
             // clean up now
-            RTFileDelete(mConsoleTaskData.mSnapshot->i_getStateFilePath().c_str());
-            machineLock.acquire();
-
-
-        mConsoleTaskData.mSnapshot->uninit();
-        machineLock.release();
+            RTFileDelete(task.m_pSnapshot->i_getStateFilePath().c_str());
+
+        alock.acquire();
+
+        task.m_pSnapshot->uninit();
+        alock.release();
 
     }
 
     /* clear out the snapshot data */
-    mConsoleTaskData.mLastState = MachineState_Null;
-    mConsoleTaskData.mSnapshot.setNull();
-
-    /* machineLock has been released already */
-
+    task.m_pSnapshot.setNull();
+
+    /* alock has been released already */
     mParent->i_saveModifiedRegistries();
+
+    alock.acquire();
 
     return rc;
@@ -1692,32 +1914,29 @@
 ////////////////////////////////////////////////////////////////////////////////
 //
-// RestoreSnapshot methods (SessionMachine and related tasks)
+// RestoreSnapshot methods (Machine and related tasks)
 //
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
- * Implementation for IInternalMachineControl::restoreSnapshot().
- *
- * Gets called from Console::RestoreSnapshot(), and that's basically the
- * only thing Console does. Restoring a snapshot happens entirely on the
- * server side since the machine cannot be running.
- *
- * This creates a new thread that does the work and returns a progress
- * object to the client which is then returned to the caller of
- * Console::RestoreSnapshot().
- *
+HRESULT Machine::restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
+                                 ComPtr<IProgress> &aProgress)
+{
+    NOREF(aSnapshot);
+    NOREF(aProgress);
+    ReturnComNotImplemented();
+}
+
+/**
+ * Restoring a snapshot happens entirely on the server side, the machine cannot be running.
+ *
+ * This creates a new thread that does the work and returns a progress object to the client.
  * Actual work then takes place in RestoreSnapshotTask::handler().
  *
  * @note Locks this + children objects for writing!
  *
- * @param aInitiator in: rhe console on which Console::RestoreSnapshot was called.
  * @param aSnapshot in: the snapshot to restore.
- * @param aMachineState in: client-side machine state.
  * @param aProgress out: progress object to monitor restore thread.
  * @return
  */
-HRESULT SessionMachine::restoreSnapshot(const ComPtr<IConsole> &aInitiator,
-                                        const ComPtr<ISnapshot> &aSnapshot,
-                                        MachineState_T *aMachineState,
+HRESULT SessionMachine::restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
                                         ComPtr<IProgress> &aProgress)
 {
@@ -1727,10 +1946,14 @@
 
     // machine must not be running
-    ComAssertRet(!Global::IsOnlineOrTransient(mData->mMachineState),
-                 E_FAIL);
+    if (Global::IsOnlineOrTransient(mData->mMachineState))
+        return setError(VBOX_E_INVALID_VM_STATE,
+                        tr("Cannot delete the current state of the running machine (machine state: %s)"),
+                        Global::stringifyMachineState(mData->mMachineState));
 
     ISnapshot* iSnapshot = aSnapshot;
     ComObjPtr<Snapshot> pSnapshot(static_cast<Snapshot*>(iSnapshot));
     ComObjPtr<SnapshotMachine> pSnapMachine = pSnapshot->i_getSnapshotMachine();
+
+    HRESULT rc = S_OK;
 
     // create a progress object. The number of operations is:
@@ -1758,5 +1981,5 @@
     ComObjPtr<Progress> pProgress;
     pProgress.createObject();
-    pProgress->init(mParent, aInitiator,
+    pProgress->init(mParent, static_cast<IMachine*>(this),
                     BstrFmt(tr("Restoring snapshot '%s'"), pSnapshot->i_getName().c_str()).raw(),
                     FALSE /* aCancelable */,
@@ -1768,19 +1991,11 @@
     /* create and start the task on a separate thread (note that it will not
      * start working until we release alock) */
-    RestoreSnapshotTask *task = new RestoreSnapshotTask(this,
-                                                        pProgress,
-                                                        pSnapshot);
-    int vrc = RTThreadCreate(NULL,
-                             taskHandler,
-                             (void*)task,
-                             0,
-                             RTTHREADTYPE_MAIN_WORKER,
-                             0,
-                             "RestoreSnap");
-    if (RT_FAILURE(vrc))
-    {
-        delete task;
-        ComAssertRCRet(vrc, E_FAIL);
-    }
+    RestoreSnapshotTask *pTask = new RestoreSnapshotTask(this,
+                                                         pProgress,
+                                                         "RestoreSnap",
+                                                         pSnapshot);
+    rc = pTask->createThread();
+    if (FAILED(rc))
+        return rc;
 
     /* set the proper machine state (note: after creating a Task instance) */
@@ -1789,7 +2004,4 @@
     /* return the progress to the caller */
     pProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    /* return the new state to the caller */
-    *aMachineState = mData->mMachineState;
 
     LogFlowThisFuncLeave();
@@ -1808,7 +2020,7 @@
  * @note Locks mParent + this object for writing.
  *
- * @param aTask Task data.
- */
-void SessionMachine::i_restoreSnapshotHandler(RestoreSnapshotTask &aTask)
+ * @param pTask Task data.
+ */
+void SessionMachine::i_restoreSnapshotHandler(RestoreSnapshotTask &task)
 {
     LogFlowThisFuncEnter();
@@ -1821,8 +2033,8 @@
         /* we might have been uninitialized because the session was accidentally
          * closed by the client, so don't assert */
-        aTask.pProgress->i_notifyComplete(E_FAIL,
-                                          COM_IIDOF(IMachine),
-                                          getComponentName(),
-                                          tr("The session has been accidentally closed"));
+        task.m_pProgress->i_notifyComplete(E_FAIL,
+                                           COM_IIDOF(IMachine),
+                                           getComponentName(),
+                                           tr("The session has been accidentally closed"));
 
         LogFlowThisFuncLeave();
@@ -1846,5 +2058,5 @@
         /* Delete the saved state file if the machine was Saved prior to this
          * operation */
-        if (aTask.machineStateBackup == MachineState_Saved)
+        if (task.m_machineStateBackup == MachineState_Saved)
         {
             Assert(!mSSData->strStateFilePath.isEmpty());
@@ -1856,5 +2068,5 @@
             i_releaseSavedStateFile(strStateFile, NULL /* pSnapshotToIgnore */ );
 
-            aTask.modifyBackedUpState(MachineState_PoweredOff);
+            task.modifyBackedUpState(MachineState_PoweredOff);
 
             rc = i_saveStateSettings(SaveSTS_StateFilePath);
@@ -1867,10 +2079,10 @@
 
         {
-            AutoReadLock snapshotLock(aTask.pSnapshot COMMA_LOCKVAL_SRC_POS);
+            AutoReadLock snapshotLock(task.m_pSnapshot COMMA_LOCKVAL_SRC_POS);
 
             /* remember the timestamp of the snapshot we're restoring from */
-            snapshotTimeStamp = aTask.pSnapshot->i_getTimeStamp();
-
-            ComPtr<SnapshotMachine> pSnapshotMachine(aTask.pSnapshot->i_getSnapshotMachine());
+            snapshotTimeStamp = task.m_pSnapshot->i_getTimeStamp();
+
+            ComPtr<SnapshotMachine> pSnapshotMachine(task.m_pSnapshot->i_getSnapshotMachine());
 
             /* copy all hardware data from the snapshot */
@@ -1897,5 +2109,5 @@
             alock.release();
 
-            rc = i_createImplicitDiffs(aTask.pProgress,
+            rc = i_createImplicitDiffs(task.m_pProgress,
                                        1,
                                        false /* aOnline */);
@@ -1907,5 +2119,5 @@
 
             /* Note: on success, current (old) hard disks will be
-             * deassociated/deleted on #commit() called from #saveSettings() at
+             * deassociated/deleted on #commit() called from #i_saveSettings() at
              * the end. On failure, newly created implicit diffs will be
              * deleted by #rollback() at the end. */
@@ -1914,5 +2126,5 @@
             Assert(mSSData->strStateFilePath.isEmpty());
 
-            const Utf8Str &strSnapshotStateFile = aTask.pSnapshot->i_getStateFilePath();
+            const Utf8Str &strSnapshotStateFile = task.m_pSnapshot->i_getStateFilePath();
 
             if (strSnapshotStateFile.isNotEmpty())
@@ -1920,7 +2132,7 @@
                 mSSData->strStateFilePath = strSnapshotStateFile;
 
-            LogFlowThisFunc(("Setting new current snapshot {%RTuuid}\n", aTask.pSnapshot->i_getId().raw()));
+            LogFlowThisFunc(("Setting new current snapshot {%RTuuid}\n", task.m_pSnapshot->i_getId().raw()));
             /* make the snapshot we restored from the current snapshot */
-            mData->mCurrentSnapshot = aTask.pSnapshot;
+            mData->mCurrentSnapshot = task.m_pSnapshot;
         }
 
@@ -1969,5 +2181,5 @@
 
         // detach the current-state diffs that we detected above and build a list of
-        // image files to delete _after_ saveSettings()
+        // image files to delete _after_ i_saveSettings()
 
         MediaList llDiffsToDelete;
@@ -1985,5 +2197,5 @@
 
             // Normally we "detach" the medium by removing the attachment object
-            // from the current machine data; saveSettings() below would then
+            // from the current machine data; i_saveSettings() below would then
             // compare the current machine data with the one in the backup
             // and actually call Medium::removeBackReference(). But that works only half
@@ -1991,5 +2203,5 @@
             // remove from machine data
             mMediaData->mAttachments.remove(pAttach);
-            // Remove it from the backup or else saveSettings will try to detach
+            // Remove it from the backup or else i_saveSettings will try to detach
             // it again and assert. The paranoia check avoids crashes (see
             // assert above) if this code is buggy and saves settings in the
@@ -2009,10 +2221,9 @@
         if (FAILED(rc))
             throw rc;
-        // unconditionally add the parent registry. We do similar in SessionMachine::EndTakingSnapshot
-        // (mParent->saveSettings())
 
         // release the locks before updating registry and deleting image files
         alock.release();
 
+        // unconditionally add the parent registry.
         mParent->i_markRegistryModified(mParent->i_getGlobalRegistryId());
 
@@ -2028,5 +2239,5 @@
             HRESULT rc2 = pMedium->i_deleteStorage(NULL /* aProgress */,
                                                    true /* aWait */);
-            // ignore errors here because we cannot roll back after saveSettings() above
+            // ignore errors here because we cannot roll back after i_saveSettings() above
             if (SUCCEEDED(rc2))
                 pMedium->uninit();
@@ -2049,5 +2260,5 @@
         {
             /* restore the machine state */
-            i_setMachineState(aTask.machineStateBackup);
+            i_setMachineState(task.m_machineStateBackup);
             i_updateMachineStateOnClient();
         }
@@ -2057,5 +2268,5 @@
 
     /* set the result (this will try to fetch current error info on failure) */
-    aTask.pProgress->i_notifyComplete(rc);
+    task.m_pProgress->i_notifyComplete(rc);
 
     if (SUCCEEDED(rc))
@@ -2073,30 +2284,70 @@
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
- * Implementation for IInternalMachineControl::deleteSnapshot().
- *
- * Gets called from Console::DeleteSnapshot(), and that's basically the
- * only thing Console does initially. Deleting a snapshot happens entirely on
- * the server side if the machine is not running, and if it is running then
- * the individual merges are done via internal session callbacks.
+HRESULT Machine::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress)
+{
+    NOREF(aId);
+    NOREF(aProgress);
+    ReturnComNotImplemented();
+}
+
+HRESULT SessionMachine::deleteSnapshot(const com::Guid &aId, ComPtr<IProgress> &aProgress)
+{
+    return i_deleteSnapshot(aId, aId,
+                            FALSE /* fDeleteAllChildren */,
+                            aProgress);
+}
+
+HRESULT Machine::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress)
+{
+    NOREF(aId);
+    NOREF(aProgress);
+    ReturnComNotImplemented();
+}
+
+HRESULT SessionMachine::deleteSnapshotAndAllChildren(const com::Guid &aId, ComPtr<IProgress> &aProgress)
+{
+    return i_deleteSnapshot(aId, aId,
+                            TRUE /* fDeleteAllChildren */,
+                            aProgress);
+}
+
+HRESULT Machine::deleteSnapshotRange(const com::Guid &aStartId, const com::Guid &aEndId, ComPtr<IProgress> &aProgress)
+{
+    NOREF(aStartId);
+    NOREF(aEndId);
+    NOREF(aProgress);
+    ReturnComNotImplemented();
+}
+
+HRESULT SessionMachine::deleteSnapshotRange(const com::Guid &aStartId, const com::Guid &aEndId, ComPtr<IProgress> &aProgress)
+{
+    return i_deleteSnapshot(aStartId, aEndId,
+                            FALSE /* fDeleteAllChildren */,
+                            aProgress);
+}
+
+
+/**
+ * Implementation for SessionMachine::i_deleteSnapshot().
+ *
+ * Gets called from SessionMachine::DeleteSnapshot(). Deleting a snapshot
+ * happens entirely on the server side if the machine is not running, and
+ * if it is running then the merges are done via internal session callbacks.
  *
  * This creates a new thread that does the work and returns a progress
- * object to the client which is then returned to the caller of
- * Console::DeleteSnapshot().
- *
- * Actual work then takes place in DeleteSnapshotTask::handler().
+ * object to the client.
+ *
+ * Actual work then takes place in SessionMachine::i_deleteSnapshotHandler().
  *
  * @note Locks mParent + this + children objects for writing!
  */
-HRESULT SessionMachine::deleteSnapshot(const ComPtr<IConsole> &aInitiator,
-                                       const com::Guid &aStartId,
-                                       const com::Guid &aEndId,
-                                       BOOL aDeleteAllChildren,
-                                       MachineState_T *aMachineState,
-                                       ComPtr<IProgress> &aProgress)
+HRESULT SessionMachine::i_deleteSnapshot(const com::Guid &aStartId,
+                                         const com::Guid &aEndId,
+                                         BOOL aDeleteAllChildren,
+                                         ComPtr<IProgress> &aProgress)
 {
     LogFlowThisFuncEnter();
 
-    AssertReturn(aInitiator && !aStartId.isZero() && !aEndId.isZero() && aStartId.isValid() && aEndId.isValid(), E_INVALIDARG);
+    AssertReturn(!aStartId.isZero() && !aEndId.isZero() && aStartId.isValid() && aEndId.isValid(), E_INVALIDARG);
 
 
@@ -2106,4 +2357,9 @@
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (Global::IsTransient(mData->mMachineState))
+        return setError(VBOX_E_INVALID_VM_STATE,
+                        tr("Cannot delete a snapshot of the machine while it is changing the state (machine state: %s)"),
+                        Global::stringifyMachineState(mData->mMachineState));
 
     // be very picky about machine states
@@ -2200,5 +2456,5 @@
     ComObjPtr<Progress> pProgress;
     pProgress.createObject();
-    pProgress->init(mParent, aInitiator,
+    pProgress->init(mParent, static_cast<IMachine*>(this),
                     BstrFmt(tr("Deleting snapshot '%s'"), pSnapshot->i_getName().c_str()).raw(),
                     FALSE /* aCancelable */,
@@ -2212,18 +2468,11 @@
 
     /* create and start the task on a separate thread */
-    DeleteSnapshotTask *task = new DeleteSnapshotTask(this, pProgress,
-                                                      fDeleteOnline, pSnapshot);
-    int vrc = RTThreadCreate(NULL,
-                             taskHandler,
-                             (void*)task,
-                             0,
-                             RTTHREADTYPE_MAIN_WORKER,
-                             0,
-                             "DeleteSnapshot");
-    if (RT_FAILURE(vrc))
-    {
-        delete task;
-        return E_FAIL;
-    }
+    DeleteSnapshotTask *pTask = new DeleteSnapshotTask(this, pProgress,
+                                                       "DeleteSnap",
+                                                       fDeleteOnline,
+                                                       pSnapshot);
+    rc = pTask->createThread();
+    if (FAILED(rc))
+        return rc;
 
     // the task might start running but will block on acquiring the machine's write lock
@@ -2236,10 +2485,8 @@
     else
         i_setMachineState(MachineState_DeletingSnapshot);
+    i_updateMachineStateOnClient();
 
     /* return the progress to the caller */
     pProgress.queryInterfaceTo(aProgress.asOutParam());
-
-    /* return the new state to the caller */
-    *aMachineState = mData->mMachineState;
 
     LogFlowThisFuncLeave();
@@ -2341,27 +2588,24 @@
  * @note Locks the machine + the snapshot + the media tree for writing!
  *
- * @param aTask Task data.
- */
-
-void SessionMachine::i_deleteSnapshotHandler(DeleteSnapshotTask &aTask)
+ * @param pTask Task data.
+ */
+void SessionMachine::i_deleteSnapshotHandler(DeleteSnapshotTask &task)
 {
     LogFlowThisFuncEnter();
 
+    HRESULT rc = S_OK;
     AutoCaller autoCaller(this);
-
     LogFlowThisFunc(("state=%d\n", getObjectState().getState()));
-    if (!autoCaller.isOk())
+    if (FAILED(autoCaller.rc()))
     {
         /* we might have been uninitialized because the session was accidentally
          * closed by the client, so don't assert */
-        aTask.pProgress->i_notifyComplete(E_FAIL,
-                                          COM_IIDOF(IMachine),
-                                          getComponentName(),
-                                          tr("The session has been accidentally closed"));
+        rc = setError(E_FAIL,
+                      tr("The session has been accidentally closed"));
+        task.m_pProgress->i_notifyComplete(rc);
         LogFlowThisFuncLeave();
         return;
     }
 
-    HRESULT rc = S_OK;
     MediumDeleteRecList toDelete;
     Guid snapshotId;
@@ -2371,5 +2615,5 @@
         /* Locking order:  */
         AutoMultiWriteLock2 multiLock(this->lockHandle(),                   // machine
-                                      aTask.pSnapshot->lockHandle()         // snapshot
+                                      task.m_pSnapshot->lockHandle()        // snapshot
                                       COMMA_LOCKVAL_SRC_POS);
         // once we have this lock, we know that SessionMachine::DeleteSnapshot()
@@ -2379,10 +2623,10 @@
                                COMMA_LOCKVAL_SRC_POS);
 
-        ComObjPtr<SnapshotMachine> pSnapMachine = aTask.pSnapshot->i_getSnapshotMachine();
+        ComObjPtr<SnapshotMachine> pSnapMachine = task.m_pSnapshot->i_getSnapshotMachine();
         // no need to lock the snapshot machine since it is const by definition
         Guid machineId = pSnapMachine->i_getId();
 
         // save the snapshot ID (for callbacks)
-        snapshotId = aTask.pSnapshot->i_getId();
+        snapshotId = task.m_pSnapshot->i_getId();
 
         // first pass:
@@ -2428,5 +2672,5 @@
             MediumLockList *pChildrenToReparent = NULL;
             bool fNeedsOnlineMerge = false;
-            bool fOnlineMergePossible = aTask.m_fDeleteOnline;
+            bool fOnlineMergePossible = task.m_fDeleteOnline;
             MediumLockList *pMediumLockList = NULL;
             MediumLockList *pVMMALockList = NULL;
@@ -2666,11 +2910,11 @@
             AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
 
-            Utf8Str stateFilePath = aTask.pSnapshot->i_getStateFilePath();
+            Utf8Str stateFilePath = task.m_pSnapshot->i_getStateFilePath();
             if (!stateFilePath.isEmpty())
             {
-                aTask.pProgress->SetNextOperation(Bstr(tr("Deleting the execution state")).raw(),
-                                                  1);        // weight
-
-                i_releaseSavedStateFile(stateFilePath, aTask.pSnapshot /* pSnapshotToIgnore */);
+                task.m_pProgress->SetNextOperation(Bstr(tr("Deleting the execution state")).raw(),
+                                                   1);        // weight
+
+                i_releaseSavedStateFile(stateFilePath, task.m_pSnapshot /* pSnapshotToIgnore */);
 
                 // machine will need saving now
@@ -2697,7 +2941,7 @@
             }
 
-            aTask.pProgress->SetNextOperation(BstrFmt(tr("Merging differencing image '%s'"),
-                                              pMedium->i_getName().c_str()).raw(),
-                                              ulWeight);
+            task.m_pProgress->SetNextOperation(BstrFmt(tr("Merging differencing image '%s'"),
+                                               pMedium->i_getName().c_str()).raw(),
+                                               ulWeight);
 
             bool fNeedSourceUninit = false;
@@ -2722,5 +2966,5 @@
                     /* No need to hold the lock any longer. */
                     mLock.release();
-                    rc = pMedium->i_deleteStorage(&aTask.pProgress,
+                    rc = pMedium->i_deleteStorage(&task.m_pProgress,
                                                   true /* aWait */);
                     if (FAILED(rc))
@@ -2740,4 +2984,5 @@
                     // This callback will arrive while onlineMergeMedium is
                     // still executing, and there can't be two tasks.
+                    /// @todo r=klaus this hack needs to go, and the logic needs to be "unconvoluted", putting SessionMachine in charge of coordinating the reconfig/resume.
                     mConsoleTaskData.mDeleteSnapshotInfo = (void *)&(*it);
                     // online medium merge, in the direction decided earlier
@@ -2749,5 +2994,5 @@
                                              it->mpChildrenToReparent,
                                              it->mpMediumLockList,
-                                             aTask.pProgress,
+                                             task.m_pProgress,
                                              &fNeedsSave);
                     mConsoleTaskData.mDeleteSnapshotInfo = NULL;
@@ -2761,5 +3006,5 @@
                                                  it->mpChildrenToReparent,
                                                  it->mpMediumLockList,
-                                                 &aTask.pProgress,
+                                                 &task.m_pProgress,
                                                  true /* aWait */);
                 }
@@ -2826,5 +3071,5 @@
                 ComObjPtr<Machine> pMachine = this;
                 Guid childSnapshotId;
-                ComObjPtr<Snapshot> pChildSnapshot = aTask.pSnapshot->i_getFirstChild();
+                ComObjPtr<Snapshot> pChildSnapshot = task.m_pSnapshot->i_getFirstChild();
                 if (pChildSnapshot)
                 {
@@ -2871,6 +3116,6 @@
             AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
 
-            aTask.pSnapshot->i_beginSnapshotDelete();
-            aTask.pSnapshot->uninit();
+            task.m_pSnapshot->i_beginSnapshotDelete();
+            task.m_pSnapshot->uninit();
 
             machineLock.release();
@@ -2912,5 +3157,5 @@
         // restore the machine state that was saved when the
         // task was started
-        i_setMachineState(aTask.machineStateBackup);
+        i_setMachineState(task.m_machineStateBackup);
         i_updateMachineStateOnClient();
 
@@ -2919,5 +3164,5 @@
 
     // report the result (this will try to fetch current error info on failure)
-    aTask.pProgress->i_notifyComplete(rc);
+    task.m_pProgress->i_notifyComplete(rc);
 
     if (SUCCEEDED(rc))
@@ -3061,5 +3306,5 @@
             aSource = aHD;
             aTarget = pChild;
-            LogFlowFunc(("Forward merging selected\n"));
+            LogFlowThisFunc(("Forward merging selected\n"));
         }
         else
@@ -3067,5 +3312,5 @@
             aSource = pChild;
             aTarget = aHD;
-            LogFlowFunc(("Backward merging selected\n"));
+            LogFlowThisFunc(("Backward merging selected\n"));
         }
     }
@@ -3580,5 +3825,7 @@
             AssertComRC(rc);
 
+            treeLock.release();
             pMedium->uninit();
+            treeLock.acquire();
         }
 
Index: /trunk/src/VBox/ValidationKit/testdriver/vboxwrappers.py
===================================================================
--- /trunk/src/VBox/ValidationKit/testdriver/vboxwrappers.py	(revision 55213)
+++ /trunk/src/VBox/ValidationKit/testdriver/vboxwrappers.py	(revision 55214)
@@ -2190,11 +2190,14 @@
 
         Returns True on success.
-        Returns False on IConsole::restoreSnapshot() failure.
+        Returns False on IMachine::restoreSnapshot() failure.
         Returns None if the progress object returns failure.
         """
         try:
-            oProgress = self.o.console.restoreSnapshot(oSnapshot);
-        except:
-            reporter.logXcpt('IConsole::restoreSnapshot failed on %s' % (self.sName));
+            if self.fpApiVer >= 5.0:
+                oProgress = self.o.machine.restoreSnapshot(oSnapshot);
+            else:
+                oProgress = self.o.console.restoreSnapshot(oSnapshot);
+        except:
+            reporter.logXcpt('IMachine::restoreSnapshot failed on %s' % (self.sName));
             if fFudgeOnFailure:
                 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
@@ -2216,13 +2219,16 @@
 
         Returns True on success.
-        Returns False on IConsole::deleteSnapshot() failure.
-        """
-        try:
-            oProgressCom = self.o.console.deleteSnapshot(oSnapshot);
+        Returns False on IMachine::deleteSnapshot() failure.
+        """
+        try:
+            if self.fpApiVer >= 5.0:
+                oProgressCom = self.o.machine.deleteSnapshot(oSnapshot);
+            else:
+                oProgressCom = self.o.console.deleteSnapshot(oSnapshot);
             oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Delete Snapshot %s' % (oSnapshot));
             oProgress.wait(cMsTimeout);
             oProgress.logResult();
         except:
-            reporter.logXcpt('IConsole::deleteSnapshot failed on %s' % (self.sName));
+            reporter.logXcpt('IMachine::deleteSnapshot failed on %s' % (self.sName));
             if fFudgeOnFailure:
                 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
@@ -2237,5 +2243,5 @@
 
         Returns True on success.
-        Returns False on IConsole::takeSnapshot() or VM state change failure.
+        Returns False on IMachine::takeSnapshot() or VM state change failure.
         """
         try:
@@ -2243,11 +2249,13 @@
                and self.oVM.state is vboxcon.MachineState_Running:
                 self.o.console.pause();
-
-            oProgressCom = self.o.console.takeSnapshot(sName, sDescription);
+            if self.fpApiVer >= 5.0:
+                oProgressCom = self.o.machine.takeSnapshot(sName, sDescription);
+            else
+                oProgressCom = self.o.console.takeSnapshot(sName, sDescription);
             oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Take Snapshot %s' % (sName));
             oProgress.wait(cMsTimeout);
             oProgress.logResult();
         except:
-            reporter.logXcpt('IConsole::takeSnapshot failed on %s' % (self.sName));
+            reporter.logXcpt('IMachine::takeSnapshot failed on %s' % (self.sName));
             if fFudgeOnFailure:
                 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
