sourcemod/tools/installer/PerformInstall.cpp

439 lines
9.5 KiB
C++
Raw Normal View History

#include "InstallerMain.h"
#include "InstallerUtil.h"
#include "PerformInstall.h"
#include "CCriticalSection.h"
#define WMU_INSTALLER_DONE WM_USER+2
#define PBAR_RANGE_HIGH 100
#define PBAR_RANGE_LOW 0
ICopyMethod *g_pCopyMethod = NULL;
HANDLE g_hCopyThread = NULL;
copy_thread_args_t g_thread_args = {NULL, NULL, NULL, false, false};
CCriticalSection g_update_window;
class TrackProgress : public ICopyProgress
{
public:
void Initialize(HWND hTextBar, HWND hCurBar, HWND hTotalBar, size_t total_size)
{
m_hTextBar = hTextBar;
m_hCurBar = hCurBar;
m_hTotalBar = hTotalBar;
m_TotalSize = total_size;
m_TotalDone = 0;
RedrawProgressBars(0.0, 0.0);
}
void Finished()
{
RedrawProgressBars(100.0, 100.0);
}
public:
void StartingNewFile(const TCHAR *filename)
{
TCHAR buffer[255];
if (g_update_window.TryEnter())
{
UTIL_Format(buffer, sizeof(buffer) / sizeof(TCHAR), _T("Copying: %s"), filename);
SendMessage(m_hTextBar, WM_SETTEXT, 0, (LPARAM)buffer);
UpdateWindow(m_hTextBar);
g_update_window.Leave();
}
}
void UpdateProgress(size_t bytes, size_t total_bytes)
{
float fCur = (float)bytes / (float)total_bytes;
float fTotal = ((float)m_TotalDone + (float)bytes) / (float)m_TotalSize;
RedrawProgressBars(fCur, fTotal);
}
void FileDone(size_t total_size)
{
m_TotalDone += total_size;
RedrawProgressBars(0.0, (float)m_TotalDone / (float)m_TotalSize);
}
private:
void RedrawProgressBar(HWND hBar, float fPerc)
{
/* Get a percentage point in the range */
float fPointInRange = (float)(PBAR_RANGE_HIGH - PBAR_RANGE_LOW) * fPerc;
int iPointInRange = (int)fPointInRange;
/* Scale it */
iPointInRange += PBAR_RANGE_LOW;
if (g_update_window.TryEnter())
{
SendMessage(hBar,
PBM_SETPOS,
iPointInRange,
0);
g_update_window.Leave();
}
}
void RedrawProgressBars(float fCurrent, float fTotal)
{
RedrawProgressBar(m_hCurBar, fCurrent);
RedrawProgressBar(m_hTotalBar, fTotal);
}
private:
size_t m_TotalSize;
size_t m_TotalDone;
HWND m_hTextBar;
HWND m_hCurBar;
HWND m_hTotalBar;
} s_ProgressTracker;
void CancelPerformInstall()
{
delete g_thread_args.pFileList;
g_thread_args.pFileList = NULL;
}
void SetInstallMethod(ICopyMethod *pCopyMethod)
{
g_pCopyMethod = pCopyMethod;
}
bool CopyStructureRecursively(ICopyMethod *pCopyMethod,
CFileList *pFileList,
const TCHAR *basepath,
const TCHAR *local_path,
TCHAR *errbuf,
size_t maxchars)
{
TCHAR file_path[MAX_PATH];
const TCHAR *file;
CFileList *pSubList;
if (!pCopyMethod->SetCurrentFolder(local_path, errbuf, maxchars))
{
return false;
}
/* Copy files */
while ((file = pFileList->PeekCurrentFile()) != NULL)
{
if (local_path == NULL)
{
UTIL_PathFormat(file_path,
sizeof(file_path) / sizeof(TCHAR),
_T("%s\\%s"),
basepath,
file);
}
else
{
UTIL_PathFormat(file_path,
sizeof(file_path) / sizeof(TCHAR),
_T("%s\\%s\\%s"),
basepath,
local_path,
file);
}
if (!pCopyMethod->SendFile(file_path, errbuf, maxchars))
{
return false;
}
pFileList->PopCurrentFile();
}
/* Now copy folders */
while ((pSubList = pFileList->PeekCurrentFolder()) != NULL)
{
if (g_thread_args.m_bIsUpgrade)
{
/* :TODO: put this somewhere else because it technically
* means the progress bars get calculated wrong
*/
if (tstrcasecmp(pSubList->GetFolderName(), _T("cfg")) == 0
|| tstrcasecmp(pSubList->GetFolderName(), _T("configs")) == 0)
{
pFileList->PopCurrentFolder();
continue;
}
}
/* Try creating the folder */
if (!pCopyMethod->CreateFolder(pSubList->GetFolderName(), errbuf, maxchars))
{
return false;
}
TCHAR new_local_path[MAX_PATH];
if (local_path == NULL)
{
UTIL_PathFormat(new_local_path,
sizeof(new_local_path) / sizeof(TCHAR),
_T("%s"),
pSubList->GetFolderName());
}
else
{
UTIL_PathFormat(new_local_path,
sizeof(new_local_path) / sizeof(TCHAR),
_T("%s\\%s"),
local_path,
pSubList->GetFolderName());
}
if (!CopyStructureRecursively(pCopyMethod,
pSubList,
basepath,
new_local_path,
errbuf,
maxchars))
{
return false;
}
pFileList->PopCurrentFolder();
/* Set the current folder again for the next operation */
if (!pCopyMethod->SetCurrentFolder(local_path, errbuf, maxchars))
{
return false;
}
}
return true;
}
DWORD WINAPI T_CopyFiles(LPVOID arg)
{
bool result =
CopyStructureRecursively(g_thread_args.pCopyMethod,
g_thread_args.pFileList,
g_thread_args.basepath,
NULL,
g_thread_args.error,
sizeof(g_thread_args.error) / sizeof(TCHAR));
PostMessage(g_thread_args.hWnd, WMU_INSTALLER_DONE, result ? TRUE : FALSE, 0);
return 0;
}
bool StartFileCopy(HWND hWnd)
{
g_thread_args.m_bWasCancelled = false;
g_thread_args.hWnd = hWnd;
if ((g_hCopyThread = CreateThread(NULL,
0,
T_CopyFiles,
NULL,
0,
NULL))
== NULL)
{
MessageBox(
hWnd,
_T("Could not initialize copy thread."),
_T("SourceMod Installer"),
MB_OK|MB_ICONERROR);
return false;
}
return true;
}
void StopFileCopy()
{
g_thread_args.m_bWasCancelled = true;
g_pCopyMethod->CancelCurrentCopy();
if (g_hCopyThread != NULL)
{
g_update_window.Enter();
WaitForSingleObject(g_hCopyThread, INFINITE);
g_update_window.Leave();
CloseHandle(g_hCopyThread);
g_hCopyThread = NULL;
}
}
bool RequestCancelInstall(HWND hWnd)
{
StopFileCopy();
int val = MessageBox(
hWnd,
_T("Are you sure you want to cancel the install?"),
_T("SourceMod Installer"),
MB_YESNO|MB_ICONQUESTION);
if (val == IDYES)
{
return true;
}
if (g_thread_args.pFileList == NULL)
{
return false;
}
/* Start the thread, note our return value is opposite */
return !StartFileCopy(hWnd);
}
bool StartInstallProcess(HWND hWnd)
{
if (g_pCopyMethod->CheckForExistingInstall())
{
int val = MessageBox(
hWnd,
_T("It looks like a previous SourceMod installation exists. Select \"Yes\" to skip copying configuration files. Select \"No\" to perform a full re-install."),
_T("SourceMod Installer"),
MB_YESNO|MB_ICONQUESTION);
if (val == 0 || val == IDYES)
{
g_thread_args.m_bIsUpgrade = true;
}
else
{
g_thread_args.m_bIsUpgrade = false;
}
}
#if 0
TCHAR cur_path[MAX_PATH];
if (_tgetcwd(cur_path, sizeof(cur_path)) == NULL)
{
MessageBox(
hWnd,
_T("Could not locate current directory!"),
_T("SourceMod Installer"),
MB_OK|MB_ICONERROR);
return false;
}
#endif
#if 0
UTIL_PathFormat(source_path,
sizeof(source_path) / sizeof(TCHAR),
_T("%s\\files"),
cur_path);
#else
UTIL_PathFormat(g_thread_args.basepath,
sizeof(g_thread_args.basepath) / sizeof(TCHAR),
_T("C:\\real\\done\\base"));
#endif
if (GetFileAttributes(g_thread_args.basepath) == INVALID_FILE_ATTRIBUTES)
{
MessageBox(
hWnd,
_T("Could not locate the source installation files!"),
_T("SourceMod Installer"),
MB_OK|MB_ICONERROR);
return false;
}
delete g_thread_args.pFileList;
g_thread_args.pFileList = CFileList::BuildFileList(_T(""), g_thread_args.basepath);
s_ProgressTracker.Initialize(
GetDlgItem(hWnd, IDC_PROGRESS_CURCOPY),
GetDlgItem(hWnd, IDC_PROGRESS_CURRENT),
GetDlgItem(hWnd, IDC_PROGRESS_TOTAL),
(size_t)g_thread_args.pFileList->GetRecursiveSize());
g_pCopyMethod->TrackProgress(&s_ProgressTracker);
g_thread_args.pCopyMethod = g_pCopyMethod;
return StartFileCopy(hWnd);
}
INT_PTR CALLBACK PerformInstallHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
SetToGlobalPosition(hDlg);
return (INT_PTR)TRUE;
}
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_INSTALL_CANCEL
|| LOWORD(wParam) == ID_CLOSE)
{
if (RequestCancelInstall(hDlg))
{
CancelPerformInstall();
UpdateGlobalPosition(hDlg);
EndDialog(hDlg, NULL);
}
return (INT_PTR)TRUE;
}
else if (LOWORD(wParam) == ID_INSTALL_START)
{
HWND hButton = GetDlgItem(hDlg, ID_INSTALL_START);
EnableWindow(hButton, FALSE);
StartInstallProcess(hDlg);
}
break;
}
case WMU_INSTALLER_DONE:
{
if (wParam == TRUE)
{
s_ProgressTracker.Finished();
MessageBox(hDlg,
_T("SourceMod was successfully installed! Please visit http://www.sourcemod.net/ for documentation."),
_T("SourceMod Installer"),
MB_OK);
CancelPerformInstall();
UpdateGlobalPosition(hDlg);
EndDialog(hDlg, NULL);
return (INT_PTR)TRUE;
}
else if (!g_thread_args.m_bWasCancelled)
{
TCHAR buffer[500];
UTIL_Format(buffer,
sizeof(buffer) / sizeof(TCHAR),
_T("Encountered error: %s"),
g_thread_args.error);
int res = MessageBox(hDlg,
buffer,
_T("SourceMod Installer"),
MB_ICONERROR|MB_RETRYCANCEL);
if (res == IDRETRY)
{
StartFileCopy(hDlg);
}
else
{
CancelPerformInstall();
UpdateGlobalPosition(hDlg);
EndDialog(hDlg, NULL);
return (INT_PTR)TRUE;
}
}
break;
}
}
return (INT_PTR)FALSE;
}
void *DisplayPerformInstall(HWND hWnd)
{
INT_PTR val;
if ((val = DialogBox(
g_hInstance,
MAKEINTRESOURCE(IDD_PERFORM_INSTALL),
hWnd,
PerformInstallHandler)) == -1)
{
return NULL;
}
return (void *)val;
}