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