Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 59366)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 59367)
@@ -918,4 +918,7 @@
 	include
 ifeq ($(KBUILD_TARGET),win)
+ ifdef VBOX_WITH_MIDL_PROXY_STUB
+  VBoxCOM_DEFS.win      = VBOX_WITH_AUTO_COM_REG_UPDATE
+ endif
  VBoxCOM_DEFS.x86       = _WIN32_WINNT=0x0500
  VBoxCOM_DEFS.amd64     = _WIN32_WINNT=0x0510
@@ -1013,4 +1016,5 @@
 	# => 0bb3b78c-1807-4249-5ba5-ea42d66af0bf: Also hardcoded in VBoxMergeCOM32On64.wxi and VBoxMergeApp.wxi!
  VBoxProxyStub_DEFS.win.x86 = WIN32
+ VBoxProxyStub_SDKS     = VBOX_NTDLL
  VBoxProxyStub_INCS     = $(VBoxCOM_0_OUTDIR)/
  VBoxProxyStub_SOURCES  = \
@@ -1025,4 +1029,5 @@
   DLLS += VBoxProxyStub-x86
   VBoxProxyStub-x86_TEMPLATE = VBoxMainComp-x86
+  VBoxProxyStub-x86_SDKS     = VBOX_NTDLL
   VBoxProxyStub-x86_DEFS     = $(VBoxProxyStub_DEFS) VBOX_PROXY_STUB_32_ON_64 WIN32
   VBoxProxyStub-x86_INCS     = $(VBoxCOM-x86_0_OUTDIR)/
Index: /trunk/src/VBox/Main/src-all/win/VBoxProxyStub.c
===================================================================
--- /trunk/src/VBox/Main/src-all/win/VBoxProxyStub.c	(revision 59366)
+++ /trunk/src/VBox/Main/src-all/win/VBoxProxyStub.c	(revision 59367)
@@ -24,13 +24,15 @@
 *********************************************************************************************************************************/
 #define PROXY_DELEGATION                                                                             /* see generated dlldata.c */
+#include <iprt/nt/nt-and-windows.h>
 #include <rpcproxy.h>
-#include <Windows.h>
 #include <Shlwapi.h>
 #include <stdio.h>
 
 #include "VirtualBox.h"
+#include <iprt/alloca.h>
 #include <iprt/assert.h>
 #include <iprt/path.h>
 #include <iprt/string.h>
+#include <iprt/uuid.h>
 
 
@@ -42,4 +44,26 @@
 #if 1 /*defined(DEBUG) && !defined(VBOX_IN_32_ON_64_MAIN_API) - needed on testboxes (and obviously dev boxes)! */
 # define WITH_MANUAL_CLEANUP
+#endif
+
+#ifdef DEBUG_bird
+# define VBSP_LOG_ENABLED
+#endif
+
+#ifdef VBSP_LOG_ENABLED
+# define VBSP_LOG_VALUE_CHANGE(a)   RTAssertMsg2 a
+#else
+# define VBSP_LOG_VALUE_CHANGE(a)   do { } while (0)
+#endif
+
+#ifdef VBSP_LOG_ENABLED
+# define VBSP_LOG_SET_VALUE(a)      RTAssertMsg2 a
+#else
+# define VBSP_LOG_SET_VALUE(a)      do { } while (0)
+#endif
+
+#ifdef VBSP_LOG_ENABLED
+# define VBSP_LOG_NEW_KEY(a)        RTAssertMsg2 a
+#else
+# define VBSP_LOG_NEW_KEY(a)        do { } while (0)
 #endif
 
@@ -117,6 +141,11 @@
     {
         case DLL_PROCESS_ATTACH:
+            /* Save the DLL handle so we can get the path to this DLL during
+               registration and updating. */
             g_hDllSelf = hInstance;
+
+            /* We don't need callbacks for thread creation and destruction. */
             DisableThreadLibraryCalls(hInstance);
+
             /* We don't use IPRT, so no need to init it! */
             break;
@@ -138,5 +167,5 @@
     *ppapInfo = &g_apProxyFiles[0];
     *ppClsid  = &g_ProxyClsId;
-};
+}
 
 
@@ -219,4 +248,29 @@
 
 
+#ifdef VBSP_LOG_ENABLED
+# include <iprt/asm.h>
+
+/** For logging full key names.   */
+static PCRTUTF16 vbpsDebugKeyToWSZ(HKEY hKey)
+{
+    static union
+    {
+        KEY_NAME_INFORMATION NameInfo;
+        WCHAR awchPadding[260];
+    }                           s_aBufs[4];
+    static uint32_t volatile    iNext = 0;
+    uint32_t                    i = ASMAtomicIncU32(&iNext) % RT_ELEMENTS(s_aBufs);
+    ULONG                       cbRet = 0;
+    NTSTATUS                    rcNt;
+
+    memset(&s_aBufs[i], 0, sizeof(s_aBufs[i]));
+    rcNt = NtQueryKey(hKey, KeyNameInformation, &s_aBufs[i], sizeof(s_aBufs[i]) - sizeof(WCHAR), &cbRet);
+    if (!NT_SUCCESS(rcNt))
+        s_aBufs[i].NameInfo.NameLength = 0;
+    s_aBufs[i].NameInfo.Name[s_aBufs[i].NameInfo.NameLength] = '\0';
+    return s_aBufs[i].NameInfo.Name;
+}
+#endif
+
 /**
  * Registry modifier state.
@@ -228,11 +282,19 @@
     /** The handle to the CLSID key under hkeyClassesRootDst. */
     HKEY hkeyClsidRootDst;
-    /** For logging purposes.   */
-    const char *pszLogRoot;
-
-    /** Alternative location where duplicates must always be unregistered from. */
-    HKEY hkeyAltClassesRootsUnreg;
-    /** The handle to the CLSID key under hkeyAltClassesRootsUnreg. */
-    HKEY hkeyAltClsidRootsUnreg;
+    /** The handle to the Interface key under hkeyClassesRootDst. */
+    HKEY hkeyInterfaceRootDst;
+
+    /** Alternative locations where data needs to be deleted, but never updated.  */
+    struct
+    {
+        /** The classes root key handle. */
+        HKEY hkeyClasses;
+        /** The classes/CLSID key handle. */
+        HKEY hkeyClsid;
+        /** The classes/Interface key handle. */
+        HKEY hkeyInterface;
+    } aAltDeletes[3];
+    /** Alternative delete locations. */
+    uint32_t cAltDeletes;
 
     /** The current total result. */
@@ -242,10 +304,15 @@
      * almost the work from one process (at least W7+ due to aliases). */
     DWORD   fSamWow;
-    /** Desired key Access when only unregistring. */
-    DWORD   fSamUnreg;
-    /** Desired key Access when both unregistring and registering. */
+    /** Desired key access when only deleting. */
+    DWORD   fSamDelete;
+    /** Desired key access when only doing updates. */
+    DWORD   fSamUpdate;
+    /** Desired key access when both deleting and updating. */
     DWORD   fSamBoth;
-    /** Set if we're only unregistering. */
-    bool    fUnregisterOnly;
+    /** Whether to delete registrations first. */
+    bool    fDelete;
+    /** Whether to update registry value and keys. */
+    bool    fUpdate;
+
 } VBPSREGSTATE;
 
@@ -261,46 +328,52 @@
  * @param   pszSubRoot      The path to the where the classes are registered,
  *                          NULL if @a hkeyRoot.
- * @param   pszLogRoot      For error logging/debugging?
  * @param   hkeyAltRoot     The registry root tree constant for the alternative
  *                          registrations (remove only).
  * @param   pszAltSubRoot   The path to where classes could also be registered,
  *                          but shouldn't be in our setup.
- * @param   fUnregisterOnly If true, only unregister. If false, also register.
+ * @param   fDelete         Whether to delete registrations first.
+ * @param   fUpdate         Whether to update registrations.
  * @param   fSamWow         KEY_WOW64_32KEY or 0.
  */
