From: Alexander Shaposhnikov Date: Fri, 28 Jul 2017 22:37:24 +0000 (+0000) Subject: [RAPPS] Bulk install! X-Git-Tag: backups/GSoC_2017/rapps@75905~48 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=e3fdbe5806cfaea3ab4ee08fdddee2a9839b4e18;hp=084ec8dee3d9c34d2690603c845538b2d5ee07d4;ds=sidebyside [RAPPS] Bulk install! - Added ListView class - Added ListView to a dialog Dialog shows the install progress of individual apps. It also waits for an installator to finish before issuing another download-install cycle. - Fixed: Downloads pointing to "\" - Fixed: Selection data is not retrieved correctly - Yet again replacing some macros to wide functions - Minor improvements svn path=/branches/GSoC_2017/rapps/; revision=75433 --- diff --git a/reactos/base/applications/rapps/available.cpp b/reactos/base/applications/rapps/available.cpp index f889117a214..599defadda3 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; - DownloadManager::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) - DownloadManager::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 c9be7cc497f..9e4fc25e676 100644 --- a/reactos/base/applications/rapps/gui.cpp +++ b/reactos/base/applications/rapps/gui.cpp @@ -235,31 +235,31 @@ public: switch (idButton) { case ID_EXIT: - lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EXIT); + lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_EXIT); break; case ID_INSTALL: - lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_INSTALL); + lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_INSTALL); break; case ID_UNINSTALL: - lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UNINSTALL); + lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL); break; case ID_MODIFY: - lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_MODIFY); + lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_MODIFY); break; case ID_SETTINGS: - lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SETTINGS); + lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SETTINGS); break; case ID_REFRESH: - lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_REFRESH); + lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_REFRESH); break; case ID_RESETDB: - lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UPDATE_DB); + lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE_DB); break; } } @@ -380,7 +380,7 @@ public: BOOL AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format) { - LV_COLUMNW Column; + LVCOLUMNW Column; ZeroMemory(&Column, sizeof(Column)); @@ -395,7 +395,7 @@ public: INT AddItem(INT ItemIndex, INT IconIndex, LPWSTR lpText, LPARAM lParam) { - LV_ITEMW Item; + LVITEMW Item; ZeroMemory(&Item, sizeof(Item)); @@ -485,6 +485,12 @@ public: } return list; } + + PAPPLICATION_INFO GetSelectedData() + { + INT item = GetSelectionMark(); + return (PAPPLICATION_INFO) GetItemData(item); + } }; class CSideTreeView : @@ -767,7 +773,7 @@ private: RECT rBottom; /* Size status bar */ - m_StatusBar->SendMessage(WM_SIZE, 0, 0); + m_StatusBar->SendMessageW(WM_SIZE, 0, 0); /* Size tool bar */ m_Toolbar->AutoSize(); @@ -1258,10 +1264,10 @@ private: case ID_INSTALL: if (nSelectedApps) { - DownloadManager::DownloadListOfApplications(m_ListView->GetCheckedItems()); + СDownloadManager::DownloadListOfApplications(m_ListView->GetCheckedItems()); UpdateApplicationsList(-1); } - else if(DownloadManager::DownloadApplication((PAPPLICATION_INFO) m_ListView->GetSelectionMark())) + else if(СDownloadManager::DownloadApplication(m_ListView->GetSelectedData())) { UpdateApplicationsList(-1); } diff --git a/reactos/base/applications/rapps/installed.cpp b/reactos/base/applications/rapps/installed.cpp index 80630b9a30f..57e69095237 100644 --- a/reactos/base/applications/rapps/installed.cpp +++ b/reactos/base/applications/rapps/installed.cpp @@ -197,7 +197,7 @@ RemoveAppFromRegistry(INT Index) PINSTALLED_INFO Info; WCHAR szFullName[MAX_PATH] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; ATL::CStringW szMsgText, szMsgTitle; - INT ItemIndex = SendMessage(hListView, LVM_GETNEXTITEM, -1, LVNI_FOCUSED); + INT ItemIndex = SendMessageW(hListView, LVM_GETNEXTITEM, -1, LVNI_FOCUSED); if (!IS_INSTALLED_ENUM(SelectedEnumType)) return; diff --git a/reactos/base/applications/rapps/lang/en-US.rc b/reactos/base/applications/rapps/lang/en-US.rc index 9c76aae2c01..4da42526961 100644 --- a/reactos/base/applications/rapps/lang/en-US.rc +++ b/reactos/base/applications/rapps/lang/en-US.rc @@ -90,7 +90,7 @@ BEGIN PUSHBUTTON "Cancel", IDCANCEL, 150, 78, 60, 14 END -IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 72 +IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 220 STYLE DS_SHELLFONT | DS_CENTER | WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE CAPTION "Downloading %ls..." FONT 8, "MS Shell Dlg" @@ -202,6 +202,7 @@ BEGIN IDS_UNABLE_TO_DOWNLOAD "Unable to download the package! Address not found!" IDS_UNABLE_TO_DOWNLOAD2 "Unable to download the package! Check Internet Connection!" IDS_UNABLE_TO_REMOVE "Unable to remove data on the program from the registry!" + IDS_UNABLE_TO_INSTALL "Unable to open installer!" IDS_CERT_DOES_NOT_MATCH "SSL certificate verification failed." IDS_INTEG_CHECK_TITLE "Verifying package integrity..." IDS_INTEG_CHECK_FAIL "The package did not pass the integrity check, it may have been corrupted or tampered with during downloading. Running the software is not recommended." @@ -219,6 +220,8 @@ BEGIN IDS_STATUS_UPDATE_AVAILABLE "Update available" IDS_STATUS_DOWNLOADING "Downloading…" IDS_STATUS_INSTALLING "Installing…" + IDS_STATUS_WAITING "Waiting to install…" + IDS_STATUS_FINISHED "Finished" END STRINGTABLE diff --git a/reactos/base/applications/rapps/lang/ru-RU.rc b/reactos/base/applications/rapps/lang/ru-RU.rc index 3a51ed32bee..f85605da7af 100644 --- a/reactos/base/applications/rapps/lang/ru-RU.rc +++ b/reactos/base/applications/rapps/lang/ru-RU.rc @@ -90,7 +90,7 @@ BEGIN PUSHBUTTON "Отмена", IDCANCEL, 150, 78, 60, 14 END -IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 72 +IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 220 STYLE DS_SHELLFONT | DS_CENTER | WS_POPUPWINDOW | WS_SYSMENU | WS_VISIBLE CAPTION "Загрузка %ls..." FONT 8, "MS Shell Dlg" @@ -200,6 +200,7 @@ BEGIN IDS_INFORMATION "Информация" IDS_UNABLE_TO_DOWNLOAD "Не удалось скачать приложение! Не найден адрес!" IDS_UNABLE_TO_DOWNLOAD2 "Не удалось скачать приложение! Проверьте подключение к сети Интернет!" + IDS_UNABLE_TO_INSTALL "Unable to open installer!" IDS_UNABLE_TO_REMOVE "Не удалось удалить данные о программе из реестра!" IDS_CERT_DOES_NOT_MATCH "Ошибка проверки SSL сертификата." IDS_INTEG_CHECK_TITLE "Проверка целостности приложения..." @@ -216,6 +217,8 @@ BEGIN IDS_STATUS_UPDATE_AVAILABLE "Есть обновления" IDS_STATUS_DOWNLOADING "Загружается…" IDS_STATUS_INSTALLING "Установка…" + IDS_STATUS_WAITING "Ожидание установки…" + IDS_STATUS_FINISHED "Завершено" END STRINGTABLE diff --git a/reactos/base/applications/rapps/lang/uk-UA.rc b/reactos/base/applications/rapps/lang/uk-UA.rc index 4acad0758cd..258367da80f 100644 --- a/reactos/base/applications/rapps/lang/uk-UA.rc +++ b/reactos/base/applications/rapps/lang/uk-UA.rc @@ -98,7 +98,7 @@ BEGIN PUSHBUTTON "Скасувати", IDCANCEL, 150, 78, 60, 14 END -IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 72 +IDD_DOWNLOAD_DIALOG DIALOGEX 0, 0, 220, 220 STYLE DS_SHELLFONT | DS_CENTER | WS_POPUPWINDOW | WS_SYSMENU | WS_VISIBLE CAPTION "Завантаження %ls..." FONT 8, "MS Shell Dlg" @@ -208,6 +208,7 @@ BEGIN IDS_INFORMATION "Інформація" IDS_UNABLE_TO_DOWNLOAD "Неможливо завантажити додаток! Адресу не знайдено!" IDS_UNABLE_TO_DOWNLOAD2 "Неможливо завантажити додаток! Перевірте підключення до мережі Інтернет!" + IDS_UNABLE_TO_INSTALL "Unable to open installer!" IDS_UNABLE_TO_REMOVE "Не вдалося видалити дані про програму з реєстру!" IDS_CERT_DOES_NOT_MATCH "Помилка перевіки сертифікату SSL." IDS_INTEG_CHECK_TITLE "Перевірка цілістності додатку..." @@ -224,6 +225,8 @@ BEGIN IDS_STATUS_UPDATE_AVAILABLE "Є оновлення" IDS_STATUS_DOWNLOADING "Завантажується…" IDS_STATUS_INSTALLING "Встановлюється…" + IDS_STATUS_WAITING "Очікування завантаження…" + IDS_STATUS_FINISHED "Завершено" END STRINGTABLE diff --git a/reactos/base/applications/rapps/loaddlg.cpp b/reactos/base/applications/rapps/loaddlg.cpp index e9841b96066..acf1ddf9275 100644 --- a/reactos/base/applications/rapps/loaddlg.cpp +++ b/reactos/base/applications/rapps/loaddlg.cpp @@ -10,23 +10,23 @@ * Copyright 2017 Alexander Shaposhnikov (chaez.san@gmail.com) */ -/* - * Based on Wine dlls/shdocvw/shdocvw_main.c - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + /* + * Based on Wine dlls/shdocvw/shdocvw_main.c + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "rapps.h" @@ -35,10 +35,32 @@ #include #include +#include #include #include + +#include #include +#include "rosui.h" + +typedef enum +{ + DLWaiting = IDS_STATUS_WAITING, + DLDownloading = IDS_STATUS_DOWNLOADING, + DLWaitingToInstall = IDS_STATUS_DOWNLOADED, + DLInstalling = IDS_STATUS_INSTALLING, + DLInstalled = IDS_STATUS_INSTALLED, + DLFinished = IDS_STATUS_FINISHED +} DOWNLOAD_STATUS; + +ATL::CStringW LoadStatusString(DOWNLOAD_STATUS StatusParam) +{ + ATL::CStringW szString; + szString.LoadStringW(StatusParam); + return szString; +} + class CDownloadDialog : public CComObjectRootEx, public IBindStatusCallback @@ -50,7 +72,7 @@ class CDownloadDialog : public: ~CDownloadDialog() { - DestroyWindow(m_hDialog); + //DestroyWindow(m_hDialog); } HRESULT Initialize(HWND Dlg, BOOL *pbCancelled) @@ -181,6 +203,75 @@ public: END_COM_MAP() }; +class CDowloadingAppsListView + : public CUiWindow +{ +public: + HWND Create(HWND hwndParent) + { + RECT r = {10, 150, 320, 350}; + const DWORD style = WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL + | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | LVS_NOCOLUMNHEADER; + + HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE); + + AddColumn(0, 150, LVCFMT_LEFT); + AddColumn(1, 120, LVCFMT_LEFT); + + return hwnd; + } + + VOID LoadList(ATL::CSimpleArray arrInfo) + { + for (INT i = 0; i < arrInfo.GetSize(); ++i) + { + PAPPLICATION_INFO AppInfo = arrInfo[i]; + AddRow(i, AppInfo->szName.GetString(), DOWNLOAD_STATUS::DLWaiting); + } + } + + VOID SetDownloadStatus(INT ItemIndex, DOWNLOAD_STATUS Status) + { + HWND hListView = GetWindow(); + ATL::CStringW szBuffer = LoadStatusString(Status); + ListView_SetItemText(hListView, ItemIndex, 1, const_cast(szBuffer.GetString())); + } + + BOOL AddItem(INT ItemIndex, LPWSTR lpText) + { + LVITEMW Item; + + ZeroMemory(&Item, sizeof(Item)); + + Item.mask = LVIF_TEXT | LVIF_STATE; + Item.pszText = lpText; + Item.iItem = ItemIndex; + + return InsertItem(&Item); + } + + VOID AddRow(INT RowIndex, LPCWSTR szAppName, const DOWNLOAD_STATUS Status) + { + ATL::CStringW szStatus = LoadStatusString(Status); + AddItem(RowIndex, + const_cast(szAppName)); + SetDownloadStatus(RowIndex, Status); + } + + BOOL AddColumn(INT Index, INT Width, INT Format) + { + LVCOLUMNW Column; + ZeroMemory(&Column, sizeof(Column)); + + Column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; + Column.iSubItem = Index; + Column.cx = Width; + Column.fmt = Format; + + return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE; + } +}; + extern "C" HRESULT WINAPI CDownloadDialog_Constructor(HWND Dlg, BOOL *pbCancelled, REFIID riid, LPVOID *ppv) { @@ -245,26 +336,31 @@ MessageBox_LoadString(HWND hMainWnd, INT StringID) { ATL::CString szMsgText; if (szMsgText.LoadStringW(hInst, StringID)) + { MessageBoxW(hMainWnd, szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR); + } } -// DownloadManager +// ÑDownloadManager +PAPPLICATION_INFO ÑDownloadManager::AppInfo; +ATL::CSimpleArray ÑDownloadManager::AppsToInstallList; +CDowloadingAppsListView ÑDownloadManager::DownloadsListView; +INT ÑDownloadManager::iCurrentApp; -PAPPLICATION_INFO DownloadManager::AppInfo = NULL; +#define DL_START_NEW WM_APP + 1 -INT_PTR CALLBACK DownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +INT_PTR CALLBACK ÑDownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { HANDLE Thread; DWORD ThreadId; HWND Item; + static WCHAR szCaption[MAX_PATH]; 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); @@ -275,11 +371,6 @@ INT_PTR CALLBACK DownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wP 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) @@ -288,28 +379,77 @@ INT_PTR CALLBACK DownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wP // 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); } + // Get a dlg string for later use + GetWindowTextW(Dlg, szCaption, MAX_PATH); - // 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) + // Add a ListView + HWND hListView = DownloadsListView.Create(Dlg); + if (!hListView) + { return FALSE; - CloseHandle(Thread); + } + DownloadsListView.LoadList(AppsToInstallList); + iCurrentApp = -1; + + ShowWindow(Dlg, SW_SHOW); + + //Start new download + SendMessageW(Dlg, DL_START_NEW, 0, 0); + return TRUE; } case WM_COMMAND: if (wParam == IDCANCEL) { - SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1); + SetWindowLongW(Dlg, GWLP_USERDATA, 1); PostMessageW(Dlg, WM_CLOSE, 0, 0); } return FALSE; + case DL_START_NEW: + + ++iCurrentApp; + // If some downloads left we issue it + if (iCurrentApp < AppsToInstallList.GetSize()) + { + AppInfo = AppsToInstallList[iCurrentApp]; + if (!AppInfo) + { + return FALSE; + } + + ATL::CStringW szNewCaption; + + // Reset progress bar + Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS); + if (Item) + { + SendMessageW(Item, PBM_SETPOS, 0, 0); + } + + // Change caption to show the currently downloaded app + szNewCaption.Format(szCaption, AppInfo->szName.GetString()); + SetWindowTextW(Dlg, szNewCaption.GetString()); + + // 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; + } + // No downloads left, closing (fallthrough) + case WM_CLOSE: + EndDialog(Dlg, 0); DestroyWindow(Dlg); return TRUE; @@ -318,7 +458,7 @@ INT_PTR CALLBACK DownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wP } } -LRESULT CALLBACK DownloadManager::DownloadProgressProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +LRESULT CALLBACK ÑDownloadManager::DownloadProgressProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { static ATL::CStringW szProgressText; @@ -381,6 +521,7 @@ LRESULT CALLBACK DownloadManager::DownloadProgressProc(HWND hWnd, UINT uMsg, WPA /* 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(); @@ -392,41 +533,49 @@ LRESULT CALLBACK DownloadManager::DownloadProgressProc(HWND hWnd, UINT uMsg, WPA } } -DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) +DWORD WINAPI ÑDownloadManager::ThreadFunc(LPVOID Context) { CComPtr dl; ATL::CStringW Path; PWSTR p, q; HWND Dlg = (HWND) Context; + ULONG dwContentLen, dwBytesWritten, dwBytesRead, dwStatus; ULONG dwCurrentBytesRead = 0; ULONG dwStatusLen = sizeof(dwStatus); + BOOL bCancelled = FALSE; BOOL bTempfile = FALSE; BOOL bCab = FALSE; + HINTERNET hOpen = NULL; HINTERNET hFile = NULL; HANDLE hOut = INVALID_HANDLE_VALUE; + unsigned char lpBuffer[4096]; LPCWSTR lpszAgent = L"RApps/1.0"; URL_COMPONENTS urlComponents; size_t urlLength, filenameLength; + const INT iAppId = iCurrentApp; + const PAPPLICATION_INFO pCurrentInfo = AppInfo; if (!AppInfo) { MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD); goto end; } - /* build the path for the download */ - p = wcsrchr(AppInfo->szUrlDownload.GetString(), L'/'); - q = wcsrchr(AppInfo->szUrlDownload.GetString(), L'?'); + DownloadsListView.SetDownloadStatus(iAppId, DOWNLOAD_STATUS::DLDownloading); - /* do we have a final slash separator? */ + // build the path for the download + p = wcsrchr(pCurrentInfo->szUrlDownload.GetString(), L'/'); + q = wcsrchr(pCurrentInfo->szUrlDownload.GetString(), L'?'); + + // do we have a final slash separator? if (!p) goto end; - /* prepare the tentative length of the filename, maybe we've to remove part of it later on */ + // prepare the tentative length of the filename, maybe we've to remove part of it later on filenameLength = wcslen(p) * sizeof(WCHAR); /* do we have query arguments in the target URL after the filename? account for them @@ -434,8 +583,8 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) if (q && q > p && (q - p) > 0) filenameLength -= wcslen(q - 1) * sizeof(WCHAR); - /* is this URL an update package for RAPPS? if so store it in a different place */ - if (AppInfo->szUrlDownload == APPLICATION_DATABASE_URL) + // is this URL an update package for RAPPS? if so store it in a different place + if (pCurrentInfo->szUrlDownload == APPLICATION_DATABASE_URL) { bCab = TRUE; if (!GetStorageDirectory(Path)) @@ -446,24 +595,25 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) Path = SettingsInfo.szDownloadDir; } - /* is the path valid? can we access it? */ + // is the path valid? can we access it? if (GetFileAttributesW(Path.GetString()) == INVALID_FILE_ATTRIBUTES) { if (!CreateDirectoryW(Path.GetString(), NULL)) goto end; } - /* append a \ to the provided file system path, and the filename portion from the URL after that */ - Path.Format(L"\\%ls", (p + 1)); + // append a \ to the provided file system path, and the filename portion from the URL after that + Path += L"\\"; + Path += (LPWSTR) (p + 1); - if (!bCab && AppInfo->szSHA1[0] && GetFileAttributesW(Path.GetString()) != INVALID_FILE_ATTRIBUTES) + if (!bCab && pCurrentInfo->szSHA1[0] && GetFileAttributesW(Path.GetString()) != INVALID_FILE_ATTRIBUTES) { - /* only open it in case of total correctness */ - if (VerifyInteg(AppInfo->szSHA1, Path)) + // only open it in case of total correctness + if (VerifyInteg(pCurrentInfo->szSHA1, Path)) goto run; } - /* download it */ + // download it bTempfile = TRUE; CDownloadDialog_Constructor(Dlg, &bCancelled, IID_PPV_ARG(IBindStatusCallback, &dl)); @@ -473,16 +623,16 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) /* FIXME: this should just be using the system-wide proxy settings */ switch (SettingsInfo.Proxy) { - case 0: /* preconfig */ + case 0: // preconfig hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); break; - case 1: /* direct (no proxy) */ + case 1: // direct (no proxy) hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); break; - case 2: /* use proxy */ + case 2: // use proxy hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PROXY, SettingsInfo.szProxyServer, SettingsInfo.szNoProxyFor, 0); break; - default: /* preconfig */ + default: // preconfig hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); break; } @@ -490,7 +640,7 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) if (!hOpen) goto end; - hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0); + hFile = InternetOpenUrlW(hOpen, pCurrentInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0); if (!hFile) { MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD2); @@ -511,25 +661,25 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) memset(&urlComponents, 0, sizeof(urlComponents)); urlComponents.dwStructSize = sizeof(urlComponents); - urlLength = AppInfo->szUrlDownload.GetLength(); + urlLength = pCurrentInfo->szUrlDownload.GetLength(); urlComponents.dwSchemeLength = urlLength + 1; urlComponents.lpszScheme = (LPWSTR) malloc(urlComponents.dwSchemeLength * sizeof(WCHAR)); urlComponents.dwHostNameLength = urlLength + 1; urlComponents.lpszHostName = (LPWSTR) malloc(urlComponents.dwHostNameLength * sizeof(WCHAR)); - if (!InternetCrackUrlW(AppInfo->szUrlDownload, urlLength + 1, ICU_DECODE | ICU_ESCAPE, &urlComponents)) + if (!InternetCrackUrlW(pCurrentInfo->szUrlDownload, urlLength + 1, ICU_DECODE | ICU_ESCAPE, &urlComponents)) goto end; if (urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) - HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatus, 0); + HttpQueryInfoW(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatus, 0); if (urlComponents.nScheme == INTERNET_SCHEME_FTP) dwContentLen = FtpGetFileSize(hFile, &dwStatus); #ifdef USE_CERT_PINNING - /* are we using HTTPS to download the RAPPS update package? check if the certificate is original */ + // are we using HTTPS to download the RAPPS update package? check if the certificate is original if ((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) && - (wcscmp(AppInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0) && + (wcscmp(pCurrentInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0) && (!CertIsValid(hOpen, urlComponents.lpszHostName))) { MessageBox_LoadString(hMainWnd, IDS_CERT_DOES_NOT_MATCH); @@ -560,7 +710,7 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) } dwCurrentBytesRead += dwBytesRead; - dl->OnProgress(dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload); + dl->OnProgress(dwCurrentBytesRead, dwContentLen, 0, pCurrentInfo->szUrlDownload); } while (dwBytesRead && !bCancelled); CloseHandle(hOut); @@ -571,19 +721,19 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) /* 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 */ - if (!bCab && AppInfo->szSHA1[0] != 0) + if (!bCab && pCurrentInfo->szSHA1[0] != 0) { ATL::CStringW szMsgText; - /* change a few strings in the download dialog to reflect the verification process */ + // change a few strings in the download dialog to reflect the verification process if (!szMsgText.LoadStringW(hInst, IDS_INTEG_CHECK_TITLE)) goto end; - SetWindowText(Dlg, szMsgText.GetString()); + SetWindowTextW(Dlg, szMsgText.GetString()); SendMessageW(GetDlgItem(Dlg, IDC_DOWNLOAD_STATUS), WM_SETTEXT, 0, (LPARAM) Path.GetString()); - /* this may take a while, depending on the file size */ - if (!VerifyInteg(AppInfo->szSHA1, Path.GetString())) + // this may take a while, depending on the file size + if (!VerifyInteg(pCurrentInfo->szSHA1, Path.GetString())) { if (!szMsgText.LoadStringW(hInst, IDS_INTEG_CHECK_FAIL)) goto end; @@ -593,12 +743,33 @@ DWORD WINAPI DownloadManager::ThreadFunc(LPVOID Context) } } - ShowWindow(Dlg, SW_HIDE); run: - /* run it */ + DownloadsListView.SetDownloadStatus(iAppId, DOWNLOAD_STATUS::DLWaitingToInstall); + + // run it if (!bCab) - ShellExecuteW(NULL, L"open", Path.GetString(), NULL, NULL, SW_SHOWNORMAL); + { + SHELLEXECUTEINFOW shExInfo = {0}; + shExInfo.cbSize = sizeof(shExInfo); + shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + shExInfo.lpVerb = L"open"; + shExInfo.lpFile = Path.GetString(); + shExInfo.lpParameters = L""; + shExInfo.nShow = SW_SHOW; + + if (ShellExecuteExW(&shExInfo)) + { + DownloadsListView.SetDownloadStatus(iAppId, DOWNLOAD_STATUS::DLInstalling); + //TODO: issue an install operation separately so that the apps could be downloaded in the background + WaitForSingleObject(shExInfo.hProcess, INFINITE); + CloseHandle(shExInfo.hProcess); + } + else + { + MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_INSTALL); + } + } end: if (hOut != INVALID_HANDLE_VALUE) @@ -612,55 +783,55 @@ end: if (bCancelled || (SettingsInfo.bDelInstaller && !bCab)) DeleteFileW(Path.GetString()); } - - EndDialog(Dlg, 0); - + DownloadsListView.SetDownloadStatus(iAppId, DOWNLOAD_STATUS::DLFinished); + SendMessageW(Dlg, DL_START_NEW, 0, 0); return 0; } -//TODO: Maybe launch this (similar function) in a seperate thread, so the list could be updated -BOOL DownloadManager::DownloadListOfApplications(const ATL::CSimpleArray& AppsList) +BOOL ÑDownloadManager::DownloadListOfApplications(const ATL::CSimpleArray& AppsList) { - BOOL bResult = TRUE; - - for (INT i = 0; i < AppsList.GetSize(); ++i) + if (AppsList.GetSize() == 0) { - bResult = DownloadApplication(AppsList[i]) && bResult; + return FALSE; } - return bResult; + + // Initialize shared variables + AppsToInstallList = AppsList; + + // Create a dialog and issue a download process + LaunchDownloadDialog(); + + return TRUE; } -BOOL DownloadManager::DownloadApplication(PAPPLICATION_INFO pAppInfo) +BOOL ÑDownloadManager::DownloadApplication(PAPPLICATION_INFO pAppInfo) { if (!pAppInfo) { return FALSE; } - // Create a dialog and issue a download process - AppInfo = pAppInfo; + AppsToInstallList.RemoveAll(); + AppsToInstallList.Add(pAppInfo); LaunchDownloadDialog(); - WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, AppInfo->szName.GetString()); - return TRUE; } -VOID DownloadManager::DownloadApplicationsDB(LPCWSTR lpUrl) +VOID ÑDownloadManager::DownloadApplicationsDB(LPCWSTR lpUrl) { APPLICATION_INFO IntInfo; IntInfo.szUrlDownload = lpUrl; - AppInfo = &IntInfo; - - LaunchDownloadDialog(); + DownloadApplication(&IntInfo); } //TODO: Reuse the dialog -VOID DownloadManager::LaunchDownloadDialog() +VOID ÑDownloadManager::LaunchDownloadDialog() { CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), hMainWnd, DownloadDlgProc); -} \ No newline at end of file +} +// CDownloadManager \ No newline at end of file diff --git a/reactos/base/applications/rapps/misc.cpp b/reactos/base/applications/rapps/misc.cpp index e991ce90152..1a26e58efd8 100644 --- a/reactos/base/applications/rapps/misc.cpp +++ b/reactos/base/applications/rapps/misc.cpp @@ -46,7 +46,6 @@ typedef struct typedef HRESULT(WINAPI *fnExtract)(SESSION *dest, LPCSTR szCabName); fnExtract pfnExtract; - INT GetSystemColorDepth(VOID) { @@ -56,7 +55,7 @@ GetSystemColorDepth(VOID) pDevMode.dmSize = sizeof(pDevMode); pDevMode.dmDriverExtra = 0; - if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &pDevMode)) + if (!EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &pDevMode)) { /* TODO: Error message */ return ILC_COLOR; @@ -170,7 +169,7 @@ ShowPopupMenu(HWND hwnd, UINT MenuID, UINT DefaultItem) ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE; - GetMenuItemInfo(hPopupMenu, DefaultItem, FALSE, &mii); + GetMenuItemInfoW(hPopupMenu, DefaultItem, FALSE, &mii); if (!(mii.fState & MFS_GRAYED)) SetMenuDefaultItem(hPopupMenu, DefaultItem, FALSE); diff --git a/reactos/base/applications/rapps/rapps.h b/reactos/base/applications/rapps/rapps.h index 0ded9a34f73..6192a13c0ee 100644 --- a/reactos/base/applications/rapps/rapps.h +++ b/reactos/base/applications/rapps/rapps.h @@ -249,12 +249,15 @@ VOID SaveSettings(HWND hwnd); VOID FillDefaultSettings(PSETTINGS_INFO pSettingsInfo); /* loaddlg.cpp */ +class CDowloadingAppsListView; -class DownloadManager +class ÑDownloadManager { static PAPPLICATION_INFO AppInfo; + static ATL::CSimpleArray AppsToInstallList; + static CDowloadingAppsListView DownloadsListView; + static INT iCurrentApp; public: - static INT_PTR CALLBACK DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK DownloadProgressProc(HWND hWnd, UINT uMsg, diff --git a/reactos/base/applications/rapps/resource.h b/reactos/base/applications/rapps/resource.h index 2409b76eb21..77fa92238b6 100644 --- a/reactos/base/applications/rapps/resource.h +++ b/reactos/base/applications/rapps/resource.h @@ -107,6 +107,7 @@ #define IDS_UNABLE_TO_WRITE 125 #define IDS_SELECT_ALL 126 #define IDS_INSTALL_SELECTED 127 +#define IDS_UNABLE_TO_INSTALL 128 /* Tooltips */ #define IDS_TOOLTIP_INSTALL 200 @@ -176,6 +177,8 @@ #define IDS_STATUS_UPDATE_AVAILABLE 803 #define IDS_STATUS_DOWNLOADING 804 #define IDS_STATUS_INSTALLING 805 +#define IDS_STATUS_WAITING 806 +#define IDS_STATUS_FINISHED 807 /* App license names */ #define IDS_LICENSE_OPENSOURCE 900