Index: /trunk/include/VBox/ExtPack/ExtPack.h
===================================================================
--- /trunk/include/VBox/ExtPack/ExtPack.h	(revision 33692)
+++ /trunk/include/VBox/ExtPack/ExtPack.h	(revision 33693)
@@ -101,8 +101,7 @@
      * This is called in the context of the per-user service (VBoxSVC).
      *
-     * @returns VBox status code.
-     * @param   pThis       Pointer to this structure.
-     */
-    DECLCALLBACKMEMBER(int, pfnInstalled)(PCVBOXEXTPACKREG pThis);
+     * @param   pThis       Pointer to this structure.
+     */
+    DECLCALLBACKMEMBER(void, pfnInstalled)(PCVBOXEXTPACKREG pThis);
 
     /**
@@ -117,4 +116,18 @@
 
     /**
+     * Hook for doing work before unloading.
+     *
+     * This is called both in the context of the per-user service (VBoxSVC) and
+     * in context of the VM process (VBoxC).
+     *
+     * @param   pThis       Pointer to this structure.
+     *
+     * @remarks The helpers are not available at this point in time.
+     * @remarks This is not called on uninstall, then pfnUninstall will be the
+     *          last callback.
+     */
+    DECLCALLBACKMEMBER(void, pfnUnload)(PCVBOXEXTPACKREG pThis);
+
+    /**
      * Hook for changing the default VM configuration upon creation.
      *
@@ -134,32 +147,31 @@
      * @returns VBox status code.
      * @param   pThis       Pointer to this structure.
+     * @param   pConsole    The console interface.
      * @param   pVM         The VM handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnVMConfigureVMM)(PCVBOXEXTPACKREG pThis, IConsole *pConsole, PVM pVM);
+
+    /**
+     * Hook for doing work right before powering on the VM.
+     *
+     * This is called in the context of the VM process (VBoxC).
+     *
+     * @returns VBox status code.
+     * @param   pThis       Pointer to this structure.
      * @param   pConsole    The console interface.
-     */
-    DECLCALLBACKMEMBER(int, pfnVMConfigureVMM)(PCVBOXEXTPACKREG pThis, PVM pVM, IConsole *pConsole);
-
-    /**
-     * Hook for doing work right before powering on the VM.
+     * @param   pVM         The VM handle.
+     */
+    DECLCALLBACKMEMBER(int, pfnVMPowerOn)(PCVBOXEXTPACKREG pThis, IConsole *pConsole, PVM pVM);
+
+    /**
+     * Hook for doing work after powering on the VM.
      *
      * This is called in the context of the VM process (VBoxC).
      *
-     * @returns VBox status code.
-     * @param   pThis       Pointer to this structure.
-     * @param   pVM         The VM handle.
+     * @param   pThis       Pointer to this structure.
      * @param   pConsole    The console interface.
-     */
-    DECLCALLBACKMEMBER(int, pfnVMPowerOn)(PCVBOXEXTPACKREG pThis, PVM pVM, IConsole *pConsole);
-
-    /**
-     * Hook for doing work after powering on the VM.
-     *
-     * This is called in the context of the VM process (VBoxC).
-     *
-     * @returns VBox status code.
-     * @param   pThis       Pointer to this structure.
      * @param   pVM         The VM handle.  Can be NULL.
-     * @param   pConsole    The console interface.
-     */
-    DECLCALLBACKMEMBER(int, pfnVMPowerOff)(PCVBOXEXTPACKREG pThis, PVM pVM, IConsole *pConsole);
+     */
+    DECLCALLBACKMEMBER(void, pfnVMPowerOff)(PCVBOXEXTPACKREG pThis, IConsole *pConsole, PVM pVM);
 
     /** End of structure marker (VBOXEXTPACKREG_VERSION). */
Index: /trunk/src/VBox/Main/ExtPackManagerImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ExtPackManagerImpl.cpp	(revision 33692)
+++ /trunk/src/VBox/Main/ExtPackManagerImpl.cpp	(revision 33693)
@@ -41,4 +41,5 @@
 #include <VBox/version.h>
 #include "AutoCaller.h"
