Index: /trunk/include/VBox/hgcmsvc.h
===================================================================
--- /trunk/include/VBox/hgcmsvc.h	(revision 75989)
+++ /trunk/include/VBox/hgcmsvc.h	(revision 75990)
@@ -73,7 +73,8 @@
  * 6.4->6.5 Bacause pfnGetVMMDevSessionId was added pfnLoadState got the version
  *          parameter (VBox 6.0).
- * 6.5->7.1 Because pfnNotify was added.
+ * 6.5->7.1 Because pfnNotify was added (VBox 6.0).
+ * 7.1->8.1 Because pfnCancelled & pfnIsCallCancelled were added (VBox 6.0).
  */
-#define VBOX_HGCM_SVC_VERSION_MAJOR (0x0007)
+#define VBOX_HGCM_SVC_VERSION_MAJOR (0x0008)
 #define VBOX_HGCM_SVC_VERSION_MINOR (0x0001)
 #define VBOX_HGCM_SVC_VERSION ((VBOX_HGCM_SVC_VERSION_MAJOR << 16) + VBOX_HGCM_SVC_VERSION_MINOR)
@@ -102,4 +103,12 @@
      */
     DECLR3CALLBACKMEMBER(bool, pfnIsCallRestored, (VBOXHGCMCALLHANDLE callHandle));
+
+    /**
+     * Check if the @a callHandle is for a cancelled call.
+     *
+     * @returns true if cancelled, false if not.
+     * @param   callHandle      The call we're checking up on.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsCallCancelled, (VBOXHGCMCALLHANDLE callHandle));
 
     /** Access to STAMR3RegisterV. */
@@ -512,4 +521,13 @@
     DECLR3CALLBACKMEMBER(void, pfnCall, (void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient,
                                          uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival));
+    /** Informs the service that a call was cancelled by the guest (optional).
+     *
+     * This is called for guest calls, connect requests and disconnect requests.
+     * There is unfortunately no way of obtaining the call handle for a guest call
+     * or otherwise identify the request, so that's left to the service to figure
+     * out using VBOXHGCMSVCHELPERS::pfnIsCallCancelled.  Because this is an
+     * asynchronous call, the service may have completed the request already.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnCancelled, (void *pvService, uint32_t idClient, void *pvClient));
 
     /** Host Service entry point meant for privileged features invisible to the guest.
Index: /trunk/include/VBox/vmm/pdmifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmifs.h	(revision 75989)
+++ /trunk/include/VBox/vmm/pdmifs.h	(revision 75990)
@@ -2085,4 +2085,13 @@
 
     /**
+     * Checks if @a pCmd was cancelled.
+     *
+     * @returns true if cancelled, false if not.
+     * @param   pInterface          Pointer to this interface.
+     * @param   pCmd                The command we're checking on.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsCmdCancelled,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd));
+
+    /**
      * Gets the VMMDevRequestHeader::fRequestor value for @a pCmd.
      *
@@ -2104,5 +2113,5 @@
 } PDMIHGCMPORT;
 /** PDMIHGCMPORT interface ID. */
-# define PDMIHGCMPORT_IID                       "c9180235-8102-4642-0aa7-f0422124d9b5"
+# define PDMIHGCMPORT_IID                       "28c0a201-68cd-4752-9404-bb42a0c09eb7"
 
 
@@ -2158,7 +2167,15 @@
                                        uint32_t cParms, PVBOXHGCMSVCPARM paParms, uint64_t tsArrival));
 
+    /**
+     * Notification about the guest cancelling a pending request.
+     * @param   pInterface  Pointer to this interface.
+     * @param   pCmd        A pointer that identifies the command.
+     * @param   idclient    The client id returned by the pfnConnect call.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnCancelled,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t idClient));
+
 } PDMIHGCMCONNECTOR;
 /** PDMIHGCMCONNECTOR interface ID. */
-# define PDMIHGCMCONNECTOR_IID                  "a1104758-c888-4437-8f2a-7bac17865b5c"
+# define PDMIHGCMCONNECTOR_IID                  "33cb5c91-6a4a-4ad9-3fec-d1f7d413c4a5"
 
 #endif /* VBOX_WITH_HGCM */