-static LSTATUS vbpsRegInit(VBPSREGSTATE *pState, HKEY hkeyRoot, const char *pszSubRoot, const char *pszLogRoot,
-                           HKEY hkeyAltRoot, const char *pszAltSubRoot, bool fUnregisterOnly, DWORD fSamWow)
+static LSTATUS vbpsRegInit(VBPSREGSTATE *pState, HKEY hkeyRoot, const char *pszSubRoot, bool fDelete, bool fUpdate, DWORD fSamWow)
 {
     LSTATUS rc;
-    REGSAM  fAccess = !fUnregisterOnly
-                    ? DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
-                    : DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
-
+    unsigned i = 0;
+
+    /*
+     * Initialize the whole structure first so we can safely call vbpsRegTerm on failure.
+     */
     pState->hkeyClassesRootDst          = NULL;
     pState->hkeyClsidRootDst            = NULL;
-    pState->pszLogRoot                  = pszLogRoot;
-    pState->hkeyAltClassesRootsUnreg    = NULL;
-    pState->hkeyAltClsidRootsUnreg      = NULL;
-    pState->fUnregisterOnly             = fUnregisterOnly;
+    pState->hkeyInterfaceRootDst        = NULL;
+    for (i = 0; i < RT_ELEMENTS(pState->aAltDeletes); i++)
+    {
+        pState->aAltDeletes[i].hkeyClasses   = NULL;
+        pState->aAltDeletes[i].hkeyClsid     = NULL;
+        pState->aAltDeletes[i].hkeyInterface = NULL;
+    }
+    pState->cAltDeletes                 = 0;
+    pState->rc                          = ERROR_SUCCESS;
+    pState->fDelete                     = fDelete;
+    pState->fUpdate                     = fUpdate;
     pState->fSamWow                     = fSamWow;
-    pState->fSamUnreg                   = pState->fSamWow | DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
-    pState->fSamBoth                    = pState->fSamUnreg | (!fUnregisterOnly ? KEY_SET_VALUE | KEY_CREATE_SUB_KEY : 0);
-    pState->rc                          = ERROR_SUCCESS;
-
+    pState->fSamDelete                  = 0;
+    if (fDelete)
+        pState->fSamDelete = pState->fSamWow | DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE
+                           | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE;
+    pState->fSamUpdate                  = 0;
+    if (fUpdate)
+        pState->fSamUpdate = pState->fSamWow | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
+                           | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE;
+    pState->fSamBoth                    = pState->fSamDelete | pState->fSamUpdate;
+
+    /*
+     * Open the root keys.
+     */
     rc = RegOpenKeyExA(hkeyRoot, pszSubRoot, 0 /*fOptions*/, pState->fSamBoth, &pState->hkeyClassesRootDst);
     AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
     rc = RegOpenKeyExA(pState->hkeyClassesRootDst, "CLSID", 0 /*fOptions*/, pState->fSamBoth, &pState->hkeyClsidRootDst);
     AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-    if (hkeyAltRoot)
-    {
-        rc = RegOpenKeyExA(hkeyAltRoot, pszAltSubRoot, 0 /*fOptions*/, pState->fSamUnreg, &pState->hkeyAltClassesRootsUnreg);
-        AssertMsgReturn(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-        if (pState->hkeyAltClassesRootsUnreg)
-        {
-            rc = RegOpenKeyExA(pState->hkeyAltClassesRootsUnreg, "CLSID", 0 /*fOptions*/, pState->fSamUnreg,
-                               &pState->hkeyAltClsidRootsUnreg);
-            AssertMsgReturn(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-        }
-    }
+
     return ERROR_SUCCESS;
 }
@@ -327,67 +400,351 @@
         pState->hkeyClsidRootDst = NULL;
     }
-    if (pState->hkeyAltClassesRootsUnreg)
-    {
-        rc = RegCloseKey(pState->hkeyAltClassesRootsUnreg);
+    if (pState->hkeyInterfaceRootDst)
+    {
+        rc = RegCloseKey(pState->hkeyInterfaceRootDst);
         Assert(rc == ERROR_SUCCESS);
-        pState->hkeyAltClassesRootsUnreg = NULL;
-    }
-    if (pState->hkeyAltClsidRootsUnreg)
-    {
-        rc = RegCloseKey(pState->hkeyAltClsidRootsUnreg);
-        Assert(rc == ERROR_SUCCESS);
-        pState->hkeyAltClsidRootsUnreg = NULL;
-    }
+        pState->hkeyInterfaceRootDst = NULL;
+    }
+
+    while (pState->cAltDeletes > 0 && pState->cAltDeletes <= RT_ELEMENTS(pState->aAltDeletes))
+    {
+        unsigned i = --pState->cAltDeletes;
+        if (pState->aAltDeletes[i].hkeyClasses)
+        {
+            rc = RegCloseKey(pState->aAltDeletes[i].hkeyClasses);
+            Assert(rc == ERROR_SUCCESS);
+            pState->aAltDeletes[i].hkeyClasses = NULL;
+        }
+        if (pState->aAltDeletes[i].hkeyClsid)
+        {
+            rc = RegCloseKey(pState->aAltDeletes[i].hkeyClsid);
+            Assert(rc == ERROR_SUCCESS);
+            pState->aAltDeletes[i].hkeyClsid = NULL;
+        }
+        if (pState->aAltDeletes[i].hkeyInterface)
+        {
+            rc = RegCloseKey(pState->aAltDeletes[i].hkeyInterface);
+            Assert(rc == ERROR_SUCCESS);
+            pState->aAltDeletes[i].hkeyInterface = NULL;
+        }
+    }
+}
+
+
+/**
+ * Add an alternative registry classes tree from which to remove keys.
+ *
+ * @returns ERROR_SUCCESS if we successfully opened the destination root, other
+ *          wise windows error code (remebered).
+ * @param   pState              The registry modifier state.
+ * @param   hkeyAltRoot         The root of the alternate registry classes
+ *                              location.
+ * @param   pszAltSubRoot       The path to the 'classes' sub-key, or NULL if
+ *                              hkeyAltRoot is it.
+ */
+static LSTATUS vbpsRegAddAltDelete(VBPSREGSTATE *pState, HKEY hkeyAltRoot, const char *pszAltSubRoot)
+{
+    unsigned i;
+    LSTATUS rc;
+
+    /* Ignore call if not in delete mode. */
+    if (!pState->fDelete)
+        return ERROR_SUCCESS;
+
+    /* Check that there is space in the state. */
+    i = pState->cAltDeletes;
+    AssertReturn(i < RT_ELEMENTS(pState->aAltDeletes), pState->rc = ERROR_TOO_MANY_NAMES);
+
+
+    /* Open the root. */
+    rc = RegOpenKeyExA(hkeyAltRoot, pszAltSubRoot, 0 /*fOptions*/, pState->fSamDelete,
+                       &pState->aAltDeletes[i].hkeyClasses);
+    if (rc == ERROR_SUCCESS)
+    {
+        /* Try open the CLSID subkey, it's fine if it doesn't exists. */
+        rc = RegOpenKeyExA(pState->aAltDeletes[i].hkeyClasses, "CLSID", 0 /*fOptions*/, pState->fSamDelete,
+                           &pState->aAltDeletes[i].hkeyClsid);
+        if (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND)
+        {
+            if (rc == ERROR_FILE_NOT_FOUND)
+                pState->aAltDeletes[i].hkeyClsid = NULL;
+            pState->cAltDeletes = i + 1;
+            return ERROR_SUCCESS;
+        }
+        AssertMsgFailed(("%u\n", rc));
+        RegCloseKey(pState->aAltDeletes[i].hkeyClasses);
+    }
+    /* No need to add non-existing alternative roots, nothing to delete in the void. */
+    else if (rc == ERROR_FILE_NOT_FOUND)
+        rc = ERROR_SUCCESS;
+    else
+    {
+        AssertMsgFailed(("%u\n", rc));
+        pState->rc = rc;
+    }
+
+    pState->aAltDeletes[i].hkeyClasses = NULL;
+    pState->aAltDeletes[i].hkeyClsid   = NULL;
+    return rc;
+}
+
+
+/**
+ * Open the 'Interface' keys under the current classes roots.
+ *
+ * We don't do this during vbpsRegInit as it's only needed for updating.
+ *
+ * @returns ERROR_SUCCESS if we successfully opened the destination root, other
+ *          wise windows error code (remebered).
+ * @param   pState              The registry modifier state.
+ */
+static LSTATUS vbpsRegOpenInterfaceKeys(VBPSREGSTATE *pState)
+{
+    unsigned i;
+    LSTATUS rc;
+
+    /*
+     * Under the root destination.
+     */
+    if (pState->hkeyInterfaceRootDst == NULL)
+    {
+        rc = RegOpenKeyExA(pState->hkeyClassesRootDst, "Interface", 0 /*fOptions*/, pState->fSamBoth, &pState->hkeyInterfaceRootDst);
+        AssertMsgReturnStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->hkeyInterfaceRootDst = NULL,  pState->rc = rc);
+    }
+
+    /*
+     * Under the alternative delete locations.
+     */
+    i = pState->cAltDeletes;
+    while (i-- > 0)
+        if (pState->aAltDeletes[i].hkeyInterface == NULL)
+        {
+            rc = RegOpenKeyExA(pState->aAltDeletes[i].hkeyClasses, "Interface", 0 /*fOptions*/, pState->fSamDelete,
+                               &pState->aAltDeletes[i].hkeyInterface);
+            if (rc != ERROR_SUCCESS)
+            {
+                AssertMsgStmt(rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
+                pState->aAltDeletes[i].hkeyInterface = NULL;
+            }
+        }
+
+    return ERROR_SUCCESS;
 }
 
 
 /** The destination buffer size required by vbpsFormatUuidInCurly. */
