[Commits] Rev 2922: MWL#55 - mysql_upgrade_service.exe in file:///H:/bzr/5.2/

Vladislav Vaintroub wlad at montyprogram.com
Sat Jan 29 19:59:05 EET 2011


At file:///H:/bzr/5.2/

------------------------------------------------------------
revno: 2922
revision-id: wlad at montyprogram.com-20110129175914-h0syti8685p4a57y
parent: wlad at montyprogram.com-20110129175548-c7gil9k6htq7weyk
committer: Vladislav Vaintroub <wlad at montyprogram.com>
branch nick: 5.2
timestamp: Sat 2011-01-29 18:59:14 +0100
message:
  MWL#55 - mysql_upgrade_service.exe 
  New utility to upgrade Windows service to higher MariaDB version.
  Its functionality includes changing service definition as well as
  running mysql_upgrade.
-------------- next part --------------
=== added file 'sql/mysql_upgrade_service.cc'
--- a/sql/mysql_upgrade_service.cc	1970-01-01 00:00:00 +0000
+++ b/sql/mysql_upgrade_service.cc	2011-01-29 17:59:14 +0000
@@ -0,0 +1,550 @@
+/* Copyright (C) 2010 Monty Program Ab
+
+   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; version 2 of the License.
+
+   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.
+
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/*
+  mysql_upgrade_service upgrades mysql service on Windows.
+  It changes service definition to point to the new mysqld.exe, restarts the 
+  server and runs mysql_upgrade
+*/
+
+#define DONT_DEFINE_VOID
+#include <process.h>
+#include <my_global.h>
+#include <my_getopt.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <mysql_version.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windows.h>
+
+/* We're using version APIs */
+#pragma comment(lib, "version")
+
+static char mysqld_path[MAX_PATH];
+static char mysqladmin_path[MAX_PATH];
+static char mysqlupgrade_path[MAX_PATH];
+
+static char defaults_file_param[FN_REFLEN];
+static char logfile_path[FN_REFLEN];
+static char *opt_service;
+static SC_HANDLE service;
+static SC_HANDLE scm;
+HANDLE mysqld_process; // mysqld.exe started for upgrade
+DWORD initial_service_state= -1; // initial state of the service
+HANDLE logfile_handle;
+
+/*
+  Startup and shutdown timeouts, in seconds. 
+  Maybe,they can be made parameters
+*/
+static unsigned int startup_timeout= 60;
+static unsigned int shutdown_timeout= 60;
+
+static struct my_option my_long_options[]=
+{
+  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
+   NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"service", 's', "Name of the existing Windows service",
+  &opt_service, &opt_service, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+};
+
+
+
+static my_bool
+get_one_option(int optid, 
+   const struct my_option *opt __attribute__ ((unused)),
+   char *argument __attribute__ ((unused)))
+{
+  DBUG_ENTER("get_one_option");
+  switch (optid) {
+  case '?':
+    my_print_help(my_long_options);
+    exit(0);
+    break;
+  }
+  DBUG_RETURN(0);
+}
+
+
+
+static void log(const char *fmt, ...)
+{
+  va_list args;
+  char buf[4096];
+
+  /* Print the error message */
+  va_start(args, fmt);
+  if (fmt)
+  {
+    vsprintf_s(buf,  fmt, args);
+    fprintf(stdout, "%s\n", buf);
+  }
+  va_end(args);
+  my_end(0);
+}
+
+
+static void die(const char *fmt, ...)
+{
+  va_list args;
+  DBUG_ENTER("die");
+  char buf[4096];
+
+  /* Print the error message */
+  va_start(args, fmt);
+  if (fmt)
+  {
+    fprintf(stderr, "FATAL ERROR: ");
+    int count= vsprintf_s(buf,  fmt, args);
+    fprintf(stderr, "%s.", buf);
+    if(logfile_path[0])
+    {
+      fprintf(stderr, "Additional information can be found in the log file %s",
+        logfile_path);
+    }
+  }
+  va_end(args);
+
+  /* Cleanup */
+  if(service && initial_service_state != -1)
+  {
+    /* Stop service if it was not running */
+    if(initial_service_state != SERVICE_RUNNING)
+    {
+      SERVICE_STATUS service_status;
+      ControlService(service, SERVICE_CONTROL_STOP, &service_status);
+    }
+    CloseServiceHandle(service);
+  }
+  if(scm)
+    CloseServiceHandle(scm);
+
+  /* Stop mysqld.exe if it was started for upgrade */
+  if(mysqld_process)
+    TerminateProcess(mysqld_process, 3);
+  if(logfile_handle)
+    CloseHandle(logfile_handle);
+  my_end(0);
+  exit(1);
+}
+
+/*
+  spawn-like function to run subprocesses. 
+  We also redirect the full output to the log file.
+
+  Typical usage could be something like
+  run_tool(P_NOWAIT, "cmd.exe", "/c" , "echo", "foo", NULL)
+  
+  @param    wait_flag (P_WAIT or P_NOWAIT)
+  @program  program to run
+
+  Rest of the parameters is NULL terminated strings building command line.
+
+  @return intptr containing either process handle, if P_NOWAIT is used
+  or return code of the process (if P_WAIT is used)
+*/
+static intptr_t run_tool(int wait_flag, const char *program,...)
+{
+  static char cmdline[32*1024];
+  va_list args;
+  va_start(args, program);
+  if(!program)
+    die("Invalid call to run_tool");
+
+  strcpy_s(cmdline, "\"");
+  strcat_s(cmdline, program);
+  strcat_s(cmdline, "\"");
+  for(;;) 
+  {
+    char *param= va_arg(args,char *);
+    if(!param)
+      break;
+    strcat_s(cmdline, " \"");
+    strcat_s(cmdline, param);
+    strcat_s(cmdline, "\"");
+  }
+  va_end(args);
+  
+  /* Create output file if not alredy done */
+  if(!logfile_handle)
+  {
+    char tmpdir[FN_REFLEN];
+    GetTempPath(FN_REFLEN, tmpdir);
+    sprintf_s(logfile_path, "%s\\mysql_upgrade_service.%s.log", tmpdir, 
+      opt_service);
+    logfile_handle = CreateFile(logfile_path, GENERIC_WRITE,  FILE_SHARE_READ, 
+      NULL, TRUNCATE_EXISTING, 0, NULL);
+    if(!logfile_handle)
+      die("Cannot open log file %s", logfile_path);
+  }
+
+  /* Start child process */
+  STARTUPINFO si={0};
+  si.cb= sizeof(si);
+  si.hStdInput= GetStdHandle(STD_INPUT_HANDLE);
+  si.hStdError= logfile_handle;
+  si.hStdOutput= logfile_handle;
+  si.dwFlags= STARTF_USESTDHANDLES;
+  PROCESS_INFORMATION pi;
+  if (!CreateProcess(NULL, cmdline, NULL, 
+       NULL, TRUE, NULL, NULL, NULL, &si, &pi))
+  {
+    die("CreateProcess failed (commandline %s)", cmdline);
+  }
+  CloseHandle(pi.hThread);
+
+  if(wait_flag == P_NOWAIT)
+  {
+    /* Do not wait for process to complete, return handle */
+    return (intptr_t)pi.hProcess;
+  }
+
+  /* Eait for process to complete */
+  if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0)
+  {
+    die("WaitForSingleObject() failed");
+  }
+  DWORD exit_code;
+  if (!GetExitCodeProcess(pi.hProcess, &exit_code))
+  {
+    die("GetExitCodeProcess() failed");
+  }
+  return (intptr_t)exit_code;
+}
+
+
+
+void stop_mysqld_service()
+{
+  DWORD needed;
+  SERVICE_STATUS_PROCESS ssp;
+  int timeout= shutdown_timeout*1000; 
+  for(;;)
+  {
+    if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
+          (LPBYTE)&ssp, 
+          sizeof(SERVICE_STATUS_PROCESS),
+          &needed))
+    {
+      die("QueryServiceStatusEx failed (%d)\n", GetLastError()); 
+    }
+
+    /*
+      Remeber initial state of the service, we will restore it on
+      exit.
+    */
+    if(initial_service_state == -1)
+      initial_service_state =ssp.dwCurrentState;
+
+    switch(ssp.dwCurrentState)
+    {
+      case SERVICE_STOPPED:
+        return;
+      case SERVICE_RUNNING:
+        if(!ControlService(service, SERVICE_CONTROL_STOP, 
+             (SERVICE_STATUS *)&ssp))
+            die("ControlService failed, error %d\n", GetLastError());
+      case SERVICE_START_PENDING:
+      case SERVICE_STOP_PENDING:
+        if(timeout < 0)
+          die("Service does not stop after 1 minute timeout");
+        Sleep(100);
+        break;
+      default:
+        die("Unexpected service state %d",ssp.dwCurrentState);
+    }
+  }
+}
+
+
+/* Helper routine. Used to prevent downgrades by mysql_upgrade_service */
+void get_file_version(const wchar_t *path, int *major, int *minor)
+{
+  *major= *minor=0;
+  DWORD version_handle;
+  char *ver= 0;
+  VS_FIXEDFILEINFO info;
+  UINT len;
+  void *p;
+
+  DWORD size = GetFileVersionInfoSizeW(path, &version_handle);
+  if (size == 0) 
+    return;
+  ver = new char[size];
+  if(!GetFileVersionInfoW(path, version_handle, size, ver))
+    goto end;
+
+  if(!VerQueryValue(ver,"\\",&p,&len))
+    goto end;
+  memcpy(&info,p ,sizeof(VS_FIXEDFILEINFO));
+
+  *major = (info.dwFileVersionMS & 0xFFFF0000) >> 16;
+  *minor = (info.dwFileVersionMS & 0x0000FFFF);
+end:
+  delete []ver;
+}
+
+/* 
+  Shutdown mysql server. Not using mysqladmin, since 
+  our --skip-grant-tables do not work anymore after mysql_upgrade
+  that does "flush privileges". Instead, the shutdown handle is set.
+*/
+void initiate_mysqld_shutdown()
+{
+  char event_name[32];
+  DWORD pid= GetProcessId(mysqld_process);
+  sprintf_s(event_name, "MySQLShutdown%d", pid);
+  HANDLE shutdown_handle= OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name);
+  if(!shutdown_handle)
+  {
+    die("OpenEvent() failed for shutdown event");
+  }
+
+  if(!SetEvent(shutdown_handle))
+  {
+    die("SetEvent() failed");
+  }
+}
+
+
+/*
+  Change service configuration (binPath) to point to mysqld from 
+  this installation.
+*/
+static void change_service_config()
+{
+  wchar_t old_mysqld_path[MAX_PATH];
+  wchar_t *file_part;
+  char defaults_file[MAX_PATH];
+  char default_character_set[64];
+
+  scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+  if(!scm)
+    die("OpenSCManager failed with %d", GetLastError());
+  service= OpenService(scm, opt_service, SERVICE_ALL_ACCESS);
+  if (!service)
+    die("OpenService failed with %d", GetLastError());
+
+  BYTE config_buffer[8*1024];
+  LPQUERY_SERVICE_CONFIGW config= (LPQUERY_SERVICE_CONFIGW)config_buffer;
+  DWORD size=sizeof(config_buffer);
+  DWORD needed;
+  if (!QueryServiceConfigW(service, config, size, &needed))
+    die("QueryServiceConfig failed with %d\n", GetLastError());
+
+  int numargs;
+  LPWSTR *args= CommandLineToArgvW(config->lpBinaryPathName, &numargs);
+
+  char commandline[3*FN_REFLEN +32];
+
+  /* Run some checks to ensure we're really upgrading mysql service */
+
+  if(numargs != 3)
+  {
+    die("Expected 3 parameters in service configuration binPath,"
+      "got %d parameters instead\n. binPath: %S", numargs, 
+      config->lpBinaryPathName);
+  }
+  if(wcsncmp(args[1], L"--defaults-file=", 16) != 0)
+  {
+    die("Unexpected service configuration, second parameter must start with "
+      "--defaults-file. binPath= %S", config->lpBinaryPathName);
+  }
+  GetFullPathNameW(args[0], MAX_PATH, old_mysqld_path, &file_part);
+
+  if(wcsicmp(file_part, L"mysqld.exe") != 0 && 
+    wcsicmp(file_part, L"mysqld") != 0)
+  {
+    die("The service executable is not mysqld. binPath: %S", 
+         config->lpBinaryPathName);
+  }
+
+  if(wcsicmp(file_part, L"mysqld") == 0)
+    wcscat_s(old_mysqld_path, L".exe");
+
+  int old_mysqld_major, old_mysqld_minor;
+  get_file_version(old_mysqld_path, &old_mysqld_major, &old_mysqld_minor);
+  int my_major= MYSQL_VERSION_ID/10000;
+  int my_minor= (MYSQL_VERSION_ID - 10000*my_major)/100;
+
+  if(my_major < old_mysqld_major || 
+    (my_major == old_mysqld_major && my_minor < old_mysqld_minor))
+  {
+    die("Can not downgrade, the service is currently running as version %d.%d"
+      ", my version is %d.%d", old_mysqld_major, old_mysqld_minor, my_major, 
+      my_minor);
+  }
+
+  wcstombs(defaults_file, args[1] + 16, MAX_PATH);
+  /*
+    Remove basedir from defaults file, otherwise the service wont come up in 
+    the new  version, and will complain about mismatched message file.
+  */
+  WritePrivateProfileString("mysqld", "basedir",NULL, defaults_file);
+
+#ifdef _WIN64
+  /* Currently, pbxt is non-functional on x64 */
+  WritePrivateProfileString("mysqld", "loose-skip-pbxt","1", defaults_file);
+#endif
+  /* 
+    Replace default-character-set  with character-set-server, to avoid 
+    "default-character-set is deprecated and will be replaced ..."
+    message.
+  */
+  default_character_set[0]=0;
+  GetPrivateProfileStringA("mysqld", "default-character-set", NULL,
+    default_character_set, sizeof(default_character_set), defaults_file);
+  if(default_character_set[0])
+  {
+    WritePrivateProfileString("mysqld", "default-character-set", NULL, 
+      defaults_file);
+    WritePrivateProfileString("mysqld", "character-set-server",
+      default_character_set, defaults_file);
+  }
+
+  sprintf_s(commandline, "\"%s\" \"%S\" \"%S\"", mysqld_path, args[1], args[2]);
+  if (!ChangeServiceConfig(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 
+         SERVICE_NO_CHANGE, commandline, NULL, NULL, NULL, NULL, NULL, NULL))
+  {
+    die("ChangeServiceConfigW failed with %d", GetLastError());
+  }
+
+  sprintf_s(defaults_file_param, "%S", args[1]);
+  LocalFree(args);
+}
+
+
+
+int main(int argc, char **argv)
+{
+  int error;
+  MY_INIT(argv[0]);
+  char bindir[FN_REFLEN];
+  char *p;
+
+  /*
+    Get full path to mysqld, we need it when changing service configuration.
+    Assume installation layout, i.e mysqld.exe, mysqladmin.exe, mysqlupgrade.exe
+    and mysql_upgrade_service.exe are in the same directory.
+  */
+  GetModuleFileName(NULL, bindir, FN_REFLEN);
+  p = strrchr(bindir, FN_LIBCHAR);
+  if(p)
+  {
+    *p=0;
+  }
+  sprintf_s(mysqld_path, "%s\\mysqld.exe", bindir);
+  sprintf_s(mysqladmin_path, "%s\\mysqladmin.exe", bindir);
+  sprintf_s(mysqlupgrade_path, "%s\\mysql_upgrade.exe", bindir);
+
+  char *paths[]= {mysqld_path, mysqladmin_path, mysqlupgrade_path};
+  for(int i=0; i< 3;i++)
+  {
+    if(GetFileAttributes(paths[i]) == INVALID_FILE_ATTRIBUTES)
+      die("File %s does not exist", paths[i]);
+  }
+
+
+  /* Parse options */
+  if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
+    die("");
+  if(!opt_service)
+    die("service parameter is mandatory");
+ 
+  /*
+    Messages written on stdout should not be buffered,  GUI upgrade program 
+    read them from pipe and uses as progress indicator.
+  */
+  setvbuf(stdout, NULL, _IONBF, 0);
+
+  log("Phase 1/8: Changing service configuration");
+  change_service_config();
+
+  log("Phase 2/8: Stopping service");
+  stop_mysqld_service();
+
+  /* 
+    Start mysqld.exe as non-service skipping privileges (so we do not 
+    care about the password). But disable networking and enable pipe 
+    for communication, for security reasons.
+  */
+  char socket_param[FN_REFLEN];
+  sprintf_s(socket_param,"--shared_memory_base_name=mysql_upgrade_service_%d", 
+    GetCurrentProcessId());
+
+  log("Phase 3/8: Starting mysqld for upgrade");
+  mysqld_process= (HANDLE)run_tool(P_NOWAIT, mysqld_path,
+    defaults_file_param, "--skip-networking",  "--skip-grant-tables", 
+    "--enable-shared-memory",  socket_param, NULL);
+
+  if(mysqld_process == INVALID_HANDLE_VALUE)
+  {
+    die("Cannot start mysqld.exe process, errno=%d", errno);
+  }
+
+  log("Phase 4/8: Waiting for startup to complete");
+  DWORD start_duration_ms= 0;
+  for (int i=0; ; i++)
+  {
+    if (WaitForSingleObject(mysqld_process, 0) != WAIT_TIMEOUT)
+      die("mysqld.exe did not start");
+
+    if (run_tool(P_WAIT, mysqladmin_path, "--protocol=memory",
+      socket_param, "ping",  NULL) == 0)
+    {
+      break;
+    }
+    if (start_duration_ms > startup_timeout*1000)
+      die("Server did not come up in %d seconds",startup_timeout);
+    Sleep(500);
+    start_duration_ms+= 500;
+  }
+
+  log("Phase 5/8: Running mysql_upgrade");
+  int upgrade_err = (int) run_tool(P_WAIT,  mysqlupgrade_path, 
+    "--protocol=memory", "--force",  socket_param,
+    NULL);
+
+  log("Phase 6/8: Initiating server shutdown");
+  initiate_mysqld_shutdown();
+
+  log("Phase 7/8: Waiting for shutdown to complete");
+  if (WaitForSingleObject(mysqld_process, shutdown_timeout*1000)
+      != WAIT_OBJECT_0)
+  {
+    /* Shutdown takes too long */
+    die("mysqld does not shutdown.");
+  }
+  CloseHandle(mysqld_process);
+  mysqld_process= NULL;
+
+  log("Phase 8/8: Starting service%s",
+    (initial_service_state == SERVICE_RUNNING)?"":" (skipped)");
+  if (initial_service_state == SERVICE_RUNNING)
+  {
+    StartService(service, NULL, NULL);
+  }
+
+  log("Service '%s' successfully upgraded.\nLog file is written to %s",
+    opt_service, logfile_path);
+  CloseServiceHandle(service);
+  CloseServiceHandle(scm);
+  if(logfile_handle)
+    CloseHandle(logfile_handle);
+  my_end(0);
+  exit(0);
+}
\ No newline at end of file