Index: /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 75989)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 75990)
@@ -4427,4 +4427,5 @@
     pThis->IHGCMPort.pfnCompleted           = hgcmCompleted;
     pThis->IHGCMPort.pfnIsCmdRestored       = hgcmIsCmdRestored;
+    pThis->IHGCMPort.pfnIsCmdCancelled      = hgcmIsCmdCancelled;
     pThis->IHGCMPort.pfnGetRequestor        = hgcmGetRequestor;
     pThis->IHGCMPort.pfnGetVMMDevSessionId  = hgcmGetVMMDevSessionId;
Index: /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp	(revision 75989)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp	(revision 75990)
@@ -1169,5 +1169,12 @@
     {
         pCmd->fCancelled = true;
+
         Log(("vmmdevHGCMCancel2: Cancelled pCmd=%p / GCPhys=%#x\n", pCmd, GCPhys));
+        if (pThis->pHGCMDrv)
+            pThis->pHGCMDrv->pfnCancelled(pThis->pHGCMDrv, pCmd,
+                                          pCmd->enmCmdType == VBOXHGCMCMDTYPE_CALL ? pCmd->u.call.u32ClientID
+                                          : pCmd->enmCmdType == VBOXHGCMCMDTYPE_CONNECT ? pCmd->u.connect.u32ClientID
+                                          : pCmd->enmCmdType == VBOXHGCMCMDTYPE_DISCONNECT ? pCmd->u.disconnect.u32ClientID
+                                          : 0);
     }
     else
@@ -1537,4 +1544,13 @@
 
 /**
+ * @interface_method_impl{PDMIHGCMPORT,pfnIsCmdCancelled}
+ */
+DECLCALLBACK(bool) hgcmIsCmdCancelled(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)
+{
+    RT_NOREF(pInterface);
+    return pCmd && pCmd->fCancelled;
+}
+
+/**
  * @interface_method_impl{PDMIHGCMPORT,pfnGetRequestor}
  */
@@ -1589,4 +1605,6 @@
             LogFlowFunc(("Saving %RGp, size %d\n", pCmd->GCPhys, pCmd->cbRequest));
 
+            /** @todo Don't save cancelled requests! It serves no purpose.  See restore and
+             *        @bugref{4032#c4} for details. */
             SSMR3PutU32     (pSSM, (uint32_t)pCmd->enmCmdType);
             SSMR3PutBool    (pSSM, pCmd->fCancelled);
Index: /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.h
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.h	(revision 75989)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.h	(revision 75990)
@@ -31,4 +31,5 @@
 DECLCALLBACK(int)  hgcmCompleted(PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmdPtr);
 DECLCALLBACK(bool) hgcmIsCmdRestored(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd);
+DECLCALLBACK(bool) hgcmIsCmdCancelled(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd);
 DECLCALLBACK(uint32_t) hgcmGetRequestor(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd);
 DECLCALLBACK(uint64_t) hgcmGetVMMDevSessionId(PPDMIHGCMPORT pInterface);
Index: /trunk/src/VBox/Devices/VMMDev/VMMDevState.h
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDevState.h	(revision 75989)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDevState.h	(revision 75990)
@@ -156,7 +156,7 @@
     /** LUN\#0: HGCM port interface. */
     PDMIHGCMPORT IHGCMPort;
-# if HC_ARCH_BITS == 32
-    RTR3PTR      R3PtrAlignment1;
-# endif
+//# if HC_ARCH_BITS == 32
+//    RTR3PTR      R3PtrAlignment1;
+//# endif
 #endif
     /** Pointer to base interface of the driver. */
Index: /trunk/src/VBox/Main/include/HGCM.h
===================================================================
--- /trunk/src/VBox/Main/include/HGCM.h	(revision 75989)
+++ /trunk/src/VBox/Main/include/HGCM.h	(revision 75990)
@@ -45,4 +45,5 @@
 int HGCMGuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmdPtr, uint32_t clientID, uint32_t function, uint32_t cParms,
                   VBOXHGCMSVCPARM *paParms, uint64_t tsArrival);