-#define CURLY_UUID_STR_BUF_SIZE     48
+#define CURLY_UUID_STR_BUF_SIZE     40
 
 /**
  * Formats a UUID to a string, inside curly braces.
  *
- * @returns ERROR_SUCCESS on success, otherwise windows error code.
- * @param   pszUuid             Output buffer of size CURLY_UUID_STR_BUF_SIZE.
- * @param   pUuid               The UUID to format.
- */
-static LSTATUS vbpsFormatUuidInCurly(char *pszUuid, const CLSID *pUuid)
-{
-    unsigned char *pszTmpStr = NULL;
-    size_t cchTmpStr;
-    RPC_STATUS rc = UuidToStringA((UUID *)pUuid, &pszTmpStr);
-    AssertReturnStmt(rc == RPC_S_OK, *pszUuid = '\0', ERROR_OUTOFMEMORY);
-
-    cchTmpStr = strlen((const char *)pszTmpStr);
-    AssertReturnStmt(cchTmpStr == 36 && cchTmpStr < CURLY_UUID_STR_BUF_SIZE - 3, RpcStringFreeA(&pszTmpStr), ERROR_INVALID_DATA);
-
-    pszUuid[0] = '{';
-    memcpy(pszUuid + 1, pszTmpStr, cchTmpStr);
-    pszUuid[1 + cchTmpStr] = '}';
-    pszUuid[1 + cchTmpStr + 1] = '\0';
-
-    RpcStringFreeA(&pszTmpStr);
-    return ERROR_SUCCESS;
-}
-
-
-/**
- * Sets a registry string value.
+ * @returns @a pszString
+ * @param   pszString           Output buffer of size CURLY_UUID_STR_BUF_SIZE.
+ * @param   pUuidIn             The UUID to format.
+ */
+static const char *vbpsFormatUuidInCurly(char pszString[CURLY_UUID_STR_BUF_SIZE], const CLSID *pUuidIn)
+{
+    static const char s_achDigits[17] = "0123456789abcdef";
+    PCRTUUID pUuid = (PCRTUUID)pUuidIn;
+    uint32_t u32TimeLow;
+    unsigned u;
+
+    pszString[ 0] = '{';
+    u32TimeLow = RT_H2LE_U32(pUuid->Gen.u32TimeLow);
+    pszString[ 1] = s_achDigits[(u32TimeLow >> 28)/*& 0xf*/];
+    pszString[ 2] = s_achDigits[(u32TimeLow >> 24) & 0xf];
+    pszString[ 3] = s_achDigits[(u32TimeLow >> 20) & 0xf];
+    pszString[ 4] = s_achDigits[(u32TimeLow >> 16) & 0xf];
+    pszString[ 5] = s_achDigits[(u32TimeLow >> 12) & 0xf];
+    pszString[ 6] = s_achDigits[(u32TimeLow >>  8) & 0xf];
+    pszString[ 7] = s_achDigits[(u32TimeLow >>  4) & 0xf];
+    pszString[ 8] = s_achDigits[(u32TimeLow/*>>0*/)& 0xf];
+    pszString[ 9] = '-';
+    u = RT_H2LE_U16(pUuid->Gen.u16TimeMid);
+    pszString[10] = s_achDigits[(u >> 12)/*& 0xf*/];
+    pszString[11] = s_achDigits[(u >>  8) & 0xf];
+    pszString[12] = s_achDigits[(u >>  4) & 0xf];
+    pszString[13] = s_achDigits[(u/*>>0*/)& 0xf];
+    pszString[14] = '-';
+    u = RT_H2LE_U16(pUuid->Gen.u16TimeHiAndVersion);
+    pszString[15] = s_achDigits[(u >> 12)/*& 0xf*/];
+    pszString[16] = s_achDigits[(u >>  8) & 0xf];
+    pszString[17] = s_achDigits[(u >>  4) & 0xf];
+    pszString[18] = s_achDigits[(u/*>>0*/)& 0xf];
+    pszString[19] = '-';
+    pszString[20] = s_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved >> 4];
+    pszString[21] = s_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved & 0xf];
+    pszString[22] = s_achDigits[pUuid->Gen.u8ClockSeqLow >> 4];
+    pszString[23] = s_achDigits[pUuid->Gen.u8ClockSeqLow & 0xf];
+    pszString[24] = '-';
+    pszString[25] = s_achDigits[pUuid->Gen.au8Node[0] >> 4];
+    pszString[26] = s_achDigits[pUuid->Gen.au8Node[0] & 0xf];
+    pszString[27] = s_achDigits[pUuid->Gen.au8Node[1] >> 4];
+    pszString[28] = s_achDigits[pUuid->Gen.au8Node[1] & 0xf];
+    pszString[29] = s_achDigits[pUuid->Gen.au8Node[2] >> 4];
+    pszString[30] = s_achDigits[pUuid->Gen.au8Node[2] & 0xf];
+    pszString[31] = s_achDigits[pUuid->Gen.au8Node[3] >> 4];
+    pszString[32] = s_achDigits[pUuid->Gen.au8Node[3] & 0xf];
+    pszString[33] = s_achDigits[pUuid->Gen.au8Node[4] >> 4];
+    pszString[34] = s_achDigits[pUuid->Gen.au8Node[4] & 0xf];
+    pszString[35] = s_achDigits[pUuid->Gen.au8Node[5] >> 4];
+    pszString[36] = s_achDigits[pUuid->Gen.au8Node[5] & 0xf];
+    pszString[37] = '}';
+    pszString[38] = '\0';
+
+    return pszString;
+
+}
+
+
+/**
+ * Sets a registry string value, wide char variant.
  *
  * @returns See RegSetValueExA (errors are remembered in the state).
  * @param   pState              The registry modifier state.
- * @param   hKey                The key to add the value to.
+ * @param   hkey                The key to add the value to.
+ * @param   pwszValueNm         The value name. NULL for setting the default.
+ * @param   pwszValue           The value string.
+ * @param   uLine               The line we're called from.
+ */
+static LSTATUS vbpsSetRegValueWW(VBPSREGSTATE *pState, HKEY hkey, PCRTUTF16 pwszValueNm, PCRTUTF16 pwszValue, unsigned uLine)
+{
+    DWORD const cbValue = (DWORD)((RTUtf16Len(pwszValue) + 1) * sizeof(RTUTF16));
+    LSTATUS rc;
+    Assert(pState->fUpdate);
+
+    /*
+     * If we're not deleting the key prior to updating, we're in gentle update
+     * mode where we will query if the existing value matches the incoming one.
+     */
+    if (!pState->fDelete)
+    {
+        DWORD       cbExistingData   = cbValue + 128;
+        PRTUTF16    pwszExistingData = (PRTUTF16)alloca(cbExistingData);
+        DWORD       dwExistingType;
+        rc = RegQueryValueExW(hkey, pwszValueNm, 0 /*Reserved*/, &dwExistingType, (BYTE *)pwszExistingData, &cbExistingData);
+        if (rc == ERROR_SUCCESS)
+        {
+            if (   dwExistingType == REG_SZ
+                && cbExistingData == cbValue)
+            {
+                if (memcmp(pwszValue, pwszExistingData, cbValue) == 0)
+                    return ERROR_SUCCESS;
+            }
+            VBSP_LOG_VALUE_CHANGE(("vbpsSetRegValueWW: Value difference: dwExistingType=%d cbExistingData=%#x cbValue=%#x\n"
+                                   " hkey=%#x %ls; value name=%ls\n"
+                                   "existing: %.*Rhxs (%.*ls)\n"
+                                   "     new: %.*Rhxs (%ls)\n",
+                                   dwExistingType, cbExistingData, cbValue,
+                                   hkey, vbpsDebugKeyToWSZ(hkey), pwszValueNm ? pwszValueNm : L"(default)",
+                                   cbExistingData, pwszExistingData, cbExistingData / sizeof(RTUTF16), pwszExistingData,
+                                   cbValue, pwszValue, pwszValue));
+        }
+        else
+            Assert(rc == ERROR_FILE_NOT_FOUND || rc == ERROR_MORE_DATA);
+    }
+
+    /*
+     * Set the value.
+     */
+    rc = RegSetValueExW(hkey, pwszValueNm, 0 /*Reserved*/, REG_SZ, (const BYTE *)pwszValue, cbValue);
+    if (rc == ERROR_SUCCESS)
+    {
+        VBSP_LOG_SET_VALUE(("vbpsSetRegValueWW: %ls/%ls=%ls (at %d)\n",
+                            vbpsDebugKeyToWSZ(hkey), pwszValueNm ? pwszValueNm : L"(Default)", pwszValue, uLine));
+        return ERROR_SUCCESS;
+    }
+
+    AssertMsgFailed(("%d: '%ls'='%ls' -> %u\n", uLine, pwszValueNm, pwszValue, rc));
+    pState->rc = rc;
+    return rc;
+}
+
+
+/**
+ * Sets a registry string value.
+ *
+ * @returns See RegSetValueExA (errors are remembered in the state).
+ * @param   pState              The registry modifier state.
+ * @param   hkey                The key to add the value to.
  * @param   pszValueNm          The value name. NULL for setting the default.
  * @param   pszValue            The value string.
  * @param   uLine               The line we're called from.
  */
