List:Commits« Previous MessageNext Message »
From:Mike Lischke Date:May 31 2011 1:10pm
Subject:bzr commit into wex-installer-1.0 branch (mike.lischke:487)
View as plain text  
#At file:///D:/Work/MySQL/installer/ based on revid:iggy@mysql.com-20110527131445-foy1j3zdqmf9m74d

  487 Mike Lischke	2011-05-31
      - Enabled "Check Requirements" page in installation wizard.
      - Added code to download and install requirements automatically, however this code is not used currently because of trouble with progress events.
      - Added external installer class which is used to chain external installers (e.g. the .NET 4.0 framework exe installer) using the IronSpigot "framework". This belongs to the not-used code above.
      - Added simplified version for the prerequisites (the user has to click Execute to launch a browser and install manually, then his must click re-check to do a new check which gives him the next task if there is still one or allows to coninue with the main installation).
      - Installer: added ability to cancel an action (not used in the msi installer, but in the external one).
      - Fixed a number of typos.
      - Enhanced the requirements setting for a package with an official link (which is thought as fallback if automatic installation fails, but is now used as the linke for the user to do the manual installation).
      - Moved OpenBrowser to the utilities class as it is used now from different places.
      - Added .net 4 client + full checks for the requirements page.
      - Win32: added support for memory mapped files.

    added:
      WexInstaller.Core/ExternalInstaller.cs
    modified:
      WexInstaller.Core/Installer.cs
      WexInstaller.Core/InstallerPanel.Designer.cs
      WexInstaller.Core/InstallerPanel.cs
      WexInstaller.Core/InstallerPanel.resx
      WexInstaller.Core/Logger.cs
      WexInstaller.Core/MsiInterop.cs
      WexInstaller.Core/Package.cs
      WexInstaller.Core/Product.cs
      WexInstaller.Core/Utilities.cs
      WexInstaller.Core/WexInstaller.Core.csproj
      WexInstaller.Core/Win32.cs
      WexInstaller/Controls/InstallWizardControl.Designer.cs
      WexInstaller/Controls/InstallWizardControl.cs
      WexInstaller/InstallWizard/CheckRequirements.Designer.cs
      WexInstaller/InstallWizard/CheckRequirements.cs
      WexInstaller/InstallWizard/CheckRequirements.resx
      WexInstaller/InstallWizard/DetailedUpdateCheck.Designer.cs
      WexInstaller/Properties/Resources.Designer.cs
      WexInstaller/Properties/Resources.resx
      WexInstaller/WexInstaller.csproj
      common/products.xml
=== added file 'WexInstaller.Core/ExternalInstaller.cs'
=== added file 'WexInstaller.Core/ExternalInstaller.cs'
--- a/WexInstaller.Core/ExternalInstaller.cs	1970-01-01 00:00:00 +0000
+++ b/WexInstaller.Core/ExternalInstaller.cs	2011-05-31 13:10:52 +0000
@@ -0,0 +1,497 @@
+
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Text;
+using System.Diagnostics;
+using System.Security.AccessControl;
+
+using Microsoft.Win32.SafeHandles;
+
+using MySQL.Utilities.SysUtils;
+
+// The external installer provides access to progress events for externally started setup
+// applications which support it (IronSpigot framework, e.g. .NET 4.0 setup). It launches the 
+// setup application as external process and listens for events using a memory mapped file.
+
+namespace WexInstaller.Core
+{
+  public interface IProgressObserver
+  {
+    void OnProgress(byte progress); // 0 - 255:  255 == 100%
+    void Finished(Win32.HRESULT result);   // Called when operation is complete
+  };
+
+  // MMIO Data Structure for inter process communication.
+  [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
+  unsafe struct MmioDataStructure
+  {
+    [MarshalAs(UnmanagedType.Bool)]
+    public bool DownloadFinished;                // Is the download done yet?
+
+    [MarshalAs(UnmanagedType.Bool)]
+    public bool InstallFinished;                 // Is installer operation done yet?
+
+    [MarshalAs(UnmanagedType.Bool)]
+    public bool DownloadAbort;                   // Set to cause downloader to abort.
+
+    [MarshalAs(UnmanagedType.Bool)]
+    public bool InstallAbort;                    // Set to cause installer operation to abort.
+
+    public Win32.HRESULT ResultDownloadFinished; // Result for download operation.
+    public Win32.HRESULT ResultInstallFinished;  // Result for installer operation.
+    public Win32.HRESULT ResultInternalError;    // "Internal" error from setup if applicable.
+
+    //[MarshalAs(UnmanagedType.ByValTStr, SizeConst=Win32.MAX_PATH)]
+    //public string CurrentItemStep;               // This gives the windows installer step being executed if an error occurs whilst processing an MSI, e.g. "Rollback"
+    public fixed Char CurrentItemStep[Win32.MAX_PATH];
+    public byte DownloadProgressSoFar;           // Download progress 0 - 255 (0 to 100% done).
+    public byte InstallProgressSoFar;            // Install progress 0 - 255 (0 to 100% done).
+
+    //[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Win32.MAX_PATH + 1)]
+    //public string EventName;                     // Name for event to sync communication.
+    public fixed Char EventName[Win32.MAX_PATH];
+  };
+
+  // This is the class structure that one needs to follow to implement a chainer.
+  // You would derive your server class from MMIOChainer to chain the .NET 4.0 Redistributable.
+  //
+  // MmioChainerBase class manages the communication and synchronization data 
+  // structures. It also implements common getters (for chainer) and setters (for chainee).
+  public unsafe class MmioChainerBase : IDisposable
+  {
+    IntPtr fileMappingHandle;
+    EventWaitHandle signal;
+    IntPtr nativeData;
+
+    public MmioChainerBase(IntPtr mappingHandle, EventWaitHandle waitEvent)
+    {
+      // The base class takes ownership of the mapping handle and closes it on destruction.
+      fileMappingHandle = mappingHandle;
+      signal = waitEvent;
+      MapView();
+    }
+
+    public virtual void Dispose()
+    {
+      if (nativeData != null)
+      {
+        Win32.UnmapViewOfFile(nativeData);
+        Win32.CloseHandle(fileMappingHandle);
+      }
+    }
+
+    /// <summary>
+    /// Creates the native file mapping for this class.
+    /// </summary>
+    protected void MapView()
+    {
+      if (fileMappingHandle != null)
+      {
+        nativeData = Win32.MapViewOfFile(fileMappingHandle, Win32.FileMapAccess.FileMapAllAccess,
+          0, 0, Marshal.SizeOf(typeof(MmioDataStructure)));
+      }
+    }
+
+    public EventWaitHandle EventHandle
+    {
+      get { return signal; }
+    }
+
+    // This is called by the chainer.
+    public void Init(string eventName)
+    {
+      if (nativeData == null)
+        return;
+      
+      //MmioDataStructure mmioData = (MmioDataStructure) Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+      MmioDataStructure* mmioData = (MmioDataStructure*) nativeData.ToPointer();
+
+      // Common items for download and install
+      //mmioData.EventName = eventName;
+      int currentIndex = 0;
+      foreach (Char ch in eventName)
+        mmioData->EventName[currentIndex++] = ch;
+
+      // Download specific data.
+      mmioData->DownloadFinished = false;
+      mmioData->DownloadProgressSoFar = 77;
+      mmioData->ResultDownloadFinished = Win32.HRESULT.E_PENDING;
+      mmioData->DownloadAbort = false;
+
+      // Install specific data
+      mmioData->InstallFinished = false;
+      mmioData->InstallProgressSoFar = 88;
+      mmioData->ResultInstallFinished = Win32.HRESULT.E_PENDING;
+      mmioData->InstallAbort = false;
+
+      mmioData->ResultInternalError = Win32.HRESULT.S_OK;
+
+      // Write the data back to the file mapping.
+      //Marshal.StructureToPtr(mmioData, nativeData, false);
+    }
+
+    // This is called by the chainer to force the chained setup to be canceled.
+    public virtual void Abort()
+    {
+      if (nativeData == null)
+        return;
+
+      MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+      // Chainer told us to cancel.
+      mmioData.DownloadAbort= true;
+      mmioData.InstallAbort = true;
+
+      Marshal.StructureToPtr(mmioData, nativeData, false);
+    }
+
+    // Called when chainer wants to know if chained setup has finished both download and install.
+    public bool Done
+    {
+      get
+      {
+        if (nativeData == null)
+          return true;
+
+        //MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+        MmioDataStructure* mmioData = (MmioDataStructure*)nativeData.ToPointer();
+
+        return mmioData->DownloadFinished && mmioData->InstallFinished; 
+      }
+    }
+
+    // Called by the chainer to get the overall progress, i.e. the combination of the download and install.
+    public byte Progress
+    {
+      get
+      {
+        if (nativeData == null)
+          return 255;
+
+        //MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+        MmioDataStructure* mmioData = (MmioDataStructure*) nativeData.ToPointer();
+
+        return (byte)((mmioData->DownloadProgressSoFar + mmioData->InstallProgressSoFar) / 2);
+      }
+    }
+
+    public byte DownloadProgress
+    {
+      get
+      {
+        if (nativeData == null)
+          return 255;
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        return mmioData.DownloadProgressSoFar;
+      }
+    }
+
+    public byte InstallProgress
+    {
+      get
+      {
+        if (nativeData == null)
+          return 255;
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        return mmioData.InstallProgressSoFar;
+      }
+    }
+
+    // Get the combined setup result. The install taking priority over download if both failed.
+    public Win32.HRESULT Result
+    {
+      get
+      {
+        if (nativeData == null)
+          return Win32.HRESULT.S_FALSE;
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        if (mmioData.ResultInstallFinished != Win32.HRESULT.S_OK)
+          return mmioData.ResultInstallFinished;
+        else
+          return mmioData.ResultDownloadFinished;
+      }
+    }
+
+    public Win32.HRESULT DownloadResult
+    {
+      get
+      {
+        if (nativeData == null)
+          return Win32.HRESULT.S_FALSE;
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        return mmioData.ResultDownloadFinished;
+      }
+    }
+
+    public Win32.HRESULT InstallResult
+    {
+      get
+      {
+        if (nativeData == null)
+          return Win32.HRESULT.S_FALSE;
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        return mmioData.ResultInstallFinished;
+      }
+    }
+
+    public Win32.HRESULT InternalResult
+    {
+      get
+      {
+        if (nativeData == null)
+          return Win32.HRESULT.S_FALSE;
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        return mmioData.ResultInternalError;
+      }
+    }
+
+    // Get the current item step from chainee.
+    public string CurrentItemStep
+    {
+      get
+      {
+        if (nativeData == null)
+          return "";
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        return new string(mmioData.CurrentItemStep);
+      }
+    }
+
+    // The chainee calls this to see if the chainer has asked that we cancel
+    public bool Aborted
+    {
+      get
+      {
+        if (nativeData == null)
+          return false;
+
+        MmioDataStructure mmioData = (MmioDataStructure)Marshal.PtrToStructure(nativeData, typeof(MmioDataStructure));
+
+        return mmioData.InstallAbort || mmioData.DownloadAbort;
+      }
+    }
+  };
+  
+  /// <summary>
+  /// This is the class that consumers (chainer) should derive from.
+  /// </summary>
+  public class MmioChainer : MmioChainerBase
+  {
+    public MmioChainer(string sectionName, string eventName)
+      : base(CreateMapping(sectionName), CreateEvent(eventName))
+    {
+      Init(eventName);
+    }
+    
+    private static IntPtr CreateMapping(string sectionName)
+    {
+      return Win32.CreateFileMapping(Win32.INVALID_HANDLE_VALUE, IntPtr.Zero,
+        Win32.FileMapProtection.PageReadWrite, 0, Marshal.SizeOf(typeof(MmioDataStructure)), sectionName);
+    }
+
+    private static EventWaitHandle CreateEvent(string name)
+    {
+      // Creation is a bit tricky. We need the AutoResetEvent class for the wait call in Run()
+      // but created handle does not work with the external installer package. So have to replace it
+      // with a "proper" one.
+      AutoResetEvent result = new AutoResetEvent(false);
+      result.Close();
+      GC.ReRegisterForFinalize(result);
+      IntPtr eh = Win32.CreateEvent(IntPtr.Zero, false, false, name);
+      result.SafeWaitHandle = new SafeWaitHandle(
+        eh,
+        true);
+
+      return result;
+    }
+
+    /// <summary>
+    /// Called by the chainer to start the chained setup. This blocks until the setup is complete.
+    /// </summary>
+    /// <param name="process">The handle to the external setup process.</param>
+    /// <param name="observer">An observer for events.</param>
+    public void Run(Process process, IProgressObserver observer)
+    {
+      AutoResetEvent waitHandle = new AutoResetEvent(false);
+      waitHandle.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);
+      EventWaitHandle[] handles = { waitHandle, EventHandle };
+      
+      while(!Done)
+      {
+        switch (WaitHandle.WaitAny(handles, 200))
+        {
+          case 0:
+            {
+              // Process handle closed. Maybe it blew up, maybe it's just really fast. Let's find out.
+              if (!Done)
+              {
+                if (Result == Win32.HRESULT.E_PENDING) // Result wasn't touched at all.
+                  observer.Finished(Win32.HRESULT.E_FAIL);
+                else
+                  observer.Finished(Result);
+                
+                return;
+              }
+              break;
+            }
+
+        case 1:
+          observer.OnProgress(Progress);
+          break;
+
+        default:
+          break;
+        }		
+      }
+      observer.Finished(Result);
+    }
+
+  };
+
+  /*
+  // This is used by the chainee
+  class MmioChainee : protected MmioChainerBase
+  {
+  public:
+      MmioChainee(LPCWSTR sectionName)
+          : MmioChainerBase(OpenSection(sectionName), OpenEvent(GetEventName(sectionName)))
+      {
+      }
+
+      virtual ~MmioChainee()
+      {
+      }
+
+  private:
+      static HANDLE OpenSection(LPCWSTR sectionName)
+      {
+          return ::OpenFileMapping(FILE_MAP_WRITE, // read/write access
+              FALSE,          // do not inherit the name
+              sectionName);
+      }
+
+      static HANDLE OpenEvent(LPCWSTR eventName)
+      {        
+          return ::OpenEvent (EVENT_MODIFY_STATE | SYNCHRONIZE,
+              FALSE,
+              eventName);
+      }
+
+      static CString GetEventName(LPCWSTR sectionName)
+      {
+          CString cs = L"";
+
+          HANDLE handle = OpenSection(sectionName);
+          if (NULL == handle)
+          {
+              DWORD dw;
+              dw = GetLastError();
+              printf("OpenFileMapping fails with last error: %08x",dw);
+          }
+          else
+          {
+              const MmioDataStructure* pData = MapView(handle);
+              if (pData)
+              {
+                  cs = pData->m_szEventName;
+                  ::UnmapViewOfFile(pData);
+              }
+              ::CloseHandle(handle);
+          }
+
+          return cs;
+      }
+  };
+  */
+
+    /// <summary>
+  /// This class runs an external installer file (usually *.exe) with some additional parameters
+  /// and hooks into its progress reporting (if supported).
+  /// </summary>
+  public class ExternalInstaller : MmioChainer, IProgressObserver
+  {
+    private string file;
+    private string arguments;
+
+    public ExternalInstaller(string file, string arguments)
+      : base("MySQLInstallerSection", "MySQLInstallerEvent")
+    {
+      this.file = file;
+      this.arguments = " /pipe MySQLInstallerSection " + arguments;
+    }
+
+    public Win32.HRESULT Run()
+    {
+      ChainedInstallerEventArgs args = new ChainedInstallerEventArgs();
+      args.Action = ChainedInstallerAction.ProgressSetRange;
+      args.ProgressMin = 0;
+      args.ProgressMax = 255;
+      args.ProgressPosition = 0;
+      SendUpdate(args);
+
+      args.Action = ChainedInstallerAction.StartInstallation;
+      args.ProgressPosition = 0;
+      SendUpdate(args);
+
+      ProcessStartInfo startInfo = new ProcessStartInfo(file, arguments);
+      startInfo.UseShellExecute = false;
+      Process setupProcess = Process.Start(startInfo);
+      Run(setupProcess, this);
+
+      return Result;
+    }
+
+    public override void Abort()
+    {
+      base.Abort();
+
+      ChainedInstallerEventArgs args = new ChainedInstallerEventArgs();
+      args.Action = ChainedInstallerAction.EndInstallation;
+      args.Message = "Setup aborted";
+      SendUpdate(args);
+    }
+
+    public void OnProgress(byte progress)
+    {
+      ChainedInstallerEventArgs args = new ChainedInstallerEventArgs();
+      args.Action = ChainedInstallerAction.ProgressSetPosition;
+      args.ProgressPosition = progress;
+      SendUpdate(args);
+    }
+
+    public void Finished(Win32.HRESULT result)
+    {
+      ChainedInstallerEventArgs args = new ChainedInstallerEventArgs();
+      args.Action = ChainedInstallerAction.EndInstallation;
+      args.ExitCode = (uint) result;
+      args.ProgressPosition = 255;
+      SendUpdate(args);
+    }
+
+    public event ChainedInstallerUpdateEventHandler Updated;
+    protected void SendUpdate(ChainedInstallerEventArgs c)
+    {
+      c.Cancel = false;
+      if (Updated != null)
+        Updated(this, c);
+      if (c.Cancel)
+        Abort();
+    }
+
+  }
+}