+void HGCMGuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmdPtr, uint32_t idClient);
 
 int HGCMHostCall(const char *pszServiceName, uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
Index: /trunk/src/VBox/Main/src-client/HGCM.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/HGCM.cpp	(revision 75989)
+++ /trunk/src/VBox/Main/src-client/HGCM.cpp	(revision 75990)
@@ -143,4 +143,5 @@
         static DECLCALLBACK(void) svcHlpDisconnectClient(void *pvInstance, uint32_t u32ClientId);
         static DECLCALLBACK(bool) svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle);
+        static DECLCALLBACK(bool) svcHlpIsCallCancelled(VBOXHGCMCALLHANDLE callHandle);
         static DECLCALLBACK(int)  svcHlpStamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType,
                                                       STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc,
@@ -197,4 +198,5 @@
         int GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId,
                       uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t tsArrival);
+        void GuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient);
 };
 
@@ -403,16 +405,17 @@
  */
 
-#define SVC_MSG_LOAD       (0)  /**< Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
-#define SVC_MSG_UNLOAD     (1)  /**< call pfnUnload and unload the service library. */
-#define SVC_MSG_CONNECT    (2)  /**< pfnConnect */
-#define SVC_MSG_DISCONNECT (3)  /**< pfnDisconnect */
-#define SVC_MSG_GUESTCALL  (4)  /**< pfnGuestCall */
-#define SVC_MSG_HOSTCALL   (5)  /**< pfnHostCall */
-#define SVC_MSG_LOADSTATE  (6)  /**< pfnLoadState. */
-#define SVC_MSG_SAVESTATE  (7)  /**< pfnSaveState. */
-#define SVC_MSG_QUIT       (8)  /**< Terminate the thread. */
-#define SVC_MSG_REGEXT     (9)  /**< pfnRegisterExtension */
-#define SVC_MSG_UNREGEXT   (10) /**< pfnRegisterExtension */
-#define SVC_MSG_NOTIFY     (11) /**< pfnNotify */
+#define SVC_MSG_LOAD            (0)  /**< Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
+#define SVC_MSG_UNLOAD          (1)  /**< call pfnUnload and unload the service library. */
+#define SVC_MSG_CONNECT         (2)  /**< pfnConnect */
+#define SVC_MSG_DISCONNECT      (3)  /**< pfnDisconnect */
+#define SVC_MSG_GUESTCALL       (4)  /**< pfnGuestCall */
+#define SVC_MSG_HOSTCALL        (5)  /**< pfnHostCall */
+#define SVC_MSG_LOADSTATE       (6)  /**< pfnLoadState. */
+#define SVC_MSG_SAVESTATE       (7)  /**< pfnSaveState. */
+#define SVC_MSG_QUIT            (8)  /**< Terminate the thread. */
+#define SVC_MSG_REGEXT          (9)  /**< pfnRegisterExtension */
+#define SVC_MSG_UNREGEXT        (10) /**< pfnRegisterExtension */
+#define SVC_MSG_NOTIFY          (11) /**< pfnNotify */
+#define SVC_MSG_GUESTCANCELLED  (12) /**< pfnCancelled */
 #ifdef VBOX_WITH_CRHGSMI
 # define SVC_MSG_HOSTFASTCALLASYNC (21) /* pfnHostCall */
@@ -487,4 +490,20 @@
         /** The STAM_GET_TS() value when the request arrived. */
         uint64_t tsArrival;
+};
+
+class HGCMMsgCancelled: public HGCMMsgHeader
+{
+    public:
+        HGCMMsgCancelled() {}
+
+        HGCMMsgCancelled(HGCMThread *pThread)
+        {
+            InitializeCore(SVC_MSG_GUESTCANCELLED, pThread);
+            Initialize();
+        }
+        ~HGCMMsgCancelled() { Log(("~HGCMMsgCancelled %p\n", this)); }
+
+        /** The client identifier. */
+        uint32_t idClient;
 };
 
