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