diff options
Diffstat (limited to 'win/upgrade_wizard')
-rw-r--r-- | win/upgrade_wizard/CMakeLists.txt | 47 | ||||
-rw-r--r-- | win/upgrade_wizard/res/upgrade.ico | bin | 0 -> 99678 bytes | |||
-rw-r--r-- | win/upgrade_wizard/res/upgrade.rc2 | 13 | ||||
-rw-r--r-- | win/upgrade_wizard/resource.h | 27 | ||||
-rw-r--r-- | win/upgrade_wizard/stdafx.h | 47 | ||||
-rw-r--r-- | win/upgrade_wizard/targetver.h | 8 | ||||
-rw-r--r-- | win/upgrade_wizard/upgrade.cpp | 57 | ||||
-rw-r--r-- | win/upgrade_wizard/upgrade.h | 32 | ||||
-rw-r--r-- | win/upgrade_wizard/upgrade.rc | 148 | ||||
-rw-r--r-- | win/upgrade_wizard/upgradeDlg.cpp | 641 | ||||
-rw-r--r-- | win/upgrade_wizard/upgradeDlg.h | 73 | ||||
-rw-r--r-- | win/upgrade_wizard/upgrade_wizard.exe.manifest | 15 |
12 files changed, 1108 insertions, 0 deletions
diff --git a/win/upgrade_wizard/CMakeLists.txt b/win/upgrade_wizard/CMakeLists.txt new file mode 100644 index 00000000..fd3560e1 --- /dev/null +++ b/win/upgrade_wizard/CMakeLists.txt @@ -0,0 +1,47 @@ +IF((NOT MSVC) OR CLANG_CL OR WITH_ASAN) + RETURN() +ENDIF() + +# We need MFC +# /permissive- flag does not play well with MFC, disable it. +STRING(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +REMOVE_DEFINITIONS(-DNOSERVICE) # fixes "already defined" warning in an AFX header + +FIND_PACKAGE(MFC) +IF(NOT MFC_FOUND) + IF(BUILD_RELEASE) + MESSAGE(FATAL_ERROR + "Can't find MFC. It is necessary for producing official package" + ) + ENDIF() + RETURN() +ENDIF() + +IF(MSVC_CRT_TYPE MATCHES "/MD") + # FORCE static CRT and MFC for upgrade wizard, + # so we do not have to redistribute MFC. + FORCE_STATIC_CRT() + SET(UPGRADE_WIZARD_SOURCES ${CMAKE_SOURCE_DIR}/sql/winservice.c) +ELSE() + SET(UPGRADE_WIZARD_LINK_LIBRARIES winservice) +ENDIF() + +# MFC should be statically linked +SET(CMAKE_MFC_FLAG 1) + +# Enable exception handling (avoids warnings) +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc -DNO_WARN_MBCS_MFC_DEPRECATION") + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql) +MYSQL_ADD_EXECUTABLE(mariadb-upgrade-wizard + upgrade.cpp upgradeDlg.cpp upgrade.rc ${UPGRADE_WIZARD_SOURCES} + COMPONENT Server) + + +TARGET_LINK_LIBRARIES(mariadb-upgrade-wizard ${UPGRADE_WIZARD_LINK_LIBRARIES}) +# upgrade_wizard is Windows executable, set WIN32_EXECUTABLE so it does not +# create a console. +SET_TARGET_PROPERTIES(mariadb-upgrade-wizard PROPERTIES + WIN32_EXECUTABLE 1 + LINK_FLAGS "/MANIFESTUAC:level='requireAdministrator'" +) diff --git a/win/upgrade_wizard/res/upgrade.ico b/win/upgrade_wizard/res/upgrade.ico Binary files differnew file mode 100644 index 00000000..33a61783 --- /dev/null +++ b/win/upgrade_wizard/res/upgrade.ico diff --git a/win/upgrade_wizard/res/upgrade.rc2 b/win/upgrade_wizard/res/upgrade.rc2 new file mode 100644 index 00000000..8a1da417 --- /dev/null +++ b/win/upgrade_wizard/res/upgrade.rc2 @@ -0,0 +1,13 @@ +// +// zzz.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/win/upgrade_wizard/resource.h b/win/upgrade_wizard/resource.h new file mode 100644 index 00000000..4c05cea2 --- /dev/null +++ b/win/upgrade_wizard/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by upgrade.rc +// +#define IDD_UPGRADE_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_LIST1 1000 +#define IDC_PROGRESS1 1004 +#define IDC_EDIT1 1005 +#define IDC_EDIT2 1006 +#define IDC_EDIT3 1007 +#define IDC_EDIT7 1011 +#define IDC_EDIT8 1012 +#define IDC_EDIT9 1013 +#define IDC_BUTTON1 1014 +#define IDC_BUTTON2 1015 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1016 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/win/upgrade_wizard/stdafx.h b/win/upgrade_wizard/stdafx.h new file mode 100644 index 00000000..86e4fd82 --- /dev/null +++ b/win/upgrade_wizard/stdafx.h @@ -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" +struct IUnknown; +#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 + + + + + + + + + + + + diff --git a/win/upgrade_wizard/targetver.h b/win/upgrade_wizard/targetver.h new file mode 100644 index 00000000..87c0086d --- /dev/null +++ b/win/upgrade_wizard/targetver.h @@ -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> diff --git a/win/upgrade_wizard/upgrade.cpp b/win/upgrade_wizard/upgrade.cpp new file mode 100644 index 00000000..ea2f894c --- /dev/null +++ b/win/upgrade_wizard/upgrade.cpp @@ -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; +} + diff --git a/win/upgrade_wizard/upgrade.h b/win/upgrade_wizard/upgrade.h new file mode 100644 index 00000000..b5dd10e7 --- /dev/null +++ b/win/upgrade_wizard/upgrade.h @@ -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 diff --git a/win/upgrade_wizard/upgrade.rc b/win/upgrade_wizard/upgrade.rc new file mode 100644 index 00000000..dbba9f67 --- /dev/null +++ b/win/upgrade_wizard/upgrade.rc @@ -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 + diff --git a/win/upgrade_wizard/upgradeDlg.cpp b/win/upgrade_wizard/upgradeDlg.cpp new file mode 100644 index 00000000..10a1787c --- /dev/null +++ b/win/upgrade_wizard/upgradeDlg.cpp @@ -0,0 +1,641 @@ + +// 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> + +#include <winservice.h> +#include <locale.h> + +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) +*/ +void 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; + } + // we have version information + UINT len = 0; + VS_FIXEDFILEINFO* vsfi = NULL; + VerQueryValue(versionInfo, "\\", (void**)&vsfi, &len); + + *major= (int)HIWORD(vsfi->dwFileVersionMS); + *minor= (int)LOWORD(vsfi->dwFileVersionMS); + *patch= (int)HIWORD(vsfi->dwFileVersionLS); + delete[] versionInfo; +} + + +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()); +} + + + +/* + 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[2*64*1024]; + static BYTE configBuffer[8*1024]; + + DWORD bufsize= sizeof(buf); + DWORD bufneed; + DWORD num_services; + BOOL ok= EnumServicesStatusExW(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_PROCESSW info = + (LPENUM_SERVICE_STATUS_PROCESSW)buf; + int index=-1; + for (ULONG i=0; i < num_services; i++) + { + SC_HANDLE service= OpenServiceW(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) + { + mysqld_service_properties service_props; + + if (get_mysql_service_properties(config->lpBinaryPathName, + &service_props)) + continue; + + /* Check if service uses mysqld in installation directory */ + if (_strnicmp(service_props.mysqld_exe, m_InstallDir.c_str(), + m_InstallDir.size()) == 0) + continue; + + if(m_MajorVersion > service_props.version_major || + (m_MajorVersion == service_props.version_major && m_MinorVersion >= + service_props.version_minor)) + { + ServiceProperties props; + props.myini= service_props.inifile; + props.datadir= service_props.datadir; + char service_name_buf[1024]; + WideCharToMultiByte(GetACP(), 0, info[i].lpServiceName, -1, + service_name_buf, sizeof(service_name_buf), + 0, 0); + props.servicename= service_name_buf; + if (service_props.version_major) + { + char ver[64]; + sprintf(ver, "%d.%d.%d", service_props.version_major, + service_props.version_minor, service_props.version_patch); + props.version= ver; + } + else + props.version= "<unknown>"; + + index = m_Services.AddString(service_name_buf); + services.resize(index+1); + services[index] = props; + } + } + 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)); + + + m_Progress.ShowWindow(SW_HIDE); + m_Ok.EnableWindow(FALSE); + if (GetACP() == CP_UTF8) + { + /* Required for mbstowcs, used in some functions.*/ + setlocale(LC_ALL, "en_US.UTF8"); + } + 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 += "\""; + commandline += servicename; + commandline += "\""; + + 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; + + + /* + We will try to assign child process to a job, to be able to + terminate the process and all of its children. It might fail, + in case current process is already part of the job which does + not allows breakaways. + */ + if (CreateProcess(NULL, (LPSTR)commandline.c_str(), NULL, NULL, TRUE, + CREATE_BREAKAWAY_FROM_JOB|CREATE_SUSPENDED, NULL, NULL, &si, &pi)) + { + if(!AssignProcessToJobObject(m_JobObject, pi.hProcess)) + { + char errmsg[128]; + sprintf(errmsg, "AssignProcessToJobObject failed, error %d", + GetLastError()); + ErrorExit(errmsg); + } + ResumeThread(pi.hThread); + } + else + { + /* + Creating a process with CREATE_BREAKAWAY_FROM_JOB failed, reset this flag + and retry. + */ + 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; + 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()); + lines++; + + int curPhase, numPhases; + + // Parse output line to update progress indicator + if (strncmp(output_line.c_str(),"Phase ",6) == 0 && + sscanf(output_line.c_str() +6 ,"%d/%d",&curPhase,&numPhases) == 2 + && numPhases > 0 ) + { + int stepsTotal= m_ProgressTotal*numPhases; + int stepsCurrent= m_ProgressCurrent*numPhases+ curPhase; + int percentDone= stepsCurrent*100/stepsTotal; + m_Progress.SetPos(percentDone); + m_Progress.SetPos(stepsCurrent * 100 / stepsTotal); + } + output_line.clear(); + } + else + { + if(pipeReadBuf[0] != '\r') + output_line.push_back(pipeReadBuf[0]); + } + } + CloseHandle(hPipeRead); + + 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; + } + } + 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); +} diff --git a/win/upgrade_wizard/upgradeDlg.h b/win/upgrade_wizard/upgradeDlg.h new file mode 100644 index 00000000..636f9489 --- /dev/null +++ b/win/upgrade_wizard/upgradeDlg.h @@ -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; +}; diff --git a/win/upgrade_wizard/upgrade_wizard.exe.manifest b/win/upgrade_wizard/upgrade_wizard.exe.manifest new file mode 100644 index 00000000..ca89deae --- /dev/null +++ b/win/upgrade_wizard/upgrade_wizard.exe.manifest @@ -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 |