+#include "Global.h"
 
 
@@ -66,4 +67,5 @@
 struct ExtPack::Data
 {
+public:
     /** The extension pack description (loaded from the XML, mostly). */
     VBOXEXTPACKDESC     Desc;
@@ -91,4 +93,6 @@
     /** The helper callbacks for the extension pack. */
     VBOXEXTPACKHLP      Hlp;
+    /** Pointer back to the extension pack object (for Hlp methods). */
+    ExtPack            *pThis;
     /** The extension pack registration structure. */
     PCVBOXEXTPACKREG    pReg;
@@ -103,6 +107,12 @@
 struct ExtPackManager::Data
 {
-    /** Where the directory where the extension packs are installed. */
-    Utf8Str     strBasePath;
+    /** The directory where the extension packs are installed. */
+    Utf8Str     strBaseDir;
+    /** The directory where the extension packs can be dropped for automatic
+     * installation. */
+    Utf8Str     strDropZoneDir;
+    /** The directory where the certificates this installation recognizes are
+     * stored. */
+    Utf8Str     strCertificatDirPath;
     /** The list of installed extension packs. */
     ExtPackList llInstalledExtPacks;
@@ -167,4 +177,5 @@
     m->Hlp.pszVBoxVersion           = RTBldCfgVersion();
     m->Hlp.uVBoxInternalRevision    = RTBldCfgRevision();
+    m->pThis                        = this;
     m->pReg                         = NULL;
 
@@ -196,6 +207,11 @@
         if (m->hMainMod != NIL_RTLDRMOD)
         {
+            AssertPtr(m->pReg);
+            if (m->pReg->pfnUnload != NULL)
+                m->pReg->pfnUnload(m->pReg);
+
             RTLdrClose(m->hMainMod);
             m->hMainMod = NIL_RTLDRMOD;
+            m->pReg = NULL;
         }
 
@@ -205,7 +221,122 @@
 }
 
-void *ExtPack::getCallbackTable()
-{
-    return NULL;
+
+/**
+ * Calls the installed hook.
+ * @remarks Caller holds the extension manager lock.
+ */
+void    ExtPack::callInstalledHook(void)
+{
+    if (   m->hMainMod != NIL_RTLDRMOD
+        && m->pReg->pfnInstalled)
+        m->pReg->pfnInstalled(m->pReg);
+}
+
+/**
+ * Calls the uninstall hook and closes the module.
+ *
+ * @returns S_OK or COM error status with error information.
+ * @param   a_fForcedRemoval    When set, we'll ignore complaints from the
+ *                              uninstall hook.
+ * @remarks The caller holds the manager's write lock.
+ */
+HRESULT ExtPack::callUninstallHookAndClose(bool a_fForcedRemoval)
+{
+    HRESULT hrc = S_OK;
+
+    if (m->hMainMod != NIL_RTLDRMOD)
+    {
+        if (m->pReg->pfnUninstall)
+        {
+            int vrc = m->pReg->pfnUninstall(m->pReg);
+            if (RT_FAILURE(vrc))
+            {
+                LogRel(("ExtPack pfnUninstall returned %Rrc for %s\n", vrc, m->Desc.strName.c_str()));
+                if (!a_fForcedRemoval)
+                    hrc = setError(E_FAIL, tr("pfnUninstall returned %Rrc"), vrc);
+            }
+        }
+        if (SUCCEEDED(hrc))
+        {
+            RTLdrClose(m->hMainMod);
+            m->hMainMod = NIL_RTLDRMOD;
+            m->pReg = NULL;
+        }
+    }
+
+    return hrc;
+}
+
+/**
+ * Calls the pfnVMCreate hook.
+ *
+ * @param   a_pMachine          The machine interface of the new VM.
+ * @remarks Caller holds the extension manager lock.
+ */
+void ExtPack::callVmCreatedHook(IMachine *a_pMachine)
+{
+    if (   m->hMainMod != NIL_RTLDRMOD
+        && m->pReg->pfnVMCreated)
+        m->pReg->pfnVMCreated(m->pReg, a_pMachine);
+}
+
+/**
+ * Calls the pfnVMConfigureVMM hook.
+ *
+ * @returns VBox status code, LogRel called on failure.
+ * @param   a_pConsole          The console interface.
+ * @param   a_pVM               The VM handle.
+ * @remarks Caller holds the extension manager lock.
+ */
+int ExtPack::callVmConfigureVmmHook(IConsole *a_pConsole, PVM a_pVM)
+{
+    if (   m->hMainMod != NIL_RTLDRMOD
+        && m->pReg->pfnVMConfigureVMM)
+    {
+        int vrc = m->pReg->pfnVMConfigureVMM(m->pReg, a_pConsole, a_pVM);
+        if (RT_FAILURE(vrc))
+        {
+            LogRel(("ExtPack pfnVMConfigureVMM returned %Rrc for %s\n", vrc, m->Desc.strName.c_str()));
+            return vrc;
+        }
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * Calls the pfnVMPowerOn hook.
+ *
+ * @returns VBox status code, LogRel called on failure.
+ * @param   a_pConsole          The console interface.
+ * @param   a_pVM               The VM handle.
+ * @remarks Caller holds the extension manager lock.
+ */
+int ExtPack::callVmPowerOnHook(IConsole *a_pConsole, PVM a_pVM)
+{
+    if (   m->hMainMod != NIL_RTLDRMOD
+        && m->pReg->pfnVMPowerOn)
+    {
+        int vrc = m->pReg->pfnVMPowerOn(m->pReg, a_pConsole, a_pVM);
+        if (RT_FAILURE(vrc))
+        {
+            LogRel(("ExtPack pfnVMPowerOn returned %Rrc for %s\n", vrc, m->Desc.strName.c_str()));
+            return vrc;
+        }
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * Calls the pfnVMPowerOff hook.
+ *
+ * @param   a_pConsole          The console interface.
+ * @param   a_pVM               The VM handle.
+ * @remarks Caller holds the extension manager lock.
+ */
+void ExtPack::callVmPowerOffHook(IConsole *a_pConsole, PVM a_pVM)
+{
+    if (   m->hMainMod != NIL_RTLDRMOD
+        && m->pReg->pfnVMPowerOff)
+        m->pReg->pfnVMPowerOff(m->pReg, a_pConsole, a_pVM);
 }
 
@@ -217,4 +348,5 @@
  * @returns S_OK or COM error status with error information.
  * @param   pfCanDelete     Optional can-delete-this-object output indicator.
+ * @remarks Caller holds the extension manager lock for writing.
  */
 HRESULT ExtPack::refresh(bool *pfCanDelete)
@@ -223,5 +355,5 @@
         *pfCanDelete = false;
 
-    AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
+    AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); /* for the COMGETTERs */
 
     /*
@@ -395,4 +527,5 @@
                 if (   (!m->pReg->pfnInstalled      || RT_VALID_PTR(m->pReg->pfnInstalled))
                     && (!m->pReg->pfnUninstall      || RT_VALID_PTR(m->pReg->pfnUninstall))
+                    && (!m->pReg->pfnUnload         || RT_VALID_PTR(m->pReg->pfnUnload))
                     && (!m->pReg->pfnVMCreated      || RT_VALID_PTR(m->pReg->pfnVMCreated))
                     && (!m->pReg->pfnVMConfigureVMM || RT_VALID_PTR(m->pReg->pfnVMConfigureVMM))
@@ -445,4 +578,73 @@
                          Utf8Str *a_pStrFound, bool *a_pfNative, PRTFSOBJINFO a_pObjInfo) const
 {
+    /*
+     * Try the native path first.
+     */
+    char szPath[RTPATH_MAX];
+    int vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), RTBldCfgTargetDotArch());
+    AssertLogRelRCReturn(vrc, false);
+    vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName);
+    AssertLogRelRCReturn(vrc, false);
+    if (!a_pszExt)
+    {
+        vrc = RTStrCat(szPath, sizeof(szPath), RTLdrGetSuff());
+        AssertLogRelRCReturn(vrc, false);
+    }
+
+    RTFSOBJINFO ObjInfo;
+    if (!a_pObjInfo)
+        a_pObjInfo = &ObjInfo;
+    vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX);
+    if (RT_SUCCESS(vrc) && RTFS_IS_FIFO(a_pObjInfo->Attr.fMode))
+    {
+        if (a_pfNative)
+            *a_pfNative = true;
+        a_pStrFound = new Utf8Str(szPath);
+        return true;
+    }
+
+    /*
+     * Try the platform agnostic modules.
+     */
+    /* gcc.x86/module.rel */
+    char szSubDir[32];
+    RTStrPrintf(szSubDir, sizeof(szSubDir), "%s.%s", RTBldCfgCompiler(), RTBldCfgTargetArch());
+    vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), szSubDir);
+    AssertLogRelRCReturn(vrc, false);
+    vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName);
+    AssertLogRelRCReturn(vrc, false);
+    if (!a_pszExt)
+    {
+        vrc = RTStrCat(szPath, sizeof(szPath), ".rel");
+        AssertLogRelRCReturn(vrc, false);
+    }
+    vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX);
+    if (RT_SUCCESS(vrc) && RTFS_IS_FIFO(a_pObjInfo->Attr.fMode))
+    {
+        if (a_pfNative)
+            *a_pfNative = false;
+        a_pStrFound = new Utf8Str(szPath);
+        return true;
+    }
+
+    /* x86/module.rel */
+    vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), RTBldCfgTargetArch());
+    AssertLogRelRCReturn(vrc, false);
+    vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName);
+    AssertLogRelRCReturn(vrc, false);
+    if (!a_pszExt)
+    {
+        vrc = RTStrCat(szPath, sizeof(szPath), ".rel");
+        AssertLogRelRCReturn(vrc, false);
+    }
+    vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX);
+    if (RT_SUCCESS(vrc) && RTFS_IS_FIFO(a_pObjInfo->Attr.fMode))
+    {
+        if (a_pfNative)
+            *a_pfNative = false;
+        a_pStrFound = new Utf8Str(szPath);
+        return true;
+    }
+
     return false;
 }