=== modified file 'WexInstaller.Core/Installer.cs'
--- a/WexInstaller.Core/Installer.cs	2011-02-21 16:37:13 +0000
+++ b/WexInstaller.Core/Installer.cs	2011-05-31 13:10:52 +0000
@@ -171,9 +171,11 @@
         public int ProgressMin { get; set;}
         public int ProgressMax {get; set;}
         public int ProgressStep {get; set;}
-        public int ProgressPosition {get; set;}
-        public uint ExitCode { get; set;}
+        public int ProgressPosition { get; set; }
+        public uint ExitCode { get; set; }
+        public bool Cancel { get; set; }
     }
+
     public delegate void ChainedInstallerUpdateEventHandler(object sender, ChainedInstallerEventArgs c);
 
     public class ChainedInstaller
@@ -187,8 +189,9 @@
         public event ChainedInstallerUpdateEventHandler Updated;
         protected void SendUpdate(ChainedInstallerEventArgs c)
         {
-            if (Updated != null)
-                Updated(this, c);
+          c.Cancel = false;
+          if (Updated != null)
+            Updated(this, c);
         }
 
         public ChainedInstaller()

=== modified file 'WexInstaller.Core/InstallerPanel.Designer.cs'
--- a/WexInstaller.Core/InstallerPanel.Designer.cs	2011-04-18 08:06:38 +0000
+++ b/WexInstaller.Core/InstallerPanel.Designer.cs	2011-05-31 13:10:52 +0000
@@ -82,9 +82,9 @@
 
         #endregion
 
-        public System.Windows.Forms.Label captionLabel;
         private System.Windows.Forms.PictureBox topDivider;
         public System.Windows.Forms.Label subCaptionLabel;
         private System.Windows.Forms.PictureBox bottomDivider;
+        public System.Windows.Forms.Label captionLabel;
     }
 }

=== modified file 'WexInstaller.Core/InstallerPanel.cs'
--- a/WexInstaller.Core/InstallerPanel.cs	2011-05-23 15:01:40 +0000
+++ b/WexInstaller.Core/InstallerPanel.cs	2011-05-31 13:10:52 +0000
@@ -57,6 +57,12 @@
       set { captionLabel.Text = value;  }
     }
 
+    public string SubCaption
+    {
+      get { return subCaptionLabel.Text; }
+      set { subCaptionLabel.Text = value; }
+    }
+
     protected void SignalChange()
     {
       if (StatusChanged != null)
@@ -172,11 +178,6 @@
       return cancelOk;
     }
 
