mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 10:56:12 +01:00 
			
		
		
		
	 2e48fbe3f5
			
		
	
	
	2e48fbe3f5
	
	
	
		
			
			Two Problems 1. Upgrade wizard failed to retrieve path to service executable, if it contained non-ASCII. Fixed by setlocale(LC_ALL, "en_US.UTF8"), which was missing in upgrade wizard 2.mysql_upgrade_service only updated (converted to UTF8) the server's sections leaving client's as-is Corrected typo. 3. Fixed assertion in my_getopt, turns out to be too strict.
		
			
				
	
	
		
			641 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			641 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| // 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);
 | |
| }
 |