[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 */
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;
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 = NULL;
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
266 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
267 if (!hOpen) goto end;
268
269 hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_KEEP_CONNECTION, 0);
270 if(!hFile) goto end;
271
272 hOut = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
273 if (hOut == INVALID_HANDLE_VALUE) goto end;
274
275 HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwBufLen, 0);
276
277 do
278 {
279 if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead)) goto end;
280 if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL)) goto end;
281 dwCurrentBytesRead += dwBytesRead;
282 IBindStatusCallback_OnProgress(dl, dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload);
283 }
284 while (dwBytesRead);
285
286 CloseHandle(hOut);
287 if (dl) IBindStatusCallback_Release(dl);
288 if (bCancelled) goto end;
289
290 ShowWindow(Dlg, SW_HIDE);
291
292 /* run it */
293 if (!bCab)
294 {
295 ShellExecute( NULL, L"open", path, NULL, NULL, SW_SHOWNORMAL );
296 }
297 end:
298 CloseHandle(hOut);
299 InternetCloseHandle(hFile);
300 InternetCloseHandle(hOpen);
301
302 if (bTempfile)
303 {
304 if (bCancelled || (SettingsInfo.bDelInstaller && !bCab))
305 DeleteFileW(path);
306 }
307
308 EndDialog(Dlg, 0);
309
310 return 0;
311 }
312
313 static
314 INT_PTR CALLBACK
315 DownloadDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
316 {
317 HANDLE Thread;
318 DWORD ThreadId;
319 HWND Item;
320
321 switch (Msg)
322 {
323 case WM_INITDIALOG:
324
325 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
326 if (hIcon)
327 {
328 SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
329 SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
330 }
331
332 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0);
333 Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS);
334 if (Item)
335 {
336 SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
337 SendMessageW(Item, PBM_SETPOS, 0, 0);
338 }
339
340 Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
341 if (!Thread) return FALSE;
342 CloseHandle(Thread);
343 return TRUE;
344
345 case WM_COMMAND:
346 if (wParam == IDCANCEL)
347 {
348 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1);
349 PostMessageW(Dlg, WM_CLOSE, 0, 0);
350 }
351 return FALSE;
352
353 case WM_CLOSE:
354 if (hIcon) DestroyIcon(hIcon);
355 EndDialog(Dlg, 0);
356 return TRUE;
357
358 default:
359 return FALSE;
360 }
361 }
362
363 BOOL
364 DownloadApplication(INT Index)
365 {
366 if (!IS_AVAILABLE_ENUM(SelectedEnumType))
367 return FALSE;
368
369 AppInfo = (PAPPLICATION_INFO) ListViewGetlParam(Index);
370 if (!AppInfo) return FALSE;
371
372 WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, AppInfo->szName);
373
374 DialogBoxW(hInst,
375 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
376 hMainWnd,
377 DownloadDlgProc);
378
379 return TRUE;
380 }
381
382 VOID
383 DownloadApplicationsDB(LPWSTR lpUrl)
384 {
385 APPLICATION_INFO IntInfo;
386
387 ZeroMemory(&IntInfo, sizeof(APPLICATION_INFO));
388 if (FAILED(StringCbCopyW(IntInfo.szUrlDownload,
389 sizeof(IntInfo.szUrlDownload),
390 lpUrl)))
391 {
392 return;
393 }
394
395 AppInfo = &IntInfo;
396
397 DialogBoxW(hInst,
398 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
399 hMainWnd,
400 DownloadDlgProc);
401 }
402