-    protected void OpenBrowser(string url)
-    {
-        Process.Start(url);
-    }
-
     private void InstallerPanel_Load(object sender, EventArgs e)
     {
       LoadingDone();

=== modified file 'WexInstaller.Core/InstallerPanel.resx'
--- a/WexInstaller.Core/InstallerPanel.resx	2011-04-18 08:06:38 +0000
+++ b/WexInstaller.Core/InstallerPanel.resx	2011-05-31 13:10:52 +0000
@@ -117,9 +117,6 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <metadata name="captionLabel.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
   <assembly alias="mscorlib" name="mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
   <data name="captionLabel.AutoSize" type="System.Boolean, mscorlib">
     <value>True</value>
@@ -156,9 +153,6 @@
   <data name="&gt;&gt;captionLabel.ZOrder" xml:space="preserve">
     <value>3</value>
   </data>
-  <metadata name="topDivider.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
   <data name="topDivider.Location" type="System.Drawing.Point, System.Drawing">
     <value>26, 56</value>
   </data>
@@ -183,12 +177,6 @@
   <data name="&gt;&gt;topDivider.ZOrder" xml:space="preserve">
     <value>2</value>
   </data>
-  <metadata name="subCaptionLabel.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <data name="subCaptionLabel.AutoSize" type="System.Boolean, mscorlib">
-    <value>True</value>
-  </data>
   <data name="subCaptionLabel.Font" type="System.Drawing.Font, System.Drawing">
     <value>Tahoma, 9pt, style=Bold</value>
   </data>
@@ -199,7 +187,7 @@
     <value>0, 0, 0, 0</value>
   </data>
   <data name="subCaptionLabel.Size" type="System.Drawing.Size, System.Drawing">
-    <value>361, 14</value>
+    <value>522, 38</value>
   </data>
   <data name="subCaptionLabel.TabIndex" type="System.Int32, mscorlib">
     <value>2</value>
@@ -219,9 +207,6 @@
   <data name="&gt;&gt;subCaptionLabel.ZOrder" xml:space="preserve">
     <value>1</value>
   </data>
-  <metadata name="bottomDivider.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
   <data name="bottomDivider.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
     <value>Bottom</value>
   </data>
@@ -255,9 +240,6 @@
   <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
-  <metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
   <data name="$this.Font" type="System.Drawing.Font, System.Drawing">
     <value>Tahoma, 8.25pt</value>
   </data>

=== modified file 'WexInstaller.Core/Logger.cs'
--- a/WexInstaller.Core/Logger.cs	2011-05-17 09:27:10 +0000
+++ b/WexInstaller.Core/Logger.cs	2011-05-31 13:10:52 +0000
@@ -10,8 +10,6 @@
 
     static Logger()
     {
-      source.Listeners.RemoveAt(0); // Remove default listener.
-
       source.Switch = new SourceSwitch("sourceSwitch");
       source.Switch.Level = SourceLevels.All;
       source.Listeners.Add(new LoggerListener());
@@ -29,7 +27,8 @@
     public static void PrepareConsoleMode()
     {
       // Remove log file listener and add a console listener instead.
-      source.Listeners.RemoveAt(0);
+      if (source.Listeners.Count > 1)
+        source.Listeners.RemoveAt(1);
       source.Listeners.Add(new ConsoleTraceListener());
     }
 

=== modified file 'WexInstaller.Core/MsiInterop.cs'
--- a/WexInstaller.Core/MsiInterop.cs	2011-02-21 16:37:13 +0000
+++ b/WexInstaller.Core/MsiInterop.cs	2011-05-31 13:10:52 +0000
@@ -104,7 +104,7 @@
     {
         Success = 0,
         InvalidHandle = 6,
-        NotEnoughMomory = 8,
+        NotEnoughMemory = 8,
         InvalidData = 13,
         InvalidParameter = 87,
         CallNotImplemented = 120,

=== modified file 'WexInstaller.Core/Package.cs'
--- a/WexInstaller.Core/Package.cs	2011-05-27 13:14:45 +0000
+++ b/WexInstaller.Core/Package.cs	2011-05-31 13:10:52 +0000
@@ -12,10 +12,27 @@
 
 namespace WexInstaller.Core
 {
-  public class PacakgeRequirement
+  /// <summary>
+  /// Type of requirements for a certain package.
+  /// </summary>
+  public enum RequirementType
+  {                          // Actions involved:
+    DotNetFramework40Client, // Download and install.
+    DotNetFramework40Full,   // Download and install.
+    MinTargetDiskSize,       // Disk check.
+    MinCacheDiskSize,        // Disk check.
+  }
+
+  /// <summary>
+  /// Describes one requirement for a package. Each package can have zero or more requirements
+  /// before it can be installed and/or used.
+  /// A requirement is an external dependency to certain system libraries/frameworks etc. or another
+  /// product/package that must be installed to be able to use this package.
+  /// </summary>
+  public class PackageRequirement
   {
-    [XmlAttribute("filename")]
-    public string FileName { get; set; }
+    [XmlAttribute("type")]
+    public RequirementType Type { get; set; }
 
     [XmlAttribute("description")]
     public string Description { get; set; }
@@ -23,6 +40,9 @@
     [XmlAttribute("location")]
     public string Location { get; set; }
 
+    [XmlAttribute("officialLink")]
+    public string OfficialLink { get; set; } // Link for manual setup if our silent setup fails.
+
     [XmlAttribute("size")]
     public long Size { get; set; }
   }
@@ -55,7 +75,7 @@
     public List<ProductFeature> Features { get; set; }
 
     [XmlElement("Requirement")]
-    public List<PacakgeRequirement> Requirements { get; set; }
+    public List<PackageRequirement> Requirements { get; set; }
 
     [XmlIgnore]
     public string UrlBase { get; set; }

=== modified file 'WexInstaller.Core/Product.cs'
--- a/WexInstaller.Core/Product.cs	2011-04-18 13:36:47 +0000
+++ b/WexInstaller.Core/Product.cs	2011-05-31 13:10:52 +0000
@@ -644,8 +644,6 @@
         CurrentState = ProductState.InstallStarted;
         ExecuteMSI(parameters, new RunWorkerCompletedEventHandler(bgw_RunExecuteMSICompleted));
       }
-
-      return;
     }
 
     public void Remove()
@@ -1287,6 +1285,7 @@
     FoundLocal,
     WillPerformUpgrade,
     CurrentlyInstalled,
+    
     DownloadStarted,
     DownloadMirrorSelection,
     DownloadInProgress,
@@ -1294,14 +1293,17 @@
     DownloadError,
     DownloadCancelled,
     DownloadNoMirror,
+    
     InstallStarted,
     InstallInProgress,
     InstallSuccess,
     InstallError,
+    
     RemoveStarted,
     RemoveInProgress,
     RemoveSuccess,
     RemoveFailed,
+
     UpdateStarted,
     UpdateInProgress,
     UpdateSuccess,

=== modified file 'WexInstaller.Core/Utilities.cs'
--- a/WexInstaller.Core/Utilities.cs	2011-05-10 10:02:42 +0000
+++ b/WexInstaller.Core/Utilities.cs	2011-05-31 13:10:52 +0000
@@ -1,9 +1,9 @@
 
+using System;
+using System.Diagnostics;
+using System.Drawing;
 using System.Windows.Forms;
 using Microsoft.Win32;
-using System;
-using System.Drawing;
-
 
 namespace WexInstaller.Core
 {
@@ -79,5 +79,71 @@
         MakeFontsNonAmbient(child);
     }
 
+    public static void OpenBrowser(string url)
+    {
+      Process.Start(url);
+    }
+
+    /// <summary>
+    /// Returns the entire version number for the currently installed .NET 4 client profile
+    /// framework installation. If that is not installed then an empty version is returned.
+    /// </summary>
+    public static Version GetDotNet4ClientVersion()
+    {
+      RegistryKey frameworkEntry = Registry.LocalMachine;
+      frameworkEntry = frameworkEntry.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v5\Client\", false);
+      try
+      {
+        if (frameworkEntry == null)
+          return new Version();
+
+        Int32 installed = (Int32) frameworkEntry.GetValue("Install", 0);
+        if (installed == 0)
+          return new Version();
+
+        return new Version(frameworkEntry.GetValue("Version", "") as string);
+      }
+      catch (Exception e)
+      {
+        Logger.LogException(e);
+        return new Version();
+      }
+      finally
+      {
+        if (frameworkEntry != null)
+          frameworkEntry.Close();
+      }
+    }
+
+    /// <summary>
+    /// Returns the entire version number for the currently installed .NET 4 full profile
+    /// framework installation. If that is not installed then an empty version is returned.
+    /// </summary>
+    public static Version GetDotNet4FullVersion()
+    {
+      RegistryKey frameworkEntry = Registry.LocalMachine;
+      frameworkEntry = frameworkEntry.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v5\Full\", false);
+      try
+      {
+        if (frameworkEntry == null)
+          return new Version();
+
+        Int32 installed = (Int32)frameworkEntry.GetValue("Install", 0);
+        if (installed == 0)
+          return new Version();
+
+        return new Version(frameworkEntry.GetValue("Version", "") as string);
+      }
+      catch (Exception e)
+      {
+        Logger.LogException(e);
+        return new Version();
+      }
+      finally
+      {
+        if (frameworkEntry != null)
+          frameworkEntry.Close();
+      }
+    }
   }
 }

=== modified file 'WexInstaller.Core/WexInstaller.Core.csproj'
--- a/WexInstaller.Core/WexInstaller.Core.csproj	2011-04-09 02:14:47 +0000
+++ b/WexInstaller.Core/WexInstaller.Core.csproj	2011-05-31 13:10:52 +0000
@@ -23,6 +23,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>

   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -32,6 +33,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <PlatformTarget>AnyCPU</PlatformTarget>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="Ionic.Zip">
@@ -45,6 +47,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="ExternalInstaller.cs" />
     <Compile Include="Installer.cs" />
     <Compile Include="InstallerConfiguration.cs" />
     <Compile Include="InstallerPanel.cs">

=== modified file 'WexInstaller.Core/Win32.cs'
--- a/WexInstaller.Core/Win32.cs	2011-04-04 17:52:54 +0000
+++ b/WexInstaller.Core/Win32.cs	2011-05-31 13:10:52 +0000
@@ -2341,6 +2341,8 @@
   /// </summary>
   public class Win32
   {
+    public const int MAX_PATH = 260;
+
     // GetWindow() constants
     public const uint GW_HWNDFIRST = 0;
     public const uint GW_HWNDLAST = 1;
@@ -2481,8 +2483,73 @@
     public const int SERVICE_TYPE_WIN32_OWN_PROCESS = 0x10;
     public const int SERVICE_TYPE_WIN32_SHARE_PROCESS = 0x20;
 
+    public static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
+
     #region Structures and data types
 
+    public enum HRESULT : long
+    {
+      S_OK          = 0x00000000,
+      S_FALSE       = 0x00000001,
+      E_PENDING     = 0x8000000A,
+      E_FAIL        = 0x80004005,
+      E_OUTOFMEMORY = 0x8007000E,
+      E_INVALIDARG  = 0x80070057
+    }
+
+    [Flags]
+    public enum FileMapProtection : uint
+    {
+      PageNone = 0,
+      PageReadonly = 0x02,
+      PageReadWrite = 0x04,
+      PageWriteCopy = 0x08,
+      PageExecuteRead = 0x20,
+      PageExecuteReadWrite = 0x40,
+      SectionCommit = 0x8000000,
+      SectionImage = 0x1000000,
+      SectionNoCache = 0x10000000,
+      SectionReserve = 0x4000000,
+    }
+
+    public enum FileMapAccess : uint
+    {
+      FileMapCopy = 0x0001,
+      FileMapWrite = 0x0002,
+      FileMapRead = 0x0004,
+      FileMapAllAccess = 0x001f,
+      fileMapExecute = 0x0020,
+    }
+
+    public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
+    public const uint SYNCHRONIZE = 0x00100000;
+    public const uint EVENT_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3);
+    public const uint EVENT_MODIFY_STATE = 0x0002;
+    public const long ERROR_FILE_NOT_FOUND = 2L;
+
+    /// <summary>
+    /// Security enumeration from:
+    /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/synchronization_object_security_and_access_rights.asp
+    /// </summary>
+    [Flags]
+    public enum SyncObjectAccess : uint
+    {
+      DELETE = 0x00010000,
+      READ_CONTROL = 0x00020000,
+      WRITE_DAC = 0x00040000,
+      WRITE_OWNER = 0x00080000,
+      SYNCHRONIZE = 0x00100000,
+      EVENT_ALL_ACCESS = 0x001F0003,
+      EVENT_MODIFY_STATE = 0x00000002,
+      MUTEX_ALL_ACCESS = 0x001F0001,
+      MUTEX_MODIFY_STATE = 0x00000001,
+      SEMAPHORE_ALL_ACCESS = 0x001F0003,
+      SEMAPHORE_MODIFY_STATE = 0x00000002,
+      TIMER_ALL_ACCESS = 0x001F0003,
+      TIMER_MODIFY_STATE = 0x00000002,
+      TIMER_QUERY_STATE = 0x00000001
+    }
+
     [StructLayout(LayoutKind.Sequential)]
     public struct MINMAXINFO
     {
@@ -2585,7 +2652,7 @@
     }
 
     [StructLayout(LayoutKind.Sequential, Pack = 1)]
