Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageImport.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageImport.cpp	(revision 17286)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageImport.cpp	(revision 17287)
@@ -581,5 +581,20 @@
             break;
 
-        CHECK_ERROR_BREAK(pAppliance, Write(Bstr(strOutputFile)));
+        ComPtr<IProgress> progress;
+        CHECK_ERROR_BREAK(pAppliance, Write(Bstr(strOutputFile), progress.asOutParam()));
+
+        showProgress(progress);
+
+        if (SUCCEEDED(rc))
+            progress->COMGETTER(ResultCode)(&rc);
+
+        if (FAILED(rc))
+        {
+            com::ProgressErrorInfo info(progress);
+            com::GluePrintErrorInfo(info);
+            com::GluePrintErrorContext("Write", __FILE__, __LINE__);
+        }
+        else
+            RTPrintf("Successfully exported %d machine(s).\n", llMachines.size());
 
     } while (0);
Index: /trunk/src/VBox/Main/ApplianceImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ApplianceImpl.cpp	(revision 17286)
+++ /trunk/src/VBox/Main/ApplianceImpl.cpp	(revision 17287)
@@ -199,12 +199,12 @@
 };
 
-struct Appliance::Task
-{
-    Task(Appliance *aThat, Progress *aProgress)
+struct Appliance::TaskImportMachines
+{
+    TaskImportMachines(Appliance *aThat, Progress *aProgress)
         : that(aThat)
         , progress(aProgress)
         , rc(S_OK)
     {}
-    ~Task() {}
+    ~TaskImportMachines() {}
 
     HRESULT startThread();
@@ -263,7 +263,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
-HRESULT Appliance::Task::startThread()
-{
-    int vrc = RTThreadCreate(NULL, Appliance::taskThread, this,
+HRESULT Appliance::TaskImportMachines::startThread()
+{
+    int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportMachines, this,
                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
                              "Appliance::Task");
@@ -1653,5 +1653,5 @@
 
         /* Initialize our worker task */
-        std::auto_ptr<Task> task(new Task(this, progress));
+        std::auto_ptr<TaskImportMachines> task(new TaskImportMachines(this, progress));
         //AssertComRCThrowRC (task->autoCaller.rc());
 
@@ -1673,5 +1673,5 @@
 }
 
-STDMETHODIMP Appliance::Write(IN_BSTR path)
+STDMETHODIMP Appliance::Write(IN_BSTR path, IProgress **aProgress)
 {
     HRESULT rc = S_OK;
@@ -1740,7 +1740,7 @@
  */
 /* static */
-DECLCALLBACK(int) Appliance::taskThread(RTTHREAD aThread, void *pvUser)
-{
-    std::auto_ptr<Task> task(static_cast<Task *>(pvUser));
+DECLCALLBACK(int) Appliance::taskThreadImportMachines(RTTHREAD aThread, void *pvUser)
+{
+    std::auto_ptr<TaskImportMachines> task(static_cast<TaskImportMachines*>(pvUser));
     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
 
@@ -2696,7 +2696,4 @@
         fDVDEnabled = 1;
 
-        // hardDiskAttachments
-//         mHDData->mAttachments @todo
-
         // this is more tricky so use the COM method
         rc = COMGETTER(USBController)(pUsbController.asOutParam());
@@ -2740,8 +2737,79 @@
                            strMemory);
 
+        uint32_t uControllerId = 1;
+        Utf8Str strIdeControllerID;
+        Utf8Str strSataControllerID;
+
 //     <const name="HardDiskControllerIDE" value="6" />
+        ComPtr<IBIOSSettings> pBiosSettings;
+        pBiosSettings = mBIOSSettings;
+        Utf8Str strConfig;
+        IDEControllerType_T ctlr;
+        rc = pBiosSettings->COMGETTER(IDEControllerType)(&ctlr);
+        if (FAILED(rc)) throw rc;
+        switch(ctlr)
+        {
+            case IDEControllerType_PIIX3: strConfig = "PIIX3"; break;
+            case IDEControllerType_PIIX4: strConfig = "PIIX4"; break;
+            case IDEControllerType_ICH6: strConfig = "ICH6"; break;
+        }
+
+        if (strConfig.length())
+        {
+            strIdeControllerID = Utf8StrFmt("%RI32", uControllerId++);
+            pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerIDE, strIdeControllerID, strConfig, "");
+        }
+
+#ifdef VBOX_WITH_AHCI
 //     <const name="HardDiskControllerSATA" value="7" />
+        ComPtr<ISATAController> pSataController;
+        pSataController = mSATAController;
+        BOOL fSataEnabled;
+        rc = pSataController->COMGETTER(Enabled)(&fSataEnabled);
+        if (FAILED(rc)) throw rc;
+        if (fSataEnabled)
+        {
+            strSataControllerID = Utf8StrFmt("%RI32", uControllerId++);
+            pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskControllerSATA, strSataControllerID, strConfig, "");
+        }
+#endif // VBOX_WITH_AHCI
+
 //     <const name="HardDiskControllerSCSI" value="8" />
+        // @todo
+
 //     <const name="HardDiskImage" value="9" />
+        // hardDiskAttachments
+//         mHDData->mAttachments @todo
+        HDData::AttachmentList::iterator itA;
+        for (itA = mHDData->mAttachments.begin();
+             itA != mHDData->mAttachments.end();
+             ++itA)
+        {
+            ComObjPtr<HardDiskAttachment> pHDA = *itA;
+
+            // get the attachment's data
+            ComPtr<IHardDisk> pHardDisk;
+            StorageBus_T storageBus;
+            LONG lChannel;
+            LONG lDevice;
+
+            rc = pHDA->COMGETTER(HardDisk)(pHardDisk.asOutParam());
+            if (FAILED(rc)) throw rc;
+
+            rc = pHDA->COMGETTER(Bus)(&storageBus);
+            if (FAILED(rc)) throw rc;
+
+            rc = pHDA->COMGETTER(Channel)(&lChannel);
+            if (FAILED(rc)) throw rc;
+
+            rc = pHDA->COMGETTER(Device)(&lDevice);
+            if (FAILED(rc)) throw rc;
+
+            pNewDesc->addEntry(VirtualSystemDescriptionType_HardDiskImage,
+                               "", // hd.strDiskId,
+                               "", // di.strHref,
+                               "",
+                               ""); // strExtraConfig
+        }
 
         /* Floppy Drive */
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 17286)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 17287)
@@ -2927,5 +2927,8 @@
     <attribute name="path" type="wstring" readonly="yes">
       <desc>Path to the main file of the OVF appliance, which is either the <tt>.ovf</tt> or
-          the <tt>.ova</tt> file passed to <link to="IAppliance::read" />.</desc>
+          the <tt>.ova</tt> file passed to <link to="#read" /> (for import) or
+          <link to="#write" /> (for export).
+          This attribute is empty until one of these methods has been called.
+      </desc>
     </attribute>
 
@@ -2971,6 +2974,7 @@
     <attribute name="virtualSystemDescriptions" type="IVirtualSystemDescription" readonly="yes" safearray="yes">
       <desc> Array of virtual system descriptions. One such description is created
-      for each virtual system found in the OVF. The array is empty until after <link to="#interpret" />
-      has been called.
+      for each virtual system found in the OVF.
+      This array is empty until either <link to="#interpret" /> (for import) or <link to="IMachine::export" />
+      (for export) has been called.
       </desc>
     </attribute>
@@ -3015,7 +3019,7 @@
         see <link to="IAppliance" /> for an overview.
 
-        Since importing the appliance may imply copying disk images, which can take a long
-        time, this method operates asynchronously and returns an IProgress object to allow
-        the caller to monitor the progress.
+        Since importing the appliance will most probably involve copying and converting
+        disk images, which can take a long time, this method operates asynchronously and
+        returns an IProgress object to allow the caller to monitor the progress.
       </desc>
 
@@ -3031,4 +3035,8 @@
           Calling this method is the final step of exporting an appliance from VirtualBox;
           see <link to="IAppliance" /> for an overview.
+
+          Since importing the appliance will most probably involve copying and converting
+          disk images, which can take a long time, this method operates asynchronously and
+          returns an IProgress object to allow the caller to monitor the progress.
       </desc>
       <param name="path" type="wstring" dir="in">
@@ -3037,4 +3045,7 @@
           on whether the appliance is distributed as a set of files or as a single file, respectively).
         </desc>
