Add progress bar

This commit is contained in:
luiscuenca 2019-07-09 12:20:09 -07:00
parent 7aef864d7f
commit 9f110cac13
No known key found for this signature in database
GPG key ID: 2387ECD129A6961D
8 changed files with 281 additions and 96 deletions

View file

@ -92,7 +92,8 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION
EXSTYLE WS_EX_APPWINDOW
FONT 10, "MS Shell Dlg", 400, 0, 0x0
BEGIN
CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,27,174,123
CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,3,174,123, NOT WS_VISIBLE
CONTROL "", IDC_PROGRESS, "Static", SS_BLACKRECT, 35, 165, 239, 5, NOT WS_VISIBLE
EDITTEXT IDC_ORGNAME,44,68,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
EDITTEXT IDC_USERNAME,44,95,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
EDITTEXT IDC_PASSWORD,44,122,219,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
@ -101,8 +102,8 @@ BEGIN
LTEXT "Password",IDC_PASSWORD_BANNER,48,122,219,12,NOT WS_VISIBLE
CTEXT "",IDC_MESSAGE_LABEL,5,39,299,23,NOT WS_VISIBLE
CTEXT "",IDC_ACTION_LABEL,10,15,286,25,NOT WS_VISIBLE
CTEXT "",IDC_MESSAGE2_LABEL,35,172,239,15,NOT WS_VISIBLE
CTEXT "",IDC_ACTION2_LABEL,15,147,278,25,NOT WS_VISIBLE
CTEXT "",IDC_MESSAGE2_LABEL,35,148,239,15,NOT WS_VISIBLE
CTEXT "",IDC_ACTION2_LABEL,15,123,278,25,NOT WS_VISIBLE
RTEXT "",IDC_TERMS,15,172,180,15,NOT WS_VISIBLE
CONTROL "",IDC_TERMS_LINK,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,197,172,80,15
CTEXT "",IDC_TROUBLE,65,203,174,15,NOT WS_VISIBLE

View file