-static LSTATUS vbpsSetRegValueAA(VBPSREGSTATE *pState, HKEY hKey, const char *pszValueNm, const char *pszValue, unsigned uLine)
-{
-    LSTATUS rc = RegSetValueExA(hKey, pszValueNm, 0 /*Reserved*/, REG_SZ, pszValue, (DWORD)strlen(pszValue) + 1);
+static LSTATUS vbpsSetRegValueAA(VBPSREGSTATE *pState, HKEY hkey, const char *pszValueNm, const char *pszValue, unsigned uLine)
+{
+    DWORD const cbValue = (DWORD)strlen(pszValue) + 1;
+    LSTATUS rc;
+    Assert(pState->fUpdate);
+
+    /*
+     * If we're not deleting the key prior to updating, we're in gentle update
+     * mode where we will query if the existing value matches the incoming one.
+     */
+    if (!pState->fDelete)
+    {
+        DWORD cbExistingData = cbValue + 128;
+        char *pszExistingData = alloca(cbExistingData);
+        DWORD dwExistingType;
+        rc = RegQueryValueExA(hkey, pszValueNm, 0 /*Reserved*/, &dwExistingType, pszExistingData, &cbExistingData);
+        if (rc == ERROR_SUCCESS)
+        {
+            if (   dwExistingType == REG_SZ
+                && cbExistingData == cbValue)
+            {
+                if (memcmp(pszValue, pszExistingData, cbValue) == 0)
+                    return ERROR_SUCCESS;
+                if (memicmp(pszValue, pszExistingData, cbValue) == 0)
+                    return ERROR_SUCCESS;
+            }
+            VBSP_LOG_VALUE_CHANGE(("vbpsSetRegValueAA: Value difference: dwExistingType=%d cbExistingData=%#x cbValue=%#x\n"
+                                   " hkey=%#x %ls; value name=%s\n"
+                                   "existing: %.*Rhxs (%.*s)\n"
+                                   "     new: %.*Rhxs (%s)\n",
+                                   dwExistingType, cbExistingData, cbValue,
+                                   hkey, vbpsDebugKeyToWSZ(hkey), pszValueNm ? pszValueNm : "(default)",
+                                   cbExistingData, pszExistingData, cbExistingData, pszExistingData,
+                                   cbValue, pszValue, pszValue));
+        }
+        else
+            Assert(rc == ERROR_FILE_NOT_FOUND || rc == ERROR_MORE_DATA);
+    }
+
+    /*
+     * Set the value.
+     */
+    rc = RegSetValueExA(hkey, pszValueNm, 0 /*Reserved*/, REG_SZ, pszValue, cbValue);
+    if (rc == ERROR_SUCCESS)
+    {
+        VBSP_LOG_SET_VALUE(("vbpsSetRegValueAA: %ls/%s=%s (at %d)\n",
+                            vbpsDebugKeyToWSZ(hkey), pszValueNm ? pszValueNm : "(Default)", pszValue, uLine));
+        return ERROR_SUCCESS;
+    }
+
+    AssertMsgFailed(("%d: '%s'='%s' -> %u\n", uLine, pszValueNm, pszValue, rc));
+    pState->rc = rc;
+    return rc;
+}
+
+
+/**
+ * Closes a registry key.
+ *
+ * @returns See RegCloseKey (errors are remembered in the state).
+ * @param   pState              The registry modifier state.
+ * @param   hkey                The key to close.
+ * @param   uLine               The line we're called from.
+ */
+static LSTATUS vbpsCloseKey(VBPSREGSTATE *pState, HKEY hkey, unsigned uLine)
+{
+    LSTATUS rc = RegCloseKey(hkey);
     if (rc == ERROR_SUCCESS)
         return ERROR_SUCCESS;
-    AssertMsgFailed(("%d: '%s'='%s' -> %u\n", uLine, pszValueNm, pszValue, rc));
-    return pState->rc = rc;
-}
+
+    AssertMsgFailed(("%d: close key -> %u\n", uLine, rc));
+    pState->rc = rc;
+    return rc;
+}
+
 
 /**
@@ -397,21 +754,29 @@
  *          state).
  * @param   pState              The registry modifier state.
- * @param   hKeyParent          The parent key.
- * @param   pszKey              The new key under @a hKeyParent.
- * @param   phKey               Where to return the handle to the new key.
+ * @param   hkeyParent          The parent key.
+ * @param   pszKey              The new key under @a hkeyParent.
+ * @param   phkey               Where to return the handle to the new key.
  * @param   uLine               The line we're called from.
  */
-static LSTATUS vbpsCreateRegKeyA(VBPSREGSTATE *pState, HKEY hKeyParent, const char *pszKey, PHKEY phKey, unsigned uLine)
-{
+static LSTATUS vbpsCreateRegKeyA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey, PHKEY phkey, unsigned uLine)
+{
+    /*
+     * This will open if it exists and create if new, which is exactly what we want.
+     */
     HKEY hNewKey;
-    LSTATUS rc = RegCreateKeyExA(hKeyParent, pszKey, 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
-                                 pState->fSamBoth, NULL /*pSecAttr*/, &hNewKey, NULL /*pdwDisposition*/);
+    DWORD dwDisposition = 0;
+    LSTATUS rc = RegCreateKeyExA(hkeyParent, pszKey, 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
+                                 pState->fSamBoth, NULL /*pSecAttr*/, &hNewKey, &dwDisposition);
     if (rc == ERROR_SUCCESS)
-        *phKey = hNewKey;
+    {
+        *phkey = hNewKey;
+        if (dwDisposition == REG_CREATED_NEW_KEY)
+            VBSP_LOG_NEW_KEY(("vbpsCreateRegKeyA: %ls/%s (at %d)\n", vbpsDebugKeyToWSZ(hkeyParent), pszKey, uLine));
+    }
     else
     {
         AssertMsgFailed(("%d: create key '%s' -> %u\n", uLine, pszKey,  rc));
         pState->rc = rc;
-        *phKey = NULL;
+        *phkey = NULL;
     }
     return rc;
@@ -425,18 +790,18 @@
  *          state).
  * @param   pState              The registry modifier state.
- * @param   hKeyParent          The parent key.
- * @param   pszKey              The new key under @a hKeyParent.
+ * @param   hkeyParent          The parent key.
+ * @param   pszKey              The new key under @a hkeyParent.
  * @param   pszValue            The value string.
  * @param   uLine               The line we're called from.
  */
-static LSTATUS vbpsCreateRegKeyWithDefaultValueAA(VBPSREGSTATE *pState, HKEY hKeyParent, const char *pszKey,
+static LSTATUS vbpsCreateRegKeyWithDefaultValueAA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
                                                   const char *pszValue, unsigned uLine)
 {
     HKEY hNewKey;
-    LSTATUS rc = vbpsCreateRegKeyA(pState, hKeyParent, pszKey, &hNewKey, uLine);
+    LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
     if (rc == ERROR_SUCCESS)
     {
         rc = vbpsSetRegValueAA(pState, hNewKey, NULL /*pszValueNm*/, pszValue, uLine);
-        RegCloseKey(hNewKey);
+        vbpsCloseKey(pState, hNewKey, uLine);
     }
     else
@@ -450,24 +815,54 @@
 
 /**
- * Creates a registry key with a default string value, return the key.
+ * Creates a registry key with a default wide string value.
  *
  * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
  *          state).
  * @param   pState              The registry modifier state.
- * @param   hKeyParent          The parent key.
- * @param   pszKey              The new key under @a hKeyParent.
+ * @param   hkeyParent          The parent key.
+ * @param   pszKey              The new key under @a hkeyParent.
+ * @param   pwszValue           The value string.
+ * @param   uLine               The line we're called from.
+ */
+static LSTATUS vbpsCreateRegKeyWithDefaultValueAW(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
+                                                  PCRTUTF16 pwszValue, unsigned uLine)
+{
+    HKEY hNewKey;
+    LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
+    if (rc == ERROR_SUCCESS)
+    {
+        rc = vbpsSetRegValueWW(pState, hNewKey, NULL /*pwszValueNm*/, pwszValue, uLine);
+        vbpsCloseKey(pState, hNewKey, uLine);
+    }
+    else
+    {
+        AssertMsgFailed(("%d: create key '%s'(/Default='%ls') -> %u\n", uLine, pszKey, pwszValue, rc));
+        pState->rc = rc;
+    }
+    return rc;
+}
+
+
+/**
+ * Creates a registry key with a default string value, return the key.
+ *
+ * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
+ *          state).
+ * @param   pState              The registry modifier state.
+ * @param   hkeyParent          The parent key.
+ * @param   pszKey              The new key under @a hkeyParent.
  * @param   pszValue            The value string.
- * @param   phKey               Where to return the handle to the new key.
+ * @param   phkey               Where to return the handle to the new key.
  * @param   uLine               The line we're called from.
  */
-static LSTATUS vbpsCreateRegKeyWithDefaultValueAAEx(VBPSREGSTATE *pState, HKEY hKeyParent, const char *pszKey,
-                                                    const char *pszValue, PHKEY phKey, unsigned uLine)
+static LSTATUS vbpsCreateRegKeyWithDefaultValueAAEx(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
+                                                    const char *pszValue, PHKEY phkey, unsigned uLine)
 {
     HKEY hNewKey;
-    LSTATUS rc = vbpsCreateRegKeyA(pState, hKeyParent, pszKey, &hNewKey, uLine);
+    LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
     if (rc == ERROR_SUCCESS)
     {
         rc = vbpsSetRegValueAA(pState, hNewKey, NULL /*pszValueNm*/, pszValue, uLine);
-        *phKey = hNewKey;
+        *phkey = hNewKey;
     }
     else
@@ -475,6 +870,34 @@
         AssertMsgFailed(("%d: create key '%s'(/Default='%s') -> %u\n", uLine, pszKey, pszValue, rc));
         pState->rc = rc;
-        *phKey = NULL;
-    }
+        *phkey = NULL;
+    }
+    return rc;
+}
+
+
+/**
+ * Recursively deletes a registry key.
+ *
+ * @returns See SHDeleteKeyA (errors are remembered in the state).
+ * @param   pState              The registry modifier state.
+ * @param   hkeyParent          The parent key.
+ * @param   pszKey              The key under @a hkeyParent that should be
+ *                              deleted.
+ * @param   uLine               The line we're called from.
+ */
+static LSTATUS vbpsDeleteKeyRecursiveA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey, unsigned uLine)
+{
+    LSTATUS rc;
+
+    Assert(pState->fDelete);
+    Assert(pszKey);
+    AssertReturn(*pszKey != '\0', pState->rc = ERROR_INVALID_PARAMETER);
+
+    rc = SHDeleteKeyA(hkeyParent, pszKey);
+    if (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND)
+        return ERROR_SUCCESS;
+
+    AssertMsgFailed(("%d: delete key '%s' -> %u\n", uLine, pszKey, rc));
+    pState->rc = rc;
     return rc;
 }
