[NTDLL]
[reactos.git] / base / applications / downloader / download.c
1 /* PROJECT: ReactOS Downloader (was GetFirefox)
2 * LICENSE: GPL - See COPYING in the top level directory
3 * FILE: base/applications/downloader/download.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 2007 Dmitry Chapyshev (lentind@yandex.ru)
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 #define COBJMACROS
29 #define WIN32_NO_STATUS
30 #include <windows.h>
31 #include <commctrl.h>
32 #include <shlobj.h>
33 #include <shlwapi.h>
34 #include <urlmon.h>
35
36 #include "resources.h"
37 #include "structures.h"
38
39 #define NDEBUG
40 #include <debug.h>
41
42 extern struct Application* SelectedApplication;
43 extern WCHAR Strings [STRING_COUNT][MAX_STRING_LENGHT];
44
45 typedef struct _IBindStatusCallbackImpl
46 {
47 const IBindStatusCallbackVtbl *vtbl;
48 LONG ref;
49 HWND hDialog;
50 BOOL *pbCancelled;
51 } IBindStatusCallbackImpl;
52
53 static HRESULT WINAPI
54 dlQueryInterface(IBindStatusCallback* This, REFIID riid, void** ppvObject)
55 {
56 if (NULL == ppvObject)
57 {
58 return E_POINTER;
59 }
60
61 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IBindStatusCallback))
62 {
63 IBindStatusCallback_AddRef( This );
64 *ppvObject = This;
65 return S_OK;
66 }
67
68 return E_NOINTERFACE;
69 }
70
71 static ULONG WINAPI
72 dlAddRef(IBindStatusCallback* iface)
73 {
74 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface;
75
76 return InterlockedIncrement(&This->ref);
77 }
78
79 static ULONG WINAPI
80 dlRelease(IBindStatusCallback* iface)
81 {
82 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface;
83 DWORD ref = InterlockedDecrement(&This->ref);
84
85 if( !ref )
86 {
87 DestroyWindow( This->hDialog );
88 HeapFree(GetProcessHeap(), 0, This);
89 }
90
91 return ref;
92 }
93
94 static HRESULT WINAPI
95 dlOnStartBinding(IBindStatusCallback* iface, DWORD dwReserved, IBinding* pib)
96 {
97 DPRINT1("OnStartBinding not implemented\n");
98
99 return S_OK;
100 }
101
102 static HRESULT WINAPI
103 dlGetPriority(IBindStatusCallback* iface, LONG* pnPriority)
104 {
105 DPRINT1("GetPriority not implemented\n");
106
107 return S_OK;
108 }
109
110 static HRESULT WINAPI
111 dlOnLowResource( IBindStatusCallback* iface, DWORD reserved)
112 {
113 DPRINT1("OnLowResource not implemented\n");
114
115 return S_OK;
116 }
117
118 static HRESULT WINAPI
119 dlOnProgress(IBindStatusCallback* iface, ULONG ulProgress,
120 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
121 {
122 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface;
123 HWND Item;
124 LONG r;
125 WCHAR OldText[100];
126
127 Item = GetDlgItem(This->hDialog, IDC_PROGRESS);
128 if (NULL != Item && 0 != ulProgressMax)
129 {
130 SendMessageW(Item, PBM_SETPOS, ((ULONGLONG)ulProgress * 100) / ulProgressMax, 0);
131 }
132
133 Item = GetDlgItem(This->hDialog, IDC_STATUS);
134 if (NULL != Item && NULL != szStatusText)
135 {
136 SendMessageW(Item, WM_GETTEXT, sizeof(OldText) / sizeof(OldText[0]),
137 (LPARAM) OldText);
138 if (sizeof(OldText) / sizeof(OldText[0]) - 1 <= wcslen(OldText) || 0 != wcscmp(OldText, szStatusText))
139 {
140 SendMessageW(Item, WM_SETTEXT, 0, (LPARAM) szStatusText);
141 }
142 }
143
144 SetLastError(0);
145 r = GetWindowLongPtrW(This->hDialog, GWLP_USERDATA);
146 if (0 != r || 0 != GetLastError())
147 {
148 *This->pbCancelled = TRUE;
149 DPRINT("Cancelled\n");
150 return E_ABORT;
151 }
152
153 return S_OK;
154 }
155
156 static HRESULT WINAPI
157 dlOnStopBinding(IBindStatusCallback* iface, HRESULT hresult, LPCWSTR szError)
158 {
159 DPRINT1("OnStopBinding not implemented\n");
160
161 return S_OK;
162 }
163
164 static HRESULT WINAPI
165 dlGetBindInfo(IBindStatusCallback* iface, DWORD* grfBINDF, BINDINFO* pbindinfo)
166 {
167 DPRINT1("GetBindInfo not implemented\n");
168
169 return S_OK;
170 }
171
172 static HRESULT WINAPI
173 dlOnDataAvailable(IBindStatusCallback* iface, DWORD grfBSCF,
174 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
175 {
176 DPRINT1("OnDataAvailable implemented\n");
177
178 return S_OK;
179 }
180
181 static HRESULT WINAPI
182 dlOnObjectAvailable(IBindStatusCallback* iface, REFIID riid, IUnknown* punk)
183 {
184 DPRINT1("OnObjectAvailable implemented\n");
185
186 return S_OK;
187 }
188
189 static const IBindStatusCallbackVtbl dlVtbl =
190 {
191 dlQueryInterface,
192 dlAddRef,
193 dlRelease,
194 dlOnStartBinding,
195 dlGetPriority,
196 dlOnLowResource,
197 dlOnProgress,
198 dlOnStopBinding,
199 dlGetBindInfo,
200 dlOnDataAvailable,
201 dlOnObjectAvailable
202 };
203
204 static IBindStatusCallback*
205 CreateDl(HWND Dlg, BOOL *pbCancelled)
206 {
207 IBindStatusCallbackImpl *This;
208
209 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IBindStatusCallbackImpl));
210 if (!This)
211 return NULL;
212
213 This->vtbl = &dlVtbl;
214 This->ref = 1;
215 This->hDialog = Dlg;
216 This->pbCancelled = pbCancelled;
217
218 return (IBindStatusCallback*) This;
219 }
220
221 static DWORD WINAPI
222 ThreadFunc(LPVOID Context)
223 {
224 //static const WCHAR szUrl[] = DownloadUrl;
225 IBindStatusCallback *dl;
226 WCHAR path[MAX_PATH];
227 LPWSTR p;
228 STARTUPINFOW si;
229 PROCESS_INFORMATION pi;
230 HWND Dlg = (HWND) Context;
231 DWORD r;
232 BOOL bCancelled = FALSE;
233 BOOL bTempfile = FALSE;
234 HKEY hKey;
235 DWORD dwSize = MAX_PATH;
236
237 /* built the path for the download */
238 p = wcsrchr(SelectedApplication->Location, L'/');
239 if (NULL == p)
240 {
241 goto end;
242 }
243
244 /* Create default download path */
245 if (GetWindowsDirectory(path, sizeof(path) / sizeof(WCHAR)))
246 {
247 WCHAR DPath[256];
248 int i;
249 for (i = 0; i < 4; i++)
250 {
251 if (i == 3)
252 {
253 DPath[i] = '\0';
254 break;
255 }
256 DPath[i] = path[i];
257 }
258 LoadString(GetModuleHandle(NULL), IDS_DOWNLOAD_FOLDER, path, sizeof(path) / sizeof(WCHAR));
259 wcscat((LPWSTR)DPath, path);
260 wcscpy(path, DPath);
261 }
262
263 if (RegOpenKey(HKEY_LOCAL_MACHINE,
264 TEXT("Software\\ReactOS\\Downloader"),
265 &hKey) == ERROR_SUCCESS)
266 {
267 if ((RegQueryValueEx(hKey,
268 L"DownloadFolder",
269 NULL,
270 NULL,
271 (LPBYTE)&path,
272 &dwSize) != ERROR_SUCCESS) && (path[0] == 0))
273 {
274 goto end;
275 }
276 }
277
278 if (GetFileAttributes(path) == 0xFFFFFFFF)
279 if (!CreateDirectory((LPCTSTR)path,NULL))
280 {
281 goto end;
282 }
283 wcscat(path, L"\\");
284 wcscat(path, p + 1);
285
286 /* download it */
287 bTempfile = TRUE;
288 dl = CreateDl(Context, &bCancelled);
289 r = URLDownloadToFileW(NULL, SelectedApplication->Location, path, 0, dl);
290 if (NULL != dl)
291 {
292 IBindStatusCallback_Release(dl);
293 }
294 if (S_OK != r)
295 {
296 MessageBoxW(0,Strings[IDS_DOWNLOAD_ERROR],0,0);
297 goto end;
298 }
299 else if (bCancelled)
300 {
301 goto end;
302 }
303 ShowWindow(Dlg, SW_HIDE);
304
305 /* run it */
306 memset(&si, 0, sizeof(si));
307 si.cb = sizeof(si);
308 r = CreateProcessW(path, NULL, NULL, NULL, 0, 0, NULL, NULL, &si, &pi);
309 if (0 == r)
310 {
311 goto end;
312 }
313 CloseHandle(pi.hThread);
314 WaitForSingleObject(pi.hProcess, INFINITE);
315 CloseHandle(pi.hProcess);
316
317 end:
318 if (bTempfile)
319 {
320 if (bCancelled)
321 DeleteFileW(path);
322 else
323 {
324 DWORD dwSize = sizeof(DWORD);
325 DWORD dwValue, dwType = REG_DWORD;
326 if (RegQueryValueEx(hKey,
327 L"DeleteInstaller",
328 NULL,
329 &dwType,
330 (LPBYTE)&dwValue,
331 &dwSize) == ERROR_SUCCESS)
332 if (dwValue == 0x1)
333 DeleteFileW(path);
334 RegCloseKey(hKey);
335 }
336 }
337 EndDialog(Dlg, 0);
338 return 0;
339 }
340
341 INT_PTR CALLBACK
342 DownloadProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
343 {
344 HANDLE Thread;
345 DWORD ThreadId;
346 HWND Item;
347
348 switch (Msg)
349 {
350 case WM_INITDIALOG:/*
351 Icon = LoadIconW((HINSTANCE) GetWindowLongPtr(Dlg, GWLP_HINSTANCE),
352 MAKEINTRESOURCEW(IDI_ICON_MAIN));
353 if (NULL != Icon)
354 {
355 SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) Icon);
356 SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) Icon);
357 }*/
358 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0);
359 Item = GetDlgItem(Dlg, IDC_PROGRESS);
360 if (NULL != Item)
361 {
362 SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0,100));
363 SendMessageW(Item, PBM_SETPOS, 0, 0);
364 }/*
365 Item = GetDlgItem(Dlg, IDC_REMOVE);
366 if (NULL != Item)
367 {
368 if (GetShortcutName(ShortcutName) &&
369 INVALID_FILE_ATTRIBUTES != GetFileAttributesW(ShortcutName))
370 {
371 SendMessageW(Item, BM_SETCHECK, BST_CHECKED, 0);
372 }
373 else
374 {
375 SendMessageW(Item, BM_SETCHECK, BST_UNCHECKED, 0);
376 ShowWindow(Item, SW_HIDE);
377 }
378 }*/
379 Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
380 if (NULL == Thread)
381 {
382 return FALSE;
383 }
384 CloseHandle(Thread);
385 return TRUE;
386
387 case WM_COMMAND:
388 if (wParam == IDCANCEL)
389 {
390 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1);
391 PostMessage(Dlg, WM_CLOSE, 0, 0);
392 }
393 return FALSE;
394
395 case WM_CLOSE:
396 EndDialog(Dlg, 0);
397 return TRUE;
398
399 default:
400 return FALSE;
401 }
402 }