=== added directory 'win/upgrade_wizard'
=== added file 'win/upgrade_wizard/CMakeLists.txt'
--- a/win/upgrade_wizard/CMakeLists.txt	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/CMakeLists.txt	2011-01-29 17:59:14 +0000
@@ -0,0 +1,37 @@
+IF(NOT MSVC)
+  RETURN()
+ENDIF()
+IF(CMAKE_USING_VC_FREE_TOOLS)
+  # No MFC, so it cannot be built
+  RETURN()
+ENDIF()
+
+# We need MFC
+FIND_PACKAGE(MFC)
+IF(NOT MFC_FOUND)
+  RETURN()
+ENDIF()  
+
+# MFC should be statically linked
+SET(CMAKE_MFC_FLAG 1)
+
+# Enable exception handling (avoids warnings)
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+
+MYSQL_ADD_EXECUTABLE(upgrade_wizard upgrade.cpp upgradeDlg.cpp upgrade.rc
+  COMPONENT Server)
+
+# upgrade_wizard is Windows executable, set WIN32_EXECUTABLE so it does not
+# create a console.
+SET_TARGET_PROPERTIES(upgrade_wizard PROPERTIES WIN32_EXECUTABLE 1)
+
+# Embed Vista "admin" manifest, since upgrade_wizard needs admin privileges
+# to change service configuration. Due to a CMake bug http://www.vtk.org/Bug/view.php?id=11171
+# it is not possible currenly to do it with linker flags. Work around is to use
+# manifest tool mt.exe and embed the manifest post-build.
+GET_TARGET_PROPERTY(upgrade_wizard_location upgrade_wizard LOCATION)
+ADD_CUSTOM_COMMAND(
+  TARGET upgrade_wizard POST_BUILD
+  COMMAND mt.exe -manifest ${CMAKE_CURRENT_SOURCE_DIR}/upgrade_wizard.exe.manifest
+  "-outputresource:${upgrade_wizard_location};#1"
+)