@@ -495,14 +918,19 @@
     Assert(*pszAppId == '{');
 
-    /* Always unregister. */
-    if (pState->hkeyAltClassesRootsUnreg)
-    {
-        rc = RegOpenKeyExW(pState->hkeyAltClassesRootsUnreg, L"AppID", 0 /*fOptions*/, pState->fSamUnreg, &hkeyAppIds);
-        AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-        if (rc == ERROR_SUCCESS)
+    /*
+     * Delete.
+     */
+    if (pState->fDelete)
+    {
+        unsigned i = pState->cAltDeletes;
+        while (i-- > 0)
         {
-            rc = SHDeleteKeyA(hkeyAppIds, pszAppId);
+            rc = RegOpenKeyExW(pState->aAltDeletes[i].hkeyClasses, L"AppID", 0 /*fOptions*/, pState->fSamDelete, &hkeyAppIds);
             AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-            RegCloseKey(hkeyAppIds);
+            if (rc == ERROR_SUCCESS)
+            {
+                vbpsDeleteKeyRecursiveA(pState, hkeyAppIds, pszAppId, __LINE__);
+                vbpsCloseKey(pState, hkeyAppIds, __LINE__);
+            }
         }
     }
@@ -510,15 +938,15 @@
     rc = RegOpenKeyExW(pState->hkeyClassesRootDst, L"AppID", 0 /*fOptions*/, pState->fSamBoth, &hkeyAppIds);
     AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-    if (rc == ERROR_SUCCESS)
-    {
-        rc = SHDeleteKeyA(hkeyAppIds, pszAppId);
-        AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-    }
-
-    /* Register */
-    if (!pState->fUnregisterOnly)
+
+    if (pState->fDelete)
+        vbpsDeleteKeyRecursiveA(pState, hkeyAppIds, pszAppId, __LINE__);
+
+    /*
+     * Update.
+     */
+    if (pState->fUpdate)
         vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyAppIds, pszAppId, pszDescription, __LINE__);
 
-    RegCloseKey(hkeyAppIds);
+    vbpsCloseKey(pState, hkeyAppIds, __LINE__);
 
     return pState->rc;
@@ -544,20 +972,19 @@
 
     /*
-     * Always unregister.
-     */
-    if (pState->hkeyAltClassesRootsUnreg)
-    {
-        rc = SHDeleteKeyA(pState->hkeyAltClassesRootsUnreg, pszClassName);
-        AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-    }
-
-    rc = SHDeleteKeyA(pState->hkeyClassesRootDst, pszClassName);
-    AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-
-    if (!pState->fUnregisterOnly)
-    {
-        /*
-         * Register
-         */
+     * Delete.
+     */
+    if (pState->fDelete)
+    {
+        unsigned i = pState->cAltDeletes;
+        while (i-- > 0)
+            vbpsDeleteKeyRecursiveA(pState, pState->aAltDeletes[i].hkeyClasses, pszClassName, __LINE__);
+        vbpsDeleteKeyRecursiveA(pState, pState->hkeyClassesRootDst, pszClassName, __LINE__);
+    }
+
+    /*
+     * Update.
+     */
+    if (pState->fUpdate)
+    {
         /* pszClassName/Default = description. */
         HKEY hkeyClass;
@@ -569,8 +996,5 @@
 
             /* CLSID/Default = pClsId. */
-            rc = vbpsFormatUuidInCurly(szClsId, pClsId);
-            AssertMsgStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-            if (rc == ERROR_SUCCESS)
-                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "CLSID", szClsId, __LINE__);
+            vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "CLSID", vbpsFormatUuidInCurly(szClsId, pClsId), __LINE__);
 
             /* CurVer/Default = pszClassName+Suffix. */
@@ -586,5 +1010,5 @@
             }
 
-            RegCloseKey(hkeyClass);
+            vbpsCloseKey(pState, hkeyClass, __LINE__);
         }
     }
@@ -623,39 +1047,29 @@
     LSTATUS rc;
     char szClsId[CURLY_UUID_STR_BUF_SIZE];
-    char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
 
     Assert(!pszAppId || *pszAppId == '{');
-    Assert((pwszVBoxDir == NULL && pState->fUnregisterOnly) || pwszVBoxDir[RTUtf16Len(pwszVBoxDir) - 1] == '\\');
-
-    /*
-     * Format the UUID first to get it over with.  We always need CLSID.
-     */
-    rc = vbpsFormatUuidInCurly(szClsId, pClsId);
-    AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-    if (pTypeLibId)
-    {
-        rc = vbpsFormatUuidInCurly(szTypeLibId, pTypeLibId);
-        AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-    }
-    else
-        szTypeLibId[0] = '\0';
-
-    /*
-     * Always unregister.
-     */
-    if (pState->hkeyAltClsidRootsUnreg)
-    {
-        rc = SHDeleteKeyA(pState->hkeyAltClsidRootsUnreg, szClsId);
-        AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-    }
-
-    rc = SHDeleteKeyA(pState->hkeyClsidRootDst, szClsId);
-    AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
-
-    if (!pState->fUnregisterOnly)
-    {
-        /*
-         * Register
-         */
+    Assert((pwszVBoxDir == NULL && !pState->fUpdate) || pwszVBoxDir[RTUtf16Len(pwszVBoxDir) - 1] == '\\');
+
+    /*
+     * We need this, whatever we end up having to do.
+     */
+    vbpsFormatUuidInCurly(szClsId, pClsId);
+
+    /*
+     * Delete.
+     */
+    if (pState->fDelete)
+    {
+        unsigned i = pState->cAltDeletes;
+        while (i-- > 0)
+            vbpsDeleteKeyRecursiveA(pState, pState->aAltDeletes[i].hkeyClsid, szClsId, __LINE__);
+        vbpsDeleteKeyRecursiveA(pState, pState->hkeyClsidRootDst, szClsId, __LINE__);
+    }
+
+    /*
+     * Update.
+     */
+    if (pState->fUpdate)
+    {
         HKEY hkeyClass;
         rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, pState->hkeyClsidRootDst, szClsId, pszDescription,
@@ -685,7 +1099,5 @@
                 *pwszCur++ = '\0';      /* included, so ++. */
 
-                rc = RegSetValueExW(hkeyServerType, NULL /*pszValueNm*/, 0 /*Reserved*/,
-                                    REG_SZ, (const BYTE *)&wszModule[0], (DWORD)((uintptr_t)pwszCur - (uintptr_t)&wszModule[0]));
-                AssertMsgStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
+                vbpsSetRegValueWW(pState, hkeyServerType, NULL /*pszValueNm*/, wszModule, __LINE__);
 
                 /* pszServerType/ThreadingModel = pszThreading Model. */
@@ -693,5 +1105,5 @@
                     vbpsSetRegValueAA(pState, hkeyServerType, "ThreadingModel", pszThreadingModel, __LINE__);
 
-                RegCloseKey(hkeyServerType);
+                vbpsCloseKey(pState, hkeyServerType, __LINE__);
             }
 
@@ -712,7 +1124,11 @@
             /* TypeLib/Default = pTypeLibId. */
             if (pTypeLibId)
-                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "TypeLib", szTypeLibId, __LINE__);
-
-            RegCloseKey(hkeyClass);
+            {
+                char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
+                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "TypeLib",
+                                                   vbpsFormatUuidInCurly(szTypeLibId, pTypeLibId), __LINE__);
+            }
+
+            vbpsCloseKey(pState, hkeyClass, __LINE__);
         }
     }
@@ -754,153 +1170,273 @@
                         "VirtualBox.VirtualBoxClient", ".1",
                         &LIBID_VirtualBox, "InprocServer32", pwszVBoxDir, pszInprocDll, "Free");