@@ -566,4 +585,5 @@
         case SVC_MSG_UNREGEXT:    return new HGCMMsgSvcUnregisterExtension();
         case SVC_MSG_NOTIFY:      return new HGCMMsgNotify();
+        case SVC_MSG_GUESTCANCELLED: return new HGCMMsgCancelled();
         default:
             AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
@@ -687,4 +707,24 @@
                                             HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function,
                                             pMsg->cParms, pMsg->paParms, pMsg->tsArrival);
+
+                    hgcmObjDereference(pClient);
+                }
+                else
+                {
+                    rc = VERR_HGCM_INVALID_CLIENT_ID;
+                }
+            } break;
+
+            case SVC_MSG_GUESTCANCELLED:
+            {
+                HGCMMsgCancelled *pMsg = (HGCMMsgCancelled *)pMsgCore;
+
+                LogFlowFunc(("SVC_MSG_GUESTCANCELLED idClient = %d\n", pMsg->idClient));
+
+                HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->idClient, HGCMOBJ_CLIENT);
+
+                if (pClient)
+                {
+                    pSvc->m_fntable.pfnCancelled(pSvc->m_fntable.pvService, pMsg->idClient, HGCM_CLIENT_DATA(pSvc, pClient));
 
                     hgcmObjDereference(pClient);
@@ -883,5 +923,5 @@
 /* static */ DECLCALLBACK(bool) HGCMService::svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle)
 {
-    HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)(callHandle);
+    HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)callHandle;
     AssertPtrReturn(pMsgHdr, false);
 
@@ -893,4 +933,21 @@
 
     return pHgcmPort->pfnIsCmdRestored(pHgcmPort, pCmd);
+}
+
+/**
+ * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnIsCallCancelled}
+ */
+/* static */ DECLCALLBACK(bool) HGCMService::svcHlpIsCallCancelled(VBOXHGCMCALLHANDLE callHandle)
+{
+    HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)callHandle;
+    AssertPtrReturn(pMsgHdr, false);
+
+    PVBOXHGCMCMD pCmd = pMsgHdr->pCmd;
+    AssertPtrReturn(pCmd, false);
+
+    PPDMIHGCMPORT pHgcmPort = pMsgHdr->pHGCMPort;
+    AssertPtrReturn(pHgcmPort, false);
+
+    return pHgcmPort->pfnIsCmdCancelled(pHgcmPort, pCmd);
 }
 
@@ -1041,4 +1098,5 @@
             m_svcHelpers.pfnDisconnectClient   = svcHlpDisconnectClient;
             m_svcHelpers.pfnIsCallRestored     = svcHlpIsCallRestored;
+            m_svcHelpers.pfnIsCallCancelled    = svcHlpIsCallCancelled;
             m_svcHelpers.pfnStamRegisterV      = svcHlpStamRegisterV;
             m_svcHelpers.pfnStamDeregisterV    = svcHlpStamDeregisterV;
@@ -1756,5 +1814,5 @@
                            uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
 {
-    LogFlow(("MAIN::HGCMService::Call\n"));
+    LogFlow(("MAIN::HGCMService::GuestCall\n"));
 
     int rc;
@@ -1762,5 +1820,5 @@
     if (pMsg)
     {
-        pMsg->Reference();
+        pMsg->Reference(); /** @todo starts out with zero references. */
 
         pMsg->pCmd        = pCmd;
@@ -1776,5 +1834,5 @@
     else
     {
-        Log(("MAIN::HGCMService::Call: Message allocation failed\n"));
+        Log(("MAIN::HGCMService::GuestCall: Message allocation failed\n"));
         rc = VERR_NO_MEMORY;
     }
@@ -1782,4 +1840,33 @@
     LogFlowFunc(("rc = %Rrc\n", rc));
     return rc;
+}
+
+/** Guest cancelled a request (call, connection attempt, disconnect attempt).
+ *
+ * @param   pHGCMPort      The port to be used for completion confirmation.
+ * @param   pCmd           The VBox HGCM context.
+ * @param   u32ClientId    The client handle to be disconnected and deleted.
+ * @return  VBox rc.
+ */
+void HGCMService::GuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient)
+{
+    LogFlow(("MAIN::HGCMService::GuestCancelled\n"));
+
+    if (m_fntable.pfnCancelled)
+    {
+        HGCMMsgCancelled *pMsg = new (std::nothrow) HGCMMsgCancelled(m_pThread);
+        if (pMsg)
+        {
+            pMsg->Reference(); /** @todo starts out with zero references. */
+
+            pMsg->pCmd      = pCmd;
+            pMsg->pHGCMPort = pHGCMPort;
+            pMsg->idClient  = idClient;
+
+            hgcmMsgPost(pMsg, NULL);
+        }
+        else
+            Log(("MAIN::HGCMService::GuestCancelled: Message allocation failed\n"));
+    }
 }
 
