tools/installer/PerformInstall.cpp
author David Anderson <dvander@alliedmods.net>
Wed Feb 25 19:22:36 2009 -0500 (2009-02-25)
changeset 2603 fa286305bd3f
parent 2289 44045ead61cd
permissions -rw-r--r--
Allow for second private chat trigger (bug 3667, r,a11=pred).
     1 #include "InstallerMain.h"
     2 #include "InstallerUtil.h"
     3 #include "PerformInstall.h"
     4 #include "CCriticalSection.h"
     5 
     6 #define WMU_INSTALLER_DONE		WM_USER+2
     7 #define PBAR_RANGE_HIGH			100
     8 #define PBAR_RANGE_LOW			0
     9 
    10 ICopyMethod *g_pCopyMethod = NULL;
    11 HANDLE g_hCopyThread = NULL;
    12 copy_thread_args_t g_thread_args = {NULL, NULL, NULL, false, false};
    13 CCriticalSection g_update_window;
    14 
    15 class TrackProgress : public ICopyProgress
    16 {
    17 public:
    18 	void Initialize(HWND hTextBar, HWND hCurBar, HWND hTotalBar, size_t total_size)
    19 	{
    20 		m_hTextBar = hTextBar;
    21 		m_hCurBar = hCurBar;
    22 		m_hTotalBar = hTotalBar;
    23 		m_TotalSize = total_size;
    24 		m_TotalDone = 0;
    25 		RedrawProgressBars(0.0, 0.0);
    26 	}
    27 	void Finished()
    28 	{
    29 		RedrawProgressBars(100.0, 100.0);
    30 	}
    31 public:
    32 	void StartingNewFile(const TCHAR *filename)
    33 	{
    34 		TCHAR buffer[255];
    35 
    36 		if (g_update_window.TryEnter())
    37 		{
    38 			UTIL_Format(buffer, sizeof(buffer) / sizeof(TCHAR), _T("Copying: %s"), filename);
    39 			SendMessage(m_hTextBar, WM_SETTEXT, 0, (LPARAM)buffer);
    40 			UpdateWindow(m_hTextBar);
    41 			g_update_window.Leave();
    42 		}
    43 	}
    44 	void UpdateProgress(size_t bytes, size_t total_bytes)
    45 	{
    46 		float fCur = (float)bytes / (float)total_bytes;
    47 		float fTotal = ((float)m_TotalDone + (float)bytes) / (float)m_TotalSize;
    48 		RedrawProgressBars(fCur, fTotal);
    49 	}
    50 	void FileDone(size_t total_size)
    51 	{
    52 		m_TotalDone += total_size;
    53 		RedrawProgressBars(0.0, (float)m_TotalDone / (float)m_TotalSize);
    54 	}
    55 private:
    56 	void RedrawProgressBar(HWND hBar, float fPerc)
    57 	{
    58 		/* Get a percentage point in the range */
    59 		float fPointInRange = (float)(PBAR_RANGE_HIGH - PBAR_RANGE_LOW) * fPerc;
    60 		int iPointInRange = (int)fPointInRange;
    61 
    62 		/* Scale it */
    63 		iPointInRange += PBAR_RANGE_LOW;
    64 
    65 		if (g_update_window.TryEnter())
    66 		{
    67 			SendMessage(hBar,
    68 				PBM_SETPOS,
    69 				iPointInRange,
    70 				0);
    71 			g_update_window.Leave();
    72 		}
    73 	}
    74 	void RedrawProgressBars(float fCurrent, float fTotal)
    75 	{
    76 		RedrawProgressBar(m_hCurBar, fCurrent);
    77 		RedrawProgressBar(m_hTotalBar, fTotal);
    78 	}
    79 private:
    80 	size_t m_TotalSize;
    81 	size_t m_TotalDone;
    82 	HWND m_hTextBar;
    83 	HWND m_hCurBar;
    84 	HWND m_hTotalBar;
    85 } s_ProgressTracker;
    86 
    87 void CancelPerformInstall()
    88 {
    89 	delete g_thread_args.pFileList;
    90 	g_thread_args.pFileList = NULL;
    91 }
    92 
    93 void SetInstallMethod(ICopyMethod *pCopyMethod)
    94 {
    95 	g_pCopyMethod = pCopyMethod;
    96 }
    97 
    98 bool CopyStructureRecursively(ICopyMethod *pCopyMethod,
    99 							  CFileList *pFileList,
   100 							  const TCHAR *basepath,
   101 							  const TCHAR *local_path,
   102 							  TCHAR *errbuf,
   103 							  size_t maxchars)
   104 {
   105 	TCHAR file_path[MAX_PATH];
   106 	const TCHAR *file;
   107 	CFileList *pSubList;
   108 
   109 	if (!pCopyMethod->SetCurrentFolder(local_path, errbuf, maxchars))
   110 	{
   111 		return false;
   112 	}
   113 
   114 	/* Copy files */
   115 	while ((file = pFileList->PeekCurrentFile()) != NULL)
   116 	{
   117 		if (local_path == NULL)
   118 		{
   119 			UTIL_PathFormat(file_path,
   120 				sizeof(file_path) / sizeof(TCHAR),
   121 				_T("%s\\%s"),
   122 				basepath,
   123 				file);
   124 		}
   125 		else
   126 		{
   127 			UTIL_PathFormat(file_path,
   128 				sizeof(file_path) / sizeof(TCHAR), 
   129 				_T("%s\\%s\\%s"),
   130 				basepath,
   131 				local_path,
   132 				file);
   133 		}
   134 
   135 		if (!pCopyMethod->SendFile(file_path, errbuf, maxchars))
   136 		{
   137 			return false;
   138 		}
   139 
   140 		pFileList->PopCurrentFile();
   141 	}
   142 
   143 	/* Now copy folders */
   144 	while ((pSubList = pFileList->PeekCurrentFolder()) != NULL)
   145 	{
   146 		if (g_thread_args.m_bIsUpgrade)
   147 		{
   148 			/* :TODO: put this somewhere else because it technically 
   149 			 * means the progress bars get calculated wrong 
   150 			 */
   151 			if (tstrcasecmp(pSubList->GetFolderName(), _T("cfg")) == 0
   152 				|| tstrcasecmp(pSubList->GetFolderName(), _T("configs")) == 0)
   153 			{
   154 				pFileList->PopCurrentFolder();
   155 				continue;
   156 			}
   157 		}
   158 
   159 		/* Try creating the folder */
   160 		if (!pCopyMethod->CreateFolder(pSubList->GetFolderName(), errbuf, maxchars))
   161 		{
   162 			return false;
   163 		}
   164 
   165 		TCHAR new_local_path[MAX_PATH];
   166 		if (local_path == NULL)
   167 		{
   168 			UTIL_PathFormat(new_local_path,
   169 				sizeof(new_local_path) / sizeof(TCHAR),
   170 				_T("%s"),
   171 				pSubList->GetFolderName());
   172 		}
   173 		else
   174 		{
   175 			UTIL_PathFormat(new_local_path,
   176 				sizeof(new_local_path) / sizeof(TCHAR),
   177 				_T("%s\\%s"),
   178 				local_path,
   179 				pSubList->GetFolderName());
   180 		}
   181 
   182 		if (!CopyStructureRecursively(pCopyMethod,
   183 				pSubList,
   184 				basepath, 
   185 				new_local_path, 
   186 				errbuf, 
   187 				maxchars))
   188 		{
   189 			return false;
   190 		}
   191 
   192 		pFileList->PopCurrentFolder();
   193 
   194 		/* Set the current folder again for the next operation */
   195 		if (!pCopyMethod->SetCurrentFolder(local_path, errbuf, maxchars))
   196 		{
   197 			return false;
   198 		}
   199 	}
   200 
   201 	return true;
   202 }
   203 
   204 DWORD WINAPI T_CopyFiles(LPVOID arg)
   205 {
   206 	bool result = 
   207 		CopyStructureRecursively(g_thread_args.pCopyMethod,
   208 		g_thread_args.pFileList,
   209 		g_thread_args.basepath,
   210 		NULL,
   211 		g_thread_args.error,
   212 		sizeof(g_thread_args.error) / sizeof(TCHAR));
   213 
   214 	PostMessage(g_thread_args.hWnd, WMU_INSTALLER_DONE, result ? TRUE : FALSE, 0);
   215 
   216 	return 0;
   217 }
   218 
   219 bool StartFileCopy(HWND hWnd)
   220 {
   221 	g_thread_args.m_bWasCancelled = false;
   222 	g_thread_args.hWnd = hWnd;
   223 	if ((g_hCopyThread = CreateThread(NULL, 
   224 		0, 
   225 		T_CopyFiles, 
   226 		NULL, 
   227 		0,
   228 		NULL))
   229 		== NULL)
   230 	{
   231 		MessageBox(
   232 			hWnd,
   233 			_T("Could not initialize copy thread."),
   234 			_T("SourceMod Installer"),
   235 			MB_OK|MB_ICONERROR);
   236 		return false;
   237 	}
   238 	return true;
   239 }
   240 
   241 void StopFileCopy()
   242 {
   243 	g_thread_args.m_bWasCancelled = true;
   244 	g_pCopyMethod->CancelCurrentCopy();
   245 
   246 	if (g_hCopyThread != NULL)
   247 	{
   248 		g_update_window.Enter();
   249 		WaitForSingleObject(g_hCopyThread, INFINITE);
   250 		g_update_window.Leave();
   251 		CloseHandle(g_hCopyThread);
   252 		g_hCopyThread = NULL;
   253 	}
   254 }
   255 
   256 bool RequestCancelInstall(HWND hWnd)
   257 {
   258 	StopFileCopy();
   259 
   260 	int val = MessageBox(
   261 		hWnd,
   262 		_T("Are you sure you want to cancel the install?"),
   263 		_T("SourceMod Installer"),
   264 		MB_YESNO|MB_ICONQUESTION);
   265 
   266 	if (val == IDYES)
   267 	{
   268 		return true;
   269 	}
   270 	
   271 	if (g_thread_args.pFileList == NULL)
   272 	{
   273 		return false;
   274 	}
   275 
   276 	/* Start the thread, note our return value is opposite */
   277 	return !StartFileCopy(hWnd);
   278 }
   279 
   280 bool StartInstallProcess(HWND hWnd)
   281 {
   282 	if (g_pCopyMethod->CheckForExistingInstall())
   283 	{
   284 		int val = MessageBox(
   285 			hWnd, 
   286 			_T("It looks like a previous SourceMod installation exists.  Select \"Yes\" to skip copying configuration files.  Select \"No\" to perform a full re-install."),
   287 			_T("SourceMod Installer"), 
   288 			MB_YESNO|MB_ICONQUESTION);
   289 
   290 		if (val == 0 || val == IDYES)
   291 		{
   292 			g_thread_args.m_bIsUpgrade = true;
   293 		}
   294 		else
   295 		{
   296 			g_thread_args.m_bIsUpgrade = false;
   297 		}
   298 	}
   299 
   300 #if 0
   301 	TCHAR cur_path[MAX_PATH];
   302 	if (_tgetcwd(cur_path, sizeof(cur_path)) == NULL)
   303 	{
   304 		MessageBox(
   305 			hWnd,
   306 			_T("Could not locate current directory!"),
   307 			_T("SourceMod Installer"),
   308 			MB_OK|MB_ICONERROR);
   309 		return false;
   310 	}
   311 #endif
   312 
   313 #if 0
   314 	UTIL_PathFormat(source_path,
   315 		sizeof(source_path) / sizeof(TCHAR),
   316 		_T("%s\\files"),
   317 		cur_path);
   318 #else
   319 	UTIL_PathFormat(g_thread_args.basepath,
   320 		sizeof(g_thread_args.basepath) / sizeof(TCHAR),
   321 		_T("C:\\real\\done\\base"));
   322 #endif
   323 
   324 	if (GetFileAttributes(g_thread_args.basepath) == INVALID_FILE_ATTRIBUTES)
   325 	{
   326 		MessageBox(
   327 			hWnd,
   328 			_T("Could not locate the source installation files!"),
   329 			_T("SourceMod Installer"),
   330 			MB_OK|MB_ICONERROR);
   331 		return false;
   332 	}
   333 
   334 	delete g_thread_args.pFileList;
   335 	g_thread_args.pFileList = CFileList::BuildFileList(_T(""), g_thread_args.basepath);
   336 
   337 	s_ProgressTracker.Initialize(
   338 		GetDlgItem(hWnd, IDC_PROGRESS_CURCOPY),
   339 		GetDlgItem(hWnd, IDC_PROGRESS_CURRENT),
   340 		GetDlgItem(hWnd, IDC_PROGRESS_TOTAL),
   341 		(size_t)g_thread_args.pFileList->GetRecursiveSize());
   342 	g_pCopyMethod->TrackProgress(&s_ProgressTracker);
   343 	g_thread_args.pCopyMethod = g_pCopyMethod;
   344 
   345 	return StartFileCopy(hWnd);
   346 }
   347 
   348 INT_PTR CALLBACK PerformInstallHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   349 {
   350 	switch (message)
   351 	{
   352 	case WM_INITDIALOG:
   353 		{
   354 			SetToGlobalPosition(hDlg);
   355 			return (INT_PTR)TRUE;
   356 		}
   357 	case WM_COMMAND:
   358 		{
   359 			if (LOWORD(wParam) == ID_INSTALL_CANCEL
   360 				|| LOWORD(wParam) == ID_CLOSE)
   361 			{
   362 				if (RequestCancelInstall(hDlg))
   363 				{
   364 					CancelPerformInstall();
   365 					UpdateGlobalPosition(hDlg);
   366 					EndDialog(hDlg, NULL);
   367 				}
   368 				return (INT_PTR)TRUE;
   369 			}
   370 			else if (LOWORD(wParam) == ID_INSTALL_START)
   371 			{
   372 				HWND hButton = GetDlgItem(hDlg, ID_INSTALL_START);
   373 				EnableWindow(hButton, FALSE);
   374 				StartInstallProcess(hDlg);
   375 			}
   376 			break;
   377 		}
   378 	case WMU_INSTALLER_DONE:
   379 		{
   380 			if (wParam == TRUE)
   381 			{
   382 				s_ProgressTracker.Finished();
   383 				MessageBox(hDlg,
   384 					_T("SourceMod was successfully installed!  Please visit http://www.sourcemod.net/ for documentation."),
   385 					_T("SourceMod Installer"),
   386 					MB_OK);
   387 				CancelPerformInstall();
   388 				UpdateGlobalPosition(hDlg);
   389 				EndDialog(hDlg, NULL);
   390 				return (INT_PTR)TRUE;
   391 			}
   392 			else if (!g_thread_args.m_bWasCancelled)
   393 			{
   394 				TCHAR buffer[500];
   395 
   396 				UTIL_Format(buffer, 
   397 					sizeof(buffer) / sizeof(TCHAR), 
   398 					_T("Encountered error: %s"),
   399 					g_thread_args.error);
   400 				int res = MessageBox(hDlg,
   401 					buffer,
   402 					_T("SourceMod Installer"),
   403 					MB_ICONERROR|MB_RETRYCANCEL);
   404 
   405 				if (res == IDRETRY)
   406 				{
   407 					StartFileCopy(hDlg);
   408 				}
   409 				else
   410 				{
   411 					CancelPerformInstall();
   412 					UpdateGlobalPosition(hDlg);
   413 					EndDialog(hDlg, NULL);
   414 					return (INT_PTR)TRUE;
   415 				}
   416 			}
   417 			break;
   418 		}
   419 	}
   420 
   421 	return (INT_PTR)FALSE;
   422 }
   423 
   424 void *DisplayPerformInstall(HWND hWnd)
   425 {
   426 	INT_PTR val;
   427 
   428 	if ((val = DialogBox(
   429 		g_hInstance, 
   430 		MAKEINTRESOURCE(IDD_PERFORM_INSTALL),
   431 		hWnd,
   432 		PerformInstallHandler)) == -1)
   433 	{
   434 		return NULL;
   435 	}
   436 
   437 	return (void *)val;
   438 }