From 61673e10f6652862055b5d54fd484b670a751c7c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 25 Nov 2007 04:46:18 +0000 Subject: [PATCH] file copying now works, dialogs re-display at their last location, fixed up a bunch of interface mistakes, etc --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401728 --- tools/installer/CCriticalSection.h | 37 +++ tools/installer/CFileList.cpp | 151 +++++++++++ tools/installer/CFileList.h | 40 +++ tools/installer/ChooseMethod.cpp | 3 + tools/installer/ICopyMethod.h | 4 +- tools/installer/InstallerMain.cpp | 30 +++ tools/installer/InstallerMain.h | 3 + tools/installer/InstallerUtil.cpp | 87 ++++++- tools/installer/InstallerUtil.h | 2 + tools/installer/LocalCopyMethod.cpp | 17 +- tools/installer/PerformInstall.cpp | 379 ++++++++++++++++++++-------- tools/installer/PerformInstall.h | 12 + tools/installer/Resource.h | 14 +- tools/installer/SelectGame.cpp | 4 + tools/installer/Welcome.cpp | 3 + tools/installer/installer.rc | 47 ++-- tools/installer/installer.vcproj | 12 + 17 files changed, 715 insertions(+), 130 deletions(-) create mode 100644 tools/installer/CCriticalSection.h create mode 100644 tools/installer/CFileList.cpp create mode 100644 tools/installer/CFileList.h diff --git a/tools/installer/CCriticalSection.h b/tools/installer/CCriticalSection.h new file mode 100644 index 00000000..bd54dae0 --- /dev/null +++ b/tools/installer/CCriticalSection.h @@ -0,0 +1,37 @@ +#ifndef _INCLUDE_INSTALLER_CRIT_SECT_H_ +#define _INCLUDE_INSTALLER_CRIT_SECT_H_ + +#include "platform_headers.h" + +class CCriticalSection +{ +public: + CCriticalSection() + { + InitializeCriticalSection(&m_crit); + } + ~CCriticalSection() + { + DeleteCriticalSection(&m_crit); + } + void Enter() + { + EnterCriticalSection(&m_crit); + } + bool TryEnter() + { + if (TryEnterCriticalSection(&m_crit)) + { + return true; + } + return false; + } + void Leave() + { + LeaveCriticalSection(&m_crit); + } +private: + CRITICAL_SECTION m_crit; +}; + +#endif //_INCLUDE_INSTALLER_CRIT_SECT_H_ diff --git a/tools/installer/CFileList.cpp b/tools/installer/CFileList.cpp new file mode 100644 index 00000000..a11f5a34 --- /dev/null +++ b/tools/installer/CFileList.cpp @@ -0,0 +1,151 @@ +#include "CFileList.h" +#include "InstallerUtil.h" + +using namespace std; + +CFileList::CFileList(const TCHAR *name) : m_TotalSize(0), m_RecursiveSize(0), + m_bGotRecursiveSize(false) +{ + UTIL_Format(m_FolderName, sizeof(m_FolderName) / sizeof(TCHAR), _T("%s"), name); +} + +CFileList::~CFileList() +{ + list::iterator iter; + + for (iter = m_folder_list.begin(); + iter != m_folder_list.end(); + iter++) + { + delete (*iter); + } +} + +const TCHAR *CFileList::GetFolderName() +{ + return m_FolderName; +} + +void CFileList::AddFolder(CFileList *pFileList) +{ + m_folder_list.push_back(pFileList); +} + +void CFileList::AddFile(const TCHAR *name, unsigned __int64 size) +{ + CFileListEntry entry; + + UTIL_Format(entry.file, sizeof(entry.file) / sizeof(TCHAR), _T("%s"), name); + entry.size = size; + + m_file_list.push_back(entry); + m_TotalSize += size; +} + +unsigned __int64 CFileList::GetRecursiveSize() +{ + if (m_bGotRecursiveSize) + { + return m_RecursiveSize; + } + + m_RecursiveSize = m_TotalSize; + + list::iterator iter; + for (iter = m_folder_list.begin(); iter != m_folder_list.end(); iter++) + { + m_RecursiveSize += (*iter)->GetRecursiveSize(); + } + + m_bGotRecursiveSize = true; + + return m_RecursiveSize; +} + +const TCHAR *CFileList::PeekCurrentFile() +{ + if (m_file_list.empty()) + { + return NULL; + } + + return m_file_list.begin()->file; +} + +void CFileList::PopCurrentFile() +{ + m_file_list.erase(m_file_list.begin()); +} + +CFileList *CFileList::PeekCurrentFolder() +{ + if (m_folder_list.empty()) + { + return NULL; + } + + return *(m_folder_list.begin()); +} + +void CFileList::PopCurrentFolder() +{ + m_folder_list.erase(m_folder_list.begin()); +} + +void RecursiveBuildFileList(CFileList *file_list, const TCHAR *current_folder) +{ + HANDLE hFind; + WIN32_FIND_DATA fd; + TCHAR path[MAX_PATH]; + + UTIL_PathFormat(path, sizeof(path) / sizeof(TCHAR), _T("%s\\*.*"), current_folder); + + if ((hFind = FindFirstFile(path, &fd)) == INVALID_HANDLE_VALUE) + { + return; + } + + do + { + if (tstrcasecmp(fd.cFileName, _T(".")) == 0 + || tstrcasecmp(fd.cFileName, _T("..")) == 0) + { + continue; + } + + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) + { + CFileList *pSubList = new CFileList(fd.cFileName); + + UTIL_PathFormat(path, + sizeof(path) / sizeof(TCHAR), + _T("%s\\%s"), + current_folder, + fd.cFileName); + + RecursiveBuildFileList(pSubList, path); + + file_list->AddFolder(pSubList); + } + else + { + LARGE_INTEGER li; + + li.LowPart = fd.nFileSizeLow; + li.HighPart = fd.nFileSizeHigh; + + file_list->AddFile(fd.cFileName, li.QuadPart); + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); +} + +CFileList *CFileList::BuildFileList(const TCHAR *name, const TCHAR *root_folder) +{ + CFileList *pFileList = new CFileList(name); + + RecursiveBuildFileList(pFileList, root_folder); + + return pFileList; +} diff --git a/tools/installer/CFileList.h b/tools/installer/CFileList.h new file mode 100644 index 00000000..9f7af183 --- /dev/null +++ b/tools/installer/CFileList.h @@ -0,0 +1,40 @@ +#ifndef _INCLUDE_FOLDER_LIST_H_ +#define _INCLUDE_FOLDER_LIST_H_ + +#include "platform_headers.h" +#include +#include + +struct CFileListEntry +{ + TCHAR file[MAX_PATH]; + unsigned __int64 size; +}; + +class CFileList +{ +public: + CFileList(const TCHAR *name); + ~CFileList(); +public: + CFileList *PeekCurrentFolder(); + void PopCurrentFolder(); + const TCHAR *PeekCurrentFile(); + void PopCurrentFile(); + const TCHAR *GetFolderName(); +public: + void AddFolder(CFileList *pFileList); + void AddFile(const TCHAR *name, unsigned __int64 size); + unsigned __int64 GetRecursiveSize(); +public: + static CFileList *BuildFileList(const TCHAR *name, const TCHAR *root_folder); +private: + std::list m_folder_list; + std::list m_file_list; + TCHAR m_FolderName[MAX_PATH]; + unsigned __int64 m_TotalSize; + unsigned __int64 m_RecursiveSize; + bool m_bGotRecursiveSize; +}; + +#endif //_INCLUDE_FOLDER_LIST_H_ diff --git a/tools/installer/ChooseMethod.cpp b/tools/installer/ChooseMethod.cpp index 0191030e..11199793 100644 --- a/tools/installer/ChooseMethod.cpp +++ b/tools/installer/ChooseMethod.cpp @@ -95,6 +95,7 @@ INT_PTR CALLBACK ChooseMethodHandler(HWND hDlg, UINT message, WPARAM wParam, LPA { if (LOWORD(wParam) == ID_METHOD_BACK) { + UpdateGlobalPosition(hDlg); EndDialog(hDlg, (INT_PTR)DisplayWelcome); return (INT_PTR)TRUE; } @@ -170,6 +171,7 @@ INT_PTR CALLBACK ChooseMethodHandler(HWND hDlg, UINT message, WPARAM wParam, LPA /* If we got a valid games list, we can display the next * dialog box. */ + UpdateGlobalPosition(hDlg); EndDialog(hDlg, (INT_PTR)DisplaySelectGame); return (INT_PTR)TRUE; } @@ -178,6 +180,7 @@ INT_PTR CALLBACK ChooseMethodHandler(HWND hDlg, UINT message, WPARAM wParam, LPA } case WM_INITDIALOG: { + SetToGlobalPosition(hDlg); return (INT_PTR)TRUE; } } diff --git a/tools/installer/ICopyMethod.h b/tools/installer/ICopyMethod.h index af9a2277..cd1c0e03 100644 --- a/tools/installer/ICopyMethod.h +++ b/tools/installer/ICopyMethod.h @@ -6,7 +6,9 @@ class ICopyProgress { public: - virtual void UpdateProgress(float percent_complete) =0; + virtual void StartingNewFile(const TCHAR *filename) =0; + virtual void UpdateProgress(size_t bytes, size_t total_bytes) =0; + virtual void FileDone(size_t file_size) =0; }; class ICopyMethod diff --git a/tools/installer/InstallerMain.cpp b/tools/installer/InstallerMain.cpp index e3d9515c..3c18f5a7 100644 --- a/tools/installer/InstallerMain.cpp +++ b/tools/installer/InstallerMain.cpp @@ -5,6 +5,35 @@ HINSTANCE g_hInstance; NEXT_DIALOG next_dialog = DisplayWelcome; +POINT g_GlobalPosition; + +void UpdateGlobalPosition(HWND hWnd) +{ + WINDOWINFO wi; + + wi.cbSize = sizeof(WINDOWINFO); + if (GetWindowInfo(hWnd, &wi)) + { + g_GlobalPosition.x = wi.rcWindow.left; + g_GlobalPosition.y = wi.rcWindow.top; + } +} + +void SetToGlobalPosition(HWND hWnd) +{ + WINDOWINFO wi; + + wi.cbSize = sizeof(WINDOWINFO); + if (GetWindowInfo(hWnd, &wi)) + { + MoveWindow(hWnd, + g_GlobalPosition.x, + g_GlobalPosition.y, + wi.rcWindow.right - wi.rcWindow.left, + wi.rcWindow.bottom - wi.rcWindow.top, + TRUE); + } +} LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -12,6 +41,7 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPar { case WMU_INIT_INSTALLER: { + UpdateGlobalPosition(hWnd); while (next_dialog != NULL) { next_dialog = (NEXT_DIALOG)next_dialog(hWnd); diff --git a/tools/installer/InstallerMain.h b/tools/installer/InstallerMain.h index 0fcf359c..e98f316d 100644 --- a/tools/installer/InstallerMain.h +++ b/tools/installer/InstallerMain.h @@ -4,6 +4,9 @@ #include "platform_headers.h" #include "Resource.h" +void UpdateGlobalPosition(HWND hWnd); +void SetToGlobalPosition(HWND hWnd); + typedef void *(*NEXT_DIALOG)(HWND); extern HINSTANCE g_hInstance; diff --git a/tools/installer/InstallerUtil.cpp b/tools/installer/InstallerUtil.cpp index 7a796384..64ebca83 100644 --- a/tools/installer/InstallerUtil.cpp +++ b/tools/installer/InstallerUtil.cpp @@ -175,13 +175,13 @@ const TCHAR *GetFileFromPath(const TCHAR *path) { size_t len = _tcslen(path); - for (size_t i = 0; - i >= 0 && i < len - 1; + for (size_t i = len - 1; + i >= 0 && i < len; i--) { if (path[i] == '\\' || path[i] == '/') { - return &path[i]; + return &path[i+1]; } } @@ -223,9 +223,90 @@ INT_PTR AskToExit(HWND hWnd) if (val == 0 || val == IDYES) { + UpdateGlobalPosition(hWnd); EndDialog(hWnd, NULL); return (INT_PTR)TRUE; } return (INT_PTR)FALSE; } + +size_t UTIL_GetFileSize(const TCHAR *file_path) +{ + HANDLE hFile; + + if ((hFile = CreateFile(file_path, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL)) + != INVALID_HANDLE_VALUE) + { + LARGE_INTEGER size; + + if (GetFileSizeEx(hFile, &size)) + { + CloseHandle(hFile); + return (size_t)size.QuadPart; + } + + CloseHandle(hFile); + } + + return 0; +} + +#if 0 +size_t UTIL_GetFolderSize(const TCHAR *basepath) +{ + HANDLE hFind; + WIN32_FIND_DATA fd; + TCHAR search_path[MAX_PATH]; + size_t total = 0; + + UTIL_PathFormat(search_path, + sizeof(search_path) / sizeof(TCHAR), + _T("%s\\*.*"), + basepath); + + if ((hFind = FindFirstFile(search_path, &fd)) == INVALID_HANDLE_VALUE) + { + return 0; + } + + do + { + if (tstrcasecmp(fd.cFileName, _T(".")) == 0 + || tstrcasecmp(fd.cFileName, _T("..")) == 0) + { + continue; + } + + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) + { + UTIL_PathFormat(search_path, + sizeof(search_path) / sizeof(TCHAR), + _T("%s\\%s"), + basepath, + fd.cFileName); + total += UTIL_GetFolderSize(search_path); + } + else + { + UTIL_PathFormat(search_path, + sizeof(search_path) / sizeof(TCHAR), + _T("%s\\%s"), + basepath, + fd.cFileName); + + total += UTIL_GetFileSize(search_path); + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + + return total; +} +#endif diff --git a/tools/installer/InstallerUtil.h b/tools/installer/InstallerUtil.h index a9d0c12c..19daa6cd 100644 --- a/tools/installer/InstallerUtil.h +++ b/tools/installer/InstallerUtil.h @@ -12,6 +12,8 @@ int BreakStringA(const char *str, char *out, size_t maxchars); size_t AnsiToUnicode(const char *str, wchar_t *buffer, size_t maxchars); const TCHAR *GetFileFromPath(const TCHAR *path); void GenerateErrorMessage(DWORD err, TCHAR *buffer, size_t maxchars); +size_t UTIL_GetFileSize(const TCHAR *file_path); +size_t UTIL_GetFolderSize(const TCHAR *basepath); INT_PTR AskToExit(HWND hWnd); diff --git a/tools/installer/LocalCopyMethod.cpp b/tools/installer/LocalCopyMethod.cpp index a6a72ad4..9ccc2391 100644 --- a/tools/installer/LocalCopyMethod.cpp +++ b/tools/installer/LocalCopyMethod.cpp @@ -15,9 +15,8 @@ DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, { ICopyProgress *progress = (ICopyProgress *)lpData; - float percent = (float)(TotalBytesTransferred.QuadPart) / (float)(TotalFileSize.QuadPart); - - progress->UpdateProgress(percent); + progress->UpdateProgress((size_t)TotalBytesTransferred.QuadPart, + (size_t)TotalFileSize.QuadPart); return PROGRESS_CONTINUE; } @@ -55,7 +54,7 @@ bool LocalCopyMethod::CreateFolder(const TCHAR *name, TCHAR *buffer, size_t maxc m_CurrentPath, name); - if (CreateDirectory(name, NULL)) + if (CreateDirectory(path, NULL)) { return true; } @@ -111,6 +110,11 @@ bool LocalCopyMethod::SendFile(const TCHAR *path, TCHAR *buffer, size_t maxchars m_bCancelStatus = FALSE; + if (m_pProgress != NULL) + { + m_pProgress->StartingNewFile(filename); + } + if (CopyFileEx(path, new_path, m_pProgress ? CopyProgressRoutine : NULL, @@ -126,6 +130,11 @@ bool LocalCopyMethod::SendFile(const TCHAR *path, TCHAR *buffer, size_t maxchars return false; } + if (m_pProgress != NULL) + { + m_pProgress->FileDone(UTIL_GetFileSize(path)); + } + return true; } diff --git a/tools/installer/PerformInstall.cpp b/tools/installer/PerformInstall.cpp index 78e70d67..1b2e54ef 100644 --- a/tools/installer/PerformInstall.cpp +++ b/tools/installer/PerformInstall.cpp @@ -1,125 +1,151 @@ #include "InstallerMain.h" #include "InstallerUtil.h" #include "PerformInstall.h" +#include "CCriticalSection.h" -struct folder_t -{ - TCHAR path[MAX_PATH]; -}; +#define WMU_INSTALLER_DONE WM_USER+2 +#define PBAR_RANGE_HIGH 100 +#define PBAR_RANGE_LOW 0 ICopyMethod *g_pCopyMethod = NULL; -bool do_not_copy_binaries = false; -TCHAR source_path[MAX_PATH]; +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(const TCHAR *basepath, +bool CopyStructureRecursively(ICopyMethod *pCopyMethod, + CFileList *pFileList, + const TCHAR *basepath, const TCHAR *local_path, TCHAR *errbuf, size_t maxchars) { - HANDLE hFind; - WIN32_FIND_DATA fd; - TCHAR search_path[MAX_PATH]; - folder_t *folder_list = NULL; - unsigned int folder_count = 0; + TCHAR file_path[MAX_PATH]; + const TCHAR *file; + CFileList *pSubList; - if (local_path == NULL) + if (!pCopyMethod->SetCurrentFolder(local_path, errbuf, maxchars)) { - UTIL_PathFormat(search_path, - sizeof(search_path) / sizeof(TCHAR), - _T("%s\\*.*"), - basepath); - } - else - { - UTIL_PathFormat(search_path, - sizeof(search_path) / sizeof(TCHAR), - _T("%s\\%s\\*.*"), - basepath, - local_path); - } - - if (!g_pCopyMethod->SetCurrentFolder(local_path, errbuf, maxchars)) - { - /* :TODO: set fail state */ return false; } - if ((hFind = FindFirstFile(search_path, &fd)) == INVALID_HANDLE_VALUE) + /* Copy files */ + while ((file = pFileList->PeekCurrentFile()) != NULL) { - /* :TODO: set a fail state */ - return false; - } - - do - { - if (tstrcasecmp(fd.cFileName, _T(".")) == 0 - || tstrcasecmp(fd.cFileName, _T("..")) == 0) + if (local_path == NULL) { - continue; - } - - if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) - { - /* We cache the folder list so we don't have to keep changing folders back and forth, - * which could be annoying on a slow copy connection. - */ - if (folder_list == NULL) - { - folder_list = (folder_t *)malloc(sizeof(folder_t) * (folder_count + 1)); - } - else - { - folder_list = (folder_t *)realloc(folder_list, sizeof(folder_t) * (folder_count + 1)); - } - - UTIL_Format(folder_list[folder_count].path, MAX_PATH, _T("%s"), fd.cFileName); - folder_count++; + UTIL_PathFormat(file_path, + sizeof(file_path) / sizeof(TCHAR), + _T("%s\\%s"), + basepath, + file); } else { - TCHAR file_path[MAX_PATH]; - - if (local_path == NULL) - { - UTIL_PathFormat(file_path, - sizeof(file_path), - _T("%s\\%s"), - basepath, - fd.cFileName); - } - else - { - UTIL_PathFormat(file_path, - sizeof(file_path), - _T("%s\\%s\\%s"), - basepath, - local_path, - fd.cFileName); - } - - if (!g_pCopyMethod->SendFile(file_path, errbuf, maxchars)) - { - FindClose(hFind); - free(folder_list); - return false; - } + UTIL_PathFormat(file_path, + sizeof(file_path) / sizeof(TCHAR), + _T("%s\\%s\\%s"), + basepath, + local_path, + file); } - } while (FindNextFile(hFind, &fd)); - FindClose(hFind); + if (!pCopyMethod->SendFile(file_path, errbuf, maxchars)) + { + return false; + } + + pFileList->PopCurrentFile(); + } /* Now copy folders */ - for (unsigned int i = 0; i < folder_count; i++) + while ((pSubList = pFileList->PeekCurrentFolder()) != NULL) { /* Try creating the folder */ - if (!g_pCopyMethod->CreateFolder(folder_list[i].path, errbuf, maxchars)) + if (!pCopyMethod->CreateFolder(pSubList->GetFolderName(), errbuf, maxchars)) { - free(folder_list); return false; } @@ -129,7 +155,7 @@ bool CopyStructureRecursively(const TCHAR *basepath, UTIL_PathFormat(new_local_path, sizeof(new_local_path) / sizeof(TCHAR), _T("%s"), - folder_list[i].path); + pSubList->GetFolderName()); } else { @@ -137,21 +163,107 @@ bool CopyStructureRecursively(const TCHAR *basepath, sizeof(new_local_path) / sizeof(TCHAR), _T("%s\\%s"), local_path, - folder_list[i].path); + pSubList->GetFolderName()); } - if (!CopyStructureRecursively(basepath, new_local_path, errbuf, maxchars)) + 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)) { - free(folder_list); return false; } } - free(folder_list); - 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()) @@ -164,14 +276,13 @@ bool StartInstallProcess(HWND hWnd) if (val == 0 || val == IDYES) { - do_not_copy_binaries = true; } else { - do_not_copy_binaries = false; } } +#if 0 TCHAR cur_path[MAX_PATH]; if (_tgetcwd(cur_path, sizeof(cur_path)) == NULL) { @@ -182,13 +293,20 @@ bool StartInstallProcess(HWND hWnd) 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(source_path) == INVALID_FILE_ATTRIBUTES) + if (GetFileAttributes(g_thread_args.basepath) == INVALID_FILE_ATTRIBUTES) { MessageBox( hWnd, @@ -198,9 +316,18 @@ bool StartInstallProcess(HWND hWnd) 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 true; + return StartFileCopy(hWnd); } INT_PTR CALLBACK PerformInstallHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) @@ -209,6 +336,7 @@ INT_PTR CALLBACK PerformInstallHandler(HWND hDlg, UINT message, WPARAM wParam, L { case WM_INITDIALOG: { + SetToGlobalPosition(hDlg); return (INT_PTR)TRUE; } case WM_COMMAND: @@ -216,10 +344,61 @@ INT_PTR CALLBACK PerformInstallHandler(HWND hDlg, UINT message, WPARAM wParam, L if (LOWORD(wParam) == ID_INSTALL_CANCEL || LOWORD(wParam) == ID_CLOSE) { - /* :TODO: enhance */ + 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; } } diff --git a/tools/installer/PerformInstall.h b/tools/installer/PerformInstall.h index 82870f94..63081dee 100644 --- a/tools/installer/PerformInstall.h +++ b/tools/installer/PerformInstall.h @@ -3,6 +3,18 @@ #include "InstallerMain.h" #include "ICopyMethod.h" +#include "CFileList.h" + +struct copy_thread_args_t +{ + ICopyMethod *pCopyMethod; + CFileList *pFileList; + HWND hWnd; + bool m_bIsUpgrade; + bool m_bWasCancelled; + TCHAR basepath[MAX_PATH]; + TCHAR error[255]; +}; void *DisplayPerformInstall(HWND hWnd); void SetInstallMethod(ICopyMethod *pCopyMethod); diff --git a/tools/installer/Resource.h b/tools/installer/Resource.h index ce94d3be..f47b0ac0 100644 --- a/tools/installer/Resource.h +++ b/tools/installer/Resource.h @@ -30,7 +30,9 @@ #define IDC_METHOD_LISTEN_SERVER 1008 #define IDC_SELGAME_LIST 1008 #define IDC_METHOD_ALONE_SERVER 1009 +#define IDC_PROGRESS_CURRENT 1009 #define IDC_METHOD_CUSTOM_FOLDER 1010 +#define IDC_PROGRESS_TOTAL 1010 #define IDC_METHOD_UPLOAD_FTP 1011 #define ID_SELGAME_NEXT 1012 #define ID_SELGAME_EXIT 1013 @@ -38,10 +40,12 @@ #define IDC_SELGAME_TEXT 1015 #define IDC_SELGAME_PANEL 1016 #define IDD_SELECT_GAME 1017 -#define IDD_PERFORM_INSTALL 1018 -#define ID_INSTALL_CANCEL 1019 -#define IDC_INSTALL_PANEL 1020 -#define IDC_INSTALL_TEXT 1021 +#define IDD_PERFORM_INSTALL 1018 +#define ID_INSTALL_CANCEL 1019 +#define IDC_INSTALL_PANEL 1020 +#define IDC_INSTALL_TEXT 1021 +#define ID_INSTALL_START 1022 +#define IDC_PROGRESS_CURCOPY 1023 #define IDC_STATIC -1 #define IDC_WELCOME_TEXT -1 #define IDC_METHOD_PANEL -1 @@ -53,7 +57,7 @@ #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 133 #define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1009 +#define _APS_NEXT_CONTROL_VALUE 1012 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif diff --git a/tools/installer/SelectGame.cpp b/tools/installer/SelectGame.cpp index 87cd8c8a..cd983f04 100644 --- a/tools/installer/SelectGame.cpp +++ b/tools/installer/SelectGame.cpp @@ -51,6 +51,8 @@ INT_PTR CALLBACK ChooseGameHandler(HWND hDlg, UINT message, WPARAM wParam, LPARA } UpdateWindow(lbox); + + SetToGlobalPosition(hDlg); return (INT_PTR)TRUE; } @@ -63,6 +65,7 @@ INT_PTR CALLBACK ChooseGameHandler(HWND hDlg, UINT message, WPARAM wParam, LPARA } else if (LOWORD(wParam) == ID_SELGAME_BACK) { + UpdateGlobalPosition(hDlg); EndDialog(hDlg, (INT_PTR)DisplayChooseMethod); return (INT_PTR)TRUE; } @@ -101,6 +104,7 @@ INT_PTR CALLBACK ChooseGameHandler(HWND hDlg, UINT message, WPARAM wParam, LPARA g_LocalCopier.SetOutputPath(game_sel_list[selected_game_index]->mod_path); SetInstallMethod(&g_LocalCopier); + UpdateGlobalPosition(hDlg); EndDialog(hDlg, (INT_PTR)DisplayPerformInstall); return (INT_PTR)TRUE; diff --git a/tools/installer/Welcome.cpp b/tools/installer/Welcome.cpp index a4171edb..741091fc 100644 --- a/tools/installer/Welcome.cpp +++ b/tools/installer/Welcome.cpp @@ -8,6 +8,7 @@ INT_PTR CALLBACK WelcomeHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM l { case WM_INITDIALOG: { + SetToGlobalPosition(hDlg); return (INT_PTR)TRUE; } case WM_COMMAND: @@ -15,11 +16,13 @@ INT_PTR CALLBACK WelcomeHandler(HWND hDlg, UINT message, WPARAM wParam, LPARAM l if (LOWORD(wParam) == ID_WELCOME_EXIT || LOWORD(wParam) == ID_CLOSE) { + UpdateGlobalPosition(hDlg); EndDialog(hDlg, NULL); return (INT_PTR)TRUE; } else if (LOWORD(wParam) == ID_WELCOME_NEXT) { + UpdateGlobalPosition(hDlg); EndDialog(hDlg, (INT_PTR)DisplayChooseMethod); return (INT_PTR)TRUE; } diff --git a/tools/installer/installer.rc b/tools/installer/installer.rc index 12f36f3f..be5d9eb8 100644 --- a/tools/installer/installer.rc +++ b/tools/installer/installer.rc @@ -67,19 +67,21 @@ END // Dialog // -IDD_WELCOME DIALOGEX 0, 0, 230, 66 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +IDD_WELCOME DIALOGEX 0, 0, 244, 74 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW CAPTION "SourceMod Installer" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "&Next",ID_WELCOME_NEXT,177,50,50,14 - GROUPBOX "",IDC_WELCOME_PANEL,2,3,225,44 - LTEXT "Welcome to the SourceMod Installer. This tool can be used to install SourcecMod to a local server/game installation, or upload SourceMod to a server via FTP.",IDC_WELCOME_TEXT,9,11,209,24 - DEFPUSHBUTTON "E&xit",ID_WELCOME_EXIT,2,50,50,14 + DEFPUSHBUTTON "&Next",ID_WELCOME_NEXT,191,58,50,14 + GROUPBOX "",IDC_WELCOME_PANEL,2,3,239,51 + LTEXT "Welcome to the SourceMod Installer. This tool can be used to install SourcecMod to a local server/game installation, or upload SourceMod to a server via FTP.",IDC_WELCOME_TEXT,9,11,225,42 + DEFPUSHBUTTON "E&xit",ID_WELCOME_EXIT,2,58,50,14 END IDD_CHOOSE_METHOD DIALOGEX 0, 0, 244, 130 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW CAPTION "SourceMod Installer" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN @@ -87,7 +89,7 @@ BEGIN PUSHBUTTON "E&xit",ID_METHOD_EXIT,2,113,50,14 GROUPBOX "",IDC_METHOD_PANEL,2,3,239,108 DEFPUSHBUTTON "&Back",ID_METHOD_BACK,136,113,50,14 - GROUPBOX "",IDC_METHOD_PANEL,17,30,154,69 + GROUPBOX "",IDC_METHOD_PANEL,17,30,181,69 LTEXT "Please select an installation method:",IDC_METHOD_TEXT,9,15,122,12 CONTROL "Steam Dedicated Server",IDC_METHOD_DED_SERVER,"Button",BS_AUTORADIOBUTTON,21,35,98,15 CONTROL "Steam Listen Server",IDC_METHOD_LISTEN_SERVER,"Button",BS_AUTORADIOBUTTON,21,46,93,16 @@ -98,7 +100,8 @@ BEGIN END IDD_SELECT_GAME DIALOGEX 0, 0, 244, 130 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW CAPTION "SourceMod Installer" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN @@ -107,17 +110,22 @@ BEGIN GROUPBOX "",IDC_SELGAME_PANEL,2,3,239,108 DEFPUSHBUTTON "&Back",ID_SELGAME_BACK,136,113,50,14 LTEXT "Please select a game:",IDC_SELGAME_TEXT,9,15,122,12 - LISTBOX IDC_SELGAME_LIST,17,30,177,69,LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LISTBOX IDC_SELGAME_LIST,17,30,199,69,LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END -IDD_PERFORM_INSTALL DIALOGEX 0, 0, 244, 130 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +IDD_PERFORM_INSTALL DIALOGEX 0, 0, 243, 116 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW CAPTION "SourceMod Installer" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - PUSHBUTTON "&Cancel",ID_INSTALL_CANCEL,2,113,50,14 - GROUPBOX "",IDC_INSTALL_PANEL,2,3,239,108 - LTEXT "Please wait while SourceMod is installed...",IDC_INSTALL_TEXT,9,15,122,12 + PUSHBUTTON "&Cancel",ID_INSTALL_CANCEL,2,99,50,14 + GROUPBOX "",IDC_INSTALL_PANEL,2,3,239,93 + LTEXT "Click ""Install"" to begin copying the SourceMod files.",IDC_INSTALL_TEXT,9,15,175,13 + CONTROL "",IDC_PROGRESS_CURRENT,"msctls_progress32",WS_BORDER | 0x1,5,50,232,17 + CONTROL "",IDC_PROGRESS_TOTAL,"msctls_progress32",WS_BORDER | 0x1,5,73,232,17 + PUSHBUTTON "&Install",ID_INSTALL_START,191,99,50,14 + LTEXT "",IDC_PROGRESS_CURCOPY,9,34,175,11 END @@ -160,9 +168,9 @@ BEGIN IDD_WELCOME, DIALOG BEGIN LEFTMARGIN, 2 - RIGHTMARGIN, 227 + RIGHTMARGIN, 241 TOPMARGIN, 3 - BOTTOMMARGIN, 64 + BOTTOMMARGIN, 72 END IDD_CHOOSE_METHOD, DIALOG @@ -172,6 +180,11 @@ BEGIN TOPMARGIN, 3 BOTTOMMARGIN, 127 END + + IDD_PERFORM_INSTALL, DIALOG + BEGIN + BOTTOMMARGIN, 113 + END END #endif // APSTUDIO_INVOKED diff --git a/tools/installer/installer.vcproj b/tools/installer/installer.vcproj index 818e9c1c..2de0a1b2 100644 --- a/tools/installer/installer.vcproj +++ b/tools/installer/installer.vcproj @@ -175,6 +175,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -193,6 +197,14 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + +