Index: /trunk/include/VBox/vd.h
===================================================================
--- /trunk/include/VBox/vd.h	(revision 52584)
+++ /trunk/include/VBox/vd.h	(revision 52585)
@@ -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
@@ -502,4 +502,20 @@
 
 /**
+ * Unloads a single plugin given by filename.
+ *
+ * @returns VBox status code.
+ * @param   pszFilename     The plugin filename to unload.
+ */
+VBOXDDU_DECL(int) VDPluginUnloadFromFilename(const char *pszFilename);
+
+/**
+ * Unload all plugins from a given path.
+ *
+ * @returns VBox statuse code.
+ * @param   pszPath         The path to unload plugins from.
+ */
+VBOXDDU_DECL(int) VDPluginUnloadFromPath(const char *pszPath);
+
+/**
  * Lists all HDD backends and their capabilities in a caller-provided buffer.
  *
Index: /trunk/src/VBox/Main/include/SystemPropertiesImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/SystemPropertiesImpl.h	(revision 52584)
+++ /trunk/src/VBox/Main/include/SystemPropertiesImpl.h	(revision 52585)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -52,4 +52,7 @@
     ComObjPtr<MediumFormat> i_mediumFormat(const Utf8Str &aFormat);
     ComObjPtr<MediumFormat> i_mediumFormatFromExtension(const Utf8Str &aExt);
+
+    void i_extPackInstallNotify(const char *pszExtPackName);
+    void i_extPackUninstallNotify(const char *pszExtPackName);
 
 private:
@@ -126,4 +129,7 @@
                                                ULONG *aMaxInstances);
 
+    HRESULT i_loadExtPackVDPluginCrypt();
+    HRESULT i_unloadExtPackVDPluginCrypt();
+
     HRESULT i_getUserHomeDirectory(Utf8Str &strPath);
     HRESULT i_setDefaultMachineFolder(const Utf8Str &strPath);
Index: /trunk/src/VBox/Main/include/VirtualBoxImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 52584)
+++ /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 52585)
@@ -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
@@ -127,4 +127,7 @@
     void i_addProcessToReap(RTPROCESS pid);
     void i_updateClientWatcher();
+
+    void i_extPackInstallNotify(const char *pszExtPackName);
+    void i_extPackUninstallNotify(const char *pszExtPackName);
 
     void i_onMachineStateChange(const Guid &aId, MachineState_T aState);
Index: /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp	(revision 52584)
+++ /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp	(revision 52585)
@@ -2530,5 +2530,8 @@
         {
             if (pExtPack && a_fReplace)
+            {
+                m->pVirtualBox->i_extPackUninstallNotify(pStrName->c_str());
                 hrc = pExtPack->i_callUninstallHookAndClose(m->pVirtualBox, false /*a_ForcedRemoval*/);
+            }
             else if (pExtPack)
                 hrc = setError(E_FAIL,
@@ -2562,5 +2565,8 @@
                     pExtPack->i_callInstalledHook(m->pVirtualBox, &autoLock, &ErrInfo.Core);
                     if (RT_SUCCESS(ErrInfo.Core.rc))
+                    {
                         LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pStrName->c_str()));