@@ -499,4 +701,25 @@
                        char *pszFound, size_t cbFound, bool *pfNative)
 {
+    /*
+     * Validate the input and get our bearings.
+     */
+    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pszExt, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszFound, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pfNative, VERR_INVALID_POINTER);
+
+    AssertPtrReturn(pHlp, VERR_INVALID_POINTER);
+    AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER);
+    ExtPack::Data *m = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
+    AssertPtrReturn(m, VERR_INVALID_POINTER);
+    ExtPack *pThis = m->pThis;
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    /*
+     * This is just a wrapper around findModule.
+     */
+    Utf8Str strFound;
+    if (pThis->findModule(pszName, pszExt, &strFound, pfNative, NULL))
+        return RTStrCopy(pszFound, cbFound, strFound.c_str());
     return VERR_FILE_NOT_FOUND;
 }
@@ -516,4 +739,18 @@
         Bstr str(m->Desc.strName);
         str.cloneTo(a_pbstrName);
+    }
+    return hrc;
+}
+
+STDMETHODIMP ExtPack::COMGETTER(Description)(BSTR *a_pbstrDescription)
+{
+    CheckComArgOutPointerValid(a_pbstrDescription);
+
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (SUCCEEDED(hrc))
+    {
+        Bstr str(m->Desc.strDescription);
+        str.cloneTo(a_pbstrDescription);
     }
     return hrc;
@@ -589,21 +826,33 @@
  *
  * @returns COM status code.
- */
-HRESULT ExtPackManager::init()
+ * @param   a_pszDropZoneDir        The path to the drop zone directory.
+ * @param   a_fCheckDropZone        Whether to check the drop zone for new
+ *                                  extensions or not.  Only VBoxSVC does this
+ *                                  and then only when wanted.
+ */
+HRESULT ExtPackManager::init(const char *a_pszDropZoneDir, bool a_fCheckDropZone)
 {
     /*
      * Figure some stuff out before creating the instance data.
      */
-    char szBasePath[RTPATH_MAX];
-    int rc = RTPathAppPrivateArch(szBasePath, sizeof(szBasePath));
+    char szBaseDir[RTPATH_MAX];
+    int rc = RTPathAppPrivateArch(szBaseDir, sizeof(szBaseDir));
     AssertLogRelRCReturn(rc, E_FAIL);
-    rc = RTPathAppend(szBasePath, sizeof(szBasePath), "ExtensionPacks");
+    rc = RTPathAppend(szBaseDir, sizeof(szBaseDir), "ExtensionPacks");
     AssertLogRelRCReturn(rc, E_FAIL);
 
+    char szCertificatDir[RTPATH_MAX];
+    rc = RTPathAppPrivateArch(szCertificatDir, sizeof(szCertificatDir));
+    AssertLogRelRCReturn(rc, E_FAIL);
+    rc = RTPathAppend(szBaseDir, sizeof(szCertificatDir), "Certificates");
+    AssertLogRelRCReturn(rc, E_FAIL);
+
     /*
      * Allocate and initialize the instance data.
      */
     m = new Data;
-    m->strBasePath = szBasePath;
+    m->strBaseDir           = szBaseDir;
+    m->strCertificatDirPath = szCertificatDir;
+    m->strDropZoneDir       = a_pszDropZoneDir;
 
     /*
@@ -615,5 +864,5 @@
      */
     PRTDIR pDir;
-    int vrc = RTDirOpen(&pDir, szBasePath);
+    int vrc = RTDirOpen(&pDir, szBaseDir);
     if (RT_FAILURE(vrc))
         return S_OK;
@@ -639,5 +888,5 @@
             HRESULT hrc2 = NewExtPack.createObject();
             if (SUCCEEDED(hrc2))
-                hrc2 = NewExtPack->init(Entry.szName, szBasePath);
+                hrc2 = NewExtPack->init(Entry.szName, szBaseDir);
             if (SUCCEEDED(hrc2))
                 m->llInstalledExtPacks.push_back(NewExtPack);
@@ -648,4 +897,10 @@
     RTDirClose(pDir);
 
+    /*
+     * Look for things in the drop zone.
+     */
+    if (SUCCEEDED(hrc) && a_fCheckDropZone)
+        processDropZone();
+
     return hrc;
 }
@@ -668,6 +923,4 @@
     if (!autoUninitSpan.uninitDone() && m != NULL)
     {
-        /** @todo do unload notifications */
-
         delete m;
         m = NULL;
@@ -779,8 +1032,9 @@
 
                                 hrc = runSetUidToRootHelper("install",
-                                                            "--basepath",   m->strBasePath.c_str(),
-                                                            "--name",       pszName,
-                                                            "--tarball",    strTarball.c_str(),
-                                                            "--tarball-fd", &szTarballFd[0],
+                                                            "--base-dir",        m->strBaseDir.c_str(),
+                                                            "--name",            pszName,
+                                                            "--certificate-dir", m->strCertificatDirPath.c_str(),
+                                                            "--tarball",         strTarball.c_str(),
+                                                            "--tarball-fd",      &szTarballFd[0],
                                                             NULL);
                                 if (SUCCEEDED(hrc))
@@ -788,5 +1042,8 @@
                                     hrc = refreshExtPack(pszName, true /*a_fUnsuableIsError*/, &pExtPack);
                                     if (SUCCEEDED(hrc))
+                                    {
                                         LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pszName));
+                                        pExtPack->callInstalledHook();
+                                    }
                                 }
                                 else
