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