-    struct ARGB
+    public struct ARGB
     {
       public byte Blue;
       public byte Green;
@@ -2988,7 +3055,10 @@
     public static extern IntPtr OpenSCManager(string machineName, string databaseName, int access);
 
     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
-    public static extern IntPtr CreateService(IntPtr databaseHandle, string serviceName, string displayName, int access, int serviceType, int startType, int errorControl, string binaryPath, string loadOrderGroup, IntPtr pTagId, string dependencies, string servicesStartName, string password);
+    public static extern IntPtr CreateService(IntPtr databaseHandle, string serviceName,
+      string displayName, int access, int serviceType, int startType, int errorControl,
+      string binaryPath, string loadOrderGroup, IntPtr pTagId, string dependencies,
+      string servicesStartName, string password);
 
     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
     public static extern bool DeleteService(IntPtr serviceHandle);
@@ -2996,6 +3066,26 @@
     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
     public static extern IntPtr OpenService(IntPtr databaseHandle, string serviceName, int access);
 
+    [DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
+    public static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpAttributes,
+      FileMapProtection flProtect, Int32 dwMaxSizeHi, Int32 dwMaxSizeLow, string lpName);
+
+    [DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
+    public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, FileMapAccess dwDesiredAccess,
+      Int32 dwFileOffsetHigh, Int32 dwFileOffsetLow, Int32 dwNumberOfBytesToMap);
+
+    [DllImport("kernel32.dll")]
+    public static extern bool FlushViewOfFile(IntPtr lpBaseAddress, Int32 dwNumberOfBytesToFlush);
+
+    [DllImport("kernel32")]
+    public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
+
+    [DllImport("kernel32.dll")]
+    public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
+
+    [DllImport("Kernel32.dll", SetLastError = true)]
+    public static extern IntPtr OpenEvent(uint dwDesiredAccess, bool bInheritHandle, string lpName);
+
     #endregion
 
     #region Helper methods

=== modified file 'WexInstaller/Controls/InstallWizardControl.Designer.cs'
--- a/WexInstaller/Controls/InstallWizardControl.Designer.cs	2011-05-23 15:01:40 +0000
+++ b/WexInstaller/Controls/InstallWizardControl.Designer.cs	2011-05-31 13:10:52 +0000
@@ -293,7 +293,7 @@
           this.installProgressPanel.Location = new System.Drawing.Point(0, 0);
           this.installProgressPanel.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
           this.installProgressPanel.Name = "installProgressPanel";
-          this.installProgressPanel.Size = new System.Drawing.Size(192, 20);
+          this.installProgressPanel.Size = new System.Drawing.Size(556, 461);
           this.installProgressPanel.TabIndex = 6;
           // 
           // allConfigTab

=== modified file 'WexInstaller/Controls/InstallWizardControl.cs'
--- a/WexInstaller/Controls/InstallWizardControl.cs	2011-05-23 15:01:40 +0000
+++ b/WexInstaller/Controls/InstallWizardControl.cs	2011-05-31 13:10:52 +0000
@@ -37,9 +37,6 @@
       // By default, don't display apply updates.
       ShowTab(detailedUpdateTab, false, 3);
 
-      // remove requirements tab until we have it working
-      ShowTab(requirementsTab, false, 4);
-
       // disable setup type tab if we are updating instead of installing
       if (!ProductManager.IsNewSetup)
       {

=== modified file 'WexInstaller/InstallWizard/CheckRequirements.Designer.cs'
--- a/WexInstaller/InstallWizard/CheckRequirements.Designer.cs	2011-04-07 14:04:55 +0000
+++ b/WexInstaller/InstallWizard/CheckRequirements.Designer.cs	2011-05-31 13:10:52 +0000
@@ -28,45 +28,128 @@
         /// </summary>
         private void InitializeComponent()
         {
-            this.components = new System.ComponentModel.Container();
-            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CheckRequirements));
-            this.images = new System.Windows.Forms.ImageList(this.components);
-            this.label1 = new System.Windows.Forms.Label();
-            this.SuspendLayout();
-            // 
-            // images
-            // 
-            this.images.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("images.ImageStream")));
-            this.images.TransparentColor = System.Drawing.Color.Transparent;
-            this.images.Images.SetKeyName(0, "check_mark.png");
-            this.images.Images.SetKeyName(1, "warning_sign.png");
-            // 
-            // label1
-            // 
-            this.label1.Font = new System.Drawing.Font("Tahoma", 14.25F);
-            this.label1.Location = new System.Drawing.Point(54, 104);
-            this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(406, 87);
-            this.label1.TabIndex = 2;
-            this.label1.Text = "This space under construction";
-            // 
-            // CheckRequirements
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
-            this.Controls.Add(this.label1);
-            this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
-            this.Name = "CheckRequirements";
-            this.Size = new System.Drawing.Size(560, 499);
-            this.Controls.SetChildIndex(this.label1, 0);
-            this.ResumeLayout(false);
-            this.PerformLayout();
+          this.components = new System.ComponentModel.Container();
+          this.images = new System.Windows.Forms.ImageList(this.components);
+          this.requirementsList = new System.Windows.Forms.ListView();
+          this.successColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+          this.requirementHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+          this.forProductHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+          this.taskPanel = new System.Windows.Forms.Panel();
+          this.taskBox = new System.Windows.Forms.GroupBox();
+          this.taskLabel = new System.Windows.Forms.Label();
+          this.taskPanel.SuspendLayout();
+          this.taskBox.SuspendLayout();
+          this.SuspendLayout();
+          // 
+          // subCaptionLabel
+          // 
+          this.subCaptionLabel.Size = new System.Drawing.Size(522, 52);
+          // 
+          // images
+          // 
+          this.images.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
+          this.images.ImageSize = new System.Drawing.Size(16, 16);
+          this.images.TransparentColor = System.Drawing.Color.Transparent;
+          // 
+          // requirementsList
+          // 
+          this.requirementsList.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+          this.requirementsList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+            this.successColumn,
+            this.requirementHeader,
+            this.forProductHeader});
+          this.requirementsList.Dock = System.Windows.Forms.DockStyle.Top;
+          this.requirementsList.Font = new System.Drawing.Font("Tahoma", 8.25F);
+          this.requirementsList.FullRowSelect = true;
+          this.requirementsList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
+          this.requirementsList.Location = new System.Drawing.Point(0, 0);
+          this.requirementsList.MultiSelect = false;
+          this.requirementsList.Name = "requirementsList";
+          this.requirementsList.ShowGroups = false;
+          this.requirementsList.ShowItemToolTips = true;
+          this.requirementsList.Size = new System.Drawing.Size(488, 195);
+          this.requirementsList.SmallImageList = this.images;
+          this.requirementsList.TabIndex = 0;
+          this.requirementsList.UseCompatibleStateImageBehavior = false;
+          this.requirementsList.View = System.Windows.Forms.View.Details;
+          // 
+          // successColumn
+          // 
+          this.successColumn.Text = "";
+          this.successColumn.Width = 20;
+          // 
+          // requirementHeader
+          // 
+          this.requirementHeader.Text = "Requirement";
+          this.requirementHeader.Width = 303;
+          // 
+          // forProductHeader
+          // 
+          this.forProductHeader.Text = "For Product";
+          this.forProductHeader.Width = 158;
+          // 
+          // taskPanel
+          // 
+          this.taskPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+                      | System.Windows.Forms.AnchorStyles.Left)
+                      | System.Windows.Forms.AnchorStyles.Right)));
+          this.taskPanel.Controls.Add(this.taskBox);
+          this.taskPanel.Controls.Add(this.requirementsList);
+          this.taskPanel.Location = new System.Drawing.Point(40, 150);
+          this.taskPanel.Name = "taskPanel";
+          this.taskPanel.Size = new System.Drawing.Size(488, 333);
+          this.taskPanel.TabIndex = 18;
+          // 
+          // taskBox
+          // 
+          this.taskBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+                      | System.Windows.Forms.AnchorStyles.Left)
+                      | System.Windows.Forms.AnchorStyles.Right)));
+          this.taskBox.Controls.Add(this.taskLabel);
+          this.taskBox.Location = new System.Drawing.Point(0, 201);
+          this.taskBox.Name = "taskBox";
+          this.taskBox.Padding = new System.Windows.Forms.Padding(10);
+          this.taskBox.Size = new System.Drawing.Size(485, 129);
+          this.taskBox.TabIndex = 20;
+          this.taskBox.TabStop = false;
+          this.taskBox.Text = "Current Task";
+          // 
+          // taskLabel
+          // 
+          this.taskLabel.Dock = System.Windows.Forms.DockStyle.Fill;
+          this.taskLabel.Location = new System.Drawing.Point(10, 24);
+          this.taskLabel.Name = "taskLabel";
+          this.taskLabel.Size = new System.Drawing.Size(465, 95);
+          this.taskLabel.TabIndex = 19;
+          this.taskLabel.Text = "label2";
+          this.taskLabel.Click += new System.EventHandler(this.taskLabel_Click);
+          // 
+          // CheckRequirements
+          // 
+          this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+          this.Controls.Add(this.taskPanel);
+          this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
+          this.Name = "CheckRequirements";
+          this.Size = new System.Drawing.Size(560, 499);
+          this.Controls.SetChildIndex(this.captionLabel, 0);
+          this.Controls.SetChildIndex(this.subCaptionLabel, 0);
+          this.Controls.SetChildIndex(this.taskPanel, 0);
+          this.taskPanel.ResumeLayout(false);
+          this.taskBox.ResumeLayout(false);
+          this.ResumeLayout(false);
+          this.PerformLayout();
 
         }
 
         #endregion
 
         private System.Windows.Forms.ImageList images;
-        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.ListView requirementsList;
+        private System.Windows.Forms.ColumnHeader requirementHeader;
+        private System.Windows.Forms.ColumnHeader forProductHeader;
+        private System.Windows.Forms.Panel taskPanel;
+        private System.Windows.Forms.Label taskLabel;
+        private System.Windows.Forms.GroupBox taskBox;
+        private System.Windows.Forms.ColumnHeader successColumn;
     }
 }

=== modified file 'WexInstaller/InstallWizard/CheckRequirements.cs'
--- a/WexInstaller/InstallWizard/CheckRequirements.cs	2011-04-18 08:06:38 +0000
+++ b/WexInstaller/InstallWizard/CheckRequirements.cs	2011-05-31 13:10:52 +0000
@@ -1,57 +1,531 @@
-using System;
-using System.Collections.Generic;
+
+using System;
+using System.Windows.Forms;
+using System.IO;
+using System.Net;
 using System.ComponentModel;
 using System.Drawing;