+      </param>
+      <param name="aProgress" type="IProgress" dir="return">
+          <desc></desc>
       </param>
     </method>
@@ -3135,5 +3146,5 @@
       </li>
       <li>
-        "Harddisk": a virtual hard disk, most probably as a reference to an image file. There can be an
+        "HardDiskImage": a virtual hard disk, most probably as a reference to an image file. There can be an
         arbitrary number of these items, one for each virtual disk image that accompanies the OVF. The
         array item in aOrigValues[] will contain the file specification from the OVF file, whereas the
Index: /trunk/src/VBox/Main/include/ApplianceImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ApplianceImpl.h	(revision 17286)
+++ /trunk/src/VBox/Main/include/ApplianceImpl.h	(revision 17287)
@@ -77,5 +77,5 @@
     STDMETHOD(Interpret)(void);
     STDMETHOD(ImportMachines)(IProgress **aProgress);
-    STDMETHOD(Write)(IN_BSTR path);
+    STDMETHOD(Write)(IN_BSTR path, IProgress **aProgress);
     /* public methods only for internal purposes */
 
@@ -85,5 +85,6 @@
     const ComObjPtr <VirtualBox, ComWeakRef> mVirtualBox;
 
-    struct Task; /* Worker thread for import */
+    struct TaskImportMachines; /* Worker thread for import */
+    struct TaskExportOVF; /* Worker thread for import */
 
     struct Data;            // obscure, defined in AppliannceImpl.cpp
@@ -98,5 +99,6 @@
     HRESULT searchUniqueDiskImageFilePath(Utf8Str& aName) const;
 
-    static DECLCALLBACK(int) taskThread(RTTHREAD thread, void *pvUser);
+    static DECLCALLBACK(int) taskThreadImportMachines(RTTHREAD thread, void *pvUser);
+    static DECLCALLBACK(int) taskThreadExportOVF(RTTHREAD thread, void *pvUser);
 
     friend class Machine;
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 17286)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 17287)
@@ -281,5 +281,5 @@
      *  taking or discarding snapshots, etc.
      *
-     *  The data variable is |mHWData|.
+     *  The data variable is |mHDData|.
      */
     struct HDData
