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