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