@@ -853,35 +1110,41 @@
             {
                 /*
-                 * Run the set-uid-to-root binary that performs the
-                 * uninstallation.  Then refresh the object.
-                 *
-                 * This refresh is theorically subject to races, but it's of
-                 * the don't-do-that variety.
+                 * Call the uninstall hook and unload the main dll.
                  */
-                const char *pszForcedOpt = a_fForcedRemoval ? "--forced" : NULL;
-                hrc = runSetUidToRootHelper("uninstall",
-                                            "--basepath", m->strBasePath.c_str(),
-                                            "--name",     strName.c_str(),
-                                            pszForcedOpt, /* Last as it may be NULL. */
-                                            NULL);
+                hrc = pExtPack->callUninstallHookAndClose(a_fForcedRemoval != FALSE);
                 if (SUCCEEDED(hrc))
                 {
-                    hrc = refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, &pExtPack);
+                    /*
+                     * Run the set-uid-to-root binary that performs the
+                     * uninstallation.  Then refresh the object.
+                     *
+                     * This refresh is theorically subject to races, but it's of
+                     * the don't-do-that variety.
+                     */
+                    const char *pszForcedOpt = a_fForcedRemoval ? "--forced" : NULL;
+                    hrc = runSetUidToRootHelper("uninstall",
+                                                "--base-dir", m->strBaseDir.c_str(),
+                                                "--name",     strName.c_str(),
+                                                pszForcedOpt, /* Last as it may be NULL. */
+                                                NULL);
                     if (SUCCEEDED(hrc))
                     {
-                        if (!pExtPack)
-                            LogRel(("ExtPackManager: Successfully uninstalled extension pack '%s'.\n", strName.c_str()));
-                        else
-                            hrc = setError(E_UNEXPECTED,
-                                           tr("Uninstall extension pack '%s' failed under mysterious circumstances"),
-                                           strName.c_str());
+                        hrc = refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, &pExtPack);
+                        if (SUCCEEDED(hrc))
+                        {
+                            if (!pExtPack)
+                                LogRel(("ExtPackManager: Successfully uninstalled extension pack '%s'.\n", strName.c_str()));
+                            else
+                                hrc = setError(E_UNEXPECTED,
+                                               tr("Uninstall extension pack '%s' failed under mysterious circumstances"),
+                                               strName.c_str());
+                        }
+                    }
+                    else
+                    {
+                        ErrorInfoKeeper Eik;
+                        refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, NULL);
                     }
                 }