=== added file 'win/upgrade_wizard/stdafx.h'
--- a/win/upgrade_wizard/stdafx.h	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/stdafx.h	2011-01-29 17:59:14 +0000
@@ -0,0 +1,47 @@
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+#ifndef _SECURE_ATL
+#define _SECURE_ATL 1
+#endif
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN            // Exclude rarely-used stuff from Windows headers
+#endif
+
+#include "targetver.h"
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit
+
+// turns off MFC's hiding of some common and often safely ignored warning messages
+#define _AFX_ALL_WARNINGS
+
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+
+
+
+
+
+#ifndef _AFX_NO_OLE_SUPPORT
+#include <afxdtctl.h>           // MFC support for Internet Explorer 4 Common Controls
+#endif
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h>             // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+
+
+
+
+
+
+
+
+
+
+

=== added file 'win/upgrade_wizard/targetver.h'
--- a/win/upgrade_wizard/targetver.h	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/targetver.h	2011-01-29 17:59:14 +0000
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>

=== added file 'win/upgrade_wizard/upgrade.cpp'
--- a/win/upgrade_wizard/upgrade.cpp	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/upgrade.cpp	2011-01-29 17:59:14 +0000
@@ -0,0 +1,57 @@
+
+// upgrade.cpp : Defines the class behaviors for the application.
+//
+
+#include "stdafx.h"
+#include "upgrade.h"
+#include "upgradeDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+// CUpgradeApp
+
+BEGIN_MESSAGE_MAP(CUpgradeApp, CWinApp)
+  ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+
+// CUpgradeApp construction
+
+CUpgradeApp::CUpgradeApp()
+{
+  // TODO: add construction code here,
+  // Place all significant initialization in InitInstance
+}
+
+
+// The one and only CUpgradeApp object
+
+CUpgradeApp theApp;
+
+
+// CUpgradeApp initialization
+
+BOOL CUpgradeApp::InitInstance()
+{
+  // InitCommonControlsEx() is required on Windows XP if an application
+  // manifest specifies use of ComCtl32.dll version 6 or later to enable
+  // visual styles.  Otherwise, any window creation will fail.
+  INITCOMMONCONTROLSEX InitCtrls;
+  InitCtrls.dwSize = sizeof(InitCtrls);
+  // Set this to include all the common control classes you want to use
+  // in your application.
+  InitCtrls.dwICC = ICC_WIN95_CLASSES;
+
+  InitCommonControlsEx(&InitCtrls);
+  CWinApp::InitInstance();
+  CUpgradeDlg dlg;
+  m_pMainWnd = &dlg;
+  dlg.DoModal();
+  // Since the dialog has been closed, return FALSE so that we exit the
+  //  application, rather than start the application's message pump.
+  return FALSE;
+}
+

