From 084ec8dee3d9c34d2690603c845538b2d5ee07d4 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Thu, 27 Jul 2017 09:02:42 +0000 Subject: [PATCH] [RAPPS] - Added DownloadManager class (static for now) - Multiple selection launches multiple download dialogs (Checkbox selection has a priority over Selection when clicking Install) *A preperation for lauching a single dialog with a list of apps* - Show currently installing app in the dialog window svn path=/branches/GSoC_2017/rapps/; revision=75417 --- reactos/base/applications/rapps/available.cpp | 4 +- reactos/base/applications/rapps/gui.cpp | 31 +- reactos/base/applications/rapps/lang/en-US.rc | 12 +- reactos/base/applications/rapps/lang/ru-RU.rc | 2 +- reactos/base/applications/rapps/lang/uk-UA.rc | 2 +- reactos/base/applications/rapps/loaddlg.cpp | 333 ++++++++++-------- reactos/base/applications/rapps/rapps.h | 24 +- 7 files changed, 221 insertions(+), 187 deletions(-) diff --git a/reactos/base/applications/rapps/available.cpp b/reactos/base/applications/rapps/available.cpp index 787f33f32a6..f889117a214 100644 --- a/reactos/base/applications/rapps/available.cpp +++ b/reactos/base/applications/rapps/available.cpp @@ -251,7 +251,7 @@ BOOL CAvailableApps::UpdateAppsDB() if (!DeleteCurrentAppsDB()) return FALSE; - DownloadApplicationsDB(APPLICATION_DATABASE_URL); + DownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL); if (m_szPath.IsEmpty()) return FALSE; @@ -280,7 +280,7 @@ BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnu if (hFind == INVALID_HANDLE_VALUE) { if (GetFileAttributesW(m_szCabPath) == INVALID_FILE_ATTRIBUTES) - DownloadApplicationsDB(APPLICATION_DATABASE_URL); + DownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL); ExtractFilesFromCab(m_szCabPath, m_szAppsPath); hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData); diff --git a/reactos/base/applications/rapps/gui.cpp b/reactos/base/applications/rapps/gui.cpp index 3e126ebe42d..c9be7cc497f 100644 --- a/reactos/base/applications/rapps/gui.cpp +++ b/reactos/base/applications/rapps/gui.cpp @@ -458,7 +458,7 @@ public: BOOL GetCheckState(INT item) { - return (BOOL) GetItemState(item, LVIS_STATEIMAGEMASK); + return (BOOL) (GetItemState(item, LVIS_STATEIMAGEMASK) >> 12) - 1; } VOID SetCheckState(INT item, BOOL fCheck) @@ -472,14 +472,15 @@ public: SetCheckState(-1, bHasAllChecked); } - ATL::CAtlList GetCheckedItems() + ATL::CSimpleArray GetCheckedItems() { - ATL::CAtlList list; - for (INT i = 0; i != -1; i = GetNextItem(i, LVNI_ALL)) + ATL::CSimpleArray list; + for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL)) { if (GetCheckState(i) != FALSE) { - list.AddTail((PAPPLICATION_INFO) GetItemData(i)); + PAPPLICATION_INFO pAppInfo = (PAPPLICATION_INFO) GetItemData(i); + list.Add(pAppInfo); } } return list; @@ -1255,11 +1256,16 @@ private: break; case ID_INSTALL: - if (DownloadApplication(-1)) - /* TODO: Implement install dialog - * if (InstallApplication(-1)) - */ + if (nSelectedApps) + { + DownloadManager::DownloadListOfApplications(m_ListView->GetCheckedItems()); UpdateApplicationsList(-1); + } + else if(DownloadManager::DownloadApplication((PAPPLICATION_INFO) m_ListView->GetSelectionMark())) + { + UpdateApplicationsList(-1); + } + break; case ID_UNINSTALL: @@ -1403,11 +1409,10 @@ private: { if (m_StatusBar) { - ATL::CStringW szBuffer1, szBuffer2; + ATL::CStringW szBuffer; - szBuffer2.LoadStringW(hInst, IDS_APPS_COUNT); - szBuffer1.Format(szBuffer2, m_ListView->GetItemCount(), nSelectedApps); - m_StatusBar->SetText(szBuffer1); + szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), nSelectedApps); + m_StatusBar->SetText(szBuffer); } } diff --git a/reactos/base/applications/rapps/lang/en-US.rc b/reactos/base/applications/rapps/lang/en-US.rc index 8bedf8ea3f6..9c76aae2c01 100644 --- a/reactos/base/applications/rapps/lang/en-US.rc +++ b/reactos/base/applications/rapps/lang/en-US.rc @@ -92,7 +92,7 @@ END IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 72 STYLE DS_SHELLFONT | DS_CENTER | WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE -CAPTION "Downloading..." +CAPTION "Downloading %ls..." FONT 8, "MS Shell Dlg" BEGIN CONTROL "Progress1", IDC_DOWNLOAD_PROGRESS, "msctls_progress32", WS_BORDER | PBS_SMOOTH, 10, 10, 200, 12 @@ -110,16 +110,6 @@ BEGIN ICON IDI_MAIN, IDC_STATIC, 10, 10, 7, 30 END -IDD_DOWNLOAD_DIALOG_MULTI DIALOGEX 0, 0, 220, 72 -STYLE DS_SHELLFONT | DS_CENTER | WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE -CAPTION "Downloading (multiple)..." -FONT 8, "MS Shell Dlg" -BEGIN - CONTROL "Progress1", IDC_DOWNLOAD_PROGRESS, "msctls_progress32", WS_BORDER | PBS_SMOOTH, 10, 10, 200, 12 - EDITTEXT IDC_DOWNLOAD_STATUS, 10, 28, 200, 22, ES_CENTER | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_DISABLED | NOT WS_BORDER - PUSHBUTTON "Cancel", IDCANCEL, 85, 53, 50, 15, WS_GROUP | WS_TABSTOP -END - STRINGTABLE BEGIN IDS_TOOLTIP_INSTALL "Install" diff --git a/reactos/base/applications/rapps/lang/ru-RU.rc b/reactos/base/applications/rapps/lang/ru-RU.rc index 40445488db0..3a51ed32bee 100644 --- a/reactos/base/applications/rapps/lang/ru-RU.rc +++ b/reactos/base/applications/rapps/lang/ru-RU.rc @@ -92,7 +92,7 @@ END IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 72 STYLE DS_SHELLFONT | DS_CENTER | WS_POPUPWINDOW | WS_SYSMENU | WS_VISIBLE -CAPTION "Загрузка..." +CAPTION "Загрузка %ls..." FONT 8, "MS Shell Dlg" BEGIN CONTROL "Progress1", IDC_DOWNLOAD_PROGRESS, "msctls_progress32", WS_BORDER | PBS_SMOOTH, 10, 10, 200, 12 diff --git a/reactos/base/applications/rapps/lang/uk-UA.rc b/reactos/base/applications/rapps/lang/uk-UA.rc index 56195d50857..4acad0758cd 100644 --- a/reactos/base/applications/rapps/lang/uk-UA.rc +++ b/reactos/base/applications/rapps/lang/uk-UA.rc @@ -100,7 +100,7 @@ END IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 72 STYLE DS_SHELLFONT | DS_CENTER | WS_POPUPWINDOW | WS_SYSMENU | WS_VISIBLE -CAPTION "Завантаження..." +CAPTION "Завантаження %ls..." FONT 8, "MS Shell Dlg" BEGIN CONTROL "Progress1", IDC_DOWNLOAD_PROGRESS, "msctls_progress32", WS_BORDER | PBS_SMOOTH, 10, 10, 200, 12 diff --git a/reactos/base/applications/rapps/loaddlg.cpp b/reactos/base/applications/rapps/loaddlg.cpp index 71844cb85fa..e9841b96066 100644 --- a/reactos/base/applications/rapps/loaddlg.cpp +++ b/reactos/base/applications/rapps/loaddlg.cpp @@ -39,8 +39,6 @@ #include #include -static PAPPLICATION_INFO AppInfo; - class CDownloadDialog : public CComObjectRootEx, public IBindStatusCallback @@ -250,9 +248,151 @@ MessageBox_LoadString(HWND hMainWnd, INT StringID) MessageBoxW(hMainWnd, szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR); } -static -DWORD WINAPI -ThreadFunc(LPVOID Context) +// DownloadManager + +PAPPLICATION_INFO DownloadManager::AppInfo = NULL; + +INT_PTR CALLBACK DownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HANDLE Thread; + DWORD ThreadId; + HWND Item; + + switch (uMsg) + { + case WM_INITDIALOG: + { + HICON hIconSm, hIconBg; + WCHAR szCaption[MAX_PATH]; + ATL::CStringW szNewCaption; + + hIconBg = (HICON) GetClassLongW(hMainWnd, GCLP_HICON); + hIconSm = (HICON) GetClassLongW(hMainWnd, GCLP_HICONSM); + + if (hIconBg && hIconSm) + { + SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) hIconBg); + SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSm); + } + + // Change caption to show the currently downloaded app + GetWindowTextW(Dlg, szCaption, MAX_PATH); + szNewCaption.Format(szCaption, AppInfo->szName.GetString()); + SetWindowTextW(Dlg, szNewCaption.GetString()); + + SetWindowLongW(Dlg, GWLP_USERDATA, 0); + Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS); + if (Item) + { + // initialize the default values for our nifty progress bar + // and subclass it so that it learns to print a status text + SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendMessageW(Item, PBM_SETPOS, 0, 0); + + SetWindowSubclass(Item, DownloadProgressProc, 0, 0); + } + + // add a neat placeholder until the download URL is retrieved + SetDlgItemTextW(Dlg, IDC_DOWNLOAD_STATUS, L"\x2022 \x2022 \x2022"); + + Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId); + if (!Thread) + return FALSE; + CloseHandle(Thread); + return TRUE; + } + case WM_COMMAND: + if (wParam == IDCANCEL) + { + SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1); + PostMessageW(Dlg, WM_CLOSE, 0, 0); + } + return FALSE; + + case WM_CLOSE: + DestroyWindow(Dlg); + return TRUE; + + default: + return FALSE; + } +} + +LRESULT CALLBACK DownloadManager::DownloadProgressProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + static ATL::CStringW szProgressText; + + switch (uMsg) + { + case WM_SETTEXT: + { + if (lParam) + { + szProgressText = (PCWSTR) lParam; + } + return TRUE; + } + + case WM_ERASEBKGND: + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps), hdcMem; + HBITMAP hbmMem; + HANDLE hOld; + RECT myRect; + UINT win_width, win_height; + + GetClientRect(hWnd, &myRect); + + /* grab the progress bar rect size */ + win_width = myRect.right - myRect.left; + win_height = myRect.bottom - myRect.top; + + /* create an off-screen DC for double-buffering */ + hdcMem = CreateCompatibleDC(hDC); + hbmMem = CreateCompatibleBitmap(hDC, win_width, win_height); + + hOld = SelectObject(hdcMem, hbmMem); + + /* call the original draw code and redirect it to our memory buffer */ + DefSubclassProc(hWnd, uMsg, (WPARAM) hdcMem, lParam); + + /* draw our nifty progress text over it */ + SelectFont(hdcMem, GetStockFont(DEFAULT_GUI_FONT)); + DrawShadowText(hdcMem, szProgressText.GetString(), szProgressText.GetLength(), + &myRect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE, + GetSysColor(COLOR_CAPTIONTEXT), + GetSysColor(COLOR_3DSHADOW), + 1, 1); + + /* transfer the off-screen DC to the screen */ + BitBlt(hDC, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY); + + /* free the off-screen DC */ + SelectObject(hdcMem, hOld); + DeleteObject(hbmMem); + DeleteDC(hdcMem); + + EndPaint(hWnd, &ps); + return 0; + } + + /* Raymond Chen says that we should safely unsubclass all the things! + (http://blogs.msdn.com/b/oldnewthing/archive/2003/11/11/55653.aspx) */ + case WM_NCDESTROY: + { + szProgressText.Empty(); + RemoveWindowSubclass(hWnd, DownloadProgressProc, uIdSubclass); + } + /* Fall-through */ + default: + return DefSubclassProc(hWnd, uMsg, wParam, lParam); + } +} + +DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) { CComPtr dl; ATL::CStringW Path; @@ -272,9 +412,15 @@ ThreadFunc(LPVOID Context) URL_COMPONENTS urlComponents; size_t urlLength, filenameLength; + if (!AppInfo) + { + MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD); + goto end; + } + /* build the path for the download */ - p = wcsrchr(AppInfo->szUrlDownload, L'/'); - q = wcsrchr(AppInfo->szUrlDownload, L'?'); + p = wcsrchr(AppInfo->szUrlDownload.GetString(), L'/'); + q = wcsrchr(AppInfo->szUrlDownload.GetString(), L'?'); /* do we have a final slash separator? */ if (!p) @@ -284,7 +430,7 @@ ThreadFunc(LPVOID Context) filenameLength = wcslen(p) * sizeof(WCHAR); /* do we have query arguments in the target URL after the filename? account for them - (e.g. https://example.org/myfile.exe?no_adware_plz) */ + (e.g. https://example.org/myfile.exe?no_adware_plz) */ if (q && q > p && (q - p) > 0) filenameLength -= wcslen(q - 1) * sizeof(WCHAR); @@ -424,7 +570,7 @@ ThreadFunc(LPVOID Context) goto end; /* if this thing isn't a RAPPS update and it has a SHA-1 checksum - verify its integrity by using the native advapi32.A_SHA1 functions */ + verify its integrity by using the native advapi32.A_SHA1 functions */ if (!bCab && AppInfo->szSHA1[0] != 0) { ATL::CStringW szMsgText; @@ -472,174 +618,49 @@ end: return 0; } - -LRESULT CALLBACK -DownloadProgressProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +//TODO: Maybe launch this (similar function) in a seperate thread, so the list could be updated +BOOL DownloadManager::DownloadListOfApplications(const ATL::CSimpleArray& AppsList) { - static ATL::CStringW szProgressText; + BOOL bResult = TRUE; - switch (uMsg) + for (INT i = 0; i < AppsList.GetSize(); ++i) { - case WM_SETTEXT: - { - if (lParam) - { - szProgressText = (PCWSTR) lParam; - } - return TRUE; - } - - case WM_ERASEBKGND: - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hDC = BeginPaint(hWnd, &ps), hdcMem; - HBITMAP hbmMem; - HANDLE hOld; - RECT myRect; - UINT win_width, win_height; - - GetClientRect(hWnd, &myRect); - - /* grab the progress bar rect size */ - win_width = myRect.right - myRect.left; - win_height = myRect.bottom - myRect.top; - - /* create an off-screen DC for double-buffering */ - hdcMem = CreateCompatibleDC(hDC); - hbmMem = CreateCompatibleBitmap(hDC, win_width, win_height); - - hOld = SelectObject(hdcMem, hbmMem); - - /* call the original draw code and redirect it to our memory buffer */ - DefSubclassProc(hWnd, uMsg, (WPARAM) hdcMem, lParam); - - /* draw our nifty progress text over it */ - SelectFont(hdcMem, GetStockFont(DEFAULT_GUI_FONT)); - DrawShadowText(hdcMem, szProgressText.GetString(), szProgressText.GetLength(), - &myRect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE, - GetSysColor(COLOR_CAPTIONTEXT), - GetSysColor(COLOR_3DSHADOW), - 1, 1); - - /* transfer the off-screen DC to the screen */ - BitBlt(hDC, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY); - - /* free the off-screen DC */ - SelectObject(hdcMem, hOld); - DeleteObject(hbmMem); - DeleteDC(hdcMem); - - EndPaint(hWnd, &ps); - return 0; - } - - /* Raymond Chen says that we should safely unsubclass all the things! - (http://blogs.msdn.com/b/oldnewthing/archive/2003/11/11/55653.aspx) */ - case WM_NCDESTROY: - { - szProgressText.Empty(); - RemoveWindowSubclass(hWnd, DownloadProgressProc, uIdSubclass); - } - /* Fall-through */ - default: - return DefSubclassProc(hWnd, uMsg, wParam, lParam); + bResult = DownloadApplication(AppsList[i]) && bResult; } + return bResult; } -static -INT_PTR CALLBACK -DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +BOOL DownloadManager::DownloadApplication(PAPPLICATION_INFO pAppInfo) { - HANDLE Thread; - DWORD ThreadId; - HWND Item; - - switch (uMsg) + if (!pAppInfo) { - case WM_INITDIALOG: - { - HICON hIconSm = NULL, hIconBg = NULL; - - hIconBg = (HICON) GetClassLongPtr(hMainWnd, GCLP_HICON); - hIconSm = (HICON) GetClassLongPtr(hMainWnd, GCLP_HICONSM); - - if (hIconBg && hIconSm) - { - SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) hIconBg); - SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSm); - } - - SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0); - Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS); - if (Item) - { - /* initialize the default values for our nifty progress bar - and subclass it so that it learns to print a status text */ - SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); - SendMessageW(Item, PBM_SETPOS, 0, 0); - - SetWindowSubclass(Item, DownloadProgressProc, 0, 0); - } - - /* add a neat placeholder until the download URL is retrieved */ - Item = GetDlgItem(Dlg, IDC_DOWNLOAD_STATUS); - SendMessageW(Item, WM_SETTEXT, 0, (LPARAM) L"\x2022 \x2022 \x2022"); - - Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId); - if (!Thread) - return FALSE; - CloseHandle(Thread); - return TRUE; - } - case WM_COMMAND: - if (wParam == IDCANCEL) - { - SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1); - PostMessageW(Dlg, WM_CLOSE, 0, 0); - } - return FALSE; - - case WM_CLOSE: - DestroyWindow(Dlg); - return TRUE; - - default: return FALSE; } -} -BOOL -DownloadApplication(INT Index) -{ - if (!IS_AVAILABLE_ENUM(SelectedEnumType)) - return FALSE; - - AppInfo = (PAPPLICATION_INFO) ListViewGetlParam(Index); - if (!AppInfo) - return FALSE; + // Create a dialog and issue a download process + AppInfo = pAppInfo; + LaunchDownloadDialog(); WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, AppInfo->szName.GetString()); - CreateDialogW(hInst, - MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), - hMainWnd, - DownloadDlgProc); - return TRUE; } -VOID -DownloadApplicationsDB(LPCWSTR lpUrl) +VOID DownloadManager::DownloadApplicationsDB(LPCWSTR lpUrl) { APPLICATION_INFO IntInfo; IntInfo.szUrlDownload = lpUrl; AppInfo = &IntInfo; - CreateDialogW(hInst, - MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), - hMainWnd, - DownloadDlgProc); + LaunchDownloadDialog(); } + +//TODO: Reuse the dialog +VOID DownloadManager::LaunchDownloadDialog() +{ + CreateDialogW(hInst, + MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), + hMainWnd, + DownloadDlgProc); +} \ No newline at end of file diff --git a/reactos/base/applications/rapps/rapps.h b/reactos/base/applications/rapps/rapps.h index 61ad87ea45a..0ded9a34f73 100644 --- a/reactos/base/applications/rapps/rapps.h +++ b/reactos/base/applications/rapps/rapps.h @@ -226,7 +226,7 @@ public: }; /* installdlg.cpp */ -BOOL InstallApplication(INT Index); +//BOOL InstallApplication(INT Index); /* installed.cpp */ typedef BOOL (CALLBACK *APPENUMPROC)(INT ItemIndex, ATL::CStringW &lpName, PINSTALLED_INFO Info); @@ -249,8 +249,26 @@ VOID SaveSettings(HWND hwnd); VOID FillDefaultSettings(PSETTINGS_INFO pSettingsInfo); /* loaddlg.cpp */ -BOOL DownloadApplication(INT Index); -VOID DownloadApplicationsDB(LPCWSTR lpUrl); + +class DownloadManager +{ + static PAPPLICATION_INFO AppInfo; +public: + + static INT_PTR CALLBACK DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK DownloadProgressProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam, + UINT_PTR uIdSubclass, + DWORD_PTR dwRefData); + + static DWORD WINAPI ThreadFunc(LPVOID Context); + static BOOL DownloadListOfApplications(const ATL::CSimpleArray& AppsList); + static BOOL DownloadApplication(PAPPLICATION_INFO pAppInfo); + static VOID DownloadApplicationsDB(LPCWSTR lpUrl); + static VOID LaunchDownloadDialog(); +}; /* misc.cpp */ INT GetSystemColorDepth(VOID);