-                else
-                {
-                    ErrorInfoKeeper Eik;
-                    refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, NULL);
-                }
-
             }
         }
@@ -981,5 +1244,5 @@
             if (hPipeR != NIL_RTPIPE)
             {
-                char    achBuf[16]; //1024
+                char    achBuf[16]; ///@todo 1024
                 size_t  cbRead;
                 vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead);
@@ -1134,4 +1397,5 @@
  *                              pack of it is still around after the refresh.
  *                              This is optional.
+ * @remarks Caller holds the extension manager lock.
  */
 HRESULT ExtPackManager::refreshExtPack(const char *a_pszName, bool a_fUnsuableIsError, ExtPack **a_ppExtPack)
@@ -1162,5 +1426,5 @@
          */
         char szDir[RTPATH_MAX];
-        int vrc = RTPathJoin(szDir, sizeof(szDir), m->strBasePath.c_str(), a_pszName);
+        int vrc = RTPathJoin(szDir, sizeof(szDir), m->strBaseDir.c_str(), a_pszName);
         AssertLogRelRCReturn(vrc, E_FAIL);
 
@@ -1172,5 +1436,5 @@
         {
             PRTDIR pDir;
-            vrc = RTDirOpen(&pDir, m->strBasePath.c_str());
+            vrc = RTDirOpen(&pDir, m->strBaseDir.c_str());
             if (RT_SUCCESS(vrc))
             {
@@ -1190,5 +1454,5 @@
                          * Update the name and directory variables.
                          */
-                        vrc = RTPathJoin(szDir, sizeof(szDir), m->strBasePath.c_str(), Entry.szName); /* not really necessary */
+                        vrc = RTPathJoin(szDir, sizeof(szDir), m->strBaseDir.c_str(), Entry.szName); /* not really necessary */
                         AssertLogRelRCReturnStmt(vrc, E_UNEXPECTED, RTDirClose(pDir));
                         a_pszName = Entry.szName;
@@ -1208,5 +1472,5 @@
             hrc = NewExtPack.createObject();
             if (SUCCEEDED(hrc))
-                hrc = NewExtPack->init(a_pszName, m->strBasePath.c_str());
+                hrc = NewExtPack->init(a_pszName, m->strBaseDir.c_str());
             if (SUCCEEDED(hrc))
             {
@@ -1239,17 +1503,184 @@
 
 
-
-int ExtPackManager::callAllConfigHooks(IConsole *a_pConsole, PVM a_pVM)
-{
-    NOREF(a_pConsole); NOREF(a_pVM);
+/**
+ * Processes anything new in the drop zone.
+ */
+void ExtPackManager::processDropZone(void)
+{
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (FAILED(hrc))
+        return;
+    AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (m->strDropZoneDir.isEmpty())
+        return;
+
+    PRTDIR pDir;
+    int vrc = RTDirOpen(&pDir, m->strDropZoneDir.c_str());
+    if (RT_FAILURE(vrc))
+        return;
+    for (;;)
+    {
+        RTDIRENTRYEX Entry;
+        vrc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+        if (RT_FAILURE(vrc))
+        {
+            AssertMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc));
+            break;
+        }
+
+        /*
+         * We're looking for files with the right extension.  Symbolic links
+         * will be ignored.
+         */
+        if (   RTFS_IS_FILE(Entry.Info.Attr.fMode)
+            && RTStrICmp(RTPathExt(Entry.szName), VBOX_EXTPACK_SUFFIX) == 0)
+        {
+            /* We create (and check for) a blocker file to prevent this
+               extension pack from being installed more than once. */
+            char szPath[RTPATH_MAX];
+            vrc = RTPathJoin(szPath, sizeof(szPath), m->strDropZoneDir.c_str(), Entry.szName);
+            if (RT_SUCCESS(vrc))
+                vrc = RTPathAppend(szPath, sizeof(szPath), "-done");
+            AssertRC(vrc);
+            if (RT_SUCCESS(vrc))
+            {
+                RTFILE hFile;
+                vrc = RTFileOpen(&hFile, szPath,  RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE);
+                if (RT_SUCCESS(vrc))
+                {
+                    /* Construct the full path to the extension pack and invoke
+                       the Install method to install it.  Write errors to the
+                       done file. */
+                    vrc = RTPathJoin(szPath, sizeof(szPath), m->strDropZoneDir.c_str(), Entry.szName); AssertRC(vrc);
+                    Bstr strName;
+                    hrc = Install(Bstr(szPath).raw(), strName.asOutParam());
+                    if (SUCCEEDED(hrc))
+                        RTFileWrite(hFile, "succeeded\n", sizeof("succeeded\n"), NULL);
+                    else
+                    {
+                        Utf8Str strErr;
+                        com::ErrorInfo Info(this, COM_IIDOF(IExtPackManager));
+                        if (Info.isFullAvailable())
+                            strErr.printf("failed\n"
+                                          "%ls\n"
+                                          "Details: code %Rhrc (%#RX32), component %ls, interface %ls, callee %ls\n"
+                                          ,
+                                          Info.getText().raw(),
+                                          Info.getResultCode(),
+                                          Info.getResultCode(),
+                                          Info.getComponent().raw(),
+                                          Info.getInterfaceName().raw(),
+                                          Info.getCalleeName().raw());
+                        else
+                            strErr.printf("failed\n"
+                                          "hrc=%Rhrc (%#RX32)\n", hrc, hrc);
+                        RTFileWrite(hFile, strErr.c_str(), strErr.length(), NULL);
+                    }
+                    RTFileClose(hFile);
+                }
+            }
+        }
+    } /* foreach dir entry */
+    RTDirClose(pDir);
+}
+
+
+/**
+ * Calls the pfnVMCreated hook for all working extension packs.
+ *
+ * @param   a_pMachine          The machine interface of the new VM.
+ */
+void ExtPackManager::callAllVmCreatedHooks(IMachine *a_pMachine)
+{
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (FAILED(hrc))
+        return;
+    AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
+
+    for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
+         it != m->llInstalledExtPacks.end();
+         it++)
+        (*it)->callVmCreatedHook(a_pMachine);
+}
+
+/**
+ * Calls the pfnVMConfigureVMM hook for all working extension packs.
+ *
+ * @returns VBox status code.  Stops on the first failure, expecting the caller
+ *          to signal this to the caller of the CFGM constructor.
+ * @param   a_pConsole          The console interface for the VM.
+ * @param   a_pVM               The VM handle.
+ */
+int ExtPackManager::callAllVmConfigureVmmHooks(IConsole *a_pConsole, PVM a_pVM)
+{
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (FAILED(hrc))
+        return Global::vboxStatusCodeFromCOM(hrc);
+    AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
+
+    for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
+         it != m->llInstalledExtPacks.end();
+         it++)
+    {
+        int vrc = (*it)->callVmConfigureVmmHook(a_pConsole, a_pVM);
+        if (RT_FAILURE(vrc))
+            return vrc;
+    }
+
     return VINF_SUCCESS;
 }
 
