* Sync up to trunk head (r64716).
[reactos.git] / 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 */
10 /*
11 * Based on Wine dlls/shdocvw/shdocvw_main.c
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28 #include "rapps.h"
29 #include <wininet.h>
30 #include <shellapi.h>
31
32 static PAPPLICATION_INFO AppInfo;
33 static HICON hIcon = NULL;
34
35 typedef struct _IBindStatusCallbackImpl
36 {
37 const IBindStatusCallbackVtbl *vtbl;
38 LONG ref;
39 HWND hDialog;
40 BOOL *pbCancelled;
41 } IBindStatusCallbackImpl;
42
43 static
44 HRESULT WINAPI
45 dlQueryInterface(IBindStatusCallback* This, REFIID riid, void** ppvObject)
46 {
47 if (!ppvObject) return E_POINTER;
48
49 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IBindStatusCallback))
50 {
51 IBindStatusCallback_AddRef(This);
52 *ppvObject = This;
53 return S_OK;
54 }
55
56 return E_NOINTERFACE;
57 }
58
59 static
60 ULONG WINAPI
61 dlAddRef(IBindStatusCallback* iface)
62 {
63 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl*) iface;
64 return InterlockedIncrement(&This->ref);
65 }
66
67 static
68 ULONG WINAPI
69 dlRelease(IBindStatusCallback* iface)
70 {
71 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl*) iface;
72 DWORD ref = InterlockedDecrement(&This->ref);
73
74 if (!ref)
75 {
76 DestroyWindow(This->hDialog);
77 HeapFree(GetProcessHeap(), 0, This);
78 }
79
80 return ref;
81 }
82
83 static
84 HRESULT WINAPI
85 dlOnStartBinding(IBindStatusCallback* iface, DWORD dwReserved, IBinding* pib)
86 {
87 return S_OK;
88 }
89
90 static
91 HRESULT WINAPI
92 dlGetPriority(IBindStatusCallback* iface, LONG* pnPriority)
93 {
94 return S_OK;
95 }
96
97 static
98 HRESULT WINAPI
99 dlOnLowResource( IBindStatusCallback* iface, DWORD reserved)
100 {
101 return S_OK;
102 }
103
104 static
105 HRESULT WINAPI
106 dlOnProgress(IBindStatusCallback* iface,
107 ULONG ulProgress,
108 ULONG ulProgressMax,
109 ULONG ulStatusCode,
110 LPCWSTR szStatusText)
111 {
112 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface;
113 HWND Item;
114 LONG r;
115 WCHAR OldText[100];
116
117 Item = GetDlgItem(This->hDialog, IDC_DOWNLOAD_PROGRESS);
118 if (Item && ulProgressMax)
119 {
120 SendMessageW(Item, PBM_SETPOS, ((ULONGLONG)ulProgress * 100) / ulProgressMax, 0);
121 }
122
123 Item = GetDlgItem(This->hDialog, IDC_DOWNLOAD_STATUS);
124 if (Item && szStatusText)
125 {
126 SendMessageW(Item, WM_GETTEXT, sizeof(OldText) / sizeof(OldText[0]), (LPARAM) OldText);
127 if (sizeof(OldText) / sizeof(OldText[0]) - 1 <= wcslen(OldText) || 0 != wcscmp(OldText, szStatusText))
128 {
129 SendMessageW(Item, WM_SETTEXT, 0, (LPARAM) szStatusText);
130 }
131 }
132
133 SetLastError(0);
134 r = GetWindowLongPtrW(This->hDialog, GWLP_USERDATA);
135 if (0 != r || 0 != GetLastError())
136 {
137 *This->pbCancelled = TRUE;
138 return E_ABORT;
139 }
140
141 return S_OK;
142 }
143
144 static
145 HRESULT WINAPI
146 dlOnStopBinding(IBindStatusCallback* iface, HRESULT hresult, LPCWSTR szError)
147 {
148 return S_OK;
149 }
150
151 static
152 HRESULT WINAPI
153 dlGetBindInfo(IBindStatusCallback* iface, DWORD* grfBINDF, BINDINFO* pbindinfo)
154 {
155 return S_OK;
156 }
157
158 static
159 HRESULT WINAPI
160 dlOnDataAvailable(IBindStatusCallback* iface, DWORD grfBSCF,
161 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
162 {
163 return S_OK;
164 }
165
166 static
167 HRESULT WINAPI
168 dlOnObjectAvailable(IBindStatusCallback* iface, REFIID riid, IUnknown* punk)
169 {
170 return S_OK;
171 }
172
173 static const IBindStatusCallbackVtbl dlVtbl =
174 {
175 dlQueryInterface,
176 dlAddRef,
177 dlRelease,
178 dlOnStartBinding,
179 dlGetPriority,
180 dlOnLowResource,
181 dlOnProgress,
182 dlOnStopBinding,
183 dlGetBindInfo,
184 dlOnDataAvailable,
185 dlOnObjectAvailable
186 };
187
188 static IBindStatusCallback*
189 CreateDl(HWND Dlg, BOOL *pbCancelled)
190 {
191 IBindStatusCallbackImpl *This;
192
193 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IBindStatusCallbackImpl));
194 if (!This) return NULL;
195
196 This->vtbl = &dlVtbl;
197 This->ref = 1;
198 This->hDialog = Dlg;
199 This->pbCancelled = pbCancelled;
200
201 return (IBindStatusCallback*) This;
202 }
203
204 static
205 DWORD WINAPI
206 ThreadFunc(LPVOID Context)
207 {
208 IBindStatusCallback *dl = NULL;
209 WCHAR path[MAX_PATH];
210 LPWSTR p;
211 HWND Dlg = (HWND) Context;
212 DWORD len, dwContentLen, dwBytesWritten, dwBytesRead;
213 DWORD dwCurrentBytesRead = 0;
214 DWORD dwBufLen = sizeof(dwContentLen);
215 BOOL bCancelled = FALSE;
216 BOOL bTempfile = FALSE;
217 BOOL bCab = FALSE;
218 HINTERNET hOpen = NULL;
219 HINTERNET hFile = NULL;
220 HANDLE hOut = INVALID_HANDLE_VALUE;
221 unsigned char lpBuffer[4096];
222 const LPWSTR lpszAgent = L"RApps/1.0";
223
224 /* built the path for the download */
225 p = wcsrchr(AppInfo->szUrlDownload, L'/');
226 if (!p) goto end;
227
228 len = wcslen(AppInfo->szUrlDownload);
229 if (len > 4)
230 {
231 if (AppInfo->szUrlDownload[len - 4] == '.' &&
232 AppInfo->szUrlDownload[len - 3] == 'c' &&
233 AppInfo->szUrlDownload[len - 2] == 'a' &&
234 AppInfo->szUrlDownload[len - 1] == 'b')
235 {
236 bCab = TRUE;
237 if (!GetStorageDirectory(path, sizeof(path) / sizeof(path[0])))
238 goto end;
239 }
240 else
241 {
242 if (FAILED(StringCbCopyW(path, sizeof(path),
243 SettingsInfo.szDownloadDir)))
244 {
245 goto end;
246 }
247 }
248 }
249 else goto end;
250
251 if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
252 {
253 if (!CreateDirectoryW(path, NULL))
254 goto end;
255 }
256
257 if (FAILED(StringCbCatW(path, sizeof(path), L"\\")))
258 goto end;
259 if (FAILED(StringCbCatW(path, sizeof(path), p + 1)))
260 goto end;
261
262 /* download it */
263 bTempfile = TRUE;
264 dl = CreateDl(Context, &bCancelled);
265 if (dl == NULL) goto end;
266
267 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
268 if (!hOpen) goto end;
269
270 hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_KEEP_CONNECTION, 0);
271 if(!hFile) goto end;
272
273 hOut = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
274 if (hOut == INVALID_HANDLE_VALUE) goto end;
275
276 HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwBufLen, 0);
277
278 do
279 {
280 if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead)) goto end;
281 if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL)) goto end;
282 dwCurrentBytesRead += dwBytesRead;
283 IBindStatusCallback_OnProgress(dl, dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload);
284 }
285 while (dwBytesRead);
286
287 CloseHandle(hOut);
288 hOut = INVALID_HANDLE_VALUE;
289
290 if (bCancelled) goto end;
291
292 ShowWindow(Dlg, SW_HIDE);
293
294 /* run it */
295 if (!bCab)
296 {
297 ShellExecuteW( NULL, L"open", path, NULL, NULL, SW_SHOWNORMAL );
298 }
299 end:
300 if (hOut != INVALID_HANDLE_VALUE) CloseHandle(hOut);
301 InternetCloseHandle(hFile);
302 InternetCloseHandle(hOpen);
303
304 if (dl) IBindStatusCallback_Release(dl);
305
306 if (bTempfile)
307 {
308 if (bCancelled || (SettingsInfo.bDelInstaller && !bCab))
309 DeleteFileW(path);
310 }
311
312 EndDialog(Dlg, 0);
313
314 return 0;
315 }
316
317 static
318 INT_PTR CALLBACK
319 DownloadDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
320 {
321 HANDLE Thread;
322 DWORD ThreadId;
323 HWND Item;
324
325 switch (Msg)
326 {
327 case WM_INITDIALOG:
328
329 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
330 if (hIcon)
331 {
332 SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
333 SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
334 }
335
336 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0);
337 Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS);
338 if (Item)
339 {
340 SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
341 SendMessageW(Item, PBM_SETPOS, 0, 0);
342 }
343
344 Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
345 if (!Thread) return FALSE;
346 CloseHandle(Thread);
347 return TRUE;
348
349 case WM_COMMAND:
350 if (wParam == IDCANCEL)
351 {
352 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1);
353 PostMessageW(Dlg, WM_CLOSE, 0, 0);
354 }
355 return FALSE;
356
357 case WM_CLOSE:
358 if (hIcon) DestroyIcon(hIcon);
359 EndDialog(Dlg, 0);
360 return TRUE;
361
362 default:
363 return FALSE;
364 }
365 }
366
367 BOOL
368 DownloadApplication(INT Index)
369 {
370 if (!IS_AVAILABLE_ENUM(SelectedEnumType))
371 return FALSE;
372
373 AppInfo = (PAPPLICATION_INFO) ListViewGetlParam(Index);
374 if (!AppInfo) return FALSE;
375
376 WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, AppInfo->szName);
377
378 DialogBoxW(hInst,
379 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
380 hMainWnd,
381 DownloadDlgProc);
382
383 return TRUE;
384 }
385
386 VOID
387 DownloadApplicationsDB(LPWSTR lpUrl)
388 {
389 APPLICATION_INFO IntInfo;
390
391 ZeroMemory(&IntInfo, sizeof(APPLICATION_INFO));
392 if (FAILED(StringCbCopyW(IntInfo.szUrlDownload,
393 sizeof(IntInfo.szUrlDownload),
394 lpUrl)))
395 {
396 return;
397 }
398
399 AppInfo = &IntInfo;
400
401 DialogBoxW(hInst,
402 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
403 hMainWnd,
404 DownloadDlgProc);
405 }
406