install the registry keys before enabling the driver
[reactos.git] / reactos / subsys / system / vmwinst / vmwinst.c
index f7f781f..74b5397 100644 (file)
@@ -1,27 +1,30 @@
 /*
- *  ReactOS applications
- *  Copyright (C) 2004 ReactOS Team
+ * ReactOS VMware(r) driver installation utility
+ * Copyright (C) 2004 ReactOS Team
  *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
  *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * VMware is a registered trademark of VMware, Inc.
  */
-/* $Id: vmwinst.c,v 1.2 2004/04/12 16:09:45 weiden Exp $
+/* $Id$
  *
  * COPYRIGHT:   See COPYING in the top level directory
  * PROJECT:     ReactOS VMware(r) driver installation utility
  * FILE:        subsys/system/vmwinst/vmwinst.c
  * PROGRAMMERS: Thomas Weidenmueller (w3seek@users.sourceforge.net)
+ *              Klemens Friedl (frik85@hotmail.com)
  */
 #include <windows.h>
 #include <commctrl.h>
 #include <string.h>
 #include "vmwinst.h"
 
+extern VOID CALLBACK InstallHinfSectionW(HWND hwnd, HINSTANCE ModuleHandle,
+                                         PCWSTR CmdLineBuffer, INT nCmdShow);
+
+
 HINSTANCE hAppInstance;
 BOOL StartVMwConfigWizard, DriverFilesFound, ActivateVBE = FALSE, UninstallDriver = FALSE;
 
@@ -43,13 +50,20 @@ static WCHAR *vmx_svga = L"vmx_svga.sys";
 
 static WCHAR *SrcPath = PathToVideoDrivers45;
 
+static HANDLE hInstallationThread = NULL;
+static HWND hInstallationNotifyWnd = NULL;
+static LONG AbortInstall = 0;
+#define WM_INSTABORT        (WM_USER + 2)
+#define WM_INSTCOMPLETE     (WM_USER + 3)
+#define WM_INSTSTATUSUPDATE (WM_USER + 4)
+
 /* Helper functions */
 
 LONG WINAPI ExceptionHandler(LPEXCEPTION_POINTERS ExceptionInfo)
 {
   /* This is rude, but i don't know how to continue execution properly, that's why
      we just exit here when we're not running inside of VMware */
-  ExitProcess(ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION);
+  ExitProcess(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION);
   return EXCEPTION_CONTINUE_EXECUTION;
 }
 
@@ -57,10 +71,10 @@ BOOL
 DetectVMware(int *Version)
 {
   int magic, ver;
-  
+
   magic = 0;
   ver = 0;
-  
+
   /* Try using a VMware I/O port. If not running in VMware this'll throw an
      exception! */
   __asm__ __volatile__("inl  %%dx, %%eax"
@@ -72,7 +86,7 @@ DetectVMware(int *Version)
     *Version = ver;
     return TRUE;
   }
-  
+
   return FALSE;
 }
 