-int ExtPackManager::callAllNewMachineHooks(IMachine *a_pMachine)
-{
-    NOREF(a_pMachine);
+/**
+ * Calls the pfnVMPowerOn hook for all working extension packs.
+ *
+ * @returns VBox status code.  Stops on the first failure, expecting the caller
+ *          to not power on the VM.
+ * @param   a_pConsole          The console interface for the VM.
+ * @param   a_pVM               The VM handle.
+ */
+int ExtPackManager::callAllVmPowerOnHooks(IConsole *a_pConsole, PVM a_pVM)
+{
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (FAILED(hrc))
+        return Global::vboxStatusCodeFromCOM(hrc);
+    AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
+
+    for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
+         it != m->llInstalledExtPacks.end();
+         it++)
+    {
+        int vrc = (*it)->callVmPowerOnHook(a_pConsole, a_pVM);
+        if (RT_FAILURE(vrc))
+            return vrc;
+    }
+
     return VINF_SUCCESS;
 }
 
+/**
+ * Calls the pfnVMPowerOff hook for all working extension packs.
+ *
+ * @param   a_pConsole          The console interface for the VM.
+ * @param   a_pVM               The VM handle. Can be NULL.
+ */
+void ExtPackManager::callAllVmPowerOffHooks(IConsole *a_pConsole, PVM a_pVM)
+{
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (FAILED(hrc))
+        return;
+    AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
+
+    for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
+         it != m->llInstalledExtPacks.end();
+         it++)
+        (*it)->callVmPowerOnHook(a_pConsole, a_pVM);
+}
+
 
 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 33692)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 33693)