+                        m->pVirtualBox->i_extPackInstallNotify(pStrName->c_str());
+                    }
                     else
                     {
@@ -2665,4 +2671,5 @@
                  * Call the uninstall hook and unload the main dll.
                  */
+                m->pVirtualBox->i_extPackUninstallNotify(a_pstrName->c_str());
                 hrc = pExtPack->i_callUninstallHookAndClose(m->pVirtualBox, a_fForcedRemoval);
                 if (SUCCEEDED(hrc))
Index: /trunk/src/VBox/Main/src-server/SystemPropertiesImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/SystemPropertiesImpl.cpp	(revision 52584)
+++ /trunk/src/VBox/Main/src-server/SystemPropertiesImpl.cpp	(revision 52585)
@@ -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
@@ -44,4 +44,9 @@
 /////////////////////////////////////////////////////////////////////////////
 
+// globals
+/////////////////////////////////////////////////////////////////////////////
+static const Utf8Str g_strExtPackPuel("Oracle VM VirtualBox Extension Pack");
+static const char *g_pszVDPluginCrypt = "VDPluginCrypt";
+
 // constructor / destructor
 /////////////////////////////////////////////////////////////////////////////
@@ -113,22 +118,7 @@
     HRESULT rc = S_OK;
 
-# ifdef VBOX_WITH_EXTPACK
     /* Load all VD plugins from all extension packs first. */
     /** @todo: Make generic for 4.4 (requires interface changes). */
-    static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack");
-    static const char *s_pszVDPlugin = "VDPluginCrypt";
-    if (mParent->i_getExtPackManager()->i_isExtPackUsable(strExtPackPuel.c_str()))
-    {
-        Utf8Str strPlugin;
-        rc = mParent->i_getExtPackManager()->i_getLibraryPathForExtPack(s_pszVDPlugin, &strExtPackPuel, &strPlugin);
-        if (SUCCEEDED(rc))
-        {
-            int vrc = VDPluginLoadFromFilename(strPlugin.c_str());
-            NOREF(vrc); /** @todo: Don't ignore errors. */
-        }
-        else
-            rc = S_OK; /* ignore errors */
-    }
-# endif
+    rc = i_loadExtPackVDPluginCrypt();
 
     /* Fetch info of all available hd backends. */
@@ -1127,4 +1117,64 @@
 }
 
+
+/**
+ * Extension pack install notification
+ */
+void SystemProperties::i_extPackInstallNotify(const char *pszExtPackName)
+{
+    if (g_strExtPackPuel.equals(pszExtPackName))
+    {
+        i_loadExtPackVDPluginCrypt();
+    }
+}
+
+/**
+ * Extension pack uninstall notification
+ */
+void SystemProperties::i_extPackUninstallNotify(const char *pszExtPackName)
+{
+    if (g_strExtPackPuel.equals(pszExtPackName))
+    {
+        i_unloadExtPackVDPluginCrypt();
+    }
+}
+
+HRESULT SystemProperties::i_loadExtPackVDPluginCrypt()
+{
+    HRESULT rc = S_OK;
+#ifdef VBOX_WITH_EXTPACK
+    if (mParent->i_getExtPackManager()->i_isExtPackUsable(g_strExtPackPuel.c_str()))
+    {
+        Utf8Str strPlugin;
+        rc = mParent->i_getExtPackManager()->i_getLibraryPathForExtPack(g_pszVDPluginCrypt, &g_strExtPackPuel, &strPlugin);
+        if (SUCCEEDED(rc))
+        {
+            int vrc = VDPluginLoadFromFilename(strPlugin.c_str());
+            NOREF(vrc); /** @todo: don't ignore errors. */
+        }
+        else
+            rc = S_OK; /* ignore errors */
+    }
+# endif
+    return rc;
+}
+
+HRESULT SystemProperties::i_unloadExtPackVDPluginCrypt()
+{
+    HRESULT rc = S_OK;
+#ifdef VBOX_WITH_EXTPACK
+    Utf8Str strPlugin;
+    rc = mParent->i_getExtPackManager()->i_getLibraryPathForExtPack(g_pszVDPluginCrypt, &g_strExtPackPuel, &strPlugin);
+    if (SUCCEEDED(rc))
+    {
+        int vrc = VDPluginUnloadFromFilename(strPlugin.c_str());
+        NOREF(vrc); /** @todo: don't ignore errors. */
+    }
+    else
+        rc = S_OK; /* ignore errors */
+# endif
+    return rc;
+}
+
 // private methods
 /////////////////////////////////////////////////////////////////////////////
Index: /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp	(revision 52584)
+++ /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp	(revision 52585)
@@ -2635,4 +2635,22 @@
 };
 
+
+/**
+ * Extpack install notification
+ */
+void VirtualBox::i_extPackInstallNotify(const char *pszExtPackName)
+{
+    m->pSystemProperties->i_extPackInstallNotify(pszExtPackName);
+}
+
+/**
+ * Extpack uninstall notification
+ */
+void VirtualBox::i_extPackUninstallNotify(const char *pszExtPackName)
+{
+    m->pSystemProperties->i_extPackUninstallNotify(pszExtPackName);
+}
+
+
 /**
  *  @note Doesn't lock any object.
Index: /trunk/src/VBox/Storage/VD.cpp
===================================================================
--- /trunk/src/VBox/Storage/VD.cpp	(revision 52584)
+++ /trunk/src/VBox/Storage/VD.cpp	(revision 52585)
@@ -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
@@ -622,4 +622,6 @@
 /** Array of pointers to the image backends. */
 static PCVBOXHDDBACKEND *g_apBackends = NULL;