@@ -101,13 +115,13 @@ FileExists(WCHAR *Path, WCHAR *File)
 {
   WCHAR FileName[MAX_PATH + 1];
   HANDLE FileHandle;
-  
+
   FileName[0] = L'\0';
   wcscat(FileName, Path);
   wcscat(FileName, File);
 
   FileHandle = CreateFile(FileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-  
+
   if(FileHandle == INVALID_HANDLE_VALUE)
   {
     return FALSE;
@@ -118,11 +132,35 @@ FileExists(WCHAR *Path, WCHAR *File)
     CloseHandle(FileHandle);
     return FALSE;
   }
-  
+
   CloseHandle(FileHandle);
   return TRUE;
 }
 
+static VOID
+CenterWindow(HWND hWnd)
+{
+  HWND hWndParent;
+  RECT rcParent;
+  RECT rcWindow;
+
+  hWndParent = GetParent(hWnd);
+  if (hWndParent == NULL)
+    hWndParent = GetDesktopWindow();
+
+  GetWindowRect(hWndParent, &rcParent);
+  GetWindowRect(hWnd, &rcWindow);
+
+  SetWindowPos(hWnd,
+              HWND_TOP,
+              ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2,
+              ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2,
+              0,
+              0,
+              SWP_NOSIZE);
+}
+
+
 /* Copy file */
 BOOL
 InstallFile(WCHAR *Destination, WCHAR *File)
@@ -132,14 +170,14 @@ InstallFile(WCHAR *Destination, WCHAR *File)
   WCHAR DestFileName[MAX_PATH + 1];
   HANDLE SourceFileHandle, DestFileHandle;
   DWORD DataRead, DataWritten;
-  
+
   SourceFileName[0] = L'\0';
   DestFileName[0] = L'\0';
   wcscat(SourceFileName, SrcPath);
   wcscat(SourceFileName, File);
   wcscat(DestFileName, Destination);
   wcscat(DestFileName, File);
-  
+
   SourceFileHandle = CreateFile(SourceFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
   if(SourceFileHandle == INVALID_HANDLE_VALUE)
   {
@@ -151,7 +189,7 @@ InstallFile(WCHAR *Destination, WCHAR *File)
     CloseHandle(SourceFileHandle);
     return FALSE;
   }
-  
+
   while(ReadFile(SourceFileHandle, Buffer, sizeof(Buffer), &DataRead, NULL) && DataRead > 0)
   {
     if(!WriteFile(DestFileHandle, Buffer, DataRead, &DataWritten, NULL) ||
@@ -163,7 +201,7 @@ InstallFile(WCHAR *Destination, WCHAR *File)
       return FALSE;
     }
   }
-  
+
   CloseHandle(SourceFileHandle);
   CloseHandle(DestFileHandle);
   return TRUE;
@@ -175,7 +213,7 @@ IsVMwareCDInDrive(WCHAR *Drv)
 {
   static WCHAR Drive[4] = L"X:\\";
   WCHAR Current;
-  
+
   *Drv = L'\0';
   for(Current = 'C'; Current <= 'Z'; Current++)
   {
@@ -195,7 +233,7 @@ IsVMwareCDInDrive(WCHAR *Drv)
         SetCurrentDirectory(DestinationPath);
         continue;
       }
-      
+
       if(FileExists(SrcPath, vmx_fb) &&
          FileExists(SrcPath, vmx_mode) &&
          FileExists(SrcPath, vmx_svga))
@@ -207,7 +245,7 @@ IsVMwareCDInDrive(WCHAR *Drv)
     }
 #endif
   }
-  
+
   return FALSE;
 }
 
@@ -216,9 +254,9 @@ LoadResolutionSettings(DWORD *ResX, DWORD *ResY, DWORD *ColDepth)
 {
   HKEY hReg;
   DWORD Type, Size;
-  
-  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
-                  L"SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\vmx_svga\\Device0", 
+
+  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                  L"SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\vmx_svga\\Device0",
                   0, KEY_QUERY_VALUE, &hReg) != ERROR_SUCCESS)
   {
     return FALSE;
@@ -229,21 +267,21 @@ LoadResolutionSettings(DWORD *ResX, DWORD *ResY, DWORD *ColDepth)
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   if(RegQueryValueEx(hReg, L"DefaultSettings.XResolution", 0, &Type, (BYTE*)ResX, &Size) != ERROR_SUCCESS ||
      Type != REG_DWORD)
   {
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   if(RegQueryValueEx(hReg, L"DefaultSettings.YResolution", 0, &Type, (BYTE*)ResY, &Size) != ERROR_SUCCESS ||
      Type != REG_DWORD)
   {
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   RegCloseKey(hReg);
   return TRUE;
 }
@@ -253,9 +291,9 @@ IsVmwSVGAEnabled(VOID)
 {
   HKEY hReg;
   DWORD Type, Size, Value;
-  
-  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
-                  L"SYSTEM\\CurrentControlSet\\Services\\vmx_svga", 
+
+  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                  L"SYSTEM\\CurrentControlSet\\Services\\vmx_svga",
                   0, KEY_QUERY_VALUE, &hReg) != ERROR_SUCCESS)
   {
     return FALSE;
@@ -266,19 +304,21 @@ IsVmwSVGAEnabled(VOID)
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   RegCloseKey(hReg);
   return (Value == 1);
 }
 
+
+
 BOOL
 SaveResolutionSettings(DWORD ResX, DWORD ResY, DWORD ColDepth)
 {
   HKEY hReg;
-  
-  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
-                  L"SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\vmx_svga\\Device0", 
-                  0, KEY_QUERY_VALUE, &hReg) != ERROR_SUCCESS)
+
+  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                  L"SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\vmx_svga\\Device0",
+                  0, KEY_SET_VALUE, &hReg) != ERROR_SUCCESS)
   {
     return FALSE;
   }