-
-}
-
-#ifndef VBOX_PROXY_STUB_32_ON_64
-void RegisterOtherProxyStubAndTypelibDll(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
-{
-    if (!pState->fUnregisterOnly)
-    {
-        const char *pszWinXx = !fIs32On64 ? "win64"             : "win32";
-        const char *pszPsDll = !fIs32On64 ? "VBoxProxyStub.dll" : "VBoxProxyStub-x86.dll";
-        char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
+}
+
+
+/**
+ * Updates the VBox type lib registration.
+ *
+ * This is only used when updating COM registrations during com::Initialize.
+ * For normal registration and unregistrations we use the RegisterTypeLib and
+ * UnRegisterTypeLib APIs.
+ *
+ * @param   pState              The registry modifier state.
+ * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
+ *                              trailing slash.
+ * @param   fIs32On64           Set if we're registering the 32-bit proxy stub
+ *                              on a 64-bit system.
+ */
+static void vbpsUpdateTypeLibRegistration(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
+{
+    const char * const pszTypeLibDll = !fIs32On64 ? "VBoxProxyStub.dll" : "x86\\VBoxProxyStub-x86.dll";
+    const char * const pszWinXx      = !fIs32On64 ? "win64"             : "win32";
+    const char * const pszDescription = "VirtualBox Type Library";
+
+    char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
+    HKEY hkeyTypeLibs;
+    HKEY hkeyTypeLibId;
+    LSTATUS rc;
+
+    Assert(pState->fUpdate && !pState->fDelete);
+
+    /*
+     * Type library registration (w/o interfaces).
+     */
+
+    /* Open Classes/TypeLib/. */
+    rc = vbpsCreateRegKeyA(pState, pState->hkeyClassesRootDst, "TypeLib", &hkeyTypeLibs, __LINE__);
+    AssertReturnVoid(rc == ERROR_SUCCESS);
+
+    /* Create TypeLib/{UUID}. */
+    rc = vbpsCreateRegKeyA(pState, hkeyTypeLibs, vbpsFormatUuidInCurly(szTypeLibId, &LIBID_VirtualBox), &hkeyTypeLibId, __LINE__);
+    if (rc == ERROR_SUCCESS)
+    {
+        /* {UUID}/Major.Minor/Default = pszDescription. */
+        HKEY hkeyMajMin;
         char szMajMin[64];
-        HKEY hKeyTypeLibs;
-        HKEY hKeyTypeLibId;
-        HKEY hKeyMajMin;
-        HKEY hKey0;
-        HKEY hKeyWinXx;
-        LSTATUS rc;
-
-        /* Proxy stub factory class ID. */
-        VbpsRegisterClassId(pState, &g_ProxyClsId, "PSFactoryBuffer", NULL /*pszAppId*/,
-                            NULL /*pszClassName*/, NULL /*pszCurClassNameVerSuffix*/, NULL /*pTypeLibId*/,
-                            "InprocServer32", pwszVBoxDir, pszPsDll, "Both");
-
-        /*
-         * Typelib DLL.
-         */
-        rc = vbpsFormatUuidInCurly(szTypeLibId, &LIBID_VirtualBox);
-        AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-
-        rc = RegOpenKeyExA(pState->hkeyClassesRootDst, "TypeLib", 0 /*fOptions*/, pState->fSamBoth, &hKeyTypeLibs);
-        AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-        rc = RegOpenKeyExA(hKeyTypeLibs, szTypeLibId, 0 /*fOptions*/, pState->fSamBoth, &hKeyTypeLibId);
-        if (rc == ERROR_FILE_NOT_FOUND)
-            rc = vbpsCreateRegKeyA(pState, hKeyTypeLibs, szTypeLibId, &hKeyTypeLibId, __LINE__);
-        RegCloseKey(hKeyTypeLibs);
-
-        AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-
-        /* Major.Minor/Default = Name. */
         sprintf(szMajMin, "%u.%u", kTypeLibraryMajorVersion, kTypeLibraryMinorVersion);
-        rc = RegOpenKeyExA(hKeyTypeLibId, szMajMin, 0 /*fOptions*/, pState->fSamBoth, &hKeyMajMin);
-        if (rc == ERROR_FILE_NOT_FOUND)
-            rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, hKeyTypeLibId, szMajMin, "VirtualBox Type Library",
-                                                      &hKeyMajMin, __LINE__);
-        RegCloseKey(hKeyTypeLibId);
-        AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-
-        /* 0/. */
-        rc = RegOpenKeyExA(hKeyMajMin, "0", 0 /*fOptions*/, pState->fSamBoth, &hKey0);
-        if (rc == ERROR_FILE_NOT_FOUND)
-            rc = vbpsCreateRegKeyA(pState, hKeyMajMin, "0", &hKey0, __LINE__);
-        RegCloseKey(hKeyMajMin);
-        AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-
-        /* winXx/Default = VBoxProxyStub. */
-        rc = RegOpenKeyExA(hKey0, pszWinXx, 0 /*fOptions*/, pState->fSamBoth, &hKeyWinXx);
-        if (rc == ERROR_FILE_NOT_FOUND)
+        rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, hkeyTypeLibId, szMajMin, pszDescription, &hkeyMajMin, __LINE__);
+        if (rc == ERROR_SUCCESS)
         {
-            RTUTF16 wszDllPath[MAX_PATH * 2];
-
-            rc = RTUtf16Copy(wszDllPath, MAX_PATH, pwszVBoxDir); AssertRC(rc);
-            rc = RTUtf16CatAscii(wszDllPath, MAX_PATH * 2, pszPsDll); AssertRC(rc);
-
-            rc = vbpsCreateRegKeyA(pState, hKey0, pszWinXx, &hKeyWinXx, __LINE__);
+            RTUTF16 wszBuf[MAX_PATH * 2];
+            size_t  off;
+
+            /* {UUID}/Major.Minor/0. */
+            HKEY hkey0;
+            rc = vbpsCreateRegKeyA(pState, hkeyMajMin, "0", &hkey0, __LINE__);
             if (rc == ERROR_SUCCESS)
             {
-                rc = RegSetValueExW(hKeyWinXx, NULL /*pszValueNm*/, 0 /*Reserved*/,
-                                    REG_SZ, (const BYTE *)&wszDllPath[0], (DWORD)((RTUtf16Len(wszDllPath) + 1 )* 2));
-                AssertMsgStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
+                /* {UUID}/Major.Minor/0/winXX/Default = VBoxProxyStub. */
+                rc = RTUtf16Copy(wszBuf, MAX_PATH, pwszVBoxDir); AssertRC(rc);
+                rc = RTUtf16CatAscii(wszBuf, MAX_PATH * 2, pszTypeLibDll); AssertRC(rc);
+
+                vbpsCreateRegKeyWithDefaultValueAW(pState, hkey0, pszWinXx, wszBuf, __LINE__);
+                vbpsCloseKey(pState, hkey0, __LINE__);
+            }
+
+            /* {UUID}/Major.Minor/FLAGS */
+            vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyMajMin, "FLAGS", "0", __LINE__);
+
+            /* {UUID}/Major.Minor/HELPDIR */
+            rc = RTUtf16Copy(wszBuf, MAX_PATH, pwszVBoxDir); AssertRC(rc);
+            off = RTUtf16Len(wszBuf);
+            while (off > 2 && wszBuf[off - 2] != ':' && RTPATH_IS_SLASH(wszBuf[off - 1]))
+                off--;
+            wszBuf[off] = '\0';
+            vbpsCreateRegKeyWithDefaultValueAW(pState, hkeyMajMin, "HELPDIR", wszBuf, __LINE__);
+
+            vbpsCloseKey(pState, hkeyMajMin, __LINE__);
+        }
+        vbpsCloseKey(pState, hkeyTypeLibId, __LINE__);
+    }
+    vbpsCloseKey(pState, hkeyTypeLibs, __LINE__);
+}
+
+
+/**
+ * Update the VBox proxy stub registration.
+ *
+ * This is only used when updating COM registrations during com::Initialize.
+ * For normal registration and unregistrations we use the NdrDllRegisterProxy
+ * and NdrDllUnregisterProxy.
+ *
+ * @param   pState              The registry modifier state.
+ * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
+ *                              trailing slash.
+ * @param   fIs32On64           Set if we're registering the 32-bit proxy stub
+ *                              on a 64-bit system.
+ */
+static void vbpsUpdateProxyStubRegistration(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
+{
+    /*
+     * Register the proxy stub factory class ID.
+     * It's simple compared to the VBox classes, thus all the NULL parameters.
+     */
+    const char *pszPsDll = !fIs32On64 ? "VBoxProxyStub.dll" : "x86\\VBoxProxyStub-x86.dll";
+    Assert(pState->fUpdate && !pState->fDelete);
+    VbpsRegisterClassId(pState, &g_ProxyClsId, "PSFactoryBuffer", NULL /*pszAppId*/,
+                        NULL /*pszClassName*/, NULL /*pszCurClassNameVerSuffix*/, NULL /*pTypeLibId*/,
+                        "InprocServer32", pwszVBoxDir, pszPsDll, "Both");
+}
+
+
+/**
+ * Updates the VBox interface registrations.
+ *
+ * This is only used when updating COM registrations during com::Initialize.
+ * For normal registration and unregistrations we use the NdrDllRegisterProxy
+ * and NdrDllUnregisterProxy.
+ *
+ * @param   pState              The registry modifier state.
+ * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
+ *                              trailing slash.
+ * @param   fIs32On64           Set if we're registering the 32-bit proxy stub
+ *                              on a 64-bit system.
+ */
+static void vbpsUpdateInterfaceRegistrations(VBPSREGSTATE *pState)
+{
+    const ProxyFileInfo **ppProxyFile = &g_apProxyFiles[0];
+    const ProxyFileInfo  *pProxyFile;
+    LSTATUS               rc;
+    char                  szProxyClsId[CURLY_UUID_STR_BUF_SIZE];
+
+    vbpsFormatUuidInCurly(szProxyClsId, &g_ProxyClsId);
+
+    Assert(pState->fUpdate && !pState->fDelete);
+    rc = vbpsRegOpenInterfaceKeys(pState);
+    AssertReturnVoid(rc == ERROR_SUCCESS);
+
+    /*
+     * We walk the proxy file list (even if we only have one).
+     */
+    while ((pProxyFile = *ppProxyFile++) != NULL)
+    {
+        const PCInterfaceStubVtblList * const   papStubVtbls  = pProxyFile->pStubVtblList;
+        const char * const                     *papszNames    = pProxyFile->pNamesArray;
+        unsigned                                iIf           = pProxyFile->TableSize;
+        AssertStmt(iIf < 1024, iIf = 0);
+        Assert(pProxyFile->TableVersion == 2);
+
+        /*
+         * Walk the interfaces in that file, picking data from the various tables.
+         */
+        while (iIf-- > 0)
+        {
+            char                szIfId[CURLY_UUID_STR_BUF_SIZE];
+            const char * const  pszIfNm  = papszNames[iIf];
+            size_t const        cchIfNm  = RT_VALID_PTR(pszIfNm) ? strlen(pszIfNm) : 0;
+            char                szMethods[32];
+            uint32_t const      cMethods = papStubVtbls[iIf]->header.DispatchTableCount;
+            HKEY                hkeyIfId;
+
+            AssertReturnVoidStmt(cchIfNm >= 3 && cchIfNm <= 72, pState->rc = ERROR_INVALID_DATA);
+
+            AssertReturnVoidStmt(cMethods >= 3 && cMethods < 1024, pState->rc = ERROR_INVALID_DATA);
+            sprintf(szMethods, "%u", cMethods);
+
+            AssertReturnVoid(rc == ERROR_SUCCESS);
+
+            rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, pState->hkeyInterfaceRootDst,
+                                                      vbpsFormatUuidInCurly(szIfId, papStubVtbls[iIf]->header.piid),
+                                                      pszIfNm, &hkeyIfId, __LINE__);
+            if (rc == ERROR_SUCCESS)
+            {
+                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyIfId, "ProxyStubClsid32", szProxyClsId, __LINE__);
+                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyIfId, "NumMethods", szMethods, __LINE__);
+                /** @todo Not having the typelib here means we'll have to fix the orphan cleanup
+                 *        code below. */
+
+                vbpsCloseKey(pState, hkeyIfId, __LINE__);
             }
         }