=== added file 'win/upgrade_wizard/upgrade.h'
--- a/win/upgrade_wizard/upgrade.h	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/upgrade.h	2011-01-29 17:59:14 +0000
@@ -0,0 +1,32 @@
+
+// zzz.h : main header file for the PROJECT_NAME application
+//
+
+#pragma once
+
+#ifndef __AFXWIN_H__
+	#error "include 'stdafx.h' before including this file for PCH"
+#endif
+
+#include "resource.h"		// main symbols
+
+
+// CzzzApp:
+// See zzz.cpp for the implementation of this class
+//
+
+class CUpgradeApp : public CWinApp
+{
+public:
+	CUpgradeApp();
+
+// Overrides
+public:
+	virtual BOOL InitInstance();
+
+// Implementation
+
+	DECLARE_MESSAGE_MAP()
+};
+
+extern CUpgradeApp theApp;
\ No newline at end of file

=== added file 'win/upgrade_wizard/upgrade.rc'
--- a/win/upgrade_wizard/upgrade.rc	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/upgrade.rc	2011-01-29 17:59:14 +0000
@@ -0,0 +1,148 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#ifndef APSTUDIO_INVOKED
+#include "targetver.h"
+#endif
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Germany) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#ifndef APSTUDIO_INVOKED\r\n"
+    "#include ""targetver.h""\r\n"
+    "#endif\r\n"
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+    "#define _AFX_NO_OLE_RESOURCES\r\n"
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+    "\r\n"
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+    "LANGUAGE 9, 1\r\n"
+    "#include ""res\\upgrade.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
+    "#include ""afxres.rc""      // Standard components\r\n"
+    "#endif\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME           ICON                    "res\\upgrade.ico"
+#endif    // German (Germany) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_UPGRADE_DIALOG DIALOGEX 0, 0, 320, 200
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "MariaDB Upgrade Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,113,169,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,191,169,50,14
+    LISTBOX         IDC_LIST1,24,39,216,80,LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+    EDITTEXT        IDC_EDIT1,97,124,193,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+    EDITTEXT        IDC_EDIT2,98,138,181,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+    CONTROL         "",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH | WS_BORDER,26,153,243,14
+    EDITTEXT        IDC_EDIT3,98,151,40,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+    EDITTEXT        IDC_EDIT7,27,124,65,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+    EDITTEXT        IDC_EDIT8,27,137,62,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+    EDITTEXT        IDC_EDIT9,27,151,62,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+    PUSHBUTTON      "Select all",IDC_BUTTON1,245,61,50,14
+    PUSHBUTTON      "Clear all",IDC_BUTTON2,246,88,50,14
+    LTEXT           "Select services you want to upgrade and click on the [Upgrade] button.\nMake sure to backup data directories prior to upgrade.",IDC_STATIC,25,14,215,26
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+    IDD_UPGRADE_DIALOG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 313
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 193
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#include "res\upgrade.rc2"  // non-Microsoft Visual C++ edited resources
+#include "afxres.rc"      // Standard components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+