-using System.Text;
-using System.Windows.Forms;
+
+using WexInstaller.Core;
+using WexInstaller.Properties;
 
 namespace WexInstaller
 {
-    public partial class CheckRequirements : InstallerPanel
-    {
-        public CheckRequirements()
-        {
-            InitializeComponent();
-            Caption = "Check Requirements";
-            nextOk = true;
-        }
-
-        private void hideDetailsButton_Click(object sender, EventArgs e)
-        {
-//            ruleList.Visible = !ruleList.Visible;
-        }
-
-        //private void runButton_Click(object sender, EventArgs e)
-        //{
-        //    progressText.Text = "";
-
-        //    // first clear all the states
-        //    int i = 0;
-        //    foreach (ListViewItem item in ruleList.Items)
-        //    {
-        //        item.StateImageIndex = -1;
-        //        i++;
-        //    }
-
-        //    progressBar.Maximum = i;
-        //    progressBar.Visible = true;
-        //    progressBar.Value = 0;
-        //    progressBar.Refresh();
-
-        //    // now run the "tests" and mark the states
-        //    i = 1;
-        //    foreach (ListViewItem item in ruleList.Items)
-        //    {
-        //        System.Threading.Thread.Sleep(1000);
-        //        progressBar.Value = i;
-        //        progressBar.Refresh();
-        //        item.StateImageIndex = i++ == 3 ? 1 : 0;
-        //        ruleList.Refresh();
-        //    }
-        //    progressText.Text = "Operation completed.  Passed 3.  Failed 0.  Warning 1.  Skipped 0.";
-        //    runButton.Text = "Re-run";
-        //    hasRun = true;
-        //    SignalChange();
-        //}
-    }
+  public partial class CheckRequirements : InstallerPanel
+  {
+    #region Members and constants
+
+    /// <summary>
+    /// One entry in the requirements Listview.
+    /// </summary>
+    private class RequirementEntry
+    {
+      public PackageRequirement Requirement { get; set; }
+      public Product Product { get; set; }
+      public string LocalFileName { get; set; } // Temp filename for downloads, Disk letter for size checks etc.
+
+      public RequirementEntry(PackageRequirement requirement, Product product, string tempFile)
+      {
+        Requirement = requirement;
+        Product = product;
+        LocalFileName = tempFile;
+      }
+    }
+
+    private bool finished = false;
+    private bool started = false;
+    private bool gotError = false;
+    
+    private enum ReqCheckStep { RunExternalInstaller, Recheck, Continue };
+    private ReqCheckStep currentStep;
+
+    private int currentIndex = 0;  // Index into the requirements list for the current entry.
+    private WebClient webClient;
+    private BackgroundWorker backgroundWorker;
+
+    #endregion
+
+    public CheckRequirements()
+    {
+      InitializeComponent();
+      Caption = "Check Requirements";
+      nextOk = true;
+
+      webClient = new WebClient();
+      webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadComplete);
+      webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
+
+      images.Images.Add(Resources.ActionOpen);
+      images.Images.Add(Resources.ActionDone);
+    }
+
+    #region Workflow
+
+    public override void Activate()
+    {
+      started = false;
+      finished = false;
+      gotError = false;
+      nextOk = true;
+
+      DoRequirementsChecks();
+
+      base.Activate();
+    }
+
+    /// <summary>
+    /// This function does the actual requirements checks and adjusts the UI to show the result.
+    /// If there is no requirement at all then we show only a message that nothing is required.
+    /// Otherwise a list is shown with indicators for each entry that shows what is already
+    /// like it should be and what is not.
+    /// </summary>
+    private void DoRequirementsChecks()
+    {
+      // Flag shows if we have any prerequisite at all.
+      bool needPrerequisites = false;
+
+      requirementsList.Items.Clear();
+      currentIndex = -1;
+      foreach (Product product in ProductManager.Products)
+        if ((product.ProposedInstalled && product.IsUpgrade) || product.HasChanges())
+        {
+          foreach (Package package in product.Packages)
+            foreach (PackageRequirement requirement in package.Requirements)
+            {
+              bool stillRequired = false;
+              switch (requirement.Type)
+              {
+                case RequirementType.DotNetFramework40Client:
+                  {
+                    needPrerequisites = true;
+
+                    Version version = Utilities.GetDotNet4ClientVersion();
+                    if (version.Major < 4)
+                    {
+                      // The client profile is not on the required version, but maybe we have a
+                      // full installation.
+                      version = Utilities.GetDotNet4FullVersion();
+                      if (version.Major < 4)
+                        stillRequired = true;
+                    }
+                    break;
+                  }
+
+                case RequirementType.DotNetFramework40Full:
+                  {
+                    needPrerequisites = true;
+
+                    Version version = Utilities.GetDotNet4FullVersion();
+                    if (version.Major < 4)
+                      stillRequired = true;
+                    break;
+                  }
+
+                default:
+                  Logger.LogError(string.Format("Invalid package requirement specified:\n" +
+                    "\tProduct: {0}, Requirement: {1}", product.TitleWithVersionAndArchitecture, requirement.ToString()));
+                  break;
+              }
+
+              ListViewItem item = new ListViewItem(""); // Image only
+              item.SubItems.Add(requirement.Description);
+              string tempFile = Path.Combine(InstallerConfiguration.ProductCachePath, Path.GetFileName(requirement.Location));
+              item.Tag = new RequirementEntry(requirement, product, tempFile);
+              item.SubItems.Add(product.TitleWithVersion);
+              
+              // Add pending requirements at the end of the list, otherwise at the begin.
+              // Mark the entry to show if it is already ok or not.
+              if (stillRequired)
+              {
+                item.ImageIndex = 0;
+                requirementsList.Items.Add(item);
+              }
+              else
+              {
+                item.ImageIndex = 1;
+                requirementsList.Items.Insert(0, item);
+              }
+            }
+
+        }
+
+      taskLabel.Text = "";
+      //progressBar.Value = 0;
+      if (needPrerequisites)
+      {
+        SubCaption = Resources.RequirementCheckWithRequirements;
+        taskPanel.Visible = true;
+        taskLabel.ForeColor = Color.FromKnownColor(KnownColor.ControlText);
+
+        PrepareNextTask();
+      }
+      else
+      {
+        SubCaption = Resources.RequirementCheckNoRequirements;
+        taskPanel.Visible = false;
+        NextButton.Text = Resources.NextButtonDefaultText;
+        currentStep = ReqCheckStep.Continue;
+      }
+      SignalChange();
+    }
+
+    /// <summary>
+    /// Scans the list of requirements for unfinished tasks and if one is found shows a description
+    /// for the user and sets the proper Next/Execute button text + action.
+    /// </summary>
+    private void PrepareNextTask()
+    {
+      foreach (ListViewItem item in requirementsList.Items)
+      {
+        // We use the associated image index as indicator for met and unmet requirements.
+        if (item.ImageIndex == 0)
+        {
+          // TODO: overhaul execute/recheck cycle handling if new requirement types become defined.
+          taskLabel.Text = string.Format(Resources.RequirementsCheckCurrentTaskText, item.SubItems[1].Text);
+          NextButton.Text = Resources.NextButtonExecuteText;
+          currentIndex = item.Index;
+          currentStep = ReqCheckStep.RunExternalInstaller;
+          return;
+        }
+      }
+
+      taskLabel.Text = Resources.RequirementsCheckAllMetText;
+      NextButton.Text = Resources.NextButtonDefaultText;
+      currentStep = ReqCheckStep.Continue;
+    }
+
+    public override bool Next()
+    {
+      // TODO: reactivate once we go back to internal prerequisites installation.
+      /*
+      if (taskPanel.Visible && !finished)
+      {
+        Logger.LogInformation("Begin installation of prerequisites.");
+
+        nextOk = false;
+        taskLabel.Text = "Installing prerequisites...";
+        Update();
+        SignalChange();
+
+        BeginInvoke((Action) (() => RunNextInstallation()));
+
+        return false;
+      }
+      */
+
+      switch (currentStep)
+      {
+        case ReqCheckStep.Recheck:
+          DoRequirementsChecks();
+          return false;
+
+        case ReqCheckStep.RunExternalInstaller:
+
+          RequirementEntry entry = requirementsList.Items[currentIndex].Tag as RequirementEntry;
+          Utilities.OpenBrowser(entry.Requirement.OfficialLink);
+
+          currentStep = ReqCheckStep.Recheck;
+          NextButton.Text = Resources.RequirementsCheckRecheckButtonText;
+          return false;
+
+        default: // ReqCheckStep.Continue
+          return base.Next();
+      }
+    }
+
+    public override bool Back()
+    {
+      lock (this)
+      {
+        if (started && !finished)
+        {
+          // Stop all remaining actions.
+          string message;
+          if (webClient.IsBusy)
+            message = Resources.ConfirmStopDownloadsAndGoBack;
+          else
+            message = Resources.ConfirmStopInstallationAndGoBack;
+          DialogResult answer = MessageBox.Show(message, Resources.ConfirmCancellationTitle,
+            MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
+          if (answer == DialogResult.Yes)
+          {
+            Cancel();
+            NextButton.Text = Properties.Resources.NextButtonDefaultText;
+          }
+          else
+            return false;
+        }
+      }
+      return base.Back();
+    }
+
+    public override bool Cancel()
+    {
+      Logger.LogInformation("Prerequisites installation canceled.");
+     
+      lock (this)
+      {
+        if (webClient.IsBusy)
+          webClient.CancelAsync();
+
+        if (backgroundWorker != null && backgroundWorker.WorkerSupportsCancellation)
+          backgroundWorker.CancelAsync();
+      }
+
+      nextOk = false;
+      return base.Cancel();
+    }
+
+    private void RunNextInstallation()
+    {
+      started = true;
+      if (++currentIndex >= requirementsList.Items.Count)
+      {
+        InstallationDone();
+        return;
+      }
+
+      // Start downloading the next package. It will trigger its installation after
+      // the download finished.
+      DownloadPackage();
+    }
+
+    /// <summary>
+    /// Asynchronously downloads the package indicated by the current index. Once done it triggers
+    /// the installation of the package.
+    /// </summary>
+    private void DownloadPackage()
+    {
+      RequirementEntry entry = requirementsList.Items[currentIndex].Tag as RequirementEntry;
+      if (File.Exists(entry.LocalFileName))
+      {
+        Logger.LogInformation(string.Format("No download necessary. Prerequisit {0} exists already on disk.",
+          entry.Requirement.Description));
+        BeginInvoke((Action)(() => InstallPackage()));
+      }
+      else
+      {
+        taskLabel.Text = string.Format(Resources.RequirementCheckDownloadingFile, entry.Requirement.Description);
+        //progressBar.Value = 0;
+        //progressBar.Minimum = 0;
+
+        Uri sourceUri = new Uri(entry.Requirement.Location);
+        try
+        {
+          Logger.LogInformation(string.Format("Attempting to download prerequisit {0} from {1}.",
+            entry.Requirement.Description, entry.Requirement.Location));
+          webClient.DownloadFileAsync(sourceUri, entry.LocalFileName, entry);
+        }
+        catch (Exception e)
+        {
+          Logger.LogError(e.Message);
+        }
+      }
+    }
+
+    /// <summary>
+    /// Event handler for the web client which is called during a download.
+    /// </summary>
+    private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
+    {
+      // Since we don't download huge files casting the byte size to an int is ok.
+      //progressBar.Maximum = (int) e.TotalBytesToReceive;
+      //progressBar.Value = (int) e.BytesReceived;
+      Update();
+    }
+
+    /// <summary>
+    /// Event handler for the web client that is called when a download was finished.
+    /// </summary>
+    private void DownloadComplete(object sender, AsyncCompletedEventArgs e)
+    {
+      RequirementEntry entry = e.UserState as RequirementEntry;
+
+      if (e.Cancelled)
+        Logger.LogInformation("Download was canceled.");
+      else
+        if (e.Error != null)
+        {
+          Logger.LogError(string.Format("Error during download encountered:\n\t{0}", e.Error.Message));
+          BeginInvoke((Action)(() => InstallationDoneWithError()));
+        }
+        else
+          BeginInvoke((Action)(() => InstallPackage()));
+    }
+
+    /// <summary>
+    /// Asynchronously installs a previously downloaded package. Afterwards the installation of
+    /// the next packages is triggered.
+    /// </summary>
+    private void InstallPackage()
+    {
+      RequirementEntry entry = requirementsList.Items[currentIndex].Tag as RequirementEntry;
+      taskLabel.Text = Resources.RequirementCheckInstalling;
+
+      backgroundWorker = new BackgroundWorker();
+      backgroundWorker.WorkerReportsProgress = true;
+      backgroundWorker.WorkerSupportsCancellation = true;
+      backgroundWorker.DoWork += new DoWorkEventHandler(DoInstallation);
+      backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CurrentInstallationCompleted);
+      backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(CurrentInstallationProgress);
+      backgroundWorker.RunWorkerAsync(entry.LocalFileName);
+    }
+
+    /// <summary>
+    /// Actual installation code, which is called in a background thread.
+    /// </summary>
+    private void DoInstallation(object sender, DoWorkEventArgs e)
+    {
+      PackageParameters parameters = new PackageParameters(e.Argument as string, InstallAction.Install);
+
+      if (Path.GetExtension(parameters.Path).Equals(".msi", StringComparison.InvariantCultureIgnoreCase))
+      {
+        ChainedInstallerEventArgs arguments;
+        arguments = new ChainedInstallerEventArgs();
+        arguments.Action = ChainedInstallerAction.StartInstallation;
+        ChainedInstallerUpdated(this, arguments);
+
+        // For msi package use our built-in chained installer.
+        ChainedInstaller installer = new ChainedInstaller();
+
+        installer.AddPackage(parameters);
+        installer.Updated += new ChainedInstallerUpdateEventHandler(ChainedInstallerUpdated);
+
+        uint[] returnCodes = installer.Install();
+        e.Result = returnCodes[0];
+
+        arguments = new ChainedInstallerEventArgs();
+        arguments.Action = ChainedInstallerAction.EndInstallation;
+        ChainedInstallerUpdated(this, arguments);
+      }
+      else
+      {
+        // For everything else use the external installer.
+        // For now we only support the .NET framework installer.
+        // Note: MSDN says there is another parameter (/ChainingPackage) however that seems only
+        // to be a way to track which installer chains MS installers, not more.
+        using (ExternalInstaller installer = new ExternalInstaller(e.Argument as string, "/norestart"))
+        {
+          installer.Updated += new ChainedInstallerUpdateEventHandler(ChainedInstallerUpdated);
+          e.Result = installer.Run();
+        }
+      }
+
+    }
+
+    /// <summary>
+    /// Event handler called by the chained installer to report progress. We just forward this
+    /// to the background worker, which in turn notifies the application.
+    /// </summary>
+    private void ChainedInstallerUpdated(object sender, ChainedInstallerEventArgs c)
+    {
+      if (backgroundWorker != null)
+        backgroundWorker.ReportProgress(0, c);
+    }
+
+    /// <summary>
+    /// Called when the installation of the current prerequisite is done. Triggers the next
+    /// installation.
+    /// </summary>
+    private void CurrentInstallationCompleted(object sender, RunWorkerCompletedEventArgs e)
+    {
+      lock (this)
+      {
+        backgroundWorker.Dispose();
+        backgroundWorker = null;
+
+        if (e.Result.ToString() == "0")
+        {
+          Logger.LogInformation("Installation completed.");
+          BeginInvoke((Action)(() => RunNextInstallation()));
+        }
+        else
+        {
+          Logger.LogError(string.Format("Installation failed. Error code is: {0}", e.Result));
+          BeginInvoke((Action)(() => InstallationDoneWithError()));
+        }
+      }
+    }
+
+    private void CurrentInstallationProgress(object sender, ProgressChangedEventArgs e)
+    {
+      ChainedInstallerEventArgs c = e.UserState as ChainedInstallerEventArgs;
+
+      switch (c.Action)
+      {
+        case ChainedInstallerAction.StartInstallation:
+          taskLabel.Text = c.Message;
+          //progressBar.Value = 0;
+          break;
+
+        case ChainedInstallerAction.ProgressSetRange:
+          //progressBar.Minimum = c.ProgressMin;
+          //progressBar.Maximum = c.ProgressMax;
+          break;
+
+        case ChainedInstallerAction.ProgressSetStep:
+          //progressBar.Value += c.ProgressStep;
+          break;
+
+        case ChainedInstallerAction.ProgressSetPosition:
+          //progressBar.Value = c.ProgressPosition;
+          break;
+
+        case ChainedInstallerAction.ProgressSingleStep:
+          //progressBar.PerformStep();
+          break;
+
+        case ChainedInstallerAction.EndInstallation:
+        case ChainedInstallerAction.LogEvent:
+        case ChainedInstallerAction.TerminateUI:
+        case ChainedInstallerAction.HandleActionData:
+        case ChainedInstallerAction.HandleActionStart:
+          taskLabel.Text = c.Message;
+          break;
+      }
+      if (backgroundWorker.CancellationPending)
+        c.Cancel = true;
+
+      Update();
+    }
+
+    private void InstallationDone()
+    {
+      finished = true;
+      NextButton.Text = Properties.Resources.NextButtonDefaultText;
+      nextOk = true;
+      SignalChange();
+      Update();
+    }
+
+    private void InstallationDoneWithError()
+    {
+      finished = true;
+      nextOk = false;
+      gotError = true;
+      SignalChange();
+
+      RequirementEntry entry = requirementsList.Items[currentIndex].Tag as RequirementEntry;
+      taskLabel.ForeColor = Color.Red;
+      taskLabel.Text = Resources.RequirementCheckError;
+
+      Update();
+    }
+
+    #endregion
+
+    #region Event handling
+
+    private void taskLabel_Click(object sender, EventArgs e)
+    {
+      // Open web browser with the official link if a prerequisite installation failed.
+      if (gotError && currentIndex < requirementsList.Items.Count)
+      {
+        RequirementEntry entry = requirementsList.Items[currentIndex].Tag as RequirementEntry;
+        Utilities.OpenBrowser(entry.Requirement.OfficialLink);
+      }
+    }
+
+    #endregion
+  }
 }