@ -109,8 +109,10 @@ BOOL CLauncherDlg::OnInitDialog() {
m_trouble = (CStatic *)GetDlgItem(IDC_TROUBLE);
m_voxel = (CStatic *)GetDlgItem(IDC_VOXEL);
m_progress = (CStatic *)GetDlgItem(IDC_PROGRESS);
m_voxel->EnableD2DSupport();
m_progress->EnableD2DSupport();
m_pRenderTarget = GetRenderTarget();
@ -292,8 +294,9 @@ afx_msg void CLauncherDlg::OnNextClicked() {
void CLauncherDlg::drawBackground(CHwndRenderTarget* pRenderTarget) {
CD2DBitmap m_pBitmamBackground(pRenderTarget, IDB_PNG1, _T("PNG"));
auto size = pRenderTarget->GetSize();
auto size = GetRenderTarget()->GetSize();
CD2DRectF backRec(0.0f, 0.0f, size.width, size.height);
GetRenderTarget()->DrawBitmap(&m_pBitmamBackground, backRec);
pRenderTarget->DrawBitmap(&m_pBitmamBackground, backRec);
}
@ -303,7 +306,7 @@ void CLauncherDlg::drawLogo(CHwndRenderTarget* pRenderTarget) {
int logoWidth = 231;
int logoHeight = 173;
float logoPosX = 0.5f * (size.width - logoWidth);
float logoPosY = 0.95f * (size.height - logoHeight);
float logoPosY = 0.5f * (size.height - logoHeight);
CD2DRectF logoRec(logoPosX, logoPosY, logoPosX + logoWidth, logoPosY + logoHeight);
pRenderTarget->DrawBitmap(&m_pBitmamLogo, logoRec);
}
@ -338,6 +341,26 @@ void CLauncherDlg::drawVoxel(CHwndRenderTarget* pRenderTarget) {
pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
}
void CLauncherDlg::drawProgress(CHwndRenderTarget* pRenderTarget, float progress, const D2D1::ColorF& color) {
auto size = pRenderTarget->GetPixelSize();
if (progress == 0.0f) {
return;
}
CRect winRec;
CD2DRectF bkCircleRect1 = CD2DRectF(0,0,(float)size.height, (float)size.height);
progress = min(1.0f, progress);
CD2DRectF bkCircleRect2 = CD2DRectF((float)size.width * progress - (float)size.height, 0,
(float)size.width * progress, (float)size.height);
CD2DRectF bkRect = CD2DRectF(0.5f*(float)size.height, 0,
(float)size.width*progress - 0.5f*(float)size.height, (float)size.height);
CD2DEllipse bkCircle1 = CD2DEllipse(bkCircleRect1);
CD2DEllipse bkCircle2 = CD2DEllipse(bkCircleRect2);
CD2DSolidColorBrush brush(pRenderTarget, color);
pRenderTarget->FillEllipse(bkCircle1, &brush);
pRenderTarget->FillEllipse(bkCircle2, &brush);
pRenderTarget->FillRectangle(bkRect, &brush);
}
void CLauncherDlg::showWindows(std::vector<CStatic*> windows, bool show) {
for (auto window : windows) {
window->ShowWindow(show ? SW_SHOW : SW_HIDE);
@ -346,6 +369,7 @@ void CLauncherDlg::showWindows(std::vector<CStatic*> windows, bool show) {
void CLauncherDlg::prepareLogin(DrawStep step) {
m_voxel->ShowWindow(SW_HIDE);
m_progress->ShowWindow(SW_HIDE);
m_orgname_banner->SetWindowTextW(_T("Organization Name"));
m_username_banner->SetWindowTextW(_T("Username"));
m_password_banner->SetWindowTextW(_T("Password"));
@ -370,7 +394,6 @@ void CLauncherDlg::prepareLogin(DrawStep step) {
m_trouble->SetWindowTextW(_T("Having Trouble?"));
m_trouble->ShowWindow(SW_SHOW);
m_trouble_link.ShowWindow(SW_SHOW);
}
void CLauncherDlg::prepareChoose() {
@ -410,6 +433,7 @@ void CLauncherDlg::prepareProcess(DrawStep step) {
m_action_label->ShowWindow(SW_HIDE);
m_message_label->ShowWindow(SW_HIDE);
m_voxel->ShowWindow(SW_SHOW);
m_progress->ShowWindow(SW_SHOW);
CString actionText = _T("");
CString messageText = _T("");
@ -440,6 +464,7 @@ void CLauncherDlg::prepareProcess(DrawStep step) {
setVerticalElement(m_message2_label, 0, 5, false);
setVerticalElement(&m_btnNext, 10);
m_btnNext.ShowWindow(SW_SHOW);
m_progress->ShowWindow(SW_HIDE);
break;
default:
break;
@ -503,7 +528,6 @@ BOOL CLauncherDlg::getTextFormat(int resID, TextFormat& formatOut) {
HBRUSH CLauncherDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
TextFormat textFormat;
int resId = pWnd->GetDlgCtrlID();
@ -523,6 +547,7 @@ HBRUSH CLauncherDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
CRect lineRect = CRect(rect.left + padding, rect.bottom, rect.right - padding, rect.bottom + borderThick);
lineRect.MoveToY(lineRect.bottom + 1);
pDC->FillSolidRect(lineRect, COLOR_GREY);
}
}
return (HBRUSH)GetStockObject(BLACK_BRUSH);
@ -622,7 +647,9 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
if (_drawStep != DrawStep::DrawError) {
if (_drawStep == DrawStep::DrawProcessSetup ||
_drawStep == DrawStep::DrawProcessUpdate ||
_drawStep == DrawStep::DrawProcessUninstall) {
_drawStep == DrawStep::DrawProcessUninstall ||
_drawStep == DrawStep::DrawProcessFinishHq ||
_drawStep == DrawStep::DrawProcessFinishUpdate) {
// Refresh
setDrawDialog(_drawStep, true);
}
@ -631,13 +658,11 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
if (theApp._manager.needsUninstall()) {
theApp._manager.addToLog(_T("Waiting to uninstall"));
setDrawDialog(DrawStep::DrawProcessUninstall);
}
else {
} else {
theApp._manager.addToLog(_T("Start splash screen"));
setDrawDialog(DrawStep::DrawLogo);
}
}
else if (_splashStep > 100) {
} else if (_splashStep > 100) {
_showSplash = false;
if (theApp._manager.shouldShutDown()) {
if (_applicationWND != NULL) {
@ -647,21 +672,17 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
if (LauncherUtils::isProcessWindowOpened(L"interface.exe")) {
exit(0);
}
}
else if (theApp._manager.needsUpdate()) {
} else if (theApp._manager.needsUpdate()) {
startProcess();
}
else if (theApp._manager.needsUninstall()) {
} else if (theApp._manager.needsUninstall()) {
if (theApp._manager.uninstallApplication()) {
theApp._manager.addToLog(_T("HQ uninstalled successfully."));
exit(0);
}
else {
} else {
theApp._manager.addToLog(_T("HQ failed to uninstall."));
theApp._manager.setFailed(true);
}
}
else {
} else {
theApp._manager.addToLog(_T("Starting login"));
setDrawDialog(DrawStep::DrawLoginLogin);
}
@ -673,6 +694,10 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
}
}
if (theApp._manager.shouldLaunch()) {
if (theApp._manager.needsInstall() || theApp._manager.needsUpdate()) {
auto finishProcess = theApp._manager.needsUpdate() ? DrawStep::DrawProcessFinishUpdate : DrawStep::DrawProcessFinishHq;
setDrawDialog(finishProcess);
}
_applicationWND = theApp._manager.launchApplication();
}
}
@ -699,16 +724,16 @@ void CLauncherDlg::setVerticalElement(CWnd* element, int verticalOffset, int hei
void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) {
_drawStep = step;
float progress = 0.0f;
auto m_pRenderTarget = GetRenderTarget();
auto m_voxelRenderTarget = m_voxel->GetRenderTarget();
auto m_progressRenderTarget = m_progress->GetRenderTarget();
switch (_drawStep) {
case DrawStep::DrawLogo:
m_pRenderTarget->BeginDraw();
drawBackground(m_pRenderTarget);
drawLogo(m_pRenderTarget);
m_pRenderTarget->EndDraw();
m_voxelRenderTarget->BeginDraw();
drawLogo(m_voxelRenderTarget);
m_voxelRenderTarget->EndDraw();
break;
case DrawStep::DrawLoginLogin:
case DrawStep::DrawLoginErrorOrg:
@ -744,7 +769,12 @@ void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) {
drawSmallLogo(m_pRenderTarget);
m_pRenderTarget->EndDraw();
RedrawWindow();
}
}
m_progressRenderTarget->BeginDraw();
m_progressRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
drawProgress(m_progressRenderTarget, 1.0f, D2D1::ColorF(0.2f, 0.2f, 0.2f));
drawProgress(m_progressRenderTarget, theApp._manager.getProgress(), D2D1::ColorF(0.0f, 0.62f, 0.9f));
m_progressRenderTarget->EndDraw();
m_voxelRenderTarget->BeginDraw();
drawVoxel(m_voxelRenderTarget);
m_voxelRenderTarget->EndDraw();

View file

@ -53,9 +53,7 @@ protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
void startProcess();
void setCustomDialog();
void setVerticalElement(CWnd* element, int verticalOffset, int heightOffset = 0, bool fromMainWindowBottom = true);
void setVerticalElement(CWnd* element, int verticalOffset, int heightOffset = 0, bool fromMainWindowBottom = true);
BOOL getHQInfo(const CString& orgname);
DrawStep _drawStep { DrawStep::DrawLogo };
BOOL getTextFormat(int ResID, TextFormat& formatOut);
@ -86,6 +84,7 @@ protected:
CStatic* m_terms;
CStatic* m_trouble;
CStatic* m_voxel;
CStatic* m_progress;
CEdit m_orgname;
CEdit m_username;
@ -101,6 +100,7 @@ protected:
void drawLogo(CHwndRenderTarget* pRenderTarget);
void drawSmallLogo(CHwndRenderTarget* pRenderTarget);
void drawVoxel(CHwndRenderTarget* pRenderTarget);
void drawProgress(CHwndRenderTarget* pRenderTarget, float progress, const D2D1::ColorF& color);
void prepareLogin(DrawStep step);
void prepareProcess(DrawStep step);

View file

@ -24,7 +24,8 @@ LauncherManager::~LauncherManager() {
void LauncherManager::init() {
initLog();
addToLog(_T("Getting most recent build"));
LauncherUtils::ResponseError error = getMostRecentBuild(_latestApplicationURL, _latestVersion);
CString response;
LauncherUtils::ResponseError error = getMostRecentBuild(_latestApplicationURL, _latestVersion, response);
if (error == LauncherUtils::ResponseError::NoError) {
addToLog(_T("Latest version: ") + _latestVersion);
CString currentVersion;
@ -41,14 +42,17 @@ void LauncherManager::init() {
} else if (_loggedIn) {
addToLog(_T("Interface not found but logged in. Reinstalling"));
_shouldUpdate = TRUE;
} else {
_shouldInstall = TRUE;
}
} else {
_hasFailed = true;
CString msg;
msg.Format(_T("Getting most recent build has failed with error: %d"), error);
addToLog(msg);
msg.Format(_T("Response: %s"), response);
addToLog(msg);
}
}
BOOL LauncherManager::initLog() {
@ -146,6 +150,37 @@ BOOL LauncherManager::restartLauncher() {
return FALSE;
}
void LauncherManager::updateProgress(ProcessType processType, float progress) {
switch (processType) {
case LauncherManager::DownloadContent:
_progress = DOWNLOAD_CONTENT_INSTALL_WEIGHT * progress;
break;
case LauncherManager::UnzipContent:
_progress = DOWNLOAD_CONTENT_INSTALL_WEIGHT +
EXTRACT_CONTENT_INSTALL_WEIGHT * progress;
break;
case LauncherManager::DownloadApplication:
_progress = !_shouldUpdate ?
(DOWNLOAD_CONTENT_INSTALL_WEIGHT +
EXTRACT_CONTENT_INSTALL_WEIGHT +
DOWNLOAD_APPLICATION_INSTALL_WEIGHT * progress) :
DOWNLOAD_APPLICATION_UPDATE_WEIGHT * progress;
break;
case LauncherManager::UnzipApplication:
_progress = !_shouldUpdate ?
(DOWNLOAD_CONTENT_INSTALL_WEIGHT +
EXTRACT_CONTENT_INSTALL_WEIGHT +
DOWNLOAD_APPLICATION_INSTALL_WEIGHT +
EXTRACT_APPLICATION_INSTALL_WEIGHT * progress) :
(DOWNLOAD_APPLICATION_UPDATE_WEIGHT +
EXTRACT_APPLICATION_UPDATE_WEIGHT * progress);
break;
default:
break;
}
TRACE("progress = %f\n", _progress);
}
BOOL LauncherManager::createShortcuts() {
CString desktopLnkPath;
addToLog(_T("Creating shortcuts."));
@ -301,7 +336,8 @@ BOOL LauncherManager::createConfigJSON() {
return TRUE;
}
LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn) {
LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain,
CString& content, bool& loggedIn) {
CString configPath;
getAndCreatePaths(PathType::Interface_Directory, configPath);
configPath += "\\config.json";
@ -329,8 +365,10 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString
CString contentTypeJson = L"content-type:application/json";
CString response;
CString url = _T("/organizations/") + hash + _T(".json");
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"orgs.highfidelity.com", url,
contentTypeJson, CStringA(), response, false);
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher",
L"orgs.highfidelity.com", url,
contentTypeJson, CStringA(),
response, false);
if (error != LauncherUtils::ResponseError::NoError) {
return error;
}
@ -345,11 +383,14 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString
return LauncherUtils::ResponseError::ParsingJSON;
}
LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) {
LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut,
CString& response) {
CString contentTypeJson = L"content-type:application/json";
CString response;
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"thunder.highfidelity.com", L"/builds/api/tags/latest?format=json",
contentTypeJson, CStringA(), response, false);
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher",
L"thunder.highfidelity.com",
L"/builds/api/tags/latest?format=json",
contentTypeJson, CStringA(),
response, false);
if (error != LauncherUtils::ResponseError::NoError) {
return error;
}
@ -377,7 +418,8 @@ LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut
return LauncherUtils::ResponseError::ParsingJSON;
}
LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, const CString& password) {
LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username,
const CString& password) {
CStringA post = "grant_type=password&username=";
post += username;
post += "&password=";
@ -386,8 +428,11 @@ LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const
CString contentTypeText = L"content-type:application/x-www-form-urlencoded";
CString response;
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"metaverse.highfidelity.com", L"/oauth/token",
contentTypeText, post, response, true);
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher",
L"metaverse.highfidelity.com",
L"/oauth/token",
contentTypeText, post,
response, true);
if (error != LauncherUtils::ResponseError::NoError) {
return error;
}
@ -438,11 +483,11 @@ BOOL LauncherManager::uninstallApplication() {
return success;
}
void LauncherManager::onZipExtracted(ZipType type, int size) {
if (type == ZipType::ZipContent) {
void LauncherManager::onZipExtracted(ProcessType type, int size) {
if (type == ProcessType::UnzipContent) {
addToLog(_T("Downloading application."));
downloadApplication();
} else if (type == ZipType::ZipApplication) {
} else if (type == ProcessType::UnzipApplication) {
createShortcuts();
addToLog(_T("Launching application."));
_shouldLaunch = TRUE;
@ -457,17 +502,23 @@ void LauncherManager::onZipExtracted(ZipType type, int size) {
BOOL LauncherManager::extractApplication() {
CString installPath;
getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installPath);
addToLog(_T("Creating config.json"));
createConfigJSON();
BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipApplication, LauncherUtils::cStringToStd(_applicationZipPath),
LauncherUtils::cStringToStd(installPath), [&](int type, int size) {
std::function<void(int, int)> onExtractFinished = [&](int type, int size) {
addToLog(_T("Creating config.json"));
createConfigJSON();
if (size > 0) {
onZipExtracted((ZipType)type, size);
onZipExtracted((ProcessType)type, size);
} else {
addToLog(_T("Error decompressing application zip file."));
_hasFailed = true;
}
});
};
std::function<void(float)> onProgress = [&](float progress) {
updateProgress(ProcessType::UnzipApplication, progress);
};
BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipApplication,
LauncherUtils::cStringToStd(_applicationZipPath),
LauncherUtils::cStringToStd(installPath),
onExtractFinished, onProgress);
if (success) {
addToLog(_T("Created thread for unzipping application."));
} else {
@ -476,8 +527,8 @@ BOOL LauncherManager::extractApplication() {
return success;
}
void LauncherManager::onFileDownloaded(DownloadType type) {
if (type == DownloadType::DownloadContent) {
void LauncherManager::onFileDownloaded(ProcessType type) {
if (type == ProcessType::DownloadContent) {
addToLog(_T("Deleting content directory before install"));
CString contentDir;
getAndCreatePaths(PathType::Content_Directory, contentDir);
@ -490,7 +541,7 @@ void LauncherManager::onFileDownloaded(DownloadType type) {
setFailed(true);
}
});
} else if (type == DownloadType::DownloadApplication) {
} else if (type == ProcessType::DownloadApplication) {
addToLog(_T("Deleting application directory before install"));
CString applicationDir;
getAndCreatePaths(PathType::Interface_Directory, applicationDir);
@ -511,16 +562,21 @@ BOOL LauncherManager::installContent() {
std::string contentZipFile = LauncherUtils::cStringToStd(_contentZipPath);
CString contentPath;
getAndCreatePaths(LauncherManager::PathType::Content_Directory, contentPath);
BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipContent, contentZipFile,
LauncherUtils::cStringToStd(contentPath), [&](int type, int size) {
std::function<void(int, int)> onInstallFinished = [&](int type, int size) {
if (size > 0) {
addToLog(_T("Content zip decompresed."));
onZipExtracted((ZipType)type, size);
} else {
onZipExtracted((ProcessType)type, size);
}
else {
addToLog(_T("Error decompressing content zip file."));
_hasFailed = true;
}
});
};
std::function<void(float)> onProgress = [&](float progress) {
updateProgress(ProcessType::UnzipContent, progress);
};
BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipContent, contentZipFile,
LauncherUtils::cStringToStd(contentPath), onInstallFinished, onProgress);
if (success) {
addToLog(_T("Created thread for unzipping content."));
} else {
@ -530,25 +586,32 @@ BOOL LauncherManager::installContent() {
}
BOOL LauncherManager::downloadFile(DownloadType type, const CString& url, CString& outPath) {
BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString& outPath) {
CString fileName = url.Mid(url.ReverseFind('/') + 1);
CString downloadDirectory;
BOOL success = getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDirectory);
outPath = downloadDirectory + fileName;
_currentProcess = type;
if (success) {
addToLog(_T("Downloading: ") + url);
if (!LauncherUtils::downloadFileOnThread(type, url, outPath, [&](int type, bool error) {
std::function<void(int, bool)> onDownloadFinished = [&](int type, bool error) {
if (!error) {
onFileDownloaded((DownloadType)type);
} else {
if (type == DownloadType::DownloadApplication) {
onFileDownloaded((ProcessType)type);
}
else {
if (type == ProcessType::DownloadApplication) {
addToLog(_T("Error downloading content."));
} else {
}
else {
addToLog(_T("Error downloading application."));
}
_hasFailed = true;
}
})) {
};
std::function<void(float)> onProgress = [&](float progress) {
updateProgress(_currentProcess, progress);
};
if (!LauncherUtils::downloadFileOnThread(type, url, outPath, onDownloadFinished, onProgress)) {
success = FALSE;
}
}
@ -558,10 +621,10 @@ BOOL LauncherManager::downloadFile(DownloadType type, const CString& url, CStrin
BOOL LauncherManager::downloadContent() {
addToLog(_T("Downloading content."));
CString contentURL = getContentURL();
return downloadFile(DownloadType::DownloadContent, contentURL, _contentZipPath);
return downloadFile(ProcessType::DownloadContent, contentURL, _contentZipPath);
}
BOOL LauncherManager::downloadApplication() {
CString applicationURL = getLatestInterfaceURL();
return downloadFile(DownloadType::DownloadApplication, applicationURL, _applicationZipPath);
}
return downloadFile(ProcessType::DownloadApplication, applicationURL, _applicationZipPath);
}

View file

@ -19,6 +19,12 @@ const CString DIRECTORY_NAME_CONTENT = _T("content");
const CString EXTRA_PARAMETERS = _T(" --suppress-settings-reset --no-launcher --no-updater");
const CString LAUNCHER_EXE_FILENAME = _T("HQ Launcher.exe");
const bool INSTALL_ZIP = true;
const float DOWNLOAD_CONTENT_INSTALL_WEIGHT = 0.2f;
const float EXTRACT_CONTENT_INSTALL_WEIGHT = 0.1f;
const float DOWNLOAD_APPLICATION_INSTALL_WEIGHT = 0.5f;
const float EXTRACT_APPLICATION_INSTALL_WEIGHT = 0.2f;
const float DOWNLOAD_APPLICATION_UPDATE_WEIGHT = 0.75f;
const float EXTRACT_APPLICATION_UPDATE_WEIGHT = 0.25f;
class LauncherManager
{
@ -33,16 +39,8 @@ public:
StartMenu_Directory,
Temp_Directory
};
enum ZipType {
ZipContent = 0,
ZipApplication
};
enum DownloadType {
DownloadContent = 0,
DownloadApplication
};
enum ErrorType {
ErrorNetworkAuth,
ErrorNetworkAuth = 0,
ErrorNetworkUpdate,
ErrorNetworkHq,
ErrorDownloading,
@ -50,6 +48,12 @@ public:
ErrorInstall,
ErrorIOFiles
};
enum ProcessType {
DownloadContent,
DownloadApplication,
UnzipContent,
UnzipApplication
};
LauncherManager();
~LauncherManager();
void init();
@ -62,7 +66,7 @@ public:
BOOL isApplicationInstalled(CString& version, CString& domain,
CString& content, bool& loggedIn);
LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password);
LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut);
LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response);
LauncherUtils::ResponseError readOrganizationJSON(const CString& hash);
LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain,
CString& content, bool& loggedIn);
@ -84,6 +88,7 @@ public:
BOOL shouldLaunch() const { return _shouldLaunch; }
BOOL needsUpdate() { return _shouldUpdate; }
BOOL needsUninstall() { return _shouldUninstall; }
BOOL needsInstall() { return _shouldInstall; }
void setDisplayName(const CString& displayName) { _displayName = displayName; }
bool isLoggedIn() { return _loggedIn; }
bool hasFailed() { return _hasFailed; }
@ -91,15 +96,18 @@ public:
const CString& getLatestInterfaceURL() const { return _latestApplicationURL; }
void uninstall() { _shouldUninstall = true; };
BOOL downloadFile(DownloadType type, const CString& url, CString& localPath);
BOOL downloadFile(ProcessType type, const CString& url, CString& localPath);
BOOL downloadContent();
BOOL downloadApplication();
BOOL installContent();
BOOL extractApplication();
void onZipExtracted(ZipType type, int size);
void onFileDownloaded(DownloadType type);
void onZipExtracted(ProcessType type, int size);
void onFileDownloaded(ProcessType type);
float getProgress() { return _progress; }
private:
void updateProgress(ProcessType processType, float progress);
ProcessType _currentProcess { ProcessType::DownloadApplication };
CString _latestApplicationURL;
CString _latestVersion;
CString _contentURL;
@ -109,12 +117,14 @@ private:
CString _tokensJSON;
CString _applicationZipPath;
CString _contentZipPath;
bool _loggedIn{ false };
bool _hasFailed{ false };
BOOL _shouldUpdate{ FALSE };
BOOL _shouldUninstall{ FALSE };
BOOL _shouldShutdown{ FALSE };
BOOL _shouldLaunch{ FALSE };
bool _loggedIn { false };
bool _hasFailed { false };
BOOL _shouldUpdate { FALSE };
BOOL _shouldUninstall { FALSE };
BOOL _shouldInstall { FALSE };
BOOL _shouldShutdown { FALSE };
BOOL _shouldLaunch { FALSE };
float _progress { 0.0f };
CStdioFile _logFile;
};

View file

@ -272,7 +272,9 @@ BOOL LauncherUtils::getFont(const CString& fontName, int fontSize, bool isBold,
return TRUE;
}
uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string& path, std::vector<std::string>& files) {
uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string& path,
std::vector<std::string>& files,
std::function<void(float)> progressCallback) {
{
CString msg;
msg.Format(_T("Reading zip file %s, extracting to %s"), CString(zipFile.c_str()), CString(path.c_str()));
@ -292,7 +294,6 @@ uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string
theApp._manager.addToLog(msg);
return 0;
}
int fileCount = (int)mz_zip_reader_get_num_files(&zip_archive);
{
CString msg;
@ -313,6 +314,7 @@ uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string
// Get root folder
CString lastDir = _T("");
uint64_t totalSize = 0;
uint64_t totalCompressedSize = 0;
bool _shouldFail = false;
for (int i = 0; i < fileCount; i++) {
if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) continue;
@ -335,7 +337,9 @@ uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string
}
CT2A destFile(fullFilename);
if (mz_zip_reader_extract_to_file(&zip_archive, i, destFile, 0)) {
totalCompressedSize += (uint64_t)file_stat.m_comp_size;
totalSize += (uint64_t)file_stat.m_uncomp_size;
progressCallback((float)totalCompressedSize / (float)zip_archive.m_archive_size);
files.emplace_back(destFile);
} else {
CString msg;
@ -466,7 +470,7 @@ BOOL LauncherUtils::hMac256(const CString& cmessage, const char* keystr, CString
DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
UnzipThreadData& data = *((UnzipThreadData*)lpParameter);
uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector<std::string>());
uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector<std::string>(), data.progressCallback);
int mb_size = (int)(size * 0.001f);
data.callback(data._type, mb_size);
delete &data;
@ -475,7 +479,10 @@ DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) {
DownloadThreadData& data = *((DownloadThreadData*)lpParameter);
auto hr = URLDownloadToFile(0, data._url, data._file, 0, NULL);
ProgressCallback progressCallback;
progressCallback.setProgressCallback(data.progressCallback);
auto hr = URLDownloadToFile(0, data._url, data._file, 0,
static_cast<LPBINDSTATUSCALLBACK>(&progressCallback));
data.callback(data._type, hr != S_OK);
return 0;
}
@ -487,13 +494,16 @@ DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) {
return 0;
}
BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function<void(int, int)> callback) {
BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, const std::string& path,
std::function<void(int, int)> callback,
std::function<void(float)> progressCallback) {
DWORD myThreadID;
UnzipThreadData* unzipThreadData = new UnzipThreadData();
unzipThreadData->_type = type;
unzipThreadData->_zipFile = zipFile;
unzipThreadData->_path = path;
unzipThreadData->setCallback(callback);
unzipThreadData->setProgressCallback(progressCallback);
HANDLE myHandle = CreateThread(0, 0, unzipThread, unzipThreadData, 0, &myThreadID);
if (myHandle) {
CloseHandle(myHandle);
@ -502,13 +512,16 @@ BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, cons
return FALSE;
}
BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CString& file, std::function<void(int, bool)> callback) {
BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CString& file,
std::function<void(int, bool)> callback,
std::function<void(float)> progressCallback) {
DWORD myThreadID;
DownloadThreadData* downloadThreadData = new DownloadThreadData();
downloadThreadData->_type = type;
downloadThreadData->_url = url;
downloadThreadData->_file = file;
downloadThreadData->setCallback(callback);
downloadThreadData->setProgressCallback(progressCallback);
HANDLE myHandle = CreateThread(0, 0, downloadThread, downloadThreadData, 0, &myThreadID);
if (myHandle) {
CloseHandle(myHandle);

View file

@ -15,9 +15,57 @@
#include "libs/json/json.h"
#include "libs/miniz.h"
class LauncherUtils
{
class LauncherUtils {
public:
class ProgressCallback : public IBindStatusCallback {
public:
HRESULT __stdcall QueryInterface(const IID &, void **) {
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef(void) {
return 1;
}
ULONG STDMETHODCALLTYPE Release(void) {
return 1;
}
HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved, IBinding *pib) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetPriority(LONG *pnPriority) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved) {
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult, LPCWSTR szError) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindinfo) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
FORMATETC *pformatetc, STGMEDIUM *pstgmed) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid, IUnknown *punk) {
return E_NOTIMPL;
}
virtual HRESULT __stdcall OnProgress(ULONG ulProgress, ULONG ulProgressMax,
ULONG ulStatusCode, LPCWSTR szStatusText) {
float progress = (float)ulProgress / ulProgressMax;
if (!isnan(progress)) {
onProgressCallback(progress);
}
return S_OK;
}
void setProgressCallback(std::function<void(float)> fn) {
onProgressCallback = std::bind(fn, std::placeholders::_1);
}
private:
std::function<void(float)> onProgressCallback;
};
enum ResponseError {
Open = 0,
Connect,
@ -35,10 +83,14 @@ public:
CString _url;
CString _file;
std::function<void(int, bool)> callback;
std::function<void(float)> progressCallback;
// function(type, errorType)
void setCallback(std::function<void(int, bool)> fn) {
callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
}
void setProgressCallback(std::function<void(float)> fn) {
progressCallback = std::bind(fn, std::placeholders::_1);
}
};
struct UnzipThreadData {
@ -47,15 +99,23 @@ public:
std::string _path;
// function(type, size)
std::function<void(int, int)> callback;
std::function<void(float)> progressCallback;
void setCallback(std::function<void(int, int)> fn) {
callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
}
void setProgressCallback(std::function<void(float)> fn) {
progressCallback = std::bind(fn, std::placeholders::_1);
}
};
struct DeleteThreadData {
CString _dirPath;
std::function<void(bool)> callback;
std::function<void(float)> progressCallback;
void setCallback(std::function<void(bool)> fn) { callback = std::bind(fn, std::placeholders::_1); }
void setProgressCallback(std::function<void(float)> fn) {
progressCallback = std::bind(fn, std::placeholders::_1);
}
};
struct ProcessData {
@ -79,11 +139,18 @@ public:
static BOOL deleteFileOrDirectory(const CString& dirPath, bool noRecycleBin = true);
static HRESULT createLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs = _T(""));
static BOOL hMac256(const CString& message, const char* key, CString& hashOut);
static uint64_t extractZip(const std::string& zipFile, const std::string& path, std::vector<std::string>& files);
static uint64_t extractZip(const std::string& zipFile, const std::string& path,
std::vector<std::string>& files,
std::function<void(float)> progressCallback);
static BOOL deleteRegistryKey(const CString& registryPath);
static BOOL unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function<void(int, int)> callback);
static BOOL downloadFileOnThread(int type, const CString& url, const CString& file, std::function<void(int, bool)> callback);
static BOOL unzipFileOnThread(int type, const std::string& zipFile, const std::string& path,
std::function<void(int, int)> callback,
std::function<void(float)> progressCallback);
static BOOL downloadFileOnThread(int type, const CString& url, const CString& file,
std::function<void(int, bool)> callback,
std::function<void(float)> progressCallback);
static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function<void(bool)> callback);
static CString urlEncodeString(const CString& url);
static HWND executeOnForeground(const CString& path, const CString& params);

View file

@ -26,6 +26,7 @@
#define IDC_TERMS_LINK 1022
#define IDC_TROUBLE 1023
#define IDC_VOXEL 1024
#define IDC_PROGRESS 1025
#define IDC_TROUBLE_LINK 1027
// Next default values for new objects