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