diff --git a/base/applications/rapps/gui.cpp b/base/applications/rapps/gui.cpp index 5e8dc85a8ba..6f2e1a1d3d8 100644 --- a/base/applications/rapps/gui.cpp +++ b/base/applications/rapps/gui.cpp @@ -816,7 +816,7 @@ CMainWindow::InstallApplication(CAppInfo *Info) { if (DownloadApplication(Info)) { - UpdateApplicationsList(SelectedEnumType); + //FIXME: Delay UpdateApplicationsList(SelectedEnumType); until install completes return TRUE; } } diff --git a/base/applications/rapps/loaddlg.cpp b/base/applications/rapps/loaddlg.cpp index c0ca9d135dc..df8afcbeeea 100644 --- a/base/applications/rapps/loaddlg.cpp +++ b/base/applications/rapps/loaddlg.cpp @@ -119,6 +119,19 @@ UrlUnescapeAndMakeFileNameValid(CStringW& str) str = szPath; } +static void +SetFriendlyUrl(HWND hWnd, LPCWSTR pszUrl) +{ + CStringW buf; + DWORD cch = (DWORD)(wcslen(pszUrl) + 1); + if (InternetCanonicalizeUrlW(pszUrl, buf.GetBuffer(cch), &cch, ICU_DECODE | ICU_NO_ENCODE)) + { + buf.ReleaseBuffer(); + pszUrl = buf; + } + SetWindowTextW(hWnd, pszUrl); +} + struct DownloadInfo { DownloadInfo() : DLType(DLTYPE_APPLICATION), IType(INSTALLER_UNKNOWN), SizeInBytes(0) @@ -130,9 +143,12 @@ struct DownloadInfo szName = AppInfo.szDisplayName; IType = AppInfo.GetInstallerType(); if (IType == INSTALLER_GENERATE) - { szPackageName = AppInfo.szIdentifier; - } + } + + bool Equal(const DownloadInfo &other) const + { + return DLType == other.DLType && !lstrcmpW(szUrl, other.szUrl); } DownloadType DLType; @@ -144,21 +160,6 @@ struct DownloadInfo ULONG SizeInBytes; }; -struct DownloadParam -{ - DownloadParam() : Dialog(NULL), AppInfo(), szCaption(NULL) - { - } - DownloadParam(HWND dlg, const ATL::CSimpleArray &info, LPCWSTR caption) - : Dialog(dlg), AppInfo(info), szCaption(caption) - { - } - - HWND Dialog; - ATL::CSimpleArray AppInfo; - LPCWSTR szCaption; -}; - class CDownloaderProgress : public CWindowImpl { CStringW m_szProgressText; @@ -313,7 +314,7 @@ class CDowloadingAppsListView : public CListView RECT r; ::GetClientRect(hwndParent, &r); r.top = (2 * r.top + 1 * r.bottom) / 3; /* The vertical position at ratio 1 : 2 */ -#define MARGIN 10 + const INT MARGIN = 10; ::InflateRect(&r, -MARGIN, -MARGIN); const DWORD style = WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | @@ -328,11 +329,12 @@ class CDowloadingAppsListView : public CListView } VOID - LoadList(ATL::CSimpleArray arrInfo) + LoadList(ATL::CSimpleArray arrInfo, UINT Start = 0) { - for (INT i = 0; i < arrInfo.GetSize(); ++i) + const INT base = GetItemCount(); + for (INT i = Start; i < arrInfo.GetSize(); ++i) { - AddRow(i, arrInfo[i].szName.GetString(), DLSTATUS_WAITING); + AddRow(base + i - Start, arrInfo[i].szName, DLSTATUS_WAITING); } } @@ -420,7 +422,7 @@ CertGetSubjectAndIssuer(HINTERNET hFile, CLocalPtr &subjectInfo, CLocalPtr } #endif -inline VOID +static inline VOID MessageBox_LoadString(HWND hOwnerWnd, INT StringID) { CStringW szMsgText; @@ -430,202 +432,7 @@ MessageBox_LoadString(HWND hOwnerWnd, INT StringID) } } -// Download dialog (loaddlg.cpp) -class CDownloadManager -{ - static ATL::CSimpleArray AppsDownloadList; - static CDowloadingAppsListView DownloadsListView; - static CDownloaderProgress ProgressBar; - static BOOL bCancelled; - static BOOL bModal; - static VOID - UpdateProgress(HWND hDlg, ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText); - - public: - static VOID - Add(DownloadInfo info); - static VOID - Download(const DownloadInfo &DLInfo, BOOL bIsModal = FALSE); - static INT_PTR CALLBACK - DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - static unsigned int WINAPI - ThreadFunc(LPVOID Context); - static VOID LaunchDownloadDialog(BOOL); -}; - -// CDownloadManager -ATL::CSimpleArray CDownloadManager::AppsDownloadList; -CDowloadingAppsListView CDownloadManager::DownloadsListView; -CDownloaderProgress CDownloadManager::ProgressBar; -BOOL CDownloadManager::bCancelled = FALSE; -BOOL CDownloadManager::bModal = FALSE; - -VOID -CDownloadManager::Add(DownloadInfo info) -{ - AppsDownloadList.Add(info); -} - -VOID -CDownloadManager::Download(const DownloadInfo &DLInfo, BOOL bIsModal) -{ - AppsDownloadList.RemoveAll(); - AppsDownloadList.Add(DLInfo); - LaunchDownloadDialog(bIsModal); -} - -INT_PTR CALLBACK -CDownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - static WCHAR szCaption[MAX_PATH]; - - switch (uMsg) - { - case WM_INITDIALOG: - { - g_Busy++; - HICON hIconSm, hIconBg; - CStringW szTempCaption; - - bCancelled = FALSE; - - if (hMainWnd) - { - hIconBg = (HICON)GetClassLongPtrW(hMainWnd, GCLP_HICON); - hIconSm = (HICON)GetClassLongPtrW(hMainWnd, GCLP_HICONSM); - } - if (!hMainWnd || (!hIconBg || !hIconSm)) - { - /* Load the default icon */ - hIconBg = hIconSm = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN)); - } - - if (hIconBg && hIconSm) - { - SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM)hIconBg); - SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm); - } - - HWND 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 - ProgressBar.SubclassWindow(Item); - ProgressBar.SendMessage(PBM_SETRANGE, 0, MAKELPARAM(0, 100)); - ProgressBar.SendMessage(PBM_SETPOS, 0, 0); - if (AppsDownloadList.GetSize() > 0) - ProgressBar.SetProgress(0, AppsDownloadList[0].SizeInBytes); - } - - // Add a ListView - HWND hListView = DownloadsListView.Create(Dlg); - if (!hListView) - { - return FALSE; - } - DownloadsListView.LoadList(AppsDownloadList); - - // Get a dlg string for later use - GetWindowTextW(Dlg, szCaption, _countof(szCaption)); - - // Hide a placeholder from displaying - szTempCaption = szCaption; - szTempCaption.Replace(L"%ls", L""); - SetWindowText(Dlg, szTempCaption.GetString()); - - ShowWindow(Dlg, SW_SHOW); - - // Start download process - DownloadParam *param = new DownloadParam(Dlg, AppsDownloadList, szCaption); - unsigned int ThreadId; - HANDLE Thread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void *)param, 0, &ThreadId); - if (!Thread) - { - return FALSE; - } - - CloseHandle(Thread); - AppsDownloadList.RemoveAll(); - return TRUE; - } - - case WM_COMMAND: - if (wParam == IDCANCEL) - { - bCancelled = TRUE; - PostMessageW(Dlg, WM_CLOSE, 0, 0); - } - return FALSE; - - case WM_CLOSE: - if (ProgressBar) - ProgressBar.UnsubclassWindow(TRUE); - if (CDownloadManager::bModal) - { - ::EndDialog(Dlg, 0); - } - else - { - ::DestroyWindow(Dlg); - } - return TRUE; - - case WM_DESTROY: - g_Busy--; - if (hMainWnd) - PostMessage(hMainWnd, WM_NOTIFY_OPERATIONCOMPLETED, 0, 0); - return FALSE; - - default: - return FALSE; - } -} - -BOOL UrlHasBeenCopied; - -VOID -CDownloadManager::UpdateProgress( - HWND hDlg, - ULONG ulProgress, - ULONG ulProgressMax, - ULONG ulStatusCode, - LPCWSTR szStatusText) -{ - HWND Item; - - if (!IsWindow(hDlg)) - return; - ProgressBar.SetProgress(ulProgress, ulProgressMax); - - if (!IsWindow(hDlg)) - return; - Item = GetDlgItem(hDlg, IDC_DOWNLOAD_STATUS); - if (Item && szStatusText && wcslen(szStatusText) > 0 && UrlHasBeenCopied == FALSE) - { - SIZE_T len = wcslen(szStatusText) + 1; - CStringW buf; - DWORD dummyLen; - - /* beautify our url for display purposes */ - if (!InternetCanonicalizeUrlW(szStatusText, buf.GetBuffer(len), &dummyLen, ICU_DECODE | ICU_NO_ENCODE)) - { - /* just use the original */ - buf.ReleaseBuffer(); - buf = szStatusText; - } - else - { - buf.ReleaseBuffer(); - } - - /* paste it into our dialog and don't do it again in this instance */ - ::SetWindowText(Item, buf.GetString()); - UrlHasBeenCopied = TRUE; - } -} - -BOOL +static BOOL ShowLastError(HWND hWndOwner, BOOL bInetError, DWORD dwLastError) { CLocalPtr lpMsg; @@ -644,61 +451,473 @@ ShowLastError(HWND hWndOwner, BOOL bInetError, DWORD dwLastError) return TRUE; } -unsigned int WINAPI -CDownloadManager::ThreadFunc(LPVOID param) +// Download dialog (loaddlg.cpp) +HWND g_hDownloadWnd = NULL; + +class CDownloadManager : + public CComCoClass, + public CComObjectRootEx, + public IUnknown { +public: + enum { + WM_ISCANCELLED = WM_APP, // Return BOOL + WM_SETSTATUS, // wParam DownloadStatus + WM_GETINSTANCE, // Return CDownloadManager* + WM_GETNEXT, // Return DownloadInfo* or NULL + }; + + CDownloadManager() : m_hDlg(NULL), m_Threads(0), m_Index(0), m_bCancelled(FALSE) {} + + static CDownloadManager* + CreateInstanceHelper(BOOL Modal) + { + if (!Modal) + { + CDownloadManager* pExisting = CDownloadManager::FindInstance(); + if (pExisting) + { + pExisting->AddRef(); + return pExisting; + } + } + CComPtr obj; + if (FAILED(ShellObjectCreator(obj))) + return NULL; + obj->m_bModal = Modal; + return obj.Detach(); + } + + static BOOL + CreateInstance(BOOL Modal, CComPtr &Obj) + { + CDownloadManager *p = CreateInstanceHelper(Modal); + if (!p) + return FALSE; + Obj.Attach(p); + return TRUE; + } + + static CDownloadManager* + FindInstance() + { + if (g_hDownloadWnd) + return (CDownloadManager*)SendMessageW(g_hDownloadWnd, WM_GETINSTANCE, 0, 0); + return NULL; + } + + BOOL + IsCancelled() + { + return !IsWindow(m_hDlg) || SendMessageW(m_hDlg, WM_ISCANCELLED, 0, 0); + } + + void StartWorkerThread(); + void Add(const DownloadInfo &Info); + void Show(); + static INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + INT_PTR RealDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + void UpdateProgress(ULONG ulProgress, ULONG ulProgressMax); + static unsigned int CALLBACK ThreadFunc(void*ThreadParam); + void PerformDownloadAndInstall(const DownloadInfo &Info); + + DECLARE_NO_REGISTRY() + DECLARE_NOT_AGGREGATABLE(CDownloadManager) + BEGIN_COM_MAP(CDownloadManager) + END_COM_MAP() + +protected: + HWND m_hDlg; + UINT m_Threads; + UINT m_Index; + BOOL m_bCancelled; + BOOL m_bModal; + WCHAR m_szCaptionFmt[100]; + ATL::CSimpleArray m_List; + CDowloadingAppsListView m_ListView; + CDownloaderProgress m_ProgressBar; +}; + +void +CDownloadManager::StartWorkerThread() +{ + AddRef(); // To keep m_List alive in thread + unsigned int ThreadId; + HANDLE Thread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, this, 0, &ThreadId); + if (Thread) + CloseHandle(Thread); + else + Release(); +} + +void +CDownloadManager::Add(const DownloadInfo &Info) +{ + const UINT count = m_List.GetSize(), start = count; + for (UINT i = 0; i < count; ++i) + { + if (Info.Equal(m_List[i])) + return; // Already in the list + } + m_List.Add(Info); + if (m_hDlg) + m_ListView.LoadList(m_List, start); +} + +void +CDownloadManager::Show() +{ + if (m_bModal) + DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), hMainWnd, DlgProc, (LPARAM)this); + else if (!m_hDlg || !IsWindow(m_hDlg)) + CreateDialogParamW(hInst, MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), hMainWnd, DlgProc, (LPARAM)this); +} + +INT_PTR CALLBACK +CDownloadManager::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CDownloadManager* pThis = (CDownloadManager*)GetWindowLongPtrW(hDlg, DWLP_USER); + if (!pThis) + { + if (uMsg != WM_INITDIALOG) + return FALSE; + SetWindowLongPtrW(hDlg, DWLP_USER, lParam); + pThis = (CDownloadManager*)lParam; + } + return pThis->RealDlgProc(hDlg, uMsg, wParam, lParam); +} + +INT_PTR +CDownloadManager::RealDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + g_Busy++; + AddRef(); + m_hDlg = hDlg; + if (!m_bModal) + g_hDownloadWnd = hDlg; + + HICON hIconSm, hIconBg; + if (hMainWnd) + { + hIconBg = (HICON)GetClassLongPtrW(hMainWnd, GCLP_HICON); + hIconSm = (HICON)GetClassLongPtrW(hMainWnd, GCLP_HICONSM); + } + if (!hMainWnd || (!hIconBg || !hIconSm)) + { + hIconBg = hIconSm = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN)); + } + SendMessageW(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIconBg); + SendMessageW(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm); + + GetWindowTextW(hDlg, m_szCaptionFmt, _countof(m_szCaptionFmt)); + CStringW buf; + buf = m_szCaptionFmt; + buf.Replace(L"%ls", L""); + SetWindowTextW(hDlg, buf); // "Downloading..." + + HWND hItem = GetDlgItem(hDlg, IDC_DOWNLOAD_PROGRESS); + if (hItem) + { + // initialize the default values for our nifty progress bar + // and subclass it so that it learns to print a status text + m_ProgressBar.SubclassWindow(hItem); + m_ProgressBar.SendMessageW(PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + m_ProgressBar.SendMessageW(PBM_SETPOS, 0, 0); + if (m_List.GetSize() > 0) + m_ProgressBar.SetProgress(0, m_List[0].SizeInBytes); + } + + if (!m_ListView.Create(hDlg)) + return FALSE; + m_ListView.LoadList(m_List); + + ShowWindow(hDlg, SW_SHOW); + StartWorkerThread(); + return TRUE; + } + + case WM_COMMAND: + if (LOWORD(wParam) == IDCANCEL) + { + m_bCancelled = TRUE; + PostMessageW(hDlg, WM_CLOSE, 0, 0); + } + return FALSE; + + case WM_CLOSE: + m_bCancelled = TRUE; + if (m_ProgressBar) + m_ProgressBar.UnsubclassWindow(TRUE); + return m_bModal ? ::EndDialog(hDlg, 0) : ::DestroyWindow(hDlg); + + case WM_DESTROY: + if (g_hDownloadWnd == hDlg) + g_hDownloadWnd = NULL; + g_Busy--; + if (hMainWnd) + PostMessage(hMainWnd, WM_NOTIFY_OPERATIONCOMPLETED, 0, 0); + Release(); + break; + + case WM_ISCANCELLED: + return SetDlgMsgResult(hDlg, uMsg, m_bCancelled); + + case WM_SETSTATUS: + m_ListView.SetDownloadStatus(m_Index - 1, (DownloadStatus)wParam); + break; + + case WM_GETINSTANCE: + return SetDlgMsgResult(hDlg, uMsg, (INT_PTR)this); + + case WM_GETNEXT: + { + DownloadInfo *pItem = NULL; + if (!m_bCancelled && m_Index < (SIZE_T)m_List.GetSize()) + pItem = &m_List[m_Index++]; + return SetDlgMsgResult(hDlg, uMsg, (INT_PTR)pItem); + } + } + return FALSE; +} + +void +CDownloadManager::UpdateProgress(ULONG ulProgress, ULONG ulProgressMax) +{ + m_ProgressBar.SetProgress(ulProgress, ulProgressMax); +} + +unsigned int CALLBACK +CDownloadManager::ThreadFunc(void* ThreadParam) +{ + CDownloadManager *pThis = (CDownloadManager*)ThreadParam; + HWND hDlg = pThis->m_hDlg; + for (;;) + { + DownloadInfo *pItem = (DownloadInfo*)SendMessageW(hDlg, WM_GETNEXT, 0, 0); + if (!pItem) + break; + pThis->PerformDownloadAndInstall(*pItem); + } + SendMessageW(hDlg, WM_CLOSE, 0, 0); + return pThis->Release(); +} + +void +CDownloadManager::PerformDownloadAndInstall(const DownloadInfo &Info) +{ + const HWND hDlg = m_hDlg; + const HWND hStatus = GetDlgItem(m_hDlg, IDC_DOWNLOAD_STATUS); + SetFriendlyUrl(hStatus, Info.szUrl); + + m_ProgressBar.SetMarquee(FALSE); + m_ProgressBar.SendMessageW(PBM_SETPOS, 0, 0); + m_ProgressBar.SetProgress(0, Info.SizeInBytes); + + CStringW str; CPathW Path; PCWSTR p, q; - HWND hDlg = static_cast(param)->Dialog; - HWND Item; - INT iAppId; - - ULONG dwContentLen, dwBytesWritten, dwBytesRead, dwStatus; + ULONG dwContentLen, dwBytesWritten, dwBytesRead, dwStatus, dwStatusLen; ULONG dwCurrentBytesRead = 0; - ULONG dwStatusLen = sizeof(dwStatus); - - BOOL bTempfile = FALSE; + BOOL bTempfile = FALSE, bCancelled = FALSE; HINTERNET hOpen = NULL; HINTERNET hFile = NULL; HANDLE hOut = INVALID_HANDLE_VALUE; - unsigned char lpBuffer[4096]; + LPCWSTR lpszAgent = L"RApps/1.1"; - URL_COMPONENTSW urlComponents; - size_t urlLength, filenameLength; - - const ATL::CSimpleArray &InfoArray = static_cast(param)->AppInfo; - LPCWSTR szCaption = static_cast(param)->szCaption; - CStringW szNewCaption; - const DWORD dwUrlConnectFlags = INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION; + URL_COMPONENTSW urlComponents; + size_t urlLength, filenameLength; + unsigned char lpBuffer[4096]; - if (InfoArray.GetSize() <= 0) + // Change caption to show the currently downloaded app + switch (Info.DLType) { - MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD); + case DLTYPE_APPLICATION: + str.Format(m_szCaptionFmt, Info.szName.GetString()); + break; + case DLTYPE_DBUPDATE: + str.LoadStringW(IDS_DL_DIALOG_DB_DOWNLOAD_DISP); + break; + case DLTYPE_DBUPDATE_UNOFFICIAL: + str.LoadStringW(IDS_DL_DIALOG_DB_UNOFFICIAL_DOWNLOAD_DISP); + break; + } + SetWindowTextW(hDlg, str); + + // is this URL an update package for RAPPS? if so store it in a different place + if (Info.DLType != DLTYPE_APPLICATION) + { + if (!GetStorageDirectory(Path)) + { + ShowLastError(hMainWnd, FALSE, GetLastError()); + goto end; + } + } + else + { + Path = SettingsInfo.szDownloadDir; + } + + // build the path for the download + p = wcsrchr(Info.szUrl.GetString(), L'/'); + q = wcsrchr(Info.szUrl.GetString(), L'?'); + + // do we have a final slash separator? + if (!p) + { + MessageBox_LoadString(hMainWnd, IDS_UNABLE_PATH); goto end; } - for (iAppId = 0; iAppId < InfoArray.GetSize(); ++iAppId) + // 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 + (e.g. https://example.org/myfile.exe?no_adware_plz) */ + if (q && q > p && (q - p) > 0) + filenameLength -= wcslen(q - 1) * sizeof(WCHAR); + + // is the path valid? can we access it? + if (GetFileAttributesW(Path) == INVALID_FILE_ATTRIBUTES) { - // Reset progress bar - if (!IsWindow(hDlg)) - break; - Item = GetDlgItem(hDlg, IDC_DOWNLOAD_PROGRESS); - if (Item) + if (!CreateDirectoryW(Path, NULL)) { - ProgressBar.SetMarquee(FALSE); - ProgressBar.SendMessage(PBM_SETPOS, 0, 0); - ProgressBar.SetProgress(0, InfoArray[iAppId].SizeInBytes); + ShowLastError(hMainWnd, FALSE, GetLastError()); + goto end; + } + } + + switch (Info.DLType) + { + case DLTYPE_DBUPDATE: + case DLTYPE_DBUPDATE_UNOFFICIAL: + Path += APPLICATION_DATABASE_NAME; + break; + case DLTYPE_APPLICATION: + { + CStringW str = p + 1; // use the filename retrieved from URL + UrlUnescapeAndMakeFileNameValid(str); + Path += str; + break; + } + } + + if ((Info.DLType == DLTYPE_APPLICATION) && Info.szSHA1[0] && + GetFileAttributesW(Path) != INVALID_FILE_ATTRIBUTES) + { + // only open it in case of total correctness + if (VerifyInteg(Info.szSHA1.GetString(), Path)) + goto run; + } + + // Download it + SendMessageW(hDlg, WM_SETSTATUS, DLSTATUS_DOWNLOADING, 0); + /* FIXME: this should just be using the system-wide proxy settings */ + switch (SettingsInfo.Proxy) + { + case 0: // preconfig + default: + hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + break; + case 1: // direct (no proxy) + hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + break; + case 2: // use proxy + hOpen = InternetOpenW( + lpszAgent, INTERNET_OPEN_TYPE_PROXY, SettingsInfo.szProxyServer, SettingsInfo.szNoProxyFor, 0); + break; + } + + if (!hOpen) + { + ShowLastError(hMainWnd, TRUE, GetLastError()); + goto end; + } + + bTempfile = TRUE; + dwContentLen = 0; + dwStatusLen = sizeof(dwStatus); + ZeroMemory(&urlComponents, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + + urlLength = Info.szUrl.GetLength(); + urlComponents.dwSchemeLength = urlLength + 1; + urlComponents.lpszScheme = (LPWSTR)malloc(urlComponents.dwSchemeLength * sizeof(WCHAR)); + + if (!InternetCrackUrlW(Info.szUrl, urlLength + 1, ICU_DECODE | ICU_ESCAPE, &urlComponents)) + { + ShowLastError(hMainWnd, TRUE, GetLastError()); + goto end; + } + + if (urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) + { + hFile = InternetOpenUrlW(hOpen, Info.szUrl, NULL, 0, dwUrlConnectFlags, 0); + if (!hFile) + { + if (!ShowLastError(hMainWnd, TRUE, GetLastError())) + { + /* Workaround for CORE-17377 */ + MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD2); + } + goto end; } - // is this URL an update package for RAPPS? if so store it in a different place - if (InfoArray[iAppId].DLType != DLTYPE_APPLICATION) + // query connection + if (!HttpQueryInfoW(hFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatus, &dwStatusLen, NULL)) { - if (!GetStorageDirectory(Path)) + ShowLastError(hMainWnd, TRUE, GetLastError()); + goto end; + } + + if (dwStatus != HTTP_STATUS_OK) + { + MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD); + goto end; + } + + // query content length + HttpQueryInfoW(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatusLen, NULL); + } + else if (urlComponents.nScheme == INTERNET_SCHEME_FTP) + { + // force passive mode on FTP + hFile = + InternetOpenUrlW(hOpen, Info.szUrl, NULL, 0, dwUrlConnectFlags | INTERNET_FLAG_PASSIVE, 0); + if (!hFile) + { + if (!ShowLastError(hMainWnd, TRUE, GetLastError())) + { + /* Workaround for CORE-17377 */ + MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD2); + } + goto end; + } + + dwContentLen = FtpGetFileSize(hFile, &dwStatus); + } + else if (urlComponents.nScheme == INTERNET_SCHEME_FILE) + { + // Add support for the file scheme so testing locally is simpler + WCHAR LocalFilePath[MAX_PATH]; + DWORD cchPath = _countof(LocalFilePath); + // Ideally we would use PathCreateFromUrlAlloc here, but that is not exported (yet) + HRESULT hr = PathCreateFromUrlW(Info.szUrl, LocalFilePath, &cchPath, 0); + if (SUCCEEDED(hr)) + { + if (CopyFileW(LocalFilePath, Path, FALSE)) + { + goto run; + } + else { ShowLastError(hMainWnd, FALSE, GetLastError()); goto end; @@ -706,420 +925,198 @@ CDownloadManager::ThreadFunc(LPVOID param) } else { - Path = SettingsInfo.szDownloadDir; - } - - // Change caption to show the currently downloaded app - switch (InfoArray[iAppId].DLType) - { - case DLTYPE_APPLICATION: - szNewCaption.Format(szCaption, InfoArray[iAppId].szName.GetString()); - break; - case DLTYPE_DBUPDATE: - szNewCaption.LoadStringW(IDS_DL_DIALOG_DB_DOWNLOAD_DISP); - break; - case DLTYPE_DBUPDATE_UNOFFICIAL: - szNewCaption.LoadStringW(IDS_DL_DIALOG_DB_UNOFFICIAL_DOWNLOAD_DISP); - break; - } - - if (!IsWindow(hDlg)) - goto end; - SetWindowTextW(hDlg, szNewCaption.GetString()); - - // build the path for the download - p = wcsrchr(InfoArray[iAppId].szUrl.GetString(), L'/'); - q = wcsrchr(InfoArray[iAppId].szUrl.GetString(), L'?'); - - // do we have a final slash separator? - if (!p) - { - MessageBox_LoadString(hMainWnd, IDS_UNABLE_PATH); + ShowLastError(hMainWnd, FALSE, hr); goto end; } + } - // 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 - (e.g. https://example.org/myfile.exe?no_adware_plz) */ - if (q && q > p && (q - p) > 0) - filenameLength -= wcslen(q - 1) * sizeof(WCHAR); - - // is the path valid? can we access it? - if (GetFileAttributesW(Path) == INVALID_FILE_ATTRIBUTES) + if (!dwContentLen) + { + // Someone was nice enough to add this, let's use it + if (Info.SizeInBytes) { - if (!CreateDirectoryW(Path, NULL)) - { - ShowLastError(hMainWnd, FALSE, GetLastError()); - goto end; - } + dwContentLen = Info.SizeInBytes; } - - switch (InfoArray[iAppId].DLType) + else { - case DLTYPE_DBUPDATE: - case DLTYPE_DBUPDATE_UNOFFICIAL: - Path += APPLICATION_DATABASE_NAME; - break; - case DLTYPE_APPLICATION: - { - CStringW str = p + 1; // use the filename retrieved from URL - UrlUnescapeAndMakeFileNameValid(str); - Path += str; - break; - } + // content-length is not known, enable marquee mode + m_ProgressBar.SetMarquee(TRUE); } + } - if ((InfoArray[iAppId].DLType == DLTYPE_APPLICATION) && InfoArray[iAppId].szSHA1[0] && - GetFileAttributesW(Path) != INVALID_FILE_ATTRIBUTES) - { - // only open it in case of total correctness - if (VerifyInteg(InfoArray[iAppId].szSHA1.GetString(), Path)) - goto run; - } - - // Add the download URL - if (!IsWindow(hDlg)) - goto end; - SetDlgItemTextW(hDlg, IDC_DOWNLOAD_STATUS, InfoArray[iAppId].szUrl.GetString()); - - DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_DOWNLOADING); - - // download it - UrlHasBeenCopied = FALSE; - bTempfile = TRUE; - - /* FIXME: this should just be using the system-wide proxy settings */ - switch (SettingsInfo.Proxy) - { - case 0: // preconfig - default: - hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - break; - case 1: // direct (no proxy) - hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); - break; - case 2: // use proxy - hOpen = InternetOpenW( - lpszAgent, INTERNET_OPEN_TYPE_PROXY, SettingsInfo.szProxyServer, SettingsInfo.szNoProxyFor, 0); - break; - } - - if (!hOpen) - { - ShowLastError(hMainWnd, TRUE, GetLastError()); - goto end; - } - - dwStatusLen = sizeof(dwStatus); - - memset(&urlComponents, 0, sizeof(urlComponents)); - urlComponents.dwStructSize = sizeof(urlComponents); - - urlLength = InfoArray[iAppId].szUrl.GetLength(); - urlComponents.dwSchemeLength = urlLength + 1; - urlComponents.lpszScheme = (LPWSTR)malloc(urlComponents.dwSchemeLength * sizeof(WCHAR)); - - if (!InternetCrackUrlW(InfoArray[iAppId].szUrl, urlLength + 1, ICU_DECODE | ICU_ESCAPE, &urlComponents)) - { - ShowLastError(hMainWnd, TRUE, GetLastError()); - goto end; - } - - dwContentLen = 0; - - if (urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) - { - hFile = InternetOpenUrlW(hOpen, InfoArray[iAppId].szUrl.GetString(), NULL, 0, dwUrlConnectFlags, 0); - if (!hFile) - { - if (!ShowLastError(hMainWnd, TRUE, GetLastError())) - { - /* Workaround for CORE-17377 */ - MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD2); - } - goto end; - } - - // query connection - if (!HttpQueryInfoW(hFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatus, &dwStatusLen, NULL)) - { - ShowLastError(hMainWnd, TRUE, GetLastError()); - goto end; - } - - if (dwStatus != HTTP_STATUS_OK) - { - MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD); - goto end; - } - - // query content length - HttpQueryInfoW( - hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatusLen, NULL); - } - else if (urlComponents.nScheme == INTERNET_SCHEME_FTP) - { - // force passive mode on FTP - hFile = - InternetOpenUrlW(hOpen, InfoArray[iAppId].szUrl, NULL, 0, dwUrlConnectFlags | INTERNET_FLAG_PASSIVE, 0); - if (!hFile) - { - if (!ShowLastError(hMainWnd, TRUE, GetLastError())) - { - /* Workaround for CORE-17377 */ - MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD2); - } - goto end; - } - - dwContentLen = FtpGetFileSize(hFile, &dwStatus); - } - else if (urlComponents.nScheme == INTERNET_SCHEME_FILE) - { - // Add support for the file scheme so testing locally is simpler - WCHAR LocalFilePath[MAX_PATH]; - DWORD cchPath = _countof(LocalFilePath); - // Ideally we would use PathCreateFromUrlAlloc here, but that is not exported (yet) - HRESULT hr = PathCreateFromUrlW(InfoArray[iAppId].szUrl, LocalFilePath, &cchPath, 0); - if (SUCCEEDED(hr)) - { - if (CopyFileW(LocalFilePath, Path, FALSE)) - { - goto run; - } - else - { - ShowLastError(hMainWnd, FALSE, GetLastError()); - goto end; - } - } - else - { - ShowLastError(hMainWnd, FALSE, hr); - goto end; - } - } - - if (!dwContentLen) - { - // Someone was nice enough to add this, let's use it - if (InfoArray[iAppId].SizeInBytes) - { - dwContentLen = InfoArray[iAppId].SizeInBytes; - } - else - { - // content-length is not known, enable marquee mode - ProgressBar.SetMarquee(TRUE); - } - } - - free(urlComponents.lpszScheme); + free(urlComponents.lpszScheme); #ifdef USE_CERT_PINNING - // are we using HTTPS to download the RAPPS update package? check if the certificate is original - if ((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) && (InfoArray[iAppId].DLType == DLTYPE_DBUPDATE)) + // are we using HTTPS to download the RAPPS update package? check if the certificate is original + if ((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) && (Info.DLType == DLTYPE_DBUPDATE)) + { + CLocalPtr subjectName, issuerName; + CStringA szMsgText; + bool bAskQuestion = false; + if (!CertGetSubjectAndIssuer(hFile, subjectName, issuerName)) { - CLocalPtr subjectName, issuerName; - CStringA szMsgText; - bool bAskQuestion = false; - if (!CertGetSubjectAndIssuer(hFile, subjectName, issuerName)) - { - szMsgText.LoadStringW(IDS_UNABLE_TO_QUERY_CERT); - bAskQuestion = true; - } - else if (!IsTrustedPinnedCert(subjectName, issuerName)) - { - szMsgText.Format(IDS_MISMATCH_CERT_INFO, (LPCSTR)subjectName, (LPCSTR)issuerName); - bAskQuestion = true; - } + szMsgText.LoadStringW(IDS_UNABLE_TO_QUERY_CERT); + bAskQuestion = true; + } + else if (!IsTrustedPinnedCert(subjectName, issuerName)) + { + szMsgText.Format(IDS_MISMATCH_CERT_INFO, (LPCSTR)subjectName, (LPCSTR)issuerName); + bAskQuestion = true; + } - if (bAskQuestion) + if (bAskQuestion) + { + if (MessageBoxA(hDlg, szMsgText, NULL, MB_YESNO | MB_ICONERROR) != IDYES) { - if (MessageBoxA(hMainWnd, szMsgText.GetString(), NULL, MB_YESNO | MB_ICONERROR) != IDYES) - { - goto end; - } + goto end; } } + } #endif - hOut = CreateFileW(Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); - - if (hOut == INVALID_HANDLE_VALUE) - { - ShowLastError(hMainWnd, FALSE, GetLastError()); - goto end; - } - - dwCurrentBytesRead = 0; - do - { - if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead)) - { - ShowLastError(hMainWnd, TRUE, GetLastError()); - goto end; - } - - if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL)) - { - ShowLastError(hMainWnd, FALSE, GetLastError()); - goto end; - } - - dwCurrentBytesRead += dwBytesRead; - if (!IsWindow(hDlg)) - goto end; - UpdateProgress(hDlg, dwCurrentBytesRead, dwContentLen, 0, InfoArray[iAppId].szUrl.GetString()); - } while (dwBytesRead && !bCancelled); - - CloseHandle(hOut); - hOut = INVALID_HANDLE_VALUE; + hOut = CreateFileW(Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); + if (hOut == INVALID_HANDLE_VALUE) + { + ShowLastError(hDlg, FALSE, GetLastError()); + goto end; + } + dwCurrentBytesRead = 0; + do + { + bCancelled = IsCancelled(); if (bCancelled) + break; + + if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead)) { - DPRINT1("Operation cancelled\n"); + ShowLastError(hDlg, TRUE, GetLastError()); goto end; } - if (!dwContentLen) + if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL)) { - // set progress bar to 100% - ProgressBar.SetMarquee(FALSE); - - dwContentLen = dwCurrentBytesRead; - if (!IsWindow(hDlg)) - goto end; - UpdateProgress(hDlg, dwCurrentBytesRead, dwContentLen, 0, InfoArray[iAppId].szUrl.GetString()); + ShowLastError(hDlg, FALSE, GetLastError()); + 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 */ - if ((InfoArray[iAppId].DLType == DLTYPE_APPLICATION) && InfoArray[iAppId].szSHA1[0] != 0) - { - CStringW szMsgText; + dwCurrentBytesRead += dwBytesRead; + UpdateProgress(dwCurrentBytesRead, dwContentLen); + + } while (dwBytesRead); - // change a few strings in the download dialog to reflect the verification process - if (!szMsgText.LoadStringW(IDS_INTEG_CHECK_TITLE)) + CloseHandle(hOut); + hOut = INVALID_HANDLE_VALUE; + + if (bCancelled) + { + DPRINT1("Operation cancelled\n"); + goto end; + } + + if (!dwContentLen) + { + // set progress bar to 100% + m_ProgressBar.SetMarquee(FALSE); + + dwContentLen = dwCurrentBytesRead; + UpdateProgress(dwCurrentBytesRead, dwContentLen); + } + + /* 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 ((Info.DLType == DLTYPE_APPLICATION) && Info.szSHA1[0] != 0) + { + CStringW szMsgText; + + // change a few strings in the download dialog to reflect the verification process + if (!szMsgText.LoadStringW(IDS_INTEG_CHECK_TITLE)) + { + DPRINT1("Unable to load string\n"); + goto end; + } + + SetWindowTextW(hDlg, szMsgText); + SetWindowTextW(hStatus, Path); + + // this may take a while, depending on the file size + if (!VerifyInteg(Info.szSHA1, Path)) + { + if (!szMsgText.LoadStringW(IDS_INTEG_CHECK_FAIL)) { DPRINT1("Unable to load string\n"); goto end; } - if (!IsWindow(hDlg)) - goto end; - SetWindowTextW(hDlg, szMsgText.GetString()); - ::SetDlgItemTextW(hDlg, IDC_DOWNLOAD_STATUS, Path); - - // this may take a while, depending on the file size - if (!VerifyInteg(InfoArray[iAppId].szSHA1.GetString(), Path)) - { - if (!szMsgText.LoadStringW(IDS_INTEG_CHECK_FAIL)) - { - DPRINT1("Unable to load string\n"); - goto end; - } - - if (!IsWindow(hDlg)) - goto end; - MessageBoxW(hDlg, szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR); - goto end; - } + MessageBoxW(hDlg, szMsgText, NULL, MB_OK | MB_ICONERROR); + goto end; } - - run: - DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_WAITING_INSTALL); - - // run it - if (InfoArray[iAppId].DLType == DLTYPE_APPLICATION) - { - CStringW app, params; - SHELLEXECUTEINFOW shExInfo = {0}; - shExInfo.cbSize = sizeof(shExInfo); - shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; - shExInfo.lpVerb = L"open"; - shExInfo.lpFile = Path; - shExInfo.lpParameters = L""; - shExInfo.nShow = SW_SHOW; - - if (InfoArray[iAppId].IType == INSTALLER_GENERATE) - { - params = L"/" + CStringW(CMD_KEY_GENINST) + L" \"" + - InfoArray[iAppId].szPackageName + L"\" \"" + - CStringW(shExInfo.lpFile) + L"\""; - shExInfo.lpParameters = params; - shExInfo.lpFile = app.GetBuffer(MAX_PATH); - GetModuleFileNameW(NULL, const_cast(shExInfo.lpFile), MAX_PATH); - app.ReleaseBuffer(); - } - - /* FIXME: Do we want to log installer status? */ - WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, InfoArray[iAppId].szName); - - if (ShellExecuteExW(&shExInfo)) - { - // reflect installation progress in the titlebar - // TODO: make a separate string with a placeholder to include app name? - CStringW szMsgText = LoadStatusString(DLSTATUS_INSTALLING); - if (!IsWindow(hDlg)) - goto end; - SetWindowTextW(hDlg, szMsgText.GetString()); - - DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_INSTALLING); - - // TODO: issue an install operation separately so that the apps could be downloaded in the background - WaitForSingleObject(shExInfo.hProcess, INFINITE); - CloseHandle(shExInfo.hProcess); - } - else - { - ShowLastError(hMainWnd, FALSE, GetLastError()); - } - } - - end: - if (hOut != INVALID_HANDLE_VALUE) - CloseHandle(hOut); - - if (hFile) - InternetCloseHandle(hFile); - InternetCloseHandle(hOpen); - - if (bTempfile) - { - if (bCancelled || (SettingsInfo.bDelInstaller && (InfoArray[iAppId].DLType == DLTYPE_APPLICATION))) - DeleteFileW(Path); - } - - if (!IsWindow(hDlg)) - return 0; - DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_FINISHED); } - delete static_cast(param); - if (!IsWindow(hDlg)) - return 0; - SendMessageW(hDlg, WM_CLOSE, 0, 0); - return 0; -} +run: + SendMessageW(hDlg, WM_SETSTATUS, DLSTATUS_WAITING_INSTALL, 0); -// TODO: Reuse the dialog -VOID -CDownloadManager::LaunchDownloadDialog(BOOL bIsModal) -{ - CDownloadManager::bModal = bIsModal; - if (bIsModal) + // run it + if (Info.DLType == DLTYPE_APPLICATION) { - DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), hMainWnd, DownloadDlgProc); + CStringW app, params; + SHELLEXECUTEINFOW shExInfo = {0}; + shExInfo.cbSize = sizeof(shExInfo); + shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + shExInfo.lpVerb = L"open"; + shExInfo.lpFile = Path; + shExInfo.lpParameters = L""; + shExInfo.nShow = SW_SHOW; + + if (Info.IType == INSTALLER_GENERATE) + { + params = L"/" + CStringW(CMD_KEY_GENINST) + L" \"" + + Info.szPackageName + L"\" \"" + + CStringW(shExInfo.lpFile) + L"\""; + shExInfo.lpParameters = params; + shExInfo.lpFile = app.GetBuffer(MAX_PATH); + GetModuleFileNameW(NULL, const_cast(shExInfo.lpFile), MAX_PATH); + app.ReleaseBuffer(); + } + + /* FIXME: Do we want to log installer status? */ + WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, Info.szName); + + if (ShellExecuteExW(&shExInfo)) + { + // reflect installation progress in the titlebar + // TODO: make a separate string with a placeholder to include app name? + CStringW szMsgText = LoadStatusString(DLSTATUS_INSTALLING); + SetWindowTextW(hDlg, szMsgText); + + SendMessageW(hDlg, WM_SETSTATUS, DLSTATUS_INSTALLING, 0); + + // TODO: issue an install operation separately so that the apps could be downloaded in the background + WaitForSingleObject(shExInfo.hProcess, INFINITE); + CloseHandle(shExInfo.hProcess); + } + else + { + ShowLastError(hMainWnd, FALSE, GetLastError()); + } } - else + +end: + if (hOut != INVALID_HANDLE_VALUE) + CloseHandle(hOut); + + if (hFile) + InternetCloseHandle(hFile); + InternetCloseHandle(hOpen); + + if (bTempfile) { - CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), hMainWnd, DownloadDlgProc); + if (bCancelled || (SettingsInfo.bDelInstaller && Info.DLType == DLTYPE_APPLICATION)) + DeleteFileW(Path); } + + SendMessageW(hDlg, WM_SETSTATUS, DLSTATUS_FINISHED, 0); } -// CDownloadManager BOOL DownloadListOfApplications(const CAtlList &AppsList, BOOL bIsModal) @@ -1127,35 +1124,44 @@ DownloadListOfApplications(const CAtlList &AppsList, BOOL bIsModal) if (AppsList.IsEmpty()) return FALSE; - POSITION CurrentListPosition = AppsList.GetHeadPosition(); - while (CurrentListPosition) + CComPtr pDM; + if (!CDownloadManager::CreateInstance(bIsModal, pDM)) + return FALSE; + + for (POSITION it = AppsList.GetHeadPosition(); it;) { - const CAppInfo *Info = AppsList.GetNext(CurrentListPosition); - CDownloadManager::Add(DownloadInfo(*Info)); + const CAppInfo *Info = AppsList.GetNext(it); + pDM->Add(DownloadInfo(*Info)); } - - // Create a dialog and issue a download process - CDownloadManager::LaunchDownloadDialog(bIsModal); - + pDM->Show(); return TRUE; } BOOL DownloadApplication(CAppInfo *pAppInfo) { + const bool bModal = false; if (!pAppInfo) return FALSE; - CDownloadManager::Download(*pAppInfo, FALSE); - return TRUE; + CAtlList list; + list.AddTail(pAppInfo); + return DownloadListOfApplications(list, bModal); } VOID DownloadApplicationsDB(LPCWSTR lpUrl, BOOL IsOfficial) { - static DownloadInfo DatabaseDLInfo; + const bool bModal = true; + CComPtr pDM; + if (!CDownloadManager::CreateInstance(bModal, pDM)) + return; + + DownloadInfo DatabaseDLInfo; DatabaseDLInfo.szUrl = lpUrl; DatabaseDLInfo.szName.LoadStringW(IDS_DL_DIALOG_DB_DISP); DatabaseDLInfo.DLType = IsOfficial ? DLTYPE_DBUPDATE : DLTYPE_DBUPDATE_UNOFFICIAL; - CDownloadManager::Download(DatabaseDLInfo, TRUE); + + pDM->Add(DatabaseDLInfo); + pDM->Show(); }