@@ -2579,9 +2666,9 @@
 }
 
-/* The guest calls the service.
+/** The guest calls the service.
  *
  * @param pHGCMPort      The port to be used for completion confirmation.
  * @param pCmd           The VBox HGCM context.
- * @param u32ClientId    The client handle to be disconnected and deleted.
+ * @param u32ClientId    The client handle.
  * @param u32Function    The function number.
  * @param cParms         Number of parameters.
@@ -2623,4 +2710,33 @@
     LogFlowFunc(("rc = %Rrc\n", rc));
     return rc;
+}
+
+/** The guest cancelled a request (call, connect, disconnect)
+ *
+ * @param   pHGCMPort      The port to be used for completion confirmation.
+ * @param   pCmd           The VBox HGCM context.
+ * @param   idClient       The client handle.
+ */
+void HGCMGuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient)
+{
+    LogFlowFunc(("pHGCMPort = %p, pCmd = %p, idClient = %d\n", pHGCMPort, pCmd, idClient));
+    AssertReturnVoid(pHGCMPort);
+    AssertReturnVoid(pCmd);
+    AssertReturnVoid(idClient != 0);
+
+    /* Resolve the client handle to the client instance pointer. */
+    HGCMClient *pClient = (HGCMClient *)hgcmObjReference(idClient, HGCMOBJ_CLIENT);
+
+    if (pClient)
+    {
+        AssertRelease(pClient->pService);
+
+        /* Forward the message to the service thread. */
+        pClient->pService->GuestCancelled(pHGCMPort, pCmd, idClient);
+
+        hgcmObjDereference(pClient);
+    }
+
+    LogFlowFunc(("returns\n"));
 }
 
Index: /trunk/src/VBox/Main/src-client/HGCMThread.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/HGCMThread.cpp	(revision 75989)
+++ /trunk/src/VBox/Main/src-client/HGCMThread.cpp	(revision 75990)
@@ -704,5 +704,5 @@
     pMsg->Dereference();
 
-    LogFlow(("MAIN::hgcmMsgPostInternal: pMsg %p, rc = %Rrc\n", pMsg, rc));
+    LogFlow(("MAIN::hgcmMsgPostInternal: pMsg = %p, rc = %Rrc\n", pMsg, rc));
     return rc;
 }
Index: /trunk/src/VBox/Main/src-client/VMMDevInterface.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/VMMDevInterface.cpp	(revision 75989)
+++ /trunk/src/VBox/Main/src-client/VMMDevInterface.cpp	(revision 75990)
@@ -649,4 +649,14 @@
 
     return HGCMGuestCall(pDrv->pHGCMPort, pCmd, u32ClientID, u32Function, cParms, paParms, tsArrival);
+}
+
+static DECLCALLBACK(void) iface_hgcmCancelled(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t idClient)
+{
+    Log9(("Enter\n"));
+
+    PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector);
+    if (   pDrv->pVMMDev
+        && pDrv->pVMMDev->hgcmIsActive())
+        return HGCMGuestCancelled(pDrv->pHGCMPort, pCmd, idClient);
 }
 
@@ -1059,4 +1069,5 @@
     pThis->HGCMConnector.pfnDisconnect                = iface_hgcmDisconnect;
     pThis->HGCMConnector.pfnCall                      = iface_hgcmCall;
+    pThis->HGCMConnector.pfnCancelled                 = iface_hgcmCancelled;
 #endif
 