=== modified file 'WexInstaller/InstallWizard/CheckRequirements.resx'
--- a/WexInstaller/InstallWizard/CheckRequirements.resx	2010-06-17 18:58:01 +0000
+++ b/WexInstaller/InstallWizard/CheckRequirements.resx	2011-05-31 13:10:52 +0000
@@ -120,51 +120,4 @@
   <metadata name="images.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
-  <data name="images.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
-    <value>
-        AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
-        LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
-        ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA6
-        CQAAAk1TRnQBSQFMAgEBAgEAATgBAAE4AQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
-        AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
-        AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
-        AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
-        AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm
-        AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM
-        AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA
-        ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz
-        AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ
-        AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM
-        AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA
-        AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA
-        AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ
-        AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/
-        AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA
-        AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm
-        ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ
-        Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz
-        AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA
-        AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM
-        AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM
-        ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM
-        Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA
-        AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM
-        AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ
-        AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz
-        AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm
-        AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw
-        AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD/wEABf8HTxT/IAAD/wNP
-        A1ADTwFJBP8FKgMDBCoBAwFRAf8gAAL/AU8DcgRQA08BSQL/ATEBNwE4AzcBMAFKAVIENwE4ATAB/yAA
-        Af8BUAFyAZcDcgRQBE8B/wFYAVkBXgM4ASIBXwFtAfsDOAE3AUsB/yAAAf8BUAKXAXIBmAHzAXgEUANP
-        Av8BWQJeATgB+wEwASIBMQM4AfsBMAFzAf8gAAFQAngBlwGYA/8BmARQA08B/wFZA14C+wE3AfsCOAFe
-        ATcBKgL/IAABUAGYAXgBmAL/AXgC/wGYBVABTwL/AVkB5QFeAfsBNwFEATcCOAH7ATABcwL/IAABUAGe
-        AXgBwgH/AXgBTwFyAv8BmARQAU8C/wFYAuUBXgE3AWYBNwL7ATgBAwP/IAABUAGfA5gBUAGXAVABcgL/
-        AZgDUAFPA/8BWQGgAV4BWAGiAVgC+wExAVED/yAAAVABnwGeAZgElwFQAXIC/wGYAnIBTwP/AVgBoAHl
-        AVEBXwFRAvsBKgT/IAABUAEIAZ8BngGYAXgDlwFQAXgC/wGXAXIBTwT/AVkB5QFKAQoBEwH7ATEBUQT/
-        IAAB/wFyAcIBnwKYAXgDlwFQAZgBCAGXAVAF/wFZAeUBUQEQAVEB+wEDBf8gAAH/AXICwgGfAZ4BmAN4
-        AZcBcgKXAU8G/wFZAeUBWAFeATcBUQX/IAAC/wGXAsIBnwGeApgDeAGXAU8H/wFYA14BAwb/IAAD/wFy
-        AZgCwgGeApgBeAGXAU8J/wFZAeUBNwFLBv8gAAT/AnIDlwJyAU8K/wNYB/8gAAFCAU0BPgcAAT4DAAEo
-        AwABQAMAARADAAEBAQABAQUAAYAXAAP/gQAL
-</value>
-  </data>
 </root>
\ No newline at end of file

=== modified file 'WexInstaller/InstallWizard/DetailedUpdateCheck.Designer.cs'
--- a/WexInstaller/InstallWizard/DetailedUpdateCheck.Designer.cs	2011-04-07 14:04:55 +0000
+++ b/WexInstaller/InstallWizard/DetailedUpdateCheck.Designer.cs	2011-05-31 13:10:52 +0000
@@ -29,196 +29,197 @@
         /// </summary>
         private void InitializeComponent()
         {
-            this.actionLabel = new System.Windows.Forms.Label();
-            this.skipUpdates = new System.Windows.Forms.CheckBox();
-            this.fetchLabel = new System.Windows.Forms.Label();
-            this.connectionLabel = new System.Windows.Forms.Label();
-            this.connectionSuccessIcon = new System.Windows.Forms.PictureBox();
-            this.fetchSuccessIcon = new System.Windows.Forms.PictureBox();
-            this.connectionEmptyIcon = new System.Windows.Forms.PictureBox();
-            this.fetchEmptyIcon = new System.Windows.Forms.PictureBox();
-            this.currentActionIcon = new System.Windows.Forms.PictureBox();
-            this.productList = new System.Windows.Forms.ListView();
-            this.productHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
-            this.currentActionFailedIcon = new System.Windows.Forms.PictureBox();
-            ((System.ComponentModel.ISupportInitialize)(this.connectionSuccessIcon)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.fetchSuccessIcon)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.connectionEmptyIcon)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.fetchEmptyIcon)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.currentActionIcon)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.currentActionFailedIcon)).BeginInit();
-            this.SuspendLayout();
-            // 
-            // actionLabel
-            // 
-            this.actionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                        | System.Windows.Forms.AnchorStyles.Right)));
-            this.actionLabel.Font = new System.Drawing.Font("Tahoma", 10F);
-            this.actionLabel.Location = new System.Drawing.Point(12, 80);
-            this.actionLabel.Name = "actionLabel";
-            this.actionLabel.Size = new System.Drawing.Size(483, 57);
-            this.actionLabel.TabIndex = 2;
-            this.actionLabel.Text = "Before the installation is performed, the Installer will check if there are newer" +
-                " versions of the products you are about to install / already installed are avail" +
-                "able.";
-            // 
-            // skipUpdates
-            // 
-            this.skipUpdates.AutoSize = true;
-            this.skipUpdates.Font = new System.Drawing.Font("Tahoma", 8.25F);
-            this.skipUpdates.Location = new System.Drawing.Point(15, 423);
-            this.skipUpdates.Name = "skipUpdates";
-            this.skipUpdates.Size = new System.Drawing.Size(250, 17);
-            this.skipUpdates.TabIndex = 3;
-            this.skipUpdates.Text = "&Skip the check for updates (not recommended)";
-            this.skipUpdates.UseVisualStyleBackColor = true;
-            this.skipUpdates.CheckedChanged += new System.EventHandler(this.skipUpdates_CheckedChanged);
-            // 
-            // fetchLabel
-            // 
-            this.fetchLabel.AutoSize = true;
-            this.fetchLabel.Font = new System.Drawing.Font("Tahoma", 8.25F);
-            this.fetchLabel.Location = new System.Drawing.Point(99, 180);
-            this.fetchLabel.Name = "fetchLabel";
-            this.fetchLabel.Size = new System.Drawing.Size(168, 13);
-            this.fetchLabel.TabIndex = 4;
-            this.fetchLabel.Text = "Fetch product update information";
-            // 
-            // connectionLabel
-            // 
-            this.connectionLabel.AutoSize = true;
-            this.connectionLabel.Font = new System.Drawing.Font("Tahoma", 8.25F);
-            this.connectionLabel.Location = new System.Drawing.Point(99, 154);
-            this.connectionLabel.Name = "connectionLabel";
-            this.connectionLabel.Size = new System.Drawing.Size(122, 13);
-            this.connectionLabel.TabIndex = 5;
-            this.connectionLabel.Text = "Connect to the Internet";
-            // 
-            // connectionSuccessIcon
-            // 
-            this.connectionSuccessIcon.BackColor = System.Drawing.Color.Transparent;
-            this.connectionSuccessIcon.Image = global::WexInstaller.Properties.Resources.ActionDone;
-            this.connectionSuccessIcon.Location = new System.Drawing.Point(80, 154);
-            this.connectionSuccessIcon.Name = "connectionSuccessIcon";
-            this.connectionSuccessIcon.Size = new System.Drawing.Size(16, 16);
-            this.connectionSuccessIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
-            this.connectionSuccessIcon.TabIndex = 9;
-            this.connectionSuccessIcon.TabStop = false;
-            this.connectionSuccessIcon.Visible = false;
-            // 
-            // fetchSuccessIcon
-            // 
-            this.fetchSuccessIcon.Image = global::WexInstaller.Properties.Resources.ActionDone;
-            this.fetchSuccessIcon.Location = new System.Drawing.Point(80, 180);
-            this.fetchSuccessIcon.Name = "fetchSuccessIcon";
-            this.fetchSuccessIcon.Size = new System.Drawing.Size(16, 16);
-            this.fetchSuccessIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
-            this.fetchSuccessIcon.TabIndex = 10;
-            this.fetchSuccessIcon.TabStop = false;
-            this.fetchSuccessIcon.Visible = false;
-            // 
-            // connectionEmptyIcon
-            // 
-            this.connectionEmptyIcon.Image = global::WexInstaller.Properties.Resources.ActionOpen;
-            this.connectionEmptyIcon.Location = new System.Drawing.Point(80, 154);
-            this.connectionEmptyIcon.Name = "connectionEmptyIcon";
-            this.connectionEmptyIcon.Size = new System.Drawing.Size(16, 16);
-            this.connectionEmptyIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
-            this.connectionEmptyIcon.TabIndex = 12;
-            this.connectionEmptyIcon.TabStop = false;
-            // 
-            // fetchEmptyIcon
-            // 
-            this.fetchEmptyIcon.Image = global::WexInstaller.Properties.Resources.ActionOpen;
-            this.fetchEmptyIcon.Location = new System.Drawing.Point(80, 180);
-            this.fetchEmptyIcon.Name = "fetchEmptyIcon";
-            this.fetchEmptyIcon.Size = new System.Drawing.Size(16, 16);
-            this.fetchEmptyIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
-            this.fetchEmptyIcon.TabIndex = 14;
-            this.fetchEmptyIcon.TabStop = false;
-            // 
-            // currentActionIcon
-            // 
-            this.currentActionIcon.Image = global::WexInstaller.Properties.Resources.ActionCurrent;
-            this.currentActionIcon.Location = new System.Drawing.Point(80, 153);
-            this.currentActionIcon.Name = "currentActionIcon";
-            this.currentActionIcon.Size = new System.Drawing.Size(16, 16);
-            this.currentActionIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
-            this.currentActionIcon.TabIndex = 15;
-            this.currentActionIcon.TabStop = false;
-            this.currentActionIcon.Visible = false;
-            // 
-            // productList
-            // 
-            this.productList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                        | System.Windows.Forms.AnchorStyles.Right)));
-            this.productList.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
-            this.productList.CheckBoxes = true;
-            this.productList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+          this.actionLabel = new System.Windows.Forms.Label();
+          this.skipUpdates = new System.Windows.Forms.CheckBox();
+          this.fetchLabel = new System.Windows.Forms.Label();
+          this.connectionLabel = new System.Windows.Forms.Label();
+          this.connectionSuccessIcon = new System.Windows.Forms.PictureBox();
+          this.fetchSuccessIcon = new System.Windows.Forms.PictureBox();
+          this.connectionEmptyIcon = new System.Windows.Forms.PictureBox();
+          this.fetchEmptyIcon = new System.Windows.Forms.PictureBox();
+          this.currentActionIcon = new System.Windows.Forms.PictureBox();
+          this.productList = new System.Windows.Forms.ListView();
+          this.productHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+          this.currentActionFailedIcon = new System.Windows.Forms.PictureBox();
+          ((System.ComponentModel.ISupportInitialize)(this.connectionSuccessIcon)).BeginInit();
+          ((System.ComponentModel.ISupportInitialize)(this.fetchSuccessIcon)).BeginInit();
+          ((System.ComponentModel.ISupportInitialize)(this.connectionEmptyIcon)).BeginInit();
+          ((System.ComponentModel.ISupportInitialize)(this.fetchEmptyIcon)).BeginInit();
+          ((System.ComponentModel.ISupportInitialize)(this.currentActionIcon)).BeginInit();
+          ((System.ComponentModel.ISupportInitialize)(this.currentActionFailedIcon)).BeginInit();
+          this.SuspendLayout();
+          // 
+          // actionLabel
+          // 
+          this.actionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                      | System.Windows.Forms.AnchorStyles.Right)));
+          this.actionLabel.Font = new System.Drawing.Font("Tahoma", 10F);
+          this.actionLabel.Location = new System.Drawing.Point(23, 80);
+          this.actionLabel.Name = "actionLabel";
+          this.actionLabel.Size = new System.Drawing.Size(523, 57);
+          this.actionLabel.TabIndex = 2;
+          this.actionLabel.Text = "Before the installation is performed, the Installer will check if there are newer" +
+              " versions of the products you are about to install / already installed are avail" +
+              "able.";
+          // 
+          // skipUpdates
+          // 
+          this.skipUpdates.AutoSize = true;
+          this.skipUpdates.Font = new System.Drawing.Font("Tahoma", 8.25F);
+          this.skipUpdates.Location = new System.Drawing.Point(26, 423);
+          this.skipUpdates.Name = "skipUpdates";
+          this.skipUpdates.Size = new System.Drawing.Size(250, 17);
+          this.skipUpdates.TabIndex = 3;
+          this.skipUpdates.Text = "&Skip the check for updates (not recommended)";
+          this.skipUpdates.UseVisualStyleBackColor = true;
+          this.skipUpdates.CheckedChanged += new System.EventHandler(this.skipUpdates_CheckedChanged);
+          // 
+          // fetchLabel
+          // 
+          this.fetchLabel.AutoSize = true;
+          this.fetchLabel.Font = new System.Drawing.Font("Tahoma", 8.25F);
+          this.fetchLabel.Location = new System.Drawing.Point(99, 180);
+          this.fetchLabel.Name = "fetchLabel";
+          this.fetchLabel.Size = new System.Drawing.Size(168, 13);
+          this.fetchLabel.TabIndex = 4;
+          this.fetchLabel.Text = "Fetch product update information";
+          // 
+          // connectionLabel
+          // 
+          this.connectionLabel.AutoSize = true;
+          this.connectionLabel.Font = new System.Drawing.Font("Tahoma", 8.25F);
+          this.connectionLabel.Location = new System.Drawing.Point(99, 154);
+          this.connectionLabel.Name = "connectionLabel";
+          this.connectionLabel.Size = new System.Drawing.Size(122, 13);
+          this.connectionLabel.TabIndex = 5;
+          this.connectionLabel.Text = "Connect to the Internet";
+          // 
+          // connectionSuccessIcon
+          // 
+          this.connectionSuccessIcon.BackColor = System.Drawing.Color.Transparent;
+          this.connectionSuccessIcon.Image = global::WexInstaller.Properties.Resources.ActionDone;
+          this.connectionSuccessIcon.Location = new System.Drawing.Point(80, 154);
+          this.connectionSuccessIcon.Name = "connectionSuccessIcon";
+          this.connectionSuccessIcon.Size = new System.Drawing.Size(16, 16);
+          this.connectionSuccessIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+          this.connectionSuccessIcon.TabIndex = 9;
+          this.connectionSuccessIcon.TabStop = false;
+          this.connectionSuccessIcon.Visible = false;
+          // 
+          // fetchSuccessIcon
+          // 
+          this.fetchSuccessIcon.Image = global::WexInstaller.Properties.Resources.ActionDone;
+          this.fetchSuccessIcon.Location = new System.Drawing.Point(80, 180);
+          this.fetchSuccessIcon.Name = "fetchSuccessIcon";
+          this.fetchSuccessIcon.Size = new System.Drawing.Size(16, 16);
+          this.fetchSuccessIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+          this.fetchSuccessIcon.TabIndex = 10;
+          this.fetchSuccessIcon.TabStop = false;
+          this.fetchSuccessIcon.Visible = false;
+          // 
+          // connectionEmptyIcon
+          // 
+          this.connectionEmptyIcon.Image = global::WexInstaller.Properties.Resources.ActionOpen;
+          this.connectionEmptyIcon.Location = new System.Drawing.Point(80, 154);
+          this.connectionEmptyIcon.Name = "connectionEmptyIcon";
+          this.connectionEmptyIcon.Size = new System.Drawing.Size(16, 16);
+          this.connectionEmptyIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+          this.connectionEmptyIcon.TabIndex = 12;
+          this.connectionEmptyIcon.TabStop = false;
+          // 
+          // fetchEmptyIcon
+          // 
+          this.fetchEmptyIcon.Image = global::WexInstaller.Properties.Resources.ActionOpen;
+          this.fetchEmptyIcon.Location = new System.Drawing.Point(80, 180);
+          this.fetchEmptyIcon.Name = "fetchEmptyIcon";
+          this.fetchEmptyIcon.Size = new System.Drawing.Size(16, 16);
+          this.fetchEmptyIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+          this.fetchEmptyIcon.TabIndex = 14;
+          this.fetchEmptyIcon.TabStop = false;
+          // 
+          // currentActionIcon
+          // 
+          this.currentActionIcon.Image = global::WexInstaller.Properties.Resources.ActionCurrent;
+          this.currentActionIcon.Location = new System.Drawing.Point(80, 153);
+          this.currentActionIcon.Name = "currentActionIcon";
+          this.currentActionIcon.Size = new System.Drawing.Size(16, 16);
+          this.currentActionIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+          this.currentActionIcon.TabIndex = 15;
+          this.currentActionIcon.TabStop = false;
+          this.currentActionIcon.Visible = false;
+          // 
+          // productList
+          // 
+          this.productList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                      | System.Windows.Forms.AnchorStyles.Right)));
+          this.productList.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+          this.productList.CheckBoxes = true;
+          this.productList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
             this.productHeader});