=== added file 'win/upgrade_wizard/upgradeDlg.cpp'
--- a/win/upgrade_wizard/upgradeDlg.cpp	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/upgradeDlg.cpp	2011-01-29 17:59:14 +0000
@@ -0,0 +1,647 @@
+
+// upgradeDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "upgrade.h"
+#include "upgradeDlg.h"
+#include "windows.h"
+#include "winsvc.h"
+#include <msi.h>
+#pragma comment(lib, "msi")
+#pragma comment(lib, "version")
+#include <map>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+#define PRODUCT_NAME "MariaDB"
+
+// CUpgradeDlg dialog
+
+CUpgradeDlg::CUpgradeDlg(CWnd* pParent /*=NULL*/)
+  : CDialog(CUpgradeDlg::IDD, pParent)
+{
+  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+}
+
+void CUpgradeDlg::DoDataExchange(CDataExchange* pDX)
+{
+  CDialog::DoDataExchange(pDX);
+  DDX_Control(pDX, IDC_LIST1, m_Services);
+  DDX_Control(pDX, IDC_PROGRESS1, m_Progress);
+  DDX_Control(pDX, IDOK, m_Ok);
+  DDX_Control(pDX, IDCANCEL, m_Cancel);
+  DDX_Control(pDX, IDC_EDIT1, m_IniFilePath);
+  DDX_Control(pDX, IDC_EDIT2, m_DataDir);
+  DDX_Control(pDX, IDC_EDIT3, m_Version);
+  DDX_Control(pDX, IDC_EDIT7, m_IniFileLabel);
+  DDX_Control(pDX, IDC_EDIT8, m_DataDirLabel);
+  DDX_Control(pDX, IDC_EDIT9, m_VersionLabel);
+  DDX_Control(pDX, IDC_BUTTON1, m_SelectAll);
+  DDX_Control(pDX, IDC_BUTTON2, m_ClearAll);
+}
+
+BEGIN_MESSAGE_MAP(CUpgradeDlg, CDialog)
+  ON_WM_PAINT()
+  ON_WM_QUERYDRAGICON()
+  ON_LBN_SELCHANGE(IDC_LIST1, &CUpgradeDlg::OnLbnSelchangeList1)
+  ON_CONTROL(CLBN_CHKCHANGE, IDC_LIST1, OnChkChange)
+  ON_BN_CLICKED(IDOK, &CUpgradeDlg::OnBnClickedOk)
+  ON_BN_CLICKED(IDCANCEL, &CUpgradeDlg::OnBnClickedCancel)
+  ON_BN_CLICKED(IDC_BUTTON1,&CUpgradeDlg::OnBnSelectAll)
+  ON_BN_CLICKED(IDC_BUTTON2,&CUpgradeDlg::OnBnClearAll)
+END_MESSAGE_MAP()
+
+
+struct ServiceProperties
+{
+  string servicename;
+  string myini;
+  string datadir;
+  string version;
+};
+
+vector<ServiceProperties> services;
+
+/*
+  Get version from an executable.
+  Returned version is either major.minor.patch or
+  <unknown> , of executable does not have any version
+  info embedded (like MySQL 5.1 for example)
+*/
+string GetExeVersion(const string& filename, int *major, int *minor, int *patch)
+{
+  DWORD handle;
+  *major= *minor= *patch= 0;
+
+  DWORD size = GetFileVersionInfoSize(filename.c_str(), &handle);
+  BYTE* versionInfo = new BYTE[size];
+  if (!GetFileVersionInfo(filename.c_str(), handle, size, versionInfo))
+  {
+    delete[] versionInfo;
+    return "<unknown>";
+  }
+  // we have version information
+  UINT len = 0;
+  VS_FIXEDFILEINFO*   vsfi = NULL;
+  VerQueryValue(versionInfo, "\\", (void**)&vsfi, &len);
+  char arr[64];
+
+  *major= (int)HIWORD(vsfi->dwFileVersionMS);
+  *minor= (int)LOWORD(vsfi->dwFileVersionMS);
+  *patch= (int)HIWORD(vsfi->dwFileVersionLS);
+  sprintf_s(arr,"%d.%d.%d", *major, *minor, *patch); 
+  delete[] versionInfo;
+  return string(arr);
+}
+
+
+void GetMyVersion(int *major, int *minor, int *patch)
+{
+  char path[MAX_PATH];
+  *major= *minor= *patch =0;
+  if (GetModuleFileName(NULL, path, MAX_PATH))
+  {
+    GetExeVersion(path, major, minor, patch);
+  }
+}
+// CUpgradeDlg message handlers
+
+/* Handle selection changes in services list */
+void CUpgradeDlg::SelectService(int index)
+{
+  m_IniFilePath.SetWindowText(services[index].myini.c_str());
+  m_DataDir.SetWindowText(services[index].datadir.c_str());
+  m_Version.SetWindowText(services[index].version.c_str());
+}
+
+
+/* Remove quotes from string */
+static char *RemoveQuotes(char *s)
+{
+  if(s[0]=='"')
+  {
+    s++;
+    char *p= strchr(s, '"');
+    if(p)
+      *p= 0;
+  }
+  return s;
+}
+
+
+/*
+  Iterate over services, lookup for mysqld.exe ones.
+  Compare mysqld.exe version with current version, and display
+  service if corresponding mysqld.exe has lower version.
+
+  The version check is not strict, i.e we allow to "upgrade" 
+  for the same major.minor combination. This can be useful for 
+  "upgrading" from 32 to 64 bit, or for MySQL=>Maria conversion.
+*/
+void CUpgradeDlg::PopulateServicesList()
+{
+
+  SC_HANDLE scm = OpenSCManager(NULL, NULL, 
+    SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT); 
+  if (scm == NULL) 
+  { 
+    ErrorExit("OpenSCManager failed");
+  }
+
+  static BYTE buf[64*1024];
+  static BYTE configBuffer[8*1024];
+  char datadirBuf[MAX_PATH];
+  char datadirNormalized[MAX_PATH];
+  DWORD bufsize= sizeof(buf);
+  DWORD bufneed;
+  DWORD num_services;
+  BOOL ok= EnumServicesStatusEx(scm, SC_ENUM_PROCESS_INFO,  SERVICE_WIN32,
+    SERVICE_STATE_ALL,  buf, bufsize,  &bufneed, &num_services, NULL, NULL);
+  if(!ok) 
+    ErrorExit("EnumServicesStatusEx failed");
+
+
+  LPENUM_SERVICE_STATUS_PROCESS info =
+    (LPENUM_SERVICE_STATUS_PROCESS)buf;
+  int index=-1;
+  for (ULONG i=0; i < num_services; i++)
+  {
+    SC_HANDLE service= OpenService(scm, info[i].lpServiceName, 
+      SERVICE_QUERY_CONFIG);
+    if (!service)
+      continue;
+    QUERY_SERVICE_CONFIGW *config= 
+      (QUERY_SERVICE_CONFIGW*)(void *)configBuffer;
+    DWORD needed;
+    BOOL ok= QueryServiceConfigW(service, config,sizeof(configBuffer), &needed);
+    CloseServiceHandle(service);
+    if (ok)
+    {
+      int argc;
+      wchar_t **wargv = CommandLineToArgvW(config->lpBinaryPathName, &argc);
+
+      // We expect  path\to\mysqld --defaults-file=<path> <servicename>
+      if(argc == 3)  
+      {
+        
+         // Convert wide strings to ANSI 
+        char *argv[3];
+        for(int k=0; k < 3;k++)
+        {
+          size_t nbytes = 2*wcslen(wargv[k])+1; 
+          argv[k]= new char[nbytes];
+          wcstombs(argv[k], wargv[k], nbytes);
+        }
+
+        size_t len= strlen(argv[0]);
+        char path[MAX_PATH]={0};
+        char *filepart;
+        GetFullPathName(argv[0],MAX_PATH, path, &filepart);
+        if(_stricmp(filepart, "mysqld.exe") == 0 ||
+          _stricmp(filepart, "mysqld") == 0)
+        {
+          if(_strnicmp(argv[1],"--defaults-file=",16) == 0)
+          {
+            /* Remove quotes around defaults-file */
+            char *inifile= argv[1] + 16;
+            inifile = RemoveQuotes(inifile);
+
+            char *datadir=datadirBuf;
+            GetPrivateProfileString("mysqld", "datadir", NULL, datadirBuf,
+              MAX_PATH, inifile);
+
+            /* Remove quotes from datadir */
+            datadir= RemoveQuotes(datadir);
+
+            GetFullPathName(datadir, MAX_PATH, datadirNormalized, NULL);
+            ServiceProperties props;
+
+            props.myini = inifile;
+            props.servicename = info[i].lpServiceName;
+            string exefilename(argv[0]);
+            if(!strstr(argv[0], ".exe"))
+              exefilename += ".exe";
+            int major, minor, patch;
+            props.version= GetExeVersion(exefilename, &major, &minor, &patch);
+            if(m_MajorVersion > major || 
+              (m_MajorVersion == major && m_MinorVersion >= minor))
+            {
+              if (_strnicmp(exefilename.c_str(), m_InstallDir.c_str(),
+                m_InstallDir.size()) != 0)
+              {
+                props.datadir = datadirNormalized;
+                index = m_Services.AddString(info[i].lpServiceName);
+                services.resize(index+1);
+                services[index] = props;
+              }
+            }
+          }
+        }
+        for(int k=0; k< 3;k++)
+          delete[] argv[k];
+      }
+      LocalFree((HLOCAL)wargv);
+    }
+    if (index != -1)
+    {
+      m_Services.SetCurSel(0);
+      SelectService(m_Services.GetCurSel());
+    }
+  }
+  if (services.size())
+  {
+    SelectService(0);
+  }
+  else
+  {
+    char message[128];
+    sprintf(message, 
+      "There is no service that can be upgraded to " PRODUCT_NAME " %d.%d.%d",
+      m_MajorVersion, m_MinorVersion, m_PatchVersion);
+    MessageBox(message, PRODUCT_NAME " Upgrade Wizard", MB_ICONINFORMATION);
+    exit(0);
+  }
+  if(scm)
+    CloseServiceHandle(scm);
+}
+
+BOOL CUpgradeDlg::OnInitDialog()
+{
+  CDialog::OnInitDialog();
+  m_UpgradeRunning= FALSE;
+  // Set the icon for this dialog.  The framework does this automatically
+  //  when the application's main window is not a dialog
+  SetIcon(m_hIcon, TRUE);			// Set big icon
+  SetIcon(m_hIcon, FALSE);		// Set small icon
+  m_Ok.SetWindowText("Upgrade");
+  m_DataDirLabel.SetWindowText("Data directory:");
+  m_IniFileLabel.SetWindowText("Configuration file:");
+  m_VersionLabel.SetWindowText("Version:");
+
+  char myFilename[MAX_PATH];
+  GetModuleFileName(NULL, myFilename, MAX_PATH);
+  char *p= strrchr(myFilename,'\\');
+  if(p)
+    p[1]=0;
+  m_InstallDir= myFilename;
+
+  GetMyVersion(&m_MajorVersion, &m_MinorVersion, &m_PatchVersion);
+  char windowTitle[64];
+
+  sprintf(windowTitle, PRODUCT_NAME " %d.%d.%d Upgrade Wizard",
+    m_MajorVersion, m_MinorVersion, m_PatchVersion);
+  SetWindowText(windowTitle);
+
+  m_JobObject= CreateJobObject(NULL, NULL);
+
+  /*
+    Make all processes associated with the job terminate when the
+    last handle to the job is closed or job is teminated.
+  */
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0};
+  jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+  SetInformationJobObject(m_JobObject, JobObjectExtendedLimitInformation,
+                              &jeli, sizeof(jeli));
+  if(!AssignProcessToJobObject(m_JobObject, GetCurrentProcess()))
+    ErrorExit("AssignProcessToJobObject failed");
+
+  m_Progress.ShowWindow(SW_HIDE);
+  m_Ok.EnableWindow(FALSE);
+  PopulateServicesList();
+  return TRUE;  // return TRUE  unless you set the focus to a control
+}
+
+// If you add a minimize button to your dialog, you will need the code below
+//  to draw the icon.  For MFC applications using the document/view model,
+//  this is automatically done for you by the framework.
+
+void CUpgradeDlg::OnPaint()
+{
+  if (IsIconic())
+  {
+    CPaintDC dc(this); // device context for painting
+
+    SendMessage(WM_ICONERASEBKGND, 
+      reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
+
+    // Center icon in client rectangle
+    int cxIcon = GetSystemMetrics(SM_CXICON);
+    int cyIcon = GetSystemMetrics(SM_CYICON);
+    CRect rect;
+    GetClientRect(&rect);
+    int x = (rect.Width() - cxIcon + 1) / 2;
+    int y = (rect.Height() - cyIcon + 1) / 2;
+
+    // Draw the icon
+    dc.DrawIcon(x, y, m_hIcon);
+  }
+  else
+  {
+    CDialog::OnPaint();
+  }
+}
+
+// The system calls this function to obtain the cursor to display while the user
+//  drags the minimized window.
+HCURSOR CUpgradeDlg::OnQueryDragIcon()
+{
+  return static_cast<HCURSOR>(m_hIcon);
+}
+
+
+void CUpgradeDlg::OnLbnSelchangeList1()
+{
+  SelectService(m_Services.GetCurSel());
+}
+
+void CUpgradeDlg::OnChkChange()
+{
+  if(m_Services.GetCheck( m_Services.GetCurSel()))
+  {
+    GetDlgItem(IDOK)->EnableWindow();
+  }
+  else
+  {
+    for(int i=0; i< m_Services.GetCount(); i++)
+    {
+      if(m_Services.GetCheck(i))
+        return;
+    }
+    // all items unchecked, disable OK button
+    GetDlgItem(IDOK)->EnableWindow(FALSE);
+  }
+}
+
+
+
+void CUpgradeDlg::ErrorExit(LPCSTR str)
+{
+  MessageBox(str, "Fatal Error", MB_ICONERROR);
+  exit(1);
+}
+
+
+const int MAX_MESSAGES=512;
+
+/* Main thread of the child process */
+static HANDLE hChildThread;
+
+void CUpgradeDlg::UpgradeOneService(const string& servicename)
+{
+  static string allMessages[MAX_MESSAGES];
+  static char npname[MAX_PATH];
+  static char pipeReadBuf[1];
+  SECURITY_ATTRIBUTES saAttr;
+  STARTUPINFO si={0};
+  PROCESS_INFORMATION pi;
+  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
+  saAttr.bInheritHandle = TRUE; 
+  saAttr.lpSecurityDescriptor = NULL;
+
+  HANDLE hPipeRead, hPipeWrite;
+  if(!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 1))
+    ErrorExit("CreateNamedPipe failed");
+
+  /* Make sure read end of the pipe is not inherited */
+  if (!SetHandleInformation(hPipeRead, HANDLE_FLAG_INHERIT, 0) )
+    ErrorExit("Stdout SetHandleInformation"); 
+
+  string commandline("mysql_upgrade_service.exe --service=");
+  commandline += servicename;
+  si.cb = sizeof(si);
+  si.hStdInput= GetStdHandle(STD_INPUT_HANDLE);
+  si.hStdOutput= hPipeWrite;
+  si.hStdError= hPipeWrite;
+  si.wShowWindow= SW_HIDE;
+  si.dwFlags= STARTF_USESTDHANDLES |STARTF_USESHOWWINDOW;
+  if (!CreateProcess(NULL, (LPSTR)commandline.c_str(), NULL, NULL, TRUE,
+    0, NULL, NULL, &si, &pi))
+  {
+    string errmsg("Create Process ");
+    errmsg+= commandline;
+    errmsg+= " failed";
+    ErrorExit(errmsg.c_str());
+  }
+  hChildThread = pi.hThread;
+  DWORD nbytes;
+  bool newline= false;
+  int lines=0;
+  CloseHandle(hPipeWrite);
+
+  string output_line;
+  while(ReadFile(hPipeRead, pipeReadBuf, 1, &nbytes, NULL))
+  {
+    if(pipeReadBuf[0] == '\n')
+    {
+      allMessages[lines%MAX_MESSAGES] = output_line;
+      m_DataDir.SetWindowText(allMessages[lines%MAX_MESSAGES].c_str());
+      output_line.clear();
+      lines++;
+
+      /* 
+        Updating progress dialog.There are currently 9 messages from 
+        mysql_upgrade_service (actually it also writes Phase N/M but 
+        we do not parse
+      */
+#define EXPRECTED_MYSQL_UPGRADE_MESSAGES 9
+
+      int stepsTotal= m_ProgressTotal*EXPRECTED_MYSQL_UPGRADE_MESSAGES;
+      int stepsCurrent= m_ProgressCurrent*EXPRECTED_MYSQL_UPGRADE_MESSAGES
+        + lines;
+      int percentDone= stepsCurrent*100/stepsTotal;
+      m_Progress.SetPos(percentDone);
+    }
+    else
+    {
+      if(pipeReadBuf[0] != '\r')
+       output_line.push_back(pipeReadBuf[0]);
+    }
+  }
+  CloseHandle(hPipeWrite);
+
+  if(WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0)
+    ErrorExit("WaitForSingleObject failed");
+  DWORD exitcode;
+  if (!GetExitCodeProcess(pi.hProcess, &exitcode))
+    ErrorExit("GetExitCodeProcess failed");
+
+  if (exitcode != 0)
+  {
+    string  errmsg= "mysql_upgrade_service returned error for service ";
+    errmsg += servicename;
+    errmsg += ":\r\n";
+    errmsg+= output_line;
+    ErrorExit(errmsg.c_str());
+  }
+  CloseHandle(pi.hProcess);
+  hChildThread= 0;
+  CloseHandle(pi.hThread);
+}
+
+
+void CUpgradeDlg::UpgradeServices()
+{
+
+  /*
+    Disable some dialog items during upgrade (OK button,
+    services list)
+  */
+  m_Ok.EnableWindow(FALSE);
+  m_Services.EnableWindow(FALSE);
+  m_SelectAll.EnableWindow(FALSE);
+  m_ClearAll.EnableWindow(FALSE);
+
+  /*
+    Temporarily repurpose IniFileLabel/IniFilePath and
+    DatDirLabel/DataDir controls to show progress messages.
+  */
+  m_VersionLabel.ShowWindow(FALSE);
+  m_Version.ShowWindow(FALSE);
+  m_Progress.ShowWindow(TRUE);
+  m_IniFileLabel.SetWindowText("Converting service:");
+  m_IniFilePath.SetWindowText("");
+  m_DataDirLabel.SetWindowText("Progress message:");
+  m_DataDir.SetWindowText("");
+
+
+  m_ProgressTotal=0;
+  for(int i=0; i< m_Services.GetCount(); i++)
+  {
+    if(m_Services.GetCheck(i))
+      m_ProgressTotal++;
+  }
+  m_ProgressCurrent=0;
+  for(int i=0; i< m_Services.GetCount(); i++)
+  {
+    if(m_Services.GetCheck(i))
+    {
+      m_IniFilePath.SetWindowText(services[i].servicename.c_str());
+      m_Services.SelectString(0, services[i].servicename.c_str());
+      UpgradeOneService(services[i].servicename);
+      m_ProgressCurrent++;
+    }
+  }
+
+  MessageBox("Service(s) successfully upgraded", "Success", 
+    MB_ICONINFORMATION);
+
+  /* Rebuild services list */
+  vector<ServiceProperties> new_instances;
+  for(int i=0; i< m_Services.GetCount(); i++)
+  {
+    if(!m_Services.GetCheck(i))
+      new_instances.push_back(services[i]);
+  }
+
+  services= new_instances;
+  m_Services.ResetContent();
+  for(size_t i=0; i< services.size();i++)
+    m_Services.AddString(services[i].servicename.c_str());
+  if(services.size())
+  {
+    m_Services.SelectString(0,services[0].servicename.c_str());
+    SelectService(0);
+  }
+  else
+  {
+    /* Nothing to do, there are no upgradable services */
+    exit(0);
+  }
+
+  /*
+    Restore controls that were temporarily repurposed for
+    progress info to their normal state
+  */
+  m_IniFileLabel.SetWindowText("Configuration file:");
+  m_DataDirLabel.SetWindowText("Data Directory:");
+  m_VersionLabel.ShowWindow(TRUE);
+  m_Version.ShowWindow(TRUE);
+  m_Progress.SetPos(0);
+  m_Progress.ShowWindow(FALSE);
+
+  /* Re-enable controls */
+  m_Ok.EnableWindow(TRUE);
+  m_Services.EnableWindow(TRUE);
+  m_SelectAll.EnableWindow(TRUE);
+  m_ClearAll.EnableWindow(TRUE);
+
+  m_UpgradeRunning= FALSE;
+}
+
+
+/* Thread procedure for upgrade services operation */
+static UINT UpgradeServicesThread(void *param)
+{
+  CUpgradeDlg *dlg= (CUpgradeDlg *)param;
+  dlg->UpgradeServices();
+  return 0;
+}
+
+
+/*
+  Do upgrade  for all services currently selected
+  in the list. Since it is a potentially lengthy operation that 
+  might block it has to be done in a background thread.
+*/
+void CUpgradeDlg::OnBnClickedOk()
+{
+  if(m_UpgradeRunning)
+    return;
+  m_UpgradeRunning= TRUE;
+  AfxBeginThread(UpgradeServicesThread, this);
+}
+
+
+/* 
+  Cancel button clicked.
+  If upgrade is running, suspend mysql_upgrade_service, 
+  and ask user whether he really wants to stop.Terminate
+  upgrade wizard and all subprocesses if users wants it.
+
+  If upgrade is not running, terminate the Wizard
+*/
+void CUpgradeDlg::OnBnClickedCancel()
+{
+  if(m_UpgradeRunning)
+  {
+    bool suspended = (SuspendThread(hChildThread) != (DWORD)-1);
+    int ret = MessageBox(
+      "Upgrade is in progress. Are you sure you want to terminate?",
+      0, MB_YESNO|MB_DEFBUTTON2|MB_ICONQUESTION);
+    if(ret != IDYES)
+    {
+      if(suspended)
+        ResumeThread(hChildThread);
+      return;
+    }
+  }
+  if(!TerminateJobObject(m_JobObject, 1))
+    exit(1);
+}
+
+/*
+  Select all services from the list
+*/
+void CUpgradeDlg::OnBnSelectAll()
+{
+  for(int i=0; i < m_Services.GetCount(); i++)
+   m_Services.SetCheck(i, 1);
+  m_Ok.EnableWindow(TRUE);
+}
+
+/*
+  Clear all services in the list
+*/
+void CUpgradeDlg::OnBnClearAll()
+{
+  for(int i=0; i < m_Services.GetCount(); i++)
+   m_Services.SetCheck(i, 0);
+  m_Ok.EnableWindow(FALSE);
+}

