mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MWL#55 : implement upgrade_wizard - GUI program
to uzpgrade existing MySQL/Maria services to higher version. To be used in installer (but also can be used outside of installer too)
This commit is contained in:
parent
2bc6032c99
commit
e15f914813
9 changed files with 1064 additions and 0 deletions
37
win/upgrade_wizard/CMakeLists.txt
Normal file
37
win/upgrade_wizard/CMakeLists.txt
Normal file
|
@ -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"
|
||||
)
|
47
win/upgrade_wizard/stdafx.h
Normal file
47
win/upgrade_wizard/stdafx.h
Normal file
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
8
win/upgrade_wizard/targetver.h
Normal file
8
win/upgrade_wizard/targetver.h
Normal file
|
@ -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>
|
57
win/upgrade_wizard/upgrade.cpp
Normal file
57
win/upgrade_wizard/upgrade.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
32
win/upgrade_wizard/upgrade.h
Normal file
32
win/upgrade_wizard/upgrade.h
Normal file
|
@ -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;
|
148
win/upgrade_wizard/upgrade.rc
Normal file
148
win/upgrade_wizard/upgrade.rc
Normal file
|
@ -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
|
||||
|
647
win/upgrade_wizard/upgradeDlg.cpp
Normal file
647
win/upgrade_wizard/upgradeDlg.cpp
Normal file
|
@ -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);
|
||||
}
|
73
win/upgrade_wizard/upgradeDlg.h
Normal file
73
win/upgrade_wizard/upgradeDlg.h
Normal file
|
@ -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;
|
||||
};
|
15
win/upgrade_wizard/upgrade_wizard.exe.manifest
Normal file
15
win/upgrade_wizard/upgrade_wizard.exe.manifest
Normal file
|
@ -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>
|
Loading…
Reference in a new issue