-            this.productList.Font = new System.Drawing.Font("Tahoma", 8.25F);
-            this.productList.FullRowSelect = true;
-            this.productList.Location = new System.Drawing.Point(80, 214);
-            this.productList.Name = "productList";
-            this.productList.Size = new System.Drawing.Size(415, 153);
-            this.productList.TabIndex = 16;
-            this.productList.UseCompatibleStateImageBehavior = false;
-            this.productList.View = System.Windows.Forms.View.Details;
-            // 
-            // productHeader
-            // 
-            this.productHeader.Text = "Product upgrades";
-            this.productHeader.Width = 369;
-            // 
-            // currentActionFailedIcon
-            // 
-            this.currentActionFailedIcon.Image = global::WexInstaller.Properties.Resources.ActionError;
-            this.currentActionFailedIcon.Location = new System.Drawing.Point(80, 154);
-            this.currentActionFailedIcon.Name = "currentActionFailedIcon";
-            this.currentActionFailedIcon.Size = new System.Drawing.Size(16, 16);
-            this.currentActionFailedIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
-            this.currentActionFailedIcon.TabIndex = 17;
-            this.currentActionFailedIcon.TabStop = false;
-            this.currentActionFailedIcon.Visible = false;
-            // 
-            // UpgradeCheck
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
-            this.Controls.Add(this.productList);
-            this.Controls.Add(this.connectionLabel);
-            this.Controls.Add(this.fetchLabel);
-            this.Controls.Add(this.skipUpdates);
-            this.Controls.Add(this.actionLabel);
-            this.Controls.Add(this.connectionEmptyIcon);
-            this.Controls.Add(this.currentActionIcon);
-            this.Controls.Add(this.connectionSuccessIcon);
-            this.Controls.Add(this.fetchEmptyIcon);
-            this.Controls.Add(this.fetchSuccessIcon);
-            this.Controls.Add(this.currentActionFailedIcon);
-            this.DoubleBuffered = true;
-            this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
-            this.Name = "UpgradeCheck";
-            this.Size = new System.Drawing.Size(560, 499);
-            this.Controls.SetChildIndex(this.currentActionFailedIcon, 0);
-            this.Controls.SetChildIndex(this.fetchSuccessIcon, 0);
-            this.Controls.SetChildIndex(this.fetchEmptyIcon, 0);
-            this.Controls.SetChildIndex(this.connectionSuccessIcon, 0);
-            this.Controls.SetChildIndex(this.currentActionIcon, 0);
-            this.Controls.SetChildIndex(this.connectionEmptyIcon, 0);
-            this.Controls.SetChildIndex(this.actionLabel, 0);
-            this.Controls.SetChildIndex(this.skipUpdates, 0);
-            this.Controls.SetChildIndex(this.fetchLabel, 0);
-            this.Controls.SetChildIndex(this.connectionLabel, 0);
-            this.Controls.SetChildIndex(this.productList, 0);
-            ((System.ComponentModel.ISupportInitialize)(this.connectionSuccessIcon)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.fetchSuccessIcon)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.connectionEmptyIcon)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.fetchEmptyIcon)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.currentActionIcon)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.currentActionFailedIcon)).EndInit();
-            this.ResumeLayout(false);
-            this.PerformLayout();
+          this.productList.Font = new System.Drawing.Font("Tahoma", 8.25F);
+          this.productList.FullRowSelect = true;
+          this.productList.Location = new System.Drawing.Point(80, 214);
+          this.productList.Name = "productList";
+          this.productList.Size = new System.Drawing.Size(415, 153);
+          this.productList.TabIndex = 16;
+          this.productList.UseCompatibleStateImageBehavior = false;
+          this.productList.View = System.Windows.Forms.View.Details;
+          // 
+          // productHeader
+          // 
+          this.productHeader.Text = "Product upgrades";
+          this.productHeader.Width = 369;
+          // 
+          // currentActionFailedIcon
+          // 
+          this.currentActionFailedIcon.Image = global::WexInstaller.Properties.Resources.ActionError;
+          this.currentActionFailedIcon.Location = new System.Drawing.Point(80, 154);
+          this.currentActionFailedIcon.Name = "currentActionFailedIcon";
+          this.currentActionFailedIcon.Size = new System.Drawing.Size(16, 16);
+          this.currentActionFailedIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+          this.currentActionFailedIcon.TabIndex = 17;
+          this.currentActionFailedIcon.TabStop = false;
+          this.currentActionFailedIcon.Visible = false;
+          // 
+          // UpgradeCheck
+          // 
+          this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+          this.Controls.Add(this.productList);
+          this.Controls.Add(this.connectionLabel);
+          this.Controls.Add(this.fetchLabel);
+          this.Controls.Add(this.skipUpdates);
+          this.Controls.Add(this.actionLabel);
+          this.Controls.Add(this.connectionEmptyIcon);
+          this.Controls.Add(this.currentActionIcon);
+          this.Controls.Add(this.connectionSuccessIcon);
+          this.Controls.Add(this.fetchEmptyIcon);
+          this.Controls.Add(this.fetchSuccessIcon);
+          this.Controls.Add(this.currentActionFailedIcon);
+          this.DoubleBuffered = true;
+          this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
+          this.Name = "UpgradeCheck";
+          this.Size = new System.Drawing.Size(560, 499);
+          this.Controls.SetChildIndex(this.captionLabel, 0);
+          this.Controls.SetChildIndex(this.subCaptionLabel, 0);
+          this.Controls.SetChildIndex(this.currentActionFailedIcon, 0);
+          this.Controls.SetChildIndex(this.fetchSuccessIcon, 0);
+          this.Controls.SetChildIndex(this.fetchEmptyIcon, 0);
+          this.Controls.SetChildIndex(this.connectionSuccessIcon, 0);
+          this.Controls.SetChildIndex(this.currentActionIcon, 0);
+          this.Controls.SetChildIndex(this.connectionEmptyIcon, 0);
+          this.Controls.SetChildIndex(this.actionLabel, 0);
+          this.Controls.SetChildIndex(this.skipUpdates, 0);
+          this.Controls.SetChildIndex(this.fetchLabel, 0);
+          this.Controls.SetChildIndex(this.connectionLabel, 0);
+          this.Controls.SetChildIndex(this.productList, 0);
+          ((System.ComponentModel.ISupportInitialize)(this.connectionSuccessIcon)).EndInit();
+          ((System.ComponentModel.ISupportInitialize)(this.fetchSuccessIcon)).EndInit();
+          ((System.ComponentModel.ISupportInitialize)(this.connectionEmptyIcon)).EndInit();
+          ((System.ComponentModel.ISupportInitialize)(this.fetchEmptyIcon)).EndInit();
+          ((System.ComponentModel.ISupportInitialize)(this.currentActionIcon)).EndInit();
+          ((System.ComponentModel.ISupportInitialize)(this.currentActionFailedIcon)).EndInit();
+          this.ResumeLayout(false);
+          this.PerformLayout();
 
         }
 