=== added file 'win/upgrade_wizard/upgradeDlg.h'
--- a/win/upgrade_wizard/upgradeDlg.h	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/upgradeDlg.h	2011-01-29 17:59:14 +0000
@@ -0,0 +1,73 @@
+
+// upgradeDlg.h : header file
+//
+
+#pragma once
+#include "afxcmn.h"
+#include "afxwin.h"
+#include <string>
+
+
+// CUpgradeDlg dialog
+class CUpgradeDlg : public CDialog
+{
+  // Construction
+public:
+  CUpgradeDlg(CWnd* pParent = NULL); // standard constructor
+
+  // Dialog Data
+  enum { IDD = IDD_UPGRADE_DIALOG };
+
+protected:
+  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+
+  // job object for current process and children
+  HANDLE m_JobObject;
+
+  // Services are being upgraded
+  BOOL m_UpgradeRunning;
+
+  // ProgressBar related: number of services to upgrade
+  int m_ProgressTotal;
+
+  //ProgressBar related: current service being upgraded
+  int m_ProgressCurrent; 
+
+protected:
+  HICON m_hIcon;
+
+  // Generated message map functions
+  virtual BOOL OnInitDialog();
+  void PopulateServicesList();
+  afx_msg void OnPaint();
+  afx_msg HCURSOR OnQueryDragIcon();
+  DECLARE_MESSAGE_MAP()
+public:
+  void SelectService(int index);
+  void UpgradeServices();
+  void UpgradeOneService(const std::string& name);
+  void ErrorExit(const char *);
+  std::string m_InstallDir;
+  CCheckListBox m_Services;
+  CProgressCtrl m_Progress;
+  CButton m_Ok;
+  CButton m_Cancel;
+  CButton m_SelectAll;
+  CButton m_ClearAll;
+  int m_MajorVersion;
+  int m_MinorVersion;
+  int m_PatchVersion;
+
+  CEdit m_IniFilePath;
+  afx_msg void OnLbnSelchangeList1();
+  afx_msg void OnChkChange();
+  CEdit m_DataDir;
+  CEdit m_Version;
+  afx_msg void OnBnClickedOk();
+  afx_msg void OnBnClickedCancel();
+  afx_msg void OnBnSelectAll();
+  afx_msg void OnBnClearAll();
+  CEdit m_IniFileLabel;
+  CEdit m_DataDirLabel;
+  CEdit m_VersionLabel;
+};

=== added file 'win/upgrade_wizard/upgrade_wizard.exe.manifest'
--- a/win/upgrade_wizard/upgrade_wizard.exe.manifest	1970-01-01 00:00:00 +0000
+++ b/win/upgrade_wizard/upgrade_wizard.exe.manifest	2011-01-29 17:59:14 +0000
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel>
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
+    </dependentAssembly>
+  </dependency>
+</assembly>
\ No newline at end of file



More information about the commits mailing list