+/** Array of handles to the corresponding plugin. */
+static RTLDRMOD *g_ahBackendPlugins = NULL;
 /** Builtin image backends. */
 static PCVBOXHDDBACKEND aStaticBackends[] =
@@ -641,4 +643,6 @@
 /** Array of pointers to the cache backends. */
 static PCVDCACHEBACKEND *g_apCacheBackends = NULL;
+/** Array of handles to the corresponding plugin. */
+static RTLDRMOD *g_ahCacheBackendPlugins = NULL;
 /** Builtin cache backends. */
 static PCVDCACHEBACKEND aStaticCacheBackends[] =
@@ -651,4 +655,6 @@
 /** Array of pointers to the filters backends. */
 static PCVDFILTERBACKEND *g_apFilterBackends = NULL;
+/** Array of handles to the corresponding plugin. */
+static RTLDRMOD *g_ahFilterBackendPlugins = NULL;
 
 /** Forward declaration of the async discard helper. */
@@ -662,5 +668,5 @@
  * internal: add several backends.
  */
-static int vdAddBackends(PCVBOXHDDBACKEND *ppBackends, unsigned cBackends)
+static int vdAddBackends(RTLDRMOD hPlugin, PCVBOXHDDBACKEND *ppBackends, unsigned cBackends)
 {
     PCVBOXHDDBACKEND *pTmp = (PCVBOXHDDBACKEND*)RTMemRealloc(g_apBackends,
@@ -668,6 +674,13 @@
     if (RT_UNLIKELY(!pTmp))
         return VERR_NO_MEMORY;
+    RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahBackendPlugins,
+           (g_cBackends + cBackends) * sizeof(RTLDRMOD));
+    if (RT_UNLIKELY(!pTmpPlugins))
+        return VERR_NO_MEMORY;
     g_apBackends = pTmp;
+    g_ahBackendPlugins = pTmpPlugins;
     memcpy(&g_apBackends[g_cBackends], ppBackends, cBackends * sizeof(PCVBOXHDDBACKEND));
+    for (unsigned i = g_cBackends; i < g_cBackends + cBackends; i++)
+        g_ahBackendPlugins[i] = hPlugin;
     g_cBackends += cBackends;
     return VINF_SUCCESS;
@@ -677,7 +690,7 @@
  * internal: add single backend.
  */
-DECLINLINE(int) vdAddBackend(PCVBOXHDDBACKEND pBackend)
-{
-    return vdAddBackends(&pBackend, 1);
+DECLINLINE(int) vdAddBackend(RTLDRMOD hPlugin, PCVBOXHDDBACKEND pBackend)
+{
+    return vdAddBackends(hPlugin, &pBackend, 1);
 }
 
@@ -685,5 +698,5 @@
  * internal: add several cache backends.
  */
-static int vdAddCacheBackends(PCVDCACHEBACKEND *ppBackends, unsigned cBackends)
+static int vdAddCacheBackends(RTLDRMOD hPlugin, PCVDCACHEBACKEND *ppBackends, unsigned cBackends)
 {
     PCVDCACHEBACKEND *pTmp = (PCVDCACHEBACKEND*)RTMemRealloc(g_apCacheBackends,
@@ -691,6 +704,13 @@
     if (RT_UNLIKELY(!pTmp))
         return VERR_NO_MEMORY;
+    RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahCacheBackendPlugins,
+           (g_cCacheBackends + cBackends) * sizeof(RTLDRMOD));
+    if (RT_UNLIKELY(!pTmpPlugins))
+        return VERR_NO_MEMORY;
     g_apCacheBackends = pTmp;
+    g_ahCacheBackendPlugins = pTmpPlugins;
     memcpy(&g_apCacheBackends[g_cCacheBackends], ppBackends, cBackends * sizeof(PCVDCACHEBACKEND));
+    for (unsigned i = g_cCacheBackends; i < g_cCacheBackends + cBackends; i++)
+        g_ahCacheBackendPlugins[i] = hPlugin;
     g_cCacheBackends += cBackends;
     return VINF_SUCCESS;
@@ -700,17 +720,18 @@
  * internal: add single cache backend.
  */
-DECLINLINE(int) vdAddCacheBackend(PCVDCACHEBACKEND pBackend)
-{
-    return vdAddCacheBackends(&pBackend, 1);
-}
-
-/**
- * Add several filter bakends.
+DECLINLINE(int) vdAddCacheBackend(RTLDRMOD hPlugin, PCVDCACHEBACKEND pBackend)
+{
+    return vdAddCacheBackends(hPlugin, &pBackend, 1);
+}
+
+/**
+ * Add several filter backends.
  *
  * @returns VBox status code.
+ * @param   hPlugin       Plugin handle to add.
  * @param   ppBackends    Array of filter backends to add.
  * @param   cBackends     Number of backends to add.
  */
-static int vdAddFilterBackends(PCVDFILTERBACKEND *ppBackends, unsigned cBackends)
+static int vdAddFilterBackends(RTLDRMOD hPlugin, PCVDFILTERBACKEND *ppBackends, unsigned cBackends)
 {
     PCVDFILTERBACKEND *pTmp = (PCVDFILTERBACKEND *)RTMemRealloc(g_apFilterBackends,
@@ -718,6 +739,13 @@
     if (RT_UNLIKELY(!pTmp))
         return VERR_NO_MEMORY;
+    RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahFilterBackendPlugins,
+           (g_cFilterBackends + cBackends) * sizeof(RTLDRMOD));
+    if (RT_UNLIKELY(!pTmpPlugins))
+        return VERR_NO_MEMORY;
     g_apFilterBackends = pTmp;
+    g_ahFilterBackendPlugins = pTmpPlugins;
     memcpy(&g_apFilterBackends[g_cFilterBackends], ppBackends, cBackends * sizeof(PCVDFILTERBACKEND));
+    for (unsigned i = g_cFilterBackends; i < g_cFilterBackends + cBackends; i++)
+        g_ahFilterBackendPlugins[i] = hPlugin;
     g_cFilterBackends += cBackends;
     return VINF_SUCCESS;
@@ -728,9 +756,10 @@
  *
  * @returns VBox status code.
+ * @param   hPlugin     Plugin handle to add.
  * @param   pBackend    The backend to add.
  */
-DECLINLINE(int) vdAddFilterBackend(PCVDFILTERBACKEND pBackend)
-{
-    return vdAddFilterBackends(&pBackend, 1);
+DECLINLINE(int) vdAddFilterBackend(RTLDRMOD hPlugin, PCVDFILTERBACKEND pBackend)
+{
+    return vdAddFilterBackends(hPlugin, &pBackend, 1);
 }
 
@@ -3492,5 +3521,5 @@
 
     if (pBackend->cbSize == sizeof(VBOXHDDBACKEND))
-        vdAddBackend(pBackend);
+        vdAddBackend((RTLDRMOD)pvUser, pBackend);
     else
     {
@@ -3510,5 +3539,5 @@
 
     if (pBackend->cbSize == sizeof(VDCACHEBACKEND))
-        vdAddCacheBackend(pBackend);
+        vdAddCacheBackend((RTLDRMOD)pvUser, pBackend);
     else
     {
@@ -3528,5 +3557,5 @@
 
     if (pBackend->cbSize == sizeof(VDFILTERBACKEND))
-        vdAddFilterBackend(pBackend);
+        vdAddFilterBackend((RTLDRMOD)pvUser, pBackend);
     else
     {
@@ -3562,5 +3591,5 @@
  * @returns VBox status code.
  * @param   hPlugin     Plugin handle to add.
- * @param   pszFilename The associated filename, sued for finding duplicates.
+ * @param   pszFilename The associated filename, used for finding duplicates.
  */
 static int vdAddPlugin(RTLDRMOD hPlugin, const char *pszFilename)
@@ -3586,4 +3615,59 @@
     return rc;
 }
+
+static int vdRemovePlugin(const char *pszFilename)
+{
+    /* Find plugin to be removed from the list. */
+    PVDPLUGIN pIt = NULL;
+    RTListForEach(&g_ListPluginsLoaded, pIt, VDPLUGIN, NodePlugin)
+    {
+        if (!RTStrCmp(pIt->pszFilename, pszFilename))
+            break;
+    }
+    if (!pIt)
+        return VINF_SUCCESS;
+
+    /** @todo r=klaus: need to add a plugin entry point for unregistering the
+     * backends. Only if this doesn't exist (or fails to work) we should fall
+     * back to the following uncoordinated backend cleanup. */
+    for (unsigned i = 0; i < g_cBackends; i++)
+    {
+        while (i < g_cBackends && g_ahBackendPlugins[i] == pIt->hPlugin)
+        {
+            memcpy(&g_apBackends[i], &g_apBackends[i + 1], (g_cBackends - i - 1) * sizeof(PCVBOXHDDBACKEND));
+            memcpy(&g_ahBackendPlugins[i], &g_ahBackendPlugins[i + 1], (g_cBackends - i - 1) * sizeof(RTLDRMOD));
+            /** @todo for now skip reallocating, doesn't save much */
+            g_cBackends--;
+        }
+    }
+    for (unsigned i = 0; i < g_cCacheBackends; i++)
+    {
+        while (i < g_cCacheBackends && g_ahCacheBackendPlugins[i] == pIt->hPlugin)
+        {
+            memcpy(&g_apCacheBackends[i], &g_apCacheBackends[i + 1], (g_cCacheBackends - i - 1) * sizeof(PCVBOXHDDBACKEND));
+            memcpy(&g_ahCacheBackendPlugins[i], &g_ahCacheBackendPlugins[i + 1], (g_cCacheBackends - i - 1) * sizeof(RTLDRMOD));
+            /** @todo for now skip reallocating, doesn't save much */
+            g_cCacheBackends--;
+        }
+    }
+    for (unsigned i = 0; i < g_cFilterBackends; i++)
+    {
+        while (i < g_cFilterBackends && g_ahFilterBackendPlugins[i] == pIt->hPlugin)
+        {
+            memcpy(&g_apFilterBackends[i], &g_apFilterBackends[i + 1], (g_cFilterBackends - i - 1) * sizeof(PCVBOXHDDBACKEND));
+            memcpy(&g_ahFilterBackendPlugins[i], &g_ahFilterBackendPlugins[i + 1], (g_cFilterBackends - i - 1) * sizeof(RTLDRMOD));
+            /** @todo for now skip reallocating, doesn't save much */
+            g_cFilterBackends--;
+        }
+    }
+
+    /* Remove the plugin node now, all traces of it are gone. */
+    RTListNodeRemove(&pIt->NodePlugin);
+    RTLdrClose(pIt->hPlugin);
+    RTStrFree(pIt->pszFilename);
+    RTMemFree(pIt);
+
+    return VINF_SUCCESS;
+}
 #endif
 
@@ -3624,5 +3708,5 @@
         {
             /* Get the function table. */
-            rc = pfnVDPluginLoad(NULL, &BackendRegister);
+            rc = pfnVDPluginLoad(hPlugin, &BackendRegister);
         }
         else
@@ -3744,4 +3828,103 @@
 #else
     return VINF_SUCCESS;
+#endif
+}
+
+/**
+ * Worker for VDPluginUnloadFromFilename() and vdPluginUnloadFromPath().
+ *
+ * @returns VBox status code.
+ * @param   pszFilename    The plugin filename to unload.
+ */
+static int vdPluginUnloadFromFilename(const char *pszFilename)
+{
+#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
+    return vdRemovePlugin(pszFilename);
+#else
+    return VERR_NOT_IMPLEMENTED;
+#endif
+}
+
+/**
+ * Worker for VDPluginUnloadFromPath().
+ *
+ * @returns VBox status code.
+ * @param   pszPath        The path to unload plugins from.
+ */
+static int vdPluginUnloadFromPath(const char *pszPath)
+{
+#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
+    /* To get all entries with VBoxHDD as prefix. */
+    char *pszPluginFilter = RTPathJoinA(pszPath, VD_PLUGIN_PREFIX "*");
+    if (!pszPluginFilter)
+        return VERR_NO_STR_MEMORY;
+
+    PRTDIRENTRYEX pPluginDirEntry = NULL;
+    PRTDIR pPluginDir = NULL;
+    size_t cbPluginDirEntry = sizeof(RTDIRENTRYEX);
+    int rc = RTDirOpenFiltered(&pPluginDir, pszPluginFilter, RTDIRFILTER_WINNT, 0);
+    if (RT_FAILURE(rc))
+    {
+        /* On Windows the above immediately signals that there are no
+         * files matching, while on other platforms enumerating the
+         * files below fails. Either way: no plugins. */
+        goto out;
+    }
+
+    pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(sizeof(RTDIRENTRYEX));
+    if (!pPluginDirEntry)
+    {
+        rc = VERR_NO_MEMORY;
+        goto out;
+    }
+
+    while ((rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK)) != VERR_NO_MORE_FILES)
+    {
+        char *pszPluginPath = NULL;
+
+        if (rc == VERR_BUFFER_OVERFLOW)
+        {
+            /* allocate new buffer. */
+            RTMemFree(pPluginDirEntry);
+            pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(cbPluginDirEntry);
+            if (!pPluginDirEntry)
+            {
+                rc = VERR_NO_MEMORY;
+                break;
+            }
+            /* Retry. */
+            rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+            if (RT_FAILURE(rc))
+                break;
+        }
+        else if (RT_FAILURE(rc))
+            break;
+
+        /* We got the new entry. */
+        if (!RTFS_IS_FILE(pPluginDirEntry->Info.Attr.fMode))
+            continue;
+
+        /* Prepend the path to the libraries. */
+        pszPluginPath = RTPathJoinA(pszPath, pPluginDirEntry->szName);
+        if (!pszPluginPath)
+        {
+            rc = VERR_NO_STR_MEMORY;
+            break;
+        }
+
+        rc = vdPluginUnloadFromFilename(pszPluginPath);
+        RTStrFree(pszPluginPath);
+    }
+out:
+    if (rc == VERR_NO_MORE_FILES)
+        rc = VINF_SUCCESS;
+    RTStrFree(pszPluginFilter);
+    if (pPluginDirEntry)
+        RTMemFree(pPluginDirEntry);
+    if (pPluginDir)
+        RTDirClose(pPluginDir);
+    return rc;
+#else
+    return VERR_NOT_IMPLEMENTED;
 #endif
 }
@@ -5489,8 +5672,8 @@
 VBOXDDU_DECL(int) VDInit(void)
 {
-    int rc = vdAddBackends(aStaticBackends, RT_ELEMENTS(aStaticBackends));
+    int rc = vdAddBackends(NIL_RTLDRMOD, aStaticBackends, RT_ELEMENTS(aStaticBackends));
     if (RT_SUCCESS(rc))
     {
-        rc = vdAddCacheBackends(aStaticCacheBackends, RT_ELEMENTS(aStaticCacheBackends));
+        rc = vdAddCacheBackends(NIL_RTLDRMOD, aStaticCacheBackends, RT_ELEMENTS(aStaticCacheBackends));
         if (RT_SUCCESS(rc))
         {
@@ -5577,4 +5760,40 @@
 
     return vdPluginLoadFromPath(pszPath);
+}
+
+/**
+ * Unloads a single plugin given by filename.
+ *
+ * @returns VBox status code.
+ * @param   pszFilename     The plugin filename to unload.
+ */
+VBOXDDU_DECL(int) VDPluginUnloadFromFilename(const char *pszFilename)
+{
+    if (!g_apBackends)
+    {
+        int rc = VDInit();
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    return vdPluginUnloadFromFilename(pszFilename);
+}
+
+/**
+ * Unload all plugins from a given path.
+ *
+ * @returns VBox statuse code.
+ * @param   pszPath         The path to unload plugins from.
+ */
+VBOXDDU_DECL(int) VDPluginUnloadFromPath(const char *pszPath)
+{
+    if (!g_apBackends)
+    {
+        int rc = VDInit();
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    return vdPluginUnloadFromPath(pszPath);
 }
 