@@ -287,19 +327,19 @@ SaveResolutionSettings(DWORD ResX, DWORD ResY, DWORD ColDepth)
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   if(RegSetValueEx(hReg, L"DefaultSettings.XResolution", 0, REG_DWORD, (BYTE*)&ResX, sizeof(DWORD)) != ERROR_SUCCESS)
   {
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   if(RegSetValueEx(hReg, L"DefaultSettings.YResolution", 0, REG_DWORD, (BYTE*)&ResY, sizeof(DWORD)) != ERROR_SUCCESS)
   {
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   RegCloseKey(hReg);
   return TRUE;
 }
@@ -309,9 +349,9 @@ EnableDriver(WCHAR *Key, BOOL Enable)
 {
   DWORD Value;
   HKEY hReg;
-  
+
   Value = (Enable ? 1 : 4);
-  
+
   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, Key, 0, KEY_SET_VALUE, &hReg) != ERROR_SUCCESS)
   {
     return FALSE;
@@ -321,7 +361,7 @@ EnableDriver(WCHAR *Key, BOOL Enable)
     RegCloseKey(hReg);
     return FALSE;
   }
-  
+
   RegCloseKey(hReg);
   return TRUE;
 }
@@ -342,25 +382,98 @@ EnableVmwareDriver(BOOL VBE, BOOL VGA, BOOL VMX)
   {
     return FALSE;
   }
-  
+
+  return TRUE;
+}
+
+/* Make sure the required registry entries are present */
+BOOL
+AddVmwareRegistryEntries()
+{
+  HRSRC VmwareInfResource;
+  HGLOBAL VmwareInfMem;
+  PVOID VmwareInfLocked;
+  DWORD Size;
+  WCHAR TempPath[MAX_PATH];
+  WCHAR BufferSize;
+  WCHAR TempFileName[MAX_PATH];
+  HANDLE TempFile;
+  DWORD Written;
+  WCHAR CmdLine[19 + MAX_PATH];
+
+  VmwareInfResource = FindResourceW(hAppInstance,
+                                    MAKEINTRESOURCE(IDR_VMWARE_INF),
+                                    L"RT_INF");
+  if (NULL == VmwareInfResource)
+  {
+    return FALSE;
+  }
+  Size = SizeofResource(hAppInstance, VmwareInfResource);
+  if (0 == Size)
+  {
+    return FALSE;
+  }
+  VmwareInfMem = LoadResource(hAppInstance, VmwareInfResource);
+  if (NULL == VmwareInfMem)
+  {
+    return FALSE;
+  }
+  VmwareInfLocked = LockResource(VmwareInfMem);
+  if (NULL == VmwareInfLocked)
+  {
+    return FALSE;
+  }
+
+  BufferSize = GetTempPathW(sizeof(TempPath) / sizeof(TempPath[0]), TempPath);
+  if (0 == BufferSize || sizeof(TempPath) / sizeof(TempPath[0]) < BufferSize)
+  {
+    return FALSE;
+  }
+  if (0 == GetTempFileNameW(TempPath, L"vmx", 0, TempFileName))
+  {
+    return FALSE;
+  }
+
+  TempFile = CreateFileW(TempFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+                         FILE_ATTRIBUTE_NORMAL, NULL);
+  if (INVALID_HANDLE_VALUE == TempFile)
+  {
+    DeleteFile(TempFileName);
+    return FALSE;
+  }
+  if (! WriteFile(TempFile, VmwareInfLocked, Size, &Written, NULL) ||
+      Written != Size)
+  {
+    CloseHandle(TempFile);
+    DeleteFile(TempFileName);
+    return FALSE;
+  }
+  CloseHandle(TempFile);
+
+  wcscpy(CmdLine, L"DefaultInstall 128 ");
+  wcscat(CmdLine, TempFileName);
+  InstallHinfSectionW(NULL, NULL, CmdLine, 0);
+
+  DeleteFile(TempFileName);
+
   return TRUE;
 }
 
 /* GUI */
 
 void
-InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc)
+InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DWORD Flags, DLGPROC DlgProc)
 {
   ZeroMemory(psp, sizeof(PROPSHEETPAGE));
   psp->dwSize = sizeof(PROPSHEETPAGE);
-  psp->dwFlags = PSP_DEFAULT;
+  psp->dwFlags = PSP_DEFAULT | Flags;
   psp->hInstance = hAppInstance;
   psp->pszTemplate = MAKEINTRESOURCE(idDlg);
   psp->pfnDlgProc = DlgProc;
 }
 
 /* Property page dialog callback */
