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