[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, dwCurrentBytesRead;
213 DWORD dwBufLen = sizeof(dwContentLen);
214 BOOL bCancelled = FALSE;
215 BOOL bTempfile = FALSE;
216 BOOL bCab = FALSE;
217 HINTERNET hOpen = NULL;
218 HINTERNET hFile = NULL;
219 HANDLE hOut = NULL;
220 unsigned char lpBuffer[4096];
221 const LPWSTR lpszAgent = L"RApps/1.0";
222
223 /* built the path for the download */
224 p = wcsrchr(AppInfo->szUrlDownload, L'/');
225 if (!p) goto end;
226
227 len = wcslen(AppInfo->szUrlDownload);
228 if (len > 4)
229 {
230 if (AppInfo->szUrlDownload[len - 4] == '.' &&
231 AppInfo->szUrlDownload[len - 3] == 'c' &&
232 AppInfo->szUrlDownload[len - 2] == 'a' &&
233 AppInfo->szUrlDownload[len - 1] == 'b')
234 {
235 bCab = TRUE;
236 if (!GetStorageDirectory(path, sizeof(path) / sizeof(path[0])))
237 goto end;
238 }
239 else
240 {
241 if (FAILED(StringCbCopyW(path, sizeof(path),
242 SettingsInfo.szDownloadDir)))
243 {
244 goto end;
245 }
246 }
247 }
248 else goto end;
249
250 if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
251 {
252 if (!CreateDirectoryW(path, NULL))
253 goto end;
254 }
255
256 if (FAILED(StringCbCatW(path, sizeof(path), L"\\")))
257 goto end;
258 if (FAILED(StringCbCatW(path, sizeof(path), p + 1)))
259 goto end;
260
261 /* download it */
262 bTempfile = TRUE;
263 dl = CreateDl(Context, &bCancelled);
264
265 hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
266 if (!hOpen) goto end;
267
268 hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_KEEP_CONNECTION, 0);
269 if(!hFile) goto end;
270
271 hOut = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
272 if (hOut == INVALID_HANDLE_VALUE) goto end;
273
274 HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwBufLen, 0);
275
276 do
277 {
278 if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead)) goto end;
279 if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL)) goto end;
280 dwCurrentBytesRead += dwBytesRead;
281 IBindStatusCallback_OnProgress(dl, dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload);
282 }
283 while (dwBytesRead);
284
285 CloseHandle(hOut);
286 if (dl) IBindStatusCallback_Release(dl);
287 if (bCancelled) goto end;
288
289 ShowWindow(Dlg, SW_HIDE);
290
291 /* run it */
292 if (!bCab)
293 {
294 ShellExecute( NULL, L"open", path, NULL, NULL, SW_SHOWNORMAL );
295 }
296 end:
297 CloseHandle(hOut);
298 InternetCloseHandle(hFile);
299 InternetCloseHandle(hOpen);
300
301 if (bTempfile)
302 {
303 if (bCancelled || (SettingsInfo.bDelInstaller && !bCab))
304 DeleteFileW(path);
305 }
306
307 EndDialog(Dlg, 0);
308
309 return 0;
310 }
311
312 static
313 INT_PTR CALLBACK
314 DownloadDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
315 {
316 HANDLE Thread;
317 DWORD ThreadId;
318 HWND Item;
319
320 switch (Msg)
321 {
322 case WM_INITDIALOG:
323
324 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
325 if (hIcon)
326 {
327 SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
328 SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
329 }
330
331 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0);
332 Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS);
333 if (Item)
334 {
335 SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
336 SendMessageW(Item, PBM_SETPOS, 0, 0);
337 }
338
339 Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
340 if (!Thread) return FALSE;
341 CloseHandle(Thread);
342 return TRUE;
343
344 case WM_COMMAND:
345 if (wParam == IDCANCEL)
346 {
347 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1);
348 PostMessageW(Dlg, WM_CLOSE, 0, 0);
349 }
350 return FALSE;
351
352 case WM_CLOSE:
353 if (hIcon) DestroyIcon(hIcon);
354 EndDialog(Dlg, 0);
355 return TRUE;
356
357 default:
358 return FALSE;
359 }
360 }
361
362 BOOL
363 DownloadApplication(INT Index)
364 {
365 if (!IS_AVAILABLE_ENUM(SelectedEnumType))
366 return FALSE;
367
368 AppInfo = (PAPPLICATION_INFO) ListViewGetlParam(Index);
369 if (!AppInfo) return FALSE;
370
371 WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, AppInfo->szName);
372
373 DialogBoxW(hInst,
374 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
375 hMainWnd,
376 DownloadDlgProc);
377
378 return TRUE;
379 }
380
381 VOID
382 DownloadApplicationsDB(LPWSTR lpUrl)
383 {
384 APPLICATION_INFO IntInfo;
385
386 ZeroMemory(&IntInfo, sizeof(APPLICATION_INFO));
387 if (FAILED(StringCbCopyW(IntInfo.szUrlDownload,
388 sizeof(IntInfo.szUrlDownload),
389 lpUrl)))
390 {
391 return;
392 }
393
394 AppInfo = &IntInfo;
395
396 DialogBoxW(hInst,
397 MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG),
398 hMainWnd,
399 DownloadDlgProc);
400 }
401