-int CALLBACK
+INT_PTR CALLBACK
 PageWelcomeProc(
   HWND hwndDlg,
   UINT uMsg,
@@ -372,6 +485,12 @@ PageWelcomeProc(
   {
     case WM_NOTIFY:
     {
+      HWND hwndControl;
+
+      /* Center the wizard window */
+      hwndControl = GetParent(hwndDlg);
+      CenterWindow (hwndControl);
+
       LPNMHDR pnmh = (LPNMHDR)lParam;
       switch(pnmh->code)
       {
@@ -384,8 +503,10 @@ PageWelcomeProc(
         {
           if(DriverFilesFound)
           {
-            if(!EnableVmwareDriver(FALSE, FALSE, TRUE))
+            /* FIXME - check for existing registry entries! */
+            if(!EnableVmwareDriver(TRUE, TRUE, TRUE))
             {
+
               WCHAR Msg[1024];
               LoadString(hAppInstance, IDS_FAILEDTOACTIVATEDRIVER, Msg, sizeof(Msg) / sizeof(WCHAR));
               MessageBox(GetParent(hwndDlg), Msg, NULL, MB_ICONWARNING);
@@ -405,7 +526,7 @@ PageWelcomeProc(
 }
 
 /* Property page dialog callback */
-int CALLBACK
+INT_PTR CALLBACK
 PageInsertDiscProc(
   HWND hwndDlg,
   UINT uMsg,
@@ -424,50 +545,217 @@ PageInsertDiscProc(
           PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
           break;
         case PSN_WIZNEXT:
-          PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
-          ProcessMessages();
-          if(!IsVMwareCDInDrive(&CDDrive))
+          SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_INSTALLING_VMWARE_TOOLS);
+          break;
+      }
+      break;
+    }
+  }
+  return FALSE;
+}
+
+VOID
+InstTerminateInstaller(BOOL Wait)
+{
+  if(hInstallationThread != NULL)
+  {
+    if(Wait)
+    {
+      InterlockedExchange((LONG*)&AbortInstall, 2);
+      WaitForSingleObject(hInstallationThread, INFINITE);
+    }
+    else
+    {
+      InterlockedExchange((LONG*)&AbortInstall, 1);
+    }
+  }
+}
+
+DWORD STDCALL
+InstInstallationThread(LPVOID lpParameter)
+{
+  HANDLE hThread;
+  BOOL DriveAvailable;
+  int DrivesTested = 0;
+
+  if(AbortInstall != 0) goto done;
+  PostMessage(hInstallationNotifyWnd, WM_INSTSTATUSUPDATE, IDS_SEARCHINGFORCDROM, 0);
+
+  while(AbortInstall == 0)
+  {
+    Sleep(500);
+    DriveAvailable = IsVMwareCDInDrive(&CDDrive);
+    if(DriveAvailable)
+      break;
+    if(DrivesTested++ > 20)
+    {
+      PostMessage(hInstallationNotifyWnd, WM_INSTABORT, IDS_FAILEDTOLOCATEDRIVERS, 0);
+      goto cleanup;
+    }
+  }
+
+  if(AbortInstall != 0) goto done;
+  PostMessage(hInstallationNotifyWnd, WM_INSTSTATUSUPDATE, IDS_COPYINGFILES, 0);
+
+  if(AbortInstall != 0) goto done;
+  if(!InstallFile(DestinationPath, vmx_fb))
+  {
+    PostMessage(hInstallationNotifyWnd, WM_INSTABORT, IDS_FAILEDTOCOPYFILES, 0);
+    goto cleanup;
+  }
+
+  Sleep(250);
+
+  if(AbortInstall != 0) goto done;
+  if(!InstallFile(DestinationPath, vmx_mode))
+  {
+    PostMessage(hInstallationNotifyWnd, WM_INSTABORT, IDS_FAILEDTOCOPYFILES, 0);
+    goto cleanup;
+  }
+
+  Sleep(250);
+
+  if(AbortInstall != 0) goto done;
+  if(!InstallFile(DestinationDriversPath, vmx_svga))
+  {
+    PostMessage(hInstallationNotifyWnd, WM_INSTABORT, IDS_FAILEDTOCOPYFILES, 0);
+    goto cleanup;
+  }
+
+  Sleep(250);
+
+  if(AbortInstall != 0) goto done;
+  PostMessage(hInstallationNotifyWnd, WM_INSTSTATUSUPDATE, IDS_ENABLINGDRIVER, 0);
+  if(!AddVmwareRegistryEntries())
+  {
+    PostMessage(hInstallationNotifyWnd, WM_INSTABORT, IDS_FAILEDTOADDREGENTRIES, 0);
+    goto cleanup;
+  }
+  if(!EnableVmwareDriver(TRUE, TRUE, TRUE))
+  {
+    PostMessage(hInstallationNotifyWnd, WM_INSTABORT, IDS_FAILEDTOACTIVATEDRIVER, 0);
+    goto cleanup;
+  }
+
+  Sleep(500);
+
+done:
+  switch(AbortInstall)
+  {
+    case 0:
+      SendMessage(hInstallationNotifyWnd, WM_INSTCOMPLETE, 0, 0);
+      break;
+    case 1:
+      SendMessage(hInstallationNotifyWnd, WM_INSTABORT, 0, 0);
+      break;
+  }
+
+cleanup:
+  hThread = (HANDLE)InterlockedExchange((LONG*)&hInstallationThread, 0);
+  if(hThread != NULL)
+  {
+    CloseHandle(hThread);
+  }
+  return 0;
+}
+
+BOOL
+InstStartInstallationThread(HWND hwndNotify)
+{
+  if(hInstallationThread == NULL)
+  {
+    DWORD ThreadId;
+    hInstallationNotifyWnd = hwndNotify;
+    AbortInstall = 0;
+    hInstallationThread = CreateThread(NULL,
+                                       0,
+                                       InstInstallationThread,
+                                       NULL,
+                                       CREATE_SUSPENDED,
+                                       &ThreadId);
+    if(hInstallationThread == NULL)
+    {
+      return FALSE;
+    }
+
+    ResumeThread(hInstallationThread);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* Property page dialog callback */
+INT_PTR CALLBACK
+PageInstallingProc(
+  HWND hwndDlg,
+  UINT uMsg,
+  WPARAM wParam,
+  LPARAM lParam
+)
+{
+  switch(uMsg)
+  {
+    case WM_NOTIFY:
+    {
+      LPNMHDR pnmh = (LPNMHDR)lParam;
+      switch(pnmh->code)
+      {
+        case PSN_SETACTIVE:
+          SetDlgItemText(hwndDlg, IDC_INSTALLINGSTATUS, NULL);
+          SendDlgItemMessage(hwndDlg, IDC_INSTALLINGPROGRESS, PBM_SETMARQUEE, TRUE, 50);
+          PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
+          InstStartInstallationThread(hwndDlg);
+          break;
+        case PSN_RESET:
+          InstTerminateInstaller(TRUE);
+          break;
+        case PSN_WIZBACK:
+          if(hInstallationThread != NULL)
           {
-            WCHAR Msg[1024];
-            LoadString(hAppInstance, IDS_FAILEDTOLOCATEDRIVERS, Msg, sizeof(Msg) / sizeof(WCHAR));
-            MessageBox(GetParent(hwndDlg), Msg, NULL, MB_ICONWARNING);
-            PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
-            SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_INSERT_VMWARE_TOOLS);
-            return TRUE;
+            PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
+            InstTerminateInstaller(FALSE);
+            SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+            return -1;
           }
-          
-          if(!InstallFile(DestinationPath, vmx_fb) ||
-             !InstallFile(DestinationPath, vmx_mode) ||
-             !InstallFile(DestinationDriversPath, vmx_svga))
+          else
           {
-            WCHAR Msg[1024];
-            LoadString(hAppInstance, IDS_FAILEDTOCOPYFILES, Msg, sizeof(Msg) / sizeof(WCHAR));
-            MessageBox(GetParent(hwndDlg), Msg, NULL, MB_ICONWARNING);
-            PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+            SendDlgItemMessage(hwndDlg, IDC_INSTALLINGPROGRESS, PBM_SETMARQUEE, FALSE, 0);
             SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_INSERT_VMWARE_TOOLS);
-            return TRUE;
           }
-          
-          if(!EnableVmwareDriver(FALSE, FALSE, TRUE))
-          {
-            WCHAR Msg[1024];
-            LoadString(hAppInstance, IDS_FAILEDTOACTIVATEDRIVER, Msg, sizeof(Msg) / sizeof(WCHAR));
-            MessageBox(GetParent(hwndDlg), Msg, NULL, MB_ICONWARNING);
-            SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_INSTALLATION_FAILED);
-            return TRUE;
-          }
-          
-          PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
           break;
       }
       break;
     }
+    case WM_INSTABORT:
+      /* go back in case we aborted the installation thread */
+      SendDlgItemMessage(hwndDlg, IDC_INSTALLINGPROGRESS, PBM_SETMARQUEE, FALSE, 0);
+      PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSERT_VMWARE_TOOLS);
+      if(wParam != 0)
+      {
+        WCHAR Msg[1024];
+        LoadString(hAppInstance, wParam, Msg, sizeof(Msg) / sizeof(WCHAR));
+        MessageBox(GetParent(hwndDlg), Msg, NULL, MB_ICONWARNING);
+      }
+      break;
+    case WM_INSTCOMPLETE:
+      SendDlgItemMessage(hwndDlg, IDC_INSTALLINGPROGRESS, PBM_SETMARQUEE, FALSE, 0);
+      PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+      PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_CONFIG);
+      break;
+    case WM_INSTSTATUSUPDATE:
+    {
+      WCHAR Msg[1024];
+      LoadString(hAppInstance, wParam, Msg, sizeof(Msg) / sizeof(WCHAR));
+      SetDlgItemText(hwndDlg, IDC_INSTALLINGSTATUS, Msg);
+      break;
+    }
   }
   return FALSE;
 }
 
 /* Property page dialog callback */
-BOOL CALLBACK
+INT_PTR CALLBACK
 PageInstallFailedProc(
   HWND hwndDlg,
   UINT uMsg,
@@ -497,7 +785,7 @@ FillComboBox(HWND Dlg, int idComboBox, int From, int To)
 {
   int i;
   WCHAR Text[256];
-  
+
   for(i = From; i <= To; i++)
   {
     if(LoadString(hAppInstance, i, Text, 255) > 0)
@@ -515,7 +803,7 @@ typedef struct
 } MAPCTLRES;
 
 /* Property page dialog callback */
-BOOL CALLBACK
+INT_PTR CALLBACK
 PageConfigProc(
   HWND hwndDlg,
   UINT uMsg,
@@ -529,7 +817,7 @@ PageConfigProc(
     {
       DWORD ResX = 0, ResY = 0, ColDepth = 0;
       int cbSel;
-      
+
       FillComboBox(hwndDlg, IDC_COLORQUALITY, 10001, 10003);
       if(LoadResolutionSettings(&ResX, &ResY, &ColDepth))
       {
@@ -555,12 +843,18 @@ PageConfigProc(
     }
     case WM_NOTIFY:
     {
+      HWND hwndControl;
+
+      /* Center the wizard window */
+      hwndControl = GetParent(hwndDlg);
+      CenterWindow (hwndControl);
+
       LPNMHDR pnmh = (LPNMHDR)lParam;
       switch(pnmh->code)
       {
         case PSN_SETACTIVE:
         {
-          PropSheet_SetWizButtons(GetParent(hwndDlg), (StartVMwConfigWizard ? PSWIZB_FINISH | PSWIZB_BACK : PSWIZB_FINISH));
+          PropSheet_SetWizButtons(GetParent(hwndDlg), ((StartVMwConfigWizard || DriverFilesFound) ? PSWIZB_FINISH | PSWIZB_BACK : PSWIZB_FINISH));
           break;
         }
         case PSN_WIZBACK:
@@ -603,7 +897,7 @@ PageConfigProc(
               break;
             }
           }
-          
+
           switch(SendDlgItemMessage(hwndDlg, IDC_COLORQUALITY, CB_GETCURSEL, 0, 0))
           {
             case 0:
@@ -616,7 +910,7 @@ PageConfigProc(
               cd = 32;
               break;
           }
-          
+
           SaveResolutionSettings(rx, ry, cd);
           break;
         }
@@ -628,7 +922,7 @@ PageConfigProc(
 }
 
 /* Property page dialog callback */
-BOOL CALLBACK
+INT_PTR CALLBACK
 PageChooseActionProc(
   HWND hwndDlg,
   UINT uMsg,
@@ -658,7 +952,7 @@ PageChooseActionProc(
         {
           static ULONG SelPage[4] = {IDD_CONFIG, IDD_SELECTDRIVER, IDD_SELECTDRIVER, IDD_CHOOSEACTION};
           int i;
-          
+
           for(i = IDC_CONFIGSETTINGS; i <= IDC_UNINSTALL; i++)
           {
             if(SendDlgItemMessage(hwndDlg, i, BM_GETCHECK, 0, 0) == BST_CHECKED)
@@ -666,9 +960,9 @@ PageChooseActionProc(
               break;
             }
           }
-          
+
           UninstallDriver = (i == IDC_UNINSTALL);
-          
+
           SetWindowLong(hwndDlg, DWL_MSGRESULT, SelPage[i - IDC_CONFIGSETTINGS]);
           return TRUE;
         }
@@ -680,7 +974,7 @@ PageChooseActionProc(
 }
 
 /* Property page dialog callback */
-BOOL CALLBACK
+INT_PTR CALLBACK
 PageSelectDriverProc(
   HWND hwndDlg,
   UINT uMsg,
@@ -691,7 +985,7 @@ PageSelectDriverProc(
   switch(uMsg)
   {
     case WM_INITDIALOG:
-      SendDlgItemMessage(hwndDlg, IDC_VGA, BM_SETCHECK, BST_CHECKED, 0);
+      SendDlgItemMessage(hwndDlg, IDC_VBE, BM_SETCHECK, BST_CHECKED, 0);
       break;
     case WM_NOTIFY:
     {
@@ -724,7 +1018,7 @@ PageSelectDriverProc(
           }
           ActivateVBE = (SendDlgItemMessage(hwndDlg, IDC_VBE, BM_GETCHECK, 0, 0) == BST_CHECKED);
           if(!EnableVmwareDriver(ActivateVBE,
-                                 !ActivateVBE,
+                                 TRUE,
                                  FALSE))
           {
             WCHAR Msg[1024];
@@ -750,7 +1044,7 @@ ShowUninstNotice(HWND Owner)
   MessageBox(Owner, Msg, NULL, MB_ICONINFORMATION);
 }
 
-BOOL CALLBACK
+INT_PTR CALLBACK
 PageDoUninstallProc(
   HWND hwndDlg,
   UINT uMsg,
@@ -773,7 +1067,7 @@ PageDoUninstallProc(
           if(UninstallDriver)
           {
             if(!EnableVmwareDriver(ActivateVBE,
-                                   !ActivateVBE,
+                                   TRUE,
                                    FALSE))
             {
               WCHAR Msg[1024];
@@ -796,58 +1090,118 @@ PageDoUninstallProc(
 static LONG
 CreateWizard(VOID)
 {
-  PROPSHEETPAGE psp[7];
   PROPSHEETHEADER psh;
+  HPROPSHEETPAGE ahpsp[8];
+  PROPSHEETPAGE psp;
   WCHAR Caption[1024];
-  
+
   LoadString(hAppInstance, IDS_WIZARD_NAME, Caption, sizeof(Caption) / sizeof(TCHAR));
-  
-  ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
+
+  /* Create the Welcome page */
+  ZeroMemory (&psp, sizeof(PROPSHEETPAGE));
+  psp.dwSize = sizeof(PROPSHEETPAGE);
+  psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
+  psp.hInstance = hAppInstance;
+  psp.pfnDlgProc = PageWelcomeProc;
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
+  ahpsp[0] = CreatePropertySheetPage(&psp);
+
+  /* Create the INSERT_VMWARE_TOOLS page */
+  psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+  psp.pszHeaderTitle = MAKEINTRESOURCE(IDD_INSERT_VMWARE_TOOLSTITLE);
+  psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDD_INSERT_VMWARE_TOOLSSUBTITLE);
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_INSERT_VMWARE_TOOLS);
+  psp.pfnDlgProc = PageInsertDiscProc;
+  ahpsp[1] = CreatePropertySheetPage(&psp);
+
+  /* Create the INSTALLING_VMWARE_TOOLS page */
+  psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+  psp.pszHeaderTitle = MAKEINTRESOURCE(IDD_INSTALLING_VMWARE_TOOLSTITLE);
+  psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDD_INSTALLING_VMWARE_TOOLSSUBTITLE);
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLING_VMWARE_TOOLS);
+  psp.pfnDlgProc = PageInstallingProc;
+  ahpsp[2] = CreatePropertySheetPage(&psp);
+
+  /* Create the CONFIG page */
+  psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+  psp.pszHeaderTitle = MAKEINTRESOURCE(IDD_CONFIGTITLE);
+  psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDD_CONFIGSUBTITLE);
+  psp.pfnDlgProc = PageConfigProc;
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_CONFIG);
+  ahpsp[3] = CreatePropertySheetPage(&psp);
+
+  /* Create the INSTALLATION_FAILED page */
+  psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+  psp.pszHeaderTitle = MAKEINTRESOURCE(IDD_INSTALLATION_FAILEDTITLE);
+  psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDD_INSTALLATION_FAILEDSUBTITLE);
+  psp.pfnDlgProc = PageInstallFailedProc;
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLATION_FAILED);
+  ahpsp[4] = CreatePropertySheetPage(&psp);
+
+  /* Create the CHOOSEACTION page */
+  psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+  psp.pszHeaderTitle = MAKEINTRESOURCE(IDD_CHOOSEACTIONTITLE);
+  psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDD_CHOOSEACTIONSUBTITLE);
+  psp.pfnDlgProc = PageChooseActionProc;
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_CHOOSEACTION);
+  ahpsp[5] = CreatePropertySheetPage(&psp);
+
+  /* Create the SELECTDRIVER page */
+  psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+  psp.pszHeaderTitle = MAKEINTRESOURCE(IDD_SELECTDRIVERTITLE);
+  psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDD_SELECTDRIVERSUBTITLE);
+  psp.pfnDlgProc = PageSelectDriverProc;
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_SELECTDRIVER);
+  ahpsp[6] = CreatePropertySheetPage(&psp);
+
+  /* Create the DOUNINSTALL page */
+  psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+  psp.pszHeaderTitle = MAKEINTRESOURCE(IDD_DOUNINSTALLTITLE);
+  psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDD_DOUNINSTALLSUBTITLE);
+  psp.pfnDlgProc = PageDoUninstallProc;
+  psp.pszTemplate = MAKEINTRESOURCE(IDD_DOUNINSTALL);
+  ahpsp[7] = CreatePropertySheetPage(&psp);
+
+  /* Create the property sheet */
   psh.dwSize = sizeof(PROPSHEETHEADER);
-  psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_WIZARD;
-  psh.hwndParent = NULL;
+  psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
   psh.hInstance = hAppInstance;
-  psh.hIcon = 0;
-  psh.pszCaption = Caption;
+  psh.hwndParent = NULL;
   psh.nPages = 7;
-  psh.nStartPage = (StartVMwConfigWizard ? 4 : 0);
-  psh.ppsp = psp;
-  
-  InitPropSheetPage(&psp[0], IDD_WELCOMEPAGE, PageWelcomeProc);
-  InitPropSheetPage(&psp[1], IDD_INSERT_VMWARE_TOOLS, PageInsertDiscProc);
-  InitPropSheetPage(&psp[2], IDD_CONFIG, PageConfigProc);
-  InitPropSheetPage(&psp[3], IDD_INSTALLATION_FAILED, PageInstallFailedProc);
-  InitPropSheetPage(&psp[4], IDD_CHOOSEACTION, PageChooseActionProc);
-  InitPropSheetPage(&psp[5], IDD_SELECTDRIVER, PageSelectDriverProc);
-  InitPropSheetPage(&psp[6], IDD_DOUNINSTALL, PageDoUninstallProc);
-  
+  psh.nStartPage = (StartVMwConfigWizard ? 5 : 0);
+  psh.phpage = ahpsp;
+  psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
+  psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
+
+  /* Display the wizard */
   return (LONG)(PropertySheet(&psh) != -1);
 }
 
-int WINAPI 
+int WINAPI
 WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpszCmdLine,
        int nCmdShow)
 {
+
   LPTOP_LEVEL_EXCEPTION_FILTER OldHandler;
   int Version;
   WCHAR *lc;
-  
+
   hAppInstance = hInstance;
-  
+
   /* Setup our exception "handler" ;-) */
   OldHandler = SetUnhandledExceptionFilter(ExceptionHandler);
-  
+
   if(!DetectVMware(&Version))
   {
     ExitProcess(1);
     return 1;
   }
-  
+
   /* restore the exception handler */
   SetUnhandledExceptionFilter(OldHandler);
-  
+
   lc = DestinationPath;
   lc += GetSystemDirectory(DestinationPath, MAX_PATH) - 1;
   if(lc >= DestinationPath && *lc != L'\\')
@@ -857,18 +1211,18 @@ WinMain(HINSTANCE hInstance,
   DestinationDriversPath[0] = L'\0';
   wcscat(DestinationDriversPath, DestinationPath);
   wcscat(DestinationDriversPath, L"drivers\\");
-  
+
   SetCurrentDirectory(DestinationPath);
-  
+
   DriverFilesFound = FileExists(DestinationPath, vmx_fb) &&
                      FileExists(DestinationPath, vmx_mode) &&
                      FileExists(DestinationDriversPath, vmx_svga);
-  
+
   StartVMwConfigWizard = DriverFilesFound && IsVmwSVGAEnabled();
-  
+
   /* Show the wizard */
   CreateWizard();
-  
+
   return 2;
 }