-        RegCloseKey(hKey0);
-        AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
-        RegCloseKey(hKeyWinXx);
-    }
-
-}
+    }
+}
+
+
+static bool vbpsIsUpToDate(VBPSREGSTATE *pState)
+{
+    /** @todo read some registry key and */
+    NOREF(pState);
+    return false;
+}
+
+static bool vbpsMarkUpToDate(VBPSREGSTATE *pState)
+{
+    /** @todo write the key vbpsIsUpToDate uses, if pState indicates success. */
+    NOREF(pState);
+    return false;
+}
+
+
+
+/**
+ * Strips the stub dll name and any x86 subdir off the full DLL path to get a
+ * path to the VirtualBox application directory.
+ *
+ * @param   pwszDllPath     The path to strip, returns will end with a slash.
+ */
+static void vbpsDllPathToVBoxDir(PRTUTF16 pwszDllPath)
+{
+    RTUTF16 wc;
+    size_t off = RTUtf16Len(pwszDllPath);
+    while (   off > 0
+           && (   (wc = pwszDllPath[off - 1]) >= 127U
+               || !RTPATH_IS_SEP((unsigned char)wc)))
+        off--;
+
+#ifdef VBOX_IN_32_ON_64_MAIN_API
+    /*
+     * The -x86 variant is in a x86 subdirectory, drop it.
+     */
+    while (   off > 0
+           && (   (wc = pwszDllPath[off - 1]) < 127U
+               && RTPATH_IS_SEP((unsigned char)wc)))
+        off--;
+    while (   off > 0
+           && (   (wc = pwszDllPath[off - 1]) >= 127U
+               || !RTPATH_IS_SEP((unsigned char)wc)))
+        off--;
 #endif
-
-
-HRESULT RegisterXidlModulesAndClasses(PRTUTF16 pwszDllName, bool fUnregisterOnly)
-{
-    VBPSREGSTATE State;
-    LSTATUS rc;
-
-    /*
-     * Drop the filename and get the directory containing the DLL.
-     */
-    if (!fUnregisterOnly)
-    {
-        RTUTF16 wc;
-        size_t off = RTUtf16Len(pwszDllName);
-        while (   off > 0
-               && (   (wc = pwszDllName[off - 1]) >= 127U
-                   || !RTPATH_IS_SEP((unsigned char)wc)))
-            off--;
-#ifdef VBOX_PROXY_STUB_32_ON_64
-        /* The -x86 variant is in a x86 subdirectory, drop it. */
-        while (   off > 0
-               && (   (wc = pwszDllName[off - 1]) < 127U
-                   && RTPATH_IS_SEP((unsigned char)wc)))
-            off--;
-        while (   off > 0
-               && (   (wc = pwszDllName[off - 1]) >= 127U
-                   || !RTPATH_IS_SEP((unsigned char)wc)))
-            off--;
+    pwszDllPath[off] = '\0';
+}
+
+
+/**
+ * Wrapper around RegisterXidlModulesAndClassesGenerated for the convenience of
+ * the standard registration entry points.
+ *
+ * @returns COM status code.
+ * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
+ *                              trailing slash.
+ * @param   fDelete             Whether to delete registration keys and values.
+ * @param   fUpdate             Whether to update registration keys and values.
+ */
+HRESULT RegisterXidlModulesAndClasses(PRTUTF16 pwszVBoxDir, bool fDelete, bool fUpdate)
+{
+#ifdef VBOX_IN_32_ON_64_MAIN_API
+    bool const      fIs32On64 = true;
+#else
+    bool const      fIs32On64 = false;
 #endif
-        pwszDllName[off] = '\0';
-    }
+    VBPSREGSTATE    State;
+    LSTATUS         rc;
 
     /*
      * Do registration for the current execution mode of the DLL.
      */
-    rc = vbpsRegInit(&State,
-                     HKEY_CLASSES_ROOT, NULL, "HKCR", /* HKEY_LOCAL_MACHINE, "Software\\Classes", "HKLM\\Software\\Classes", */
-                     HKEY_CURRENT_USER,  "Software\\Classes",
-                     fUnregisterOnly, 0);
+    rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL /* Alt: HKEY_LOCAL_MACHINE, "Software\\Classes", */, fDelete, fUpdate, 0);
     if (rc == ERROR_SUCCESS)
     {
-#ifdef VBOX_PROXY_STUB_32_ON_64
-        RegisterXidlModulesAndClassesGenerated(&State, pwszDllName, true);
-#else
-        RegisterXidlModulesAndClassesGenerated(&State, pwszDllName, false);
-#endif
+        if (!fUpdate)
+        {
+            /* When only unregistering, really purge everything twice or trice. :-) */
+            vbpsRegAddAltDelete(&State, HKEY_LOCAL_MACHINE, "Software\\Classes");
+            vbpsRegAddAltDelete(&State, HKEY_CURRENT_USER,  "Software\\Classes");
+            vbpsRegAddAltDelete(&State, HKEY_CLASSES_ROOT,  NULL);
+        }
+
+        RegisterXidlModulesAndClassesGenerated(&State, pwszVBoxDir, fIs32On64);
         rc = State.rc;
     }
-
     vbpsRegTerm(&State);
-
-#ifndef VBOX_PROXY_STUB_32_ON_64
-    /*
-     * Do the WOW6432Node registrations too.
-     */
-    if (rc == ERROR_SUCCESS)
-    {
-        rc = vbpsRegInit(&State,
-                         HKEY_CLASSES_ROOT, "Wow6432Node", "HKCR\\Wow6432Node",
-                         HKEY_CURRENT_USER, "Software\\Classes",
-                         fUnregisterOnly, KEY_WOW64_32KEY);
-        if (rc == ERROR_SUCCESS)
-        {
-            RegisterXidlModulesAndClassesGenerated(&State, pwszDllName, true);
-            RegisterOtherProxyStubAndTypelibDll(&State, pwszDllName, true);
-            rc = State.rc;
-        }
-        vbpsRegTerm(&State);
-    }
-#endif
 
     /*
@@ -910,91 +1446,4 @@
         return S_OK;
     return E_FAIL;
-}
-
-
-/**
- * Register the interfaces proxied by this DLL, and to avoid duplication and
- * minimize work the VBox type library, classes and servers are also registered.
- *
- * @returns COM status code.
- */
-HRESULT STDAPICALLTYPE DllRegisterServer(void)
-{
-    HRESULT hrc;
-
-    /*
-     * Register the type library first.
-     */
-    ITypeLib *pITypeLib;
-    WCHAR wszDllName[MAX_PATH];
-    DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszDllName, RT_ELEMENTS(wszDllName));
-    AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszDllName), CO_E_PATHTOOLONG);
-
-    hrc = LoadTypeLib(wszDllName, &pITypeLib);
-    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
-    hrc = RegisterTypeLib(pITypeLib, wszDllName, NULL /*pszHelpDir*/);
-    pITypeLib->lpVtbl->Release(pITypeLib);
-    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
-
-    /*
-     * Register proxy stub.
-     */
-    hrc = NdrDllRegisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);         /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
-    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
-
-    /*
-     * Register the VBox modules and classes.
-     */
-    hrc = RegisterXidlModulesAndClasses(wszDllName, false /*fUnregisterOnly*/);
-    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
-
-    return S_OK;
-}
-
-
-/**
- * Reverse of DllRegisterServer.
- *
- * @returns COM status code.
- */
-HRESULT STDAPICALLTYPE DllUnregisterServer(void)
-{
-    HRESULT hrc = S_OK;
-    HRESULT hrc2;
-
-    /*
-     * Unregister the type library.
-     *
-     * We ignore TYPE_E_REGISTRYACCESS as that is what is returned if the
-     * type lib hasn't been registered (W10).
-     */
-    hrc2 = UnRegisterTypeLib(&LIBID_VirtualBox, kTypeLibraryMajorVersion, kTypeLibraryMinorVersion,
-                             0 /*LCid*/, RT_CONCAT(SYS_WIN, ARCH_BITS));
-    AssertMsgStmt(SUCCEEDED(hrc2) || hrc2 == TYPE_E_REGISTRYACCESS, ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
-
-    /*
-     * Unregister the proxy stub.
-     *
-     * We ignore ERROR_FILE_NOT_FOUND as that is returned if not registered (W10).
-     */
-    hrc2 = NdrDllUnregisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);      /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
-    AssertMsgStmt(   SUCCEEDED(hrc2)
-                  || hrc2 == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND),
-                  ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
-
-    /*
-     * Register the VBox modules and classes.
-     */
-    hrc2 = RegisterXidlModulesAndClasses(NULL, true /*fUnregisterOnly*/);
-    AssertMsgStmt(SUCCEEDED(hrc2), ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
-
-#ifdef WITH_MANUAL_CLEANUP
-    /*
-     * Purge old mess.
-     */
-    removeOldMess();
-#endif
-
-    return hrc;
 }
 
@@ -1272,2 +1721,170 @@
 #endif /* WITH_MANUAL_CLEANUP */
 
+
+/**
+ * Register the interfaces proxied by this DLL, and to avoid duplication and
+ * minimize work the VBox type library, classes and servers are also registered.
+ *
+ * This is normally only used by developers via comregister.cmd and the heat.exe
+ * tool during MSI creation.  The only situation where users may end up here is
+ * if they're playing around or we recommend it as a solution to COM problems.
+ * So, no problem if this approach is less gentle, though we leave the cleaning
+ * up of orphaned interfaces to DllUnregisterServer.
+ *
+ * @returns COM status code.
+ */
+HRESULT STDAPICALLTYPE DllRegisterServer(void)
+{
+    HRESULT hrc;
+
+    /*
+     * Register the type library first.
+     */
+    ITypeLib *pITypeLib;
+    WCHAR wszDllName[MAX_PATH];
+    DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszDllName, RT_ELEMENTS(wszDllName));
+    AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszDllName), CO_E_PATHTOOLONG);
+
+    hrc = LoadTypeLib(wszDllName, &pITypeLib);
+    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
+    hrc = RegisterTypeLib(pITypeLib, wszDllName, NULL /*pszHelpDir*/);
+    pITypeLib->lpVtbl->Release(pITypeLib);
+    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
+
+    /*
+     * Register proxy stub.
+     */
+    hrc = NdrDllRegisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);         /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
+    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
+
+    /*
+     * Register the VBox modules and classes.
+     */
+    vbpsDllPathToVBoxDir(wszDllName);
+    hrc = RegisterXidlModulesAndClasses(wszDllName, true /*fDelete*/, true /*fUpdate*/);
+    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
+
+    return S_OK;
+}
+
+
+/**
+ * Reverse of DllRegisterServer.
+ *
+ * This is normally only used by developers via comregister.cmd.  Users may be
+ * asked to perform it in order to fix some COM issue.  So, it's OK if we spend
+ * some extra time and clean up orphaned interfaces, because developer boxes
+ * will end up with a bunch of those as interface UUIDs changes.
+ *
+ * @returns COM status code.
+ */
+HRESULT STDAPICALLTYPE DllUnregisterServer(void)
+{
+    HRESULT hrc = S_OK;
+    HRESULT hrc2;
+
+    /*
+     * Unregister the type library.
+     *
+     * We ignore TYPE_E_REGISTRYACCESS as that is what is returned if the
+     * type lib hasn't been registered (W10).
+     */
+    hrc2 = UnRegisterTypeLib(&LIBID_VirtualBox, kTypeLibraryMajorVersion, kTypeLibraryMinorVersion,
+                             0 /*LCid*/, RT_CONCAT(SYS_WIN, ARCH_BITS));
+    AssertMsgStmt(SUCCEEDED(hrc2) || hrc2 == TYPE_E_REGISTRYACCESS, ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
+
+    /*
+     * Unregister the proxy stub.
+     *
+     * We ignore ERROR_FILE_NOT_FOUND as that is returned if not registered (W10).
+     */
+    hrc2 = NdrDllUnregisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);      /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
+    AssertMsgStmt(   SUCCEEDED(hrc2)
+                  || hrc2 == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND),
+                  ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
+
+    /*
+     * Register the VBox modules and classes.
+     */
+    hrc2 = RegisterXidlModulesAndClasses(NULL, true /*fDelete*/, false /*fUpdate*/);
+    AssertMsgStmt(SUCCEEDED(hrc2), ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
+
+#ifdef WITH_MANUAL_CLEANUP
+    /*
+     * Purge old mess.
+     */
+    removeOldMess();
+#endif
+
+    return hrc;
+}
+
+
+/**
+ * Gently update the COM registrations for VirtualBox.
+ *
+ * API that com::Initialize (VBoxCOM/initterm.cpp) calls the first time COM is
+ * initialized in a process.  ASSUMES that the caller has initialized IPRT.
+ *
+ * @returns Windows error code.
+ */
+DECLEXPORT(uint32_t) VbpsUpdateRegistrations(void)
+{
+    LSTATUS         rc;
+    VBPSREGSTATE    State;
+#ifdef VBOX_IN_32_ON_64_MAIN_API
+    bool const      fIs32On64 = true;
+#else
+    bool const      fIs32On64 = false;
+#endif
+
+    /*
+     * Find the VirtualBox application directory first.
+     */
+    WCHAR wszVBoxDir[MAX_PATH];
+    DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszVBoxDir, RT_ELEMENTS(wszVBoxDir));
+    AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszVBoxDir), ERROR_BUFFER_OVERFLOW);
+    vbpsDllPathToVBoxDir(wszVBoxDir);
+
+    /*
+     * Update registry entries for the current CPU bitness.
+     */
+    rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL, false /*fDelete*/, true /*fUpdate*/, 0);
+    if (rc == ERROR_SUCCESS && !vbpsIsUpToDate(&State))
+    {
+        vbpsUpdateTypeLibRegistration(&State, wszVBoxDir, fIs32On64);
+        vbpsUpdateProxyStubRegistration(&State, wszVBoxDir, fIs32On64);
+        vbpsUpdateInterfaceRegistrations(&State);
+        RegisterXidlModulesAndClassesGenerated(&State, wszVBoxDir, fIs32On64);
+        vbpsMarkUpToDate(&State);
+        rc = State.rc;
+    }
+    vbpsRegTerm(&State);
+
+
+//#if defined(VBOX_IN_32_ON_64_MAIN_API) || (ARCH_BITS == 64 && defined(VBOX_WITH_32_ON_64_MAIN_API))
+#ifndef VBOX_IN_32_ON_64_MAIN_API
+    /*
+     * Update registry entries for the other CPU bitness.
+     */
+    if (rc == ERROR_SUCCESS)
+    {
+        //rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, "Wow6432Node", fDelete, fUpdate, KEY_WOW64_32KEY);
+        rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL, false /*fDelete*/, true /*fUpdate*/,
+                         !fIs32On64 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
+        if (rc == ERROR_SUCCESS && !vbpsIsUpToDate(&State))
+        {
+            vbpsUpdateTypeLibRegistration(&State, wszVBoxDir, !fIs32On64);
+            vbpsUpdateProxyStubRegistration(&State, wszVBoxDir, !fIs32On64);
+            vbpsUpdateInterfaceRegistrations(&State);
+            RegisterXidlModulesAndClassesGenerated(&State, wszVBoxDir, !fIs32On64);
+            vbpsMarkUpToDate(&State);
+            rc = State.rc;
+        }
+        vbpsRegTerm(&State);
+    }
+#endif
+
+    return VINF_SUCCESS;
+}
+