@@ -192,5 +192,4 @@
 
 VBOX_AUTOGEN_EVENT_CPP  = $(PATH_TARGET)/Main/VBoxEvents.cpp
-OTHER_CLEAN    += $(VBOX_AUTOGEN_EVENT_CPP)
 
 testschemadefs: $(VBOX_XML_SCHEMADEFS_H) $(VBOX_XML_SCHEMADEFS_CPP)
@@ -323,8 +322,4 @@
 	$(if $(VBOX_WITH_EXTPACK),ExtPackManagerImpl.cpp ExtPackUtil.cpp,)
 
-$(VBOX_AUTOGEN_EVENT_CPP): $(VBOX_PATH_MAIN_SRC)/idl/comimpl.xsl $(VBOX_XIDL_FILE) | $$(dir $$@)
-	$(call MSG_TOOL,xsltproc,autogen events,$<,$@)
-	$(QUIET)$(VBOX_XSLTPROC) --stringparam G_kind VBoxEvent -o $@ $< $(VBOX_XIDL_FILE)
-
 VBoxSVC_SOURCES.darwin = \
 	darwin/iokit.cpp \
@@ -435,4 +430,5 @@
 	$(VBOX_XSLTPROC) --stringparam Module VBoxSVC -o $@ $< $(VBOX_XIDL_FILE)
 
+
 #
 # Embed XML Schema files to VBoxSVC
