36f4932e24d4459ca4045946f1ed565b692662f2
[reactos.git] / reactos / base / applications / rapps / loaddlg.cpp
1 /* PROJECT: ReactOS Applications Manager
2 * LICENSE: GPL - See COPYING in the top level directory
3 * FILE: base/applications/rapps/loaddlg.cpp
4 * PURPOSE: Displaying a download dialog
5 * COPYRIGHT: Copyright 2001 John R. Sheets (for CodeWeavers)
6 * Copyright 2004 Mike McCormack (for CodeWeavers)
7 * Copyright 2005 Ge van Geldorp (gvg@reactos.org)
8 * Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
9 * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
10 */
11 /*
12 * Based on Wine dlls/shdocvw/shdocvw_main.c
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 */
28
29 #include "rapps.h"
30
31 #include <shlobj_undoc.h>
32 #include <shlguid_undoc.h>
33
34 #include <atlbase.h>
35 #include <atlcom.h>
36 #include <wininet.h>
37 #include <shellutils.h>
38 #include <windowsx.h>
39
40 static PAPPLICATION_INFO AppInfo;
41
42 class CDownloadDialog :
43 public CComObjectRootEx<CComMultiThreadModelNoCS>,
44 public IBindStatusCallback
45 {
46 HWND m_hDialog;
47 PBOOL m_pbCancelled;
48 BOOL m_UrlHasBeenCopied;
49 WCHAR m_ProgressText[MAX_PATH];
50
51
52 public:
53 ~CDownloadDialog()
54 {
55 DestroyWindow(m_hDialog);
56 }
57
58 HRESULT Initialize(HWND Dlg, BOOL *pbCancelled)
59 {
60 m_hDialog = Dlg;
61 m_pbCancelled = pbCancelled;
62 m_UrlHasBeenCopied = FALSE;
63 return S_OK;
64 }
65
66 virtual HRESULT STDMETHODCALLTYPE OnStartBinding(
67 DWORD dwReserved,
68 IBinding *pib)
69 {
70 return S_OK;
71 }
72
73 virtual HRESULT STDMETHODCALLTYPE GetPriority(
74 LONG *pnPriority)
75 {
76 return S_OK;
77 }
78
79 virtual HRESULT STDMETHODCALLTYPE OnLowResource(
80 DWORD reserved)
81 {
82 return S_OK;
83 }
84
85 virtual HRESULT STDMETHODCALLTYPE OnProgress(
86 ULONG ulProgress,
87 ULONG ulProgressMax,
88 ULONG ulStatusCode,
89 LPCWSTR szStatusText)
90 {
91 HWND Item;
92 LONG r;
93
94 Item = GetDlgItem(m_hDialog, IDC_DOWNLOAD_PROGRESS);
95 if (Item && ulProgressMax)
96 {
97 WCHAR szProgress[100];
98 WCHAR szProgressMax[100];
99 UINT uiPercentage = ((ULONGLONG)ulProgress * 100) / ulProgressMax;
100
101 /* send the current progress to the progress bar */
102 SendMessageW(Item, PBM_SETPOS, uiPercentage, 0);
103
104 /* format the bits and bytes into pretty and accessible units... */
105 StrFormatByteSizeW(ulProgress, szProgress, _countof(szProgress));
106 StrFormatByteSizeW(ulProgressMax, szProgressMax, _countof(szProgressMax));
107
108 /* ...and post all of it to our subclassed progress bar text subroutine */
109 StringCbPrintfW(m_ProgressText,
110 sizeof(m_ProgressText),
111 L"%u%% \x2014 %ls / %ls",
112 uiPercentage,
113 szProgress,
114 szProgressMax);
115 SendMessageW(Item, WM_SETTEXT, 0, (LPARAM)m_ProgressText);
116 }
117
118 Item = GetDlgItem(m_hDialog, IDC_DOWNLOAD_STATUS);
119 if (Item && szStatusText && wcslen(szStatusText) > 0 && m_UrlHasBeenCopied == FALSE)
120 {
121 DWORD len = wcslen(szStatusText) + 1;
122 PWSTR buf = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
123
124 if (buf)
125 {
126 /* beautify our url for display purposes */
127 InternetCanonicalizeUrl(szStatusText, buf, &len, ICU_DECODE | ICU_NO_ENCODE);
128 }
129 else
130 {
131 /* just use the original */
132 buf = (PWSTR)szStatusText;
133 }
134
135 /* paste it into our dialog and don't do it again in this instance */
136 SendMessageW(Item, WM_SETTEXT, 0, (LPARAM)buf);
137 m_UrlHasBeenCopied = TRUE;
138
139 if (buf != szStatusText)
140 {
141 HeapFree(GetProcessHeap(), 0, buf);
142 }
143 }
144
145 SetLastError(0);
146 r = GetWindowLongPtrW(m_hDialog, GWLP_USERDATA);
147 if (0 != r || 0 != GetLastError())
148 {
149 *m_pbCancelled = TRUE;
150 return E_ABORT;
151 }
152
153 return S_OK;
154 }
155
156 virtual HRESULT STDMETHODCALLTYPE OnStopBinding(
157 HRESULT hresult,
158 LPCWSTR szError)
159 {
160 return S_OK;
161 }
162
163 virtual HRESULT STDMETHODCALLTYPE GetBindInfo(
164 DWORD *grfBINDF,
165 BINDINFO *pbindinfo)
166 {
167 return S_OK;
168 }
169
170 virtual HRESULT STDMETHODCALLTYPE OnDataAvailable(
171 DWORD grfBSCF,
172 DWORD dwSize,
173 FORMATETC *pformatetc,
174 STGMEDIUM *pstgmed)
175 {
176 return S_OK;
177 }
178
179 virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(
180 REFIID riid,
181 IUnknown *punk)
182 {
183 return S_OK;
184 }
185
186 BEGIN_COM_MAP(CDownloadDialog)
187 COM_INTERFACE_ENTRY_IID(IID_IBindStatusCallback, IBindStatusCallback)
188 END_COM_MAP()
189 };
190
191 extern "C"
192 HRESULT WINAPI CDownloadDialog_Constructor(HWND Dlg, BOOL *pbCancelled, REFIID riid, LPVOID *ppv)
193 {
194 return ShellObjectCreatorInit<CDownloadDialog>(Dlg, pbCancelled, riid, ppv);
195 }
196
197 #ifdef USE_CERT_PINNING
198 static BOOL CertIsValid(HINTERNET hInternet, LPWSTR lpszHostName)
199 {
200 HINTERNET hConnect;
201 HINTERNET hRequest;
202 DWORD certInfoLength;
203 BOOL Ret = FALSE;
204 INTERNET_CERTIFICATE_INFOW certInfo;
205
206 hConnect = InternetConnectW(hInternet, lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, INTERNET_FLAG_SECURE, 0);
207 if (hConnect)
208 {
209 hRequest = HttpOpenRequestW(hConnect, L"HEAD", NULL, NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0);
210 if (hRequest != NULL)
211 {
212 Ret = HttpSendRequestW(hRequest, L"", 0, NULL, 0);
213 if (Ret)
214 {
215 certInfoLength = sizeof(certInfo);
216 Ret = InternetQueryOptionW(hRequest,
217 INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
218 &certInfo,
219 &certInfoLength);
220 if (Ret)
221 {
222 if (certInfo.lpszEncryptionAlgName)
223 LocalFree(certInfo.lpszEncryptionAlgName);
224 if (certInfo.lpszIssuerInfo)
225 {
226 if (strcmp((LPSTR)certInfo.lpszIssuerInfo, CERT_ISSUER_INFO) != 0)
227 Ret = FALSE;
228 LocalFree(certInfo.lpszIssuerInfo);
229 }
230 if (certInfo.lpszProtocolName)
231 LocalFree(certInfo.lpszProtocolName);
232 if (certInfo.lpszSignatureAlgName)
233 LocalFree(certInfo.lpszSignatureAlgName);
234 if (certInfo.lpszSubjectInfo)
235 {
236 if (strcmp((LPSTR)certInfo.lpszSubjectInfo, CERT_SUBJECT_INFO) != 0)
237 Ret = FALSE;
238 LocalFree(certInfo.lpszSubjectInfo);
239 }
240 }
241 }
242 InternetCloseHandle(hRequest);
243 }
244 InternetCloseHandle(hConnect);
245 }
246 return Ret;
247 }
248 #endif
249
250
251 static
252 DWORD WINAPI
253 ThreadFunc(LPVOID Context)
254 {
255 CComPtr<IBindStatusCallback> dl;
256 WCHAR path[MAX_PATH];
257 PWSTR p, q;
258 HWND Dlg = (HWND) Context;
259 ULONG dwContentLen, dwBytesWritten, dwBytesRead, dwStatus;
260 ULONG dwCurrentBytesRead = 0;
261 ULONG dwStatusLen = sizeof(dwStatus);
262 BOOL bCancelled = FALSE;
263 BOOL bTempfile = FALSE;
264 BOOL bCab = FALSE;
265 HINTERNET hOpen = NULL;
266 HINTERNET hFile = NULL;
267 HANDLE hOut = INVALID_HANDLE_VALUE;
268 unsigned char lpBuffer[4096];
269 PCWSTR lpszAgent = L"RApps/1.0";
270 URL_COMPONENTS urlComponents;
271 size_t urlLength, filenameLength;
272
273 /* build the path for the download */
274 p = wcsrchr(AppInfo->szUrlDownload, L'/');
275 q = wcsrchr(AppInfo->szUrlDownload, L'?');
276
277 /* do we have a final slash separator? */
278 if (!p)
279 goto end;
280
281 /* prepare the tentative length of the filename, maybe we've to remove part of it later on */
282 filenameLength = wcslen(p) * sizeof(WCHAR);
283
284 /* do we have query arguments in the target URL after the filename? account for them
285 (e.g. https://example.org/myfile.exe?no_adware_plz) */
286 if (q && q > p && (q - p) > 0)
287 filenameLength -= wcslen(q - 1) * sizeof(WCHAR);
288
289 /* is this URL an update package for RAPPS? if so store it in a different place */
290 if (wcscmp(AppInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0)
291 {
292 bCab = TRUE;
293 if (!GetStorageDirectory(path, _countof(path)))
294 goto end;
295 }
296 else
297 {
298 if (FAILED(StringCbCopyW(path, sizeof(path), SettingsInfo.szDownloadDir)))
299 goto end;
300 }
301
302 /* is the path valid? can we access it? */
303 if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
304 {
305 if (!CreateDirectoryW(path, NULL))
306 goto end;
307 }
308
309 /* append a \ to the provided file system path, and the filename portion from the URL after that */
310 if (FAILED(StringCbCatW(path, sizeof(path), L"\\")))
311 goto end;
312 if (FAILED(StringCbCatNW(path, sizeof(path), p + 1, filenameLength)))
313 goto end;
314
315 if (!bCab && AppInfo->szSHA1[0] != 0 && GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
316 {
317 /* only open it in case of total correctness */
318 if (VerifyInteg(AppInfo->szSHA1, path))
319 goto run;
320 }
321
322 /* download it */
323 bTempfile = TRUE;
324 CDownloadDialog_Constructor(Dlg, &bCancelled, IID_PPV_ARG(IBindStatusCallback, &dl));
325
326 if (dl == NULL)
327 goto end;
328
329 /* FIXME: this should just be using the system-wide proxy settings */
330 switch(SettingsInfo.Proxy)
331 {
332 case 0: /* preconfig */
333 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
334 break;
335 case 1: /* direct (no proxy) */
336 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
337 break;
338 case 2: /* use proxy */
339 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PROXY, SettingsInfo.szProxyServer, SettingsInfo.szNoProxyFor, 0);
340 break;
341 default: /* preconfig */
342 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
343 break;
344 }
345
346 if (!hOpen)
347 goto end;
348
349 hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_KEEP_CONNECTION, 0);
350 if (!hFile)
351 {
352 WCHAR szMsgText[MAX_STR_LEN];
353
354 if (!LoadStringW(hInst, IDS_UNABLE_TO_DOWNLOAD2, szMsgText, _countof(szMsgText)))
355 goto end;
356
357 MessageBoxW(hMainWnd, szMsgText, NULL, MB_OK | MB_ICONERROR);
358 goto end;
359 }
360
361 if (!HttpQueryInfoW(hFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatus, &dwStatusLen, NULL))
362 goto end;
363
364 if(dwStatus != HTTP_STATUS_OK)
365 {
366 WCHAR szMsgText[MAX_STR_LEN];
367
368 if (!LoadStringW(hInst, IDS_UNABLE_TO_DOWNLOAD, szMsgText, _countof(szMsgText)))
369 goto end;
370
371 MessageBoxW(hMainWnd, szMsgText, NULL, MB_OK | MB_ICONERROR);
372 goto end;
373 }
374
375 dwStatusLen = sizeof(dwStatus);
376
377 memset(&urlComponents, 0, sizeof(urlComponents));
378 urlComponents.dwStructSize = sizeof(urlComponents);
379
380 if(FAILED(StringCbLengthW(AppInfo->szUrlDownload, sizeof(AppInfo->szUrlDownload), &urlLength)))
381 goto end;
382
383 urlLength /= sizeof(WCHAR);
384 urlComponents.dwSchemeLength = urlLength + 1;
385 urlComponents.lpszScheme = (LPWSTR)malloc(urlComponents.dwSchemeLength * sizeof(WCHAR));
386 urlComponents.dwHostNameLength = urlLength + 1;
387 urlComponents.lpszHostName = (LPWSTR)malloc(urlComponents.dwHostNameLength * sizeof(WCHAR));
388
389 if(!InternetCrackUrlW(AppInfo->szUrlDownload, urlLength+1, ICU_DECODE | ICU_ESCAPE, &urlComponents))
390 goto end;
391
392 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
393 HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatus, 0);
394
395 if(urlComponents.nScheme == INTERNET_SCHEME_FTP)
396 dwContentLen = FtpGetFileSize(hFile, &dwStatus);
397
398 #ifdef USE_CERT_PINNING
399 /* are we using HTTPS to download the RAPPS update package? check if the certificate is original */
400 if ((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) &&
401 (wcscmp(AppInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0) &&
402 (!CertIsValid(hOpen, urlComponents.lpszHostName)))
403 {
404 WCHAR szMsgText[MAX_STR_LEN];
405
406 if (!LoadStringW(hInst, IDS_CERT_DOES_NOT_MATCH, szMsgText, _countof(szMsgText)))
407 goto end;
408
409 MessageBoxW(Dlg, szMsgText, NULL, MB_OK | MB_ICONERROR);
410 goto end;
411 }
412 #endif
413
414 free(urlComponents.lpszScheme);
415 free(urlComponents.lpszHostName);
416
417 hOut = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
418
419 if (hOut == INVALID_HANDLE_VALUE)
420 goto end;
421
422 do
423 {
424 if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead))
425 {
426 WCHAR szMsgText[MAX_STR_LEN];
427
428 if (!LoadStringW(hInst, IDS_INTERRUPTED_DOWNLOAD, szMsgText, _countof(szMsgText)))
429 goto end;
430
431 MessageBoxW(hMainWnd, szMsgText, NULL, MB_OK | MB_ICONERROR);
432 goto end;
433 }
434 if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL))
435 {
436 WCHAR szMsgText[MAX_STR_LEN];
437
438 if (!LoadStringW(hInst, IDS_UNABLE_TO_WRITE, szMsgText, _countof(szMsgText)))
439 goto end;
440
441 MessageBoxW(hMainWnd, szMsgText, NULL, MB_OK | MB_ICONERROR);
442 goto end;
443 }
444 dwCurrentBytesRead += dwBytesRead;
445 dl->OnProgress(dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload);
446 }
447 while (dwBytesRead && !bCancelled);
448
449 CloseHandle(hOut);
450 hOut = INVALID_HANDLE_VALUE;
451
452 if (bCancelled)
453 goto end;
454
455 /* if this thing isn't a RAPPS update and it has a SHA-1 checksum
456 verify its integrity by using the native advapi32.A_SHA1 functions */
457 if (!bCab && AppInfo->szSHA1[0] != 0)
458 {
459 WCHAR szMsgText[MAX_STR_LEN];
460
461 /* change a few strings in the download dialog to reflect the verification process */
462 LoadStringW(hInst, IDS_INTEG_CHECK_TITLE, szMsgText, _countof(szMsgText));
463
464 SetWindowText(Dlg, szMsgText);
465 SendMessageW(GetDlgItem(Dlg, IDC_DOWNLOAD_STATUS), WM_SETTEXT, 0, (LPARAM)path);
466
467 /* this may take a while, depending on the file size */
468 if (!VerifyInteg(AppInfo->szSHA1, path))
469 {
470 if (!LoadStringW(hInst, IDS_INTEG_CHECK_FAIL, szMsgText, _countof(szMsgText)))
471 goto end;
472
473 MessageBoxW(Dlg, szMsgText, NULL, MB_OK | MB_ICONERROR);
474 goto end;
475 }
476 }
477
478 ShowWindow(Dlg, SW_HIDE);
479
480 run:
481 /* run it */
482 if (!bCab)
483 ShellExecuteW( NULL, L"open", path, NULL, NULL, SW_SHOWNORMAL );
484
485 end:
486 if (hOut != INVALID_HANDLE_VALUE)
487 CloseHandle(hOut);
488
489 InternetCloseHandle(hFile);
490 InternetCloseHandle(hOpen);
491
492 if (bTempfile)
493 {
494 if (bCancelled || (SettingsInfo.bDelInstaller && !bCab))
495 DeleteFileW(path);
496 }
497
498 EndDialog(Dlg, 0);
499
500 return 0;
501 }
502
503
504 LRESULT CALLBACK
505 DownloadProgressProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
506 {
507 static WCHAR szProgressText[MAX_STR_LEN] = {0};
508
509 switch (uMsg)
510 {
511 case WM_SETTEXT:
512 {
513 if (lParam)
514 {
515 StringCbCopyW(szProgressText,
516 sizeof(szProgressText),
517 (PCWSTR)lParam);
518 }
519 return TRUE;
520 }
521
522 case WM_ERASEBKGND:
523 case WM_PAINT:
524 {
525 PAINTSTRUCT ps;
526 HDC hDC = BeginPaint(hWnd, &ps), hdcMem;
527 HBITMAP hbmMem;
528 HANDLE hOld;
529 RECT myRect;
530 UINT win_width, win_height;
531
532 GetClientRect(hWnd, &myRect);
533
534 /* grab the progress bar rect size */
535 win_width = myRect.right - myRect.left;
536 win_height = myRect.bottom - myRect.top;
537
538 /* create an off-screen DC for double-buffering */
539 hdcMem = CreateCompatibleDC(hDC);
540 hbmMem = CreateCompatibleBitmap(hDC, win_width, win_height);
541
542 hOld = SelectObject(hdcMem, hbmMem);
543
544 /* call the original draw code and redirect it to our memory buffer */
545 DefSubclassProc(hWnd, uMsg, (WPARAM)hdcMem, lParam);
546
547 /* draw our nifty progress text over it */
548 SelectFont(hdcMem, GetStockFont(DEFAULT_GUI_FONT));
549 DrawShadowText(hdcMem, szProgressText, wcslen(szProgressText),
550 &myRect,
551 DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE,
552 GetSysColor(COLOR_CAPTIONTEXT),
553 GetSysColor(COLOR_3DSHADOW),
554 1, 1);
555
556 /* transfer the off-screen DC to the screen */
557 BitBlt(hDC, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY);
558
559 /* free the off-screen DC */
560 SelectObject(hdcMem, hOld);
561 DeleteObject(hbmMem);
562 DeleteDC(hdcMem);
563
564 EndPaint(hWnd, &ps);
565 return 0;
566 }
567
568 /* Raymond Chen says that we should safely unsubclass all the things!
569 (http://blogs.msdn.com/b/oldnewthing/archive/2003/11/11/55653.aspx) */
570 case WM_NCDESTROY:
571 {
572 ZeroMemory(szProgressText, sizeof(szProgressText));
573 RemoveWindowSubclass(hWnd, DownloadProgressProc, uIdSubclass);
574 }
575 /* Fall-through */
576 default:
577 return DefSubclassProc(hWnd, uMsg, wParam, lParam);
578 }
579 }
580
581 static
582 INT_PTR CALLBACK
583 DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
584 {
585 HANDLE Thread;
586 DWORD ThreadId;
587 HWND Item;
588
589 switch (uMsg)
590 {
591 case WM_INITDIALOG:
592 {
593 HICON hIconSm = NULL, hIconBg = NULL;
594
595 hIconBg = (HICON)GetClassLongPtr(hMainWnd, GCLP_HICON);
596 hIconSm = (HICON)GetClassLongPtr(hMainWnd, GCLP_HICONSM);
597
598 if (hIconBg && hIconSm)
599 {
600 SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) hIconBg);
601 SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSm);
602 }
603
604 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0);
605 Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS);
606 if (Item)
607 {
608 /* initialize the default values for our nifty progress bar
609 and subclass it so that it learns to print a status text */
610 SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
611 SendMessageW(Item, PBM_SETPOS, 0, 0);
612
613 SetWindowSubclass(Item, DownloadProgressProc, 0, 0);
614 }
615
616 /* add a neat placeholder until the download URL is retrieved */
617 Item = GetDlgItem(Dlg, IDC_DOWNLOAD_STATUS);
618 SendMessageW(Item, WM_SETTEXT, 0, (LPARAM)L"\x2022 \x2022 \x2022");
619
620 Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
621 if (!Thread)
622 return FALSE;
623 CloseHandle(Thread);
624 return TRUE;
625 }
626 case WM_COMMAND:
627 if (wParam == IDCANCEL)
628 {
629 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1);
630 PostMessageW(Dlg, WM_CLOSE, 0, 0);
631 }
632 return FALSE;
633
634 case WM_CLOSE:
635 EndDialog(Dlg, 0);
636 return TRUE;
637
638 default:
639 return FALSE;
640 }
641 }
642
643 BOOL
644 DownloadApplication(INT Index)
645 {
646 if (!IS_AVAILABLE_ENUM(SelectedEnumType))
647 return FALSE;
648
649 AppInfo = (PAPPLICATION_INFO) ListViewGetlParam(Index);
650 if (!AppInfo) return FALSE;
651
652 WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, AppInfo->szName);
653
654 DialogBoxW(hInst,
655 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
656 hMainWnd,
657 DownloadDlgProc);
658
659 return TRUE;
660 }
661
662 VOID
663 DownloadApplicationsDB(LPCWSTR lpUrl)
664 {
665 APPLICATION_INFO IntInfo;
666
667 ZeroMemory(&IntInfo, sizeof(IntInfo));
668 if (FAILED(StringCbCopyW(IntInfo.szUrlDownload,
669 sizeof(IntInfo.szUrlDownload),
670 lpUrl)))
671 {
672 return;
673 }
674
675 AppInfo = &IntInfo;
676
677 DialogBoxW(hInst,
678 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
679 hMainWnd,
680 DownloadDlgProc);
681 }
682