=== modified file 'WexInstaller/Properties/Resources.Designer.cs'
--- a/WexInstaller/Properties/Resources.Designer.cs	2011-05-25 22:01:32 +0000
+++ b/WexInstaller/Properties/Resources.Designer.cs	2011-05-31 13:10:52 +0000
@@ -516,7 +516,7 @@
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to &amp;Button.
+        ///   Looks up a localized string similar to &amp;Help.
         /// </summary>
         public static string HelpButtonDefaultText {
             get {
@@ -772,6 +772,80 @@
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Downloading {0}.
+        /// </summary>
+        public static string RequirementCheckDownloadingFile {
+            get {
+                return ResourceManager.GetString("RequirementCheckDownloadingFile", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Error occured during installation. Please manually install the prerequisite and restart the installer. Click on this message to open a browser window for manual installation..
+        /// </summary>
+        public static string RequirementCheckError {
+            get {
+                return ResourceManager.GetString("RequirementCheckError", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Installing prerequisite....
+        /// </summary>
+        public static string RequirementCheckInstalling {
+            get {
+                return ResourceManager.GetString("RequirementCheckInstalling", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to There are no additional requirements to be installed. Please click Next to continue with the product installation..
+        /// </summary>
+        public static string RequirementCheckNoRequirements {
+            get {
+                return ResourceManager.GetString("RequirementCheckNoRequirements", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The following requirements must be installed before the selected products can be installed. If you don&apos;t want a particular requirement then go back and deselect the product that requires it..
+        /// </summary>
+        public static string RequirementCheckWithRequirements {
+            get {
+                return ResourceManager.GetString("RequirementCheckWithRequirements", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to All required prerequisites are met. Continue by clicking on the Next button..
+        /// </summary>
+        public static string RequirementsCheckAllMetText {
+            get {
+                return ResourceManager.GetString("RequirementsCheckAllMetText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The package &quot;{0}&quot; must be installed now. Click on the Execute button to open a website which allows you to download and install the package. Once done come back here and re-check the requirements by clicking the Re-Check button.
+        ///
+        ///If you are asked to restart your computer then decline and finish the main installation first. Restart your computer after this is done..
+        /// </summary>
+        public static string RequirementsCheckCurrentTaskText {
+            get {
+                return ResourceManager.GetString("RequirementsCheckCurrentTaskText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Re-Check.
+        /// </summary>
+        public static string RequirementsCheckRecheckButtonText {
+            get {
+                return ResourceManager.GetString("RequirementsCheckRecheckButtonText", resourceCulture);
+            }
+        }
+        
         public static System.Drawing.Bitmap ResourcesBanner {
             get {
                 object obj = ResourceManager.GetObject("ResourcesBanner", resourceCulture);
@@ -951,6 +1025,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to Learn more about MySQL products and better understand how you can benefit the most..
+        /// </summary>
+        public static string WelcomePageAboutDescriptionText {
+            get {
+                return ResourceManager.GetString("WelcomePageAboutDescriptionText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to About MySQL.
         /// </summary>
         public static string WelcomePageAboutLinkText {
@@ -960,6 +1043,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to Guide you through the installation and configuration of your MySQL products..
+        /// </summary>
+        public static string WelcomePageInstallDescriptionText {
+            get {
+                return ResourceManager.GetString("WelcomePageInstallDescriptionText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Install MySQL Products.
         /// </summary>
         public static string WelcomePageInstallLinkText {
@@ -1061,24 +1153,6 @@
             }
         }
         
-        /// <summary>
-        ///   Looks up a localized string similar to Learn more about MySQL products and better understand how you can benefit the most..
-        /// </summary>
-        public static string WelcomPageAboutDescriptionText {
-            get {
-                return ResourceManager.GetString("WelcomPageAboutDescriptionText", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Remove Products.
-        /// </summary>
-        public static string WelcomPageRemoveLinkText {
-            get {
-                return ResourceManager.GetString("WelcomPageRemoveLinkText", resourceCulture);
-            }
-        }
-        
         public static System.Drawing.Bitmap wex_product_catalog {
             get {
                 object obj = ResourceManager.GetObject("wex_product_catalog", resourceCulture);
@@ -1092,14 +1166,5 @@
                 return ((System.Drawing.Bitmap)(obj));
             }
         }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Guide you through the installation and configuration of your MySQL products..
-        /// </summary>
-        public static string WlecomePageInstallDescriptionText {
-            get {
-                return ResourceManager.GetString("WlecomePageInstallDescriptionText", resourceCulture);
-            }
-        }
     }
 }

=== modified file 'WexInstaller/Properties/Resources.resx'
--- a/WexInstaller/Properties/Resources.resx	2011-05-25 22:01:32 +0000
+++ b/WexInstaller/Properties/Resources.resx	2011-05-31 13:10:52 +0000
@@ -188,7 +188,7 @@
     <value>Are you sure you wish to cancel and quit the installer?</value>
   </data>
   <data name="HelpButtonDefaultText" xml:space="preserve">
-    <value>&amp;Button</value>
+    <value>&amp;Help</value>
   </data>
   <data name="server_machine" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\server_machine.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@@ -489,16 +489,39 @@
   <data name="WelcomePageUpdateCheckLinkText" xml:space="preserve">
     <value>Check for Updates</value>
   </data>
-  <data name="WelcomPageAboutDescriptionText" xml:space="preserve">
+  <data name="WelcomePageAboutDescriptionText" xml:space="preserve">
     <value>Learn more about MySQL products and better understand how you can benefit the most.</value>
   </data>
-  <data name="WelcomPageRemoveLinkText" xml:space="preserve">
-    <value>Remove Products</value>
-  </data>
-  <data name="WlecomePageInstallDescriptionText" xml:space="preserve">
+  <data name="WelcomePageInstallDescriptionText" xml:space="preserve">
     <value>Guide you through the installation and configuration of your MySQL products.</value>
   </data>
+  <data name="RequirementCheckNoRequirements" xml:space="preserve">
+    <value>There are no additional requirements to be installed. Please click Next to continue with the product installation.</value>
+  </data>
+  <data name="RequirementCheckWithRequirements" xml:space="preserve">
+    <value>The following requirements must be installed before the selected products can be installed. If you don't want a particular requirement then go back and deselect the product that requires it.</value>
+  </data>
+  <data name="RequirementCheckDownloadingFile" xml:space="preserve">
+    <value>Downloading {0}</value>
+  </data>
+  <data name="RequirementCheckError" xml:space="preserve">
+    <value>Error occured during installation. Please manually install the prerequisite and restart the installer. Click on this message to open a browser window for manual installation.</value>
+  </data>
+  <data name="RequirementCheckInstalling" xml:space="preserve">
+    <value>Installing prerequisite...</value>
+  </data>
   <data name="WelcomePageRemoveLinkText" xml:space="preserve">
     <value>Remove MySQL Products</value>
   </data>
+  <data name="RequirementsCheckRecheckButtonText" xml:space="preserve">
+    <value>Re-Check</value>
+  </data>
+  <data name="RequirementsCheckAllMetText" xml:space="preserve">
+    <value>All required prerequisites are met. Continue by clicking on the Next button.</value>
+  </data>
+  <data name="RequirementsCheckCurrentTaskText" xml:space="preserve">
+    <value>The package "{0}" must be installed now. Click on the Execute button to open a website which allows you to download and install the package. Once done come back here and re-check the requirements by clicking the Re-Check button.
+
+If you are asked to restart your computer then decline and finish the main installation first. Restart your computer after this is done.</value>
+  </data>
 </root>
\ No newline at end of file

=== modified file 'WexInstaller/WexInstaller.csproj'
--- a/WexInstaller/WexInstaller.csproj	2011-05-23 15:01:40 +0000
+++ b/WexInstaller/WexInstaller.csproj	2011-05-31 13:10:52 +0000
@@ -207,6 +207,11 @@
     <Compile Include="Controls\WelcomeControl.Designer.cs">
       <DependentUpon>WelcomeControl.cs</DependentUpon>
     </Compile>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
     <Compile Include="RemovePanels\RemoveComplete.cs">
       <SubType>UserControl</SubType>
     </Compile>
@@ -300,14 +305,9 @@
     </EmbeddedResource>
     <EmbeddedResource Include="Properties\Resources.resx">
       <Generator>PublicResXFileCodeGenerator</Generator>
+      <SubType>Designer</SubType>
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
-      <SubType>Designer</SubType>
     </EmbeddedResource>
-    <Compile Include="Properties\Resources.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DependentUpon>Resources.resx</DependentUpon>
-      <DesignTime>True</DesignTime>
-    </Compile>
     <EmbeddedResource Include="Controls\SideBarControl.resx">
       <DependentUpon>SideBarControl.cs</DependentUpon>
       <SubType>Designer</SubType>

=== modified file 'common/products.xml'
--- a/common/products.xml	2011-05-23 15:39:37 +0000
+++ b/common/products.xml	2011-05-31 13:10:52 +0000
@@ -163,7 +163,7 @@
           <Package type="MSI" arch="X86" filename="mysql-workbench-gpl-5.2.33b-win32.msi" id="{52937564-8312-4B49-BB13-F7EDBB67EB34}" thisVersion="5.2.33">
             <Feature name="MysqlWorkbenchCore" title="MySQL Workbench Core" description="Core components needed to run MySQL Workbench" default="false" size="64498885" display="2" hasComponents="true" />
             <Feature name="WorkbenchProgramShortcut" title="Program Shortcut" description="Place a Shortcut to MySQL Workbench in your Startmenus MySQL Folder" default="false" size="0" display="4" hasComponents="true" />
-            <Requirement filename="dotNetFx40_Client_x86_x64.exe" description="Microsoft .NET Framework 4 Client Profile" location="http://download.microsoft.com/download/5/6/2/562A10F9-C9F4-4313-A044-9C94E0A8FAC8/dotNetFx40_Client_x86_x64.exe" size="43000680" />
+            <Requirement type="DotNetFramework40Client" description="Microsoft .NET Framework 4 Client Profile" location="http://download.microsoft.com/download/5/6/2/562A10F9-C9F4-4313-A044-9C94E0A8FAC8/dotNetFx40_Client_x86_x64.exe" officialLink="http://go.microsoft.com/fwlink/?LinkId=181012" size="43000680" />
           </Package>
         </Packages>
       </Product>

Attachment: [text/bzr-bundle] bzr/mike.lischke@oracle.com-20110531131052-reo2n2x4e9y5rdev.bundle
Thread
bzr commit into wex-installer-1.0 branch (mike.lischke:487) Mike Lischke31 May