@@ -471,12 +467,22 @@
 
 
+#
+# Generate some event stuff for VBoxSVC and VBoxC.
+#
+$(VBOX_AUTOGEN_EVENT_CPP): $(VBOX_PATH_MAIN_SRC)/idl/comimpl.xsl $(VBOX_XIDL_FILE) | $$(dir $$@)
+	$(call MSG_TOOL,xsltproc,autogen events,$<,$@)
+	$(QUIET)$(VBOX_XSLTPROC) --stringparam G_kind VBoxEvent -o $@ $< $(VBOX_XIDL_FILE)
+
+OTHER_CLEAN += $(VBOX_AUTOGEN_EVENT_CPP)
+
+
+#
+# VBoxTestOGL - OpenGL support test app.
+# Note! Doesn't link with VBOX_WITH_DEBUG_VCC_CRT defined because it uses Qt.
+#
 if (   defined(VBOX_WITH_QTGUI) \
     && (defined(VBOX_WITH_CROGL) || defined(VBOX_WITH_VIDEOHWACCEL)) \
     && !defined(VBOX_WITH_DEBUG_VCC_CRT))
  ifneq ($(KBUILD_TARGET),darwin)
-  #
-  # VBoxTestOGL - OpenGL support test app.
-  # Note! Doesn't link with VBOX_WITH_DEBUG_VCC_CRT defined because it uses Qt.
-  #
   ifdef VBOX_WITH_VIDEOHWACCEL
    USES += qt4
@@ -538,6 +544,6 @@
  endif
 VBoxSVCM_INTERMEDIATES += $(VBOX_IDL_HEADER.XPCOM)
-
 endif # VBOX_WITH_XPCOM
+
 
 #
Index: /trunk/src/VBox/Main/include/ExtPackManagerImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ExtPackManagerImpl.h	(revision 33692)
+++ /trunk/src/VBox/Main/include/ExtPackManagerImpl.h	(revision 33693)
@@ -55,4 +55,5 @@
      * @{ */
     STDMETHOD(COMGETTER(Name))(BSTR *a_pbstrName);
+    STDMETHOD(COMGETTER(Description))(BSTR *a_pbstrDescription);
     STDMETHOD(COMGETTER(Version))(BSTR *a_pbstrVersion);
     STDMETHOD(COMGETTER(Revision))(ULONG *a_puRevision);
@@ -63,6 +64,11 @@
     /** @name Internal interfaces used by ExtPackManager.
      * @{ */
-    void *getCallbackTable();
-    HRESULT refresh(bool *pfCanDelete);
+    void        callInstalledHook(void);
+    HRESULT     callUninstallHookAndClose(bool a_fForcedRemoval);
+    void        callVmCreatedHook(IMachine *a_pMachine);
+    int         callVmConfigureVmmHook(IConsole *a_pConsole, PVM a_pVM);
+    int         callVmPowerOnHook(IConsole *a_pConsole, PVM a_pVM);
+    void        callVmPowerOffHook(IConsole *a_pConsole, PVM a_pVM);
+    HRESULT     refresh(bool *pfCanDelete);
     /** @}  */
 
@@ -112,5 +118,5 @@
     HRESULT     FinalConstruct();
     void        FinalRelease();
-    HRESULT     init();
+    HRESULT     init(const char *a_pszDropZonePath, bool a_fCheckDropZone);
     void        uninit();
     /** @}  */
@@ -126,6 +132,9 @@
     /** @name Internal interfaces used by other Main classes.
      * @{ */
-    int         callAllConfigHooks(IConsole *a_pConsole, PVM a_pVM);
-    int         callAllNewMachineHooks(IMachine *a_pMachine);
+    void        processDropZone(void);
+    void        callAllVmCreatedHooks(IMachine *a_pMachine);
+    int         callAllVmConfigureVmmHooks(IConsole *a_pConsole, PVM a_pVM);
+    int         callAllVmPowerOnHooks(IConsole *a_pConsole, PVM a_pVM);
+    void        callAllVmPowerOffHooks(IConsole *a_pConsole, PVM a_pVM);
     /** @}  */
 
Index: /trunk/src/VBox/Main/include/ExtPackUtil.h
===================================================================
--- /trunk/src/VBox/Main/include/ExtPackUtil.h	(revision 33692)
+++ /trunk/src/VBox/Main/include/ExtPackUtil.h	(revision 33693)
@@ -21,4 +21,7 @@
  * The name of the description file in an extension pack.  */
 #define VBOX_EXTPACK_DESCRIPTION_NAME   "ExtPack.xml"
+/** @name VBOX_EXTPACK_SUFFIX
+ * The suffix of a extension pack tarball. */
+#define VBOX_EXTPACK_SUFFIX             ".vbox-extpack"
 
 
