It's a modal dialog not a window. Close it correctly.
[reactos.git] / reactos / apps / utils / getfirefox / getfirefox.c
1 /*
2 * PROJECT: ReactOS utilities
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: apps/utils/getfirefox/getfirefox.c
5 * PURPOSE: Main program
6 * COPYRIGHT: Copyright 2001 John R. Sheets (for CodeWeavers)
7 * Copyright 2004 Mike McCormack (for CodeWeavers)
8 * Copyright 2005 Ge van Geldorp (gvg@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28
29 #include <precomp.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34 #define DOWNLOAD_URL L"http://links.reactos.org/getfirefox"
35
36 typedef struct _IBindStatusCallbackImpl
37 {
38 const IBindStatusCallbackVtbl *vtbl;
39 LONG ref;
40 HWND hDialog;
41 BOOL *pbCancelled;
42 } IBindStatusCallbackImpl;
43
44 static HRESULT WINAPI
45 dlQueryInterface(IBindStatusCallback* This, REFIID riid, void** ppvObject)
46 {
47 if (NULL == ppvObject)
48 {
49 return E_POINTER;
50 }
51
52 if (IsEqualIID(riid, &IID_IUnknown) ||
53 IsEqualIID(riid, &IID_IBindStatusCallback))
54 {
55 IBindStatusCallback_AddRef( This );
56 *ppvObject = This;
57 return S_OK;
58 }
59
60 return E_NOINTERFACE;
61 }
62
63 static ULONG WINAPI
64 dlAddRef(IBindStatusCallback* iface)
65 {
66 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface;
67
68 return InterlockedIncrement(&This->ref);
69 }
70
71 static 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 HRESULT WINAPI
87 dlOnStartBinding(IBindStatusCallback* iface, DWORD dwReserved, IBinding* pib)
88 {
89 DPRINT1("OnStartBinding not implemented\n");
90
91 return S_OK;
92 }
93
94 static HRESULT WINAPI
95 dlGetPriority(IBindStatusCallback* iface, LONG* pnPriority)
96 {
97 DPRINT1("GetPriority not implemented\n");
98
99 return S_OK;
100 }
101
102 static HRESULT WINAPI
103 dlOnLowResource( IBindStatusCallback* iface, DWORD reserved)
104 {
105 DPRINT1("OnLowResource not implemented\n");
106
107 return S_OK;
108 }
109
110 static HRESULT WINAPI
111 dlOnProgress(IBindStatusCallback* iface, ULONG ulProgress,
112 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
113 {
114 IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface;
115 HWND Item;
116 LONG r;
117 WCHAR OldText[100];
118
119 Item = GetDlgItem(This->hDialog, IDC_PROGRESS);
120 if (NULL != Item && 0 != ulProgressMax)
121 {
122 SendMessageW(Item, PBM_SETPOS, (ulProgress * 100) / ulProgressMax, 0);
123 }
124
125 Item = GetDlgItem(This->hDialog, IDC_STATUS);
126 if (NULL != Item)
127 {
128 SendMessageW(Item, WM_GETTEXT, sizeof(OldText) / sizeof(OldText[0]),
129 (LPARAM) OldText);
130 if (sizeof(OldText) / sizeof(OldText[0]) - 1 <= wcslen(OldText) ||
131 0 != wcscmp(OldText, szStatusText))
132 {
133 SendMessageW(Item, WM_SETTEXT, 0, (LPARAM) szStatusText);
134 }
135 }
136
137 SetLastError(0);
138 r = GetWindowLongPtrW(This->hDialog, GWLP_USERDATA);
139 if (0 != r || 0 != GetLastError())
140 {
141 *This->pbCancelled = TRUE;
142 DPRINT("Cancelled\n");
143 return E_ABORT;
144 }
145
146 return S_OK;
147 }
148
149 static HRESULT WINAPI
150 dlOnStopBinding(IBindStatusCallback* iface, HRESULT hresult, LPCWSTR szError)
151 {
152 DPRINT1("OnStopBinding not implemented\n");
153
154 return S_OK;
155 }
156
157 static HRESULT WINAPI
158 dlGetBindInfo(IBindStatusCallback* iface, DWORD* grfBINDF, BINDINFO* pbindinfo)
159 {
160 DPRINT1("GetBindInfo not implemented\n");
161
162 return S_OK;
163 }
164
165 static HRESULT WINAPI
166 dlOnDataAvailable(IBindStatusCallback* iface, DWORD grfBSCF,
167 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
168 {
169 DPRINT1("OnDataAvailable implemented\n");
170
171 return S_OK;
172 }
173
174 static HRESULT WINAPI
175 dlOnObjectAvailable(IBindStatusCallback* iface, REFIID riid, IUnknown* punk)
176 {
177 DPRINT1("OnObjectAvailable implemented\n");
178
179 return S_OK;
180 }
181
182 static const IBindStatusCallbackVtbl dlVtbl =
183 {
184 dlQueryInterface,
185 dlAddRef,
186 dlRelease,
187 dlOnStartBinding,
188 dlGetPriority,
189 dlOnLowResource,
190 dlOnProgress,
191 dlOnStopBinding,
192 dlGetBindInfo,
193 dlOnDataAvailable,
194 dlOnObjectAvailable
195 };
196
197 static IBindStatusCallback*
198 CreateDl(HWND Dlg, BOOL *pbCancelled)
199 {
200 IBindStatusCallbackImpl *This;
201
202 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IBindStatusCallbackImpl));
203 This->vtbl = &dlVtbl;
204 This->ref = 1;
205 This->hDialog = Dlg;
206 This->pbCancelled = pbCancelled;
207
208 return (IBindStatusCallback*) This;
209 }
210
211 static BOOL
212 GetShortcutName(LPWSTR ShortcutName)
213 {
214 if (! SHGetSpecialFolderPathW(0, ShortcutName, CSIDL_PROGRAMS, FALSE))
215 {
216 return FALSE;
217 }
218 if (NULL == PathAddBackslashW(ShortcutName))
219 {
220 return FALSE;
221 }
222 if (0 == LoadStringW(GetModuleHandle(NULL), IDS_START_MENU_NAME,
223 ShortcutName + wcslen(ShortcutName),
224 MAX_PATH - wcslen(ShortcutName)))
225 {
226 return FALSE;
227 }
228 if (MAX_PATH - 5 < wcslen(ShortcutName))
229 {
230 return FALSE;
231 }
232 wcscat(ShortcutName, L".lnk");
233
234 return TRUE;
235 }
236
237 static DWORD WINAPI
238 ThreadFunc(LPVOID Context)
239 {
240 static const WCHAR szUrl[] = DOWNLOAD_URL;
241 IBindStatusCallback *dl;
242 WCHAR path[MAX_PATH], ShortcutName[MAX_PATH];
243 LPWSTR p;
244 STARTUPINFOW si;
245 PROCESS_INFORMATION pi;
246 HWND Dlg = (HWND) Context;
247 DWORD r;
248 BOOL bCancelled = FALSE;
249 BOOL bTempfile = FALSE;
250
251 /* built the path for the download */
252 p = wcsrchr(szUrl, L'/');
253 if (NULL == p)
254 {
255 goto end;
256 }
257 if (! GetTempPathW(MAX_PATH, path))
258 {
259 goto end;
260 }
261 wcscat(path, p + 1);
262
263 /* download it */
264 bTempfile = TRUE;
265 dl = CreateDl(Context, &bCancelled);
266 r = URLDownloadToFileW(NULL, szUrl, path, 0, dl);
267 if (NULL != dl)
268 {
269 IBindStatusCallback_Release(dl);
270 }
271 if (S_OK != r || bCancelled )
272 {
273 goto end;
274 }
275 ShowWindow(Dlg, SW_HIDE);
276
277 /* run it */
278 memset(&si, 0, sizeof(si));
279 si.cb = sizeof(si);
280 r = CreateProcessW(path, NULL, NULL, NULL, 0, 0, NULL, NULL, &si, &pi);
281 if (0 == r)
282 {
283 goto end;
284 }
285 CloseHandle(pi.hThread);
286 WaitForSingleObject(pi.hProcess, INFINITE);
287 CloseHandle(pi.hProcess);
288
289 if (BST_CHECKED == SendMessageW(GetDlgItem(Dlg, IDC_REMOVE), BM_GETCHECK,
290 0, 0) &&
291 GetShortcutName(ShortcutName))
292 {
293 DeleteFileW(ShortcutName);
294 }
295
296 end:
297 if (bTempfile)
298 {
299 DeleteFileW(path);
300 }
301 EndDialog(Dlg, 0);
302 return 0;
303 }
304
305 static INT_PTR CALLBACK
306 dlProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
307 {
308 HANDLE Thread;
309 DWORD ThreadId;
310 HWND Item;
311 HICON Icon;
312 WCHAR ShortcutName[MAX_PATH];
313
314 switch (Msg)
315 {
316 case WM_INITDIALOG:
317 Icon = LoadIconW((HINSTANCE) GetWindowLongPtr(Dlg, GWLP_HINSTANCE),
318 MAKEINTRESOURCEW(IDI_ICON_MAIN));
319 if (NULL != Icon)
320 {
321 SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM) Icon);
322 SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM) Icon);
323 }
324 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 0);
325 Item = GetDlgItem(Dlg, IDC_PROGRESS);
326 if (NULL != Item)
327 {
328 SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0,100));
329 SendMessageW(Item, PBM_SETPOS, 0, 0);
330 }
331 Item = GetDlgItem(Dlg, IDC_REMOVE);
332 if (NULL != Item)
333 {
334 if (GetShortcutName(ShortcutName) &&
335 INVALID_FILE_ATTRIBUTES != GetFileAttributesW(ShortcutName))
336 {
337 SendMessageW(Item, BM_SETCHECK, BST_CHECKED, 0);
338 }
339 else
340 {
341 SendMessageW(Item, BM_SETCHECK, BST_UNCHECKED, 0);
342 ShowWindow(Item, SW_HIDE);
343 }
344 }
345 Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
346 if (NULL == Thread)
347 {
348 return FALSE;
349 }
350 CloseHandle(Thread);
351 return TRUE;
352
353 case WM_COMMAND:
354 if (wParam == IDCANCEL)
355 {
356 SetWindowLongPtrW(Dlg, GWLP_USERDATA, 1);
357 PostMessage(Dlg, WM_CLOSE, 0, 0);
358 }
359 return FALSE;
360
361 case WM_CLOSE:
362 EndDialog(Dlg, 0);
363 return TRUE;
364
365 default:
366 return FALSE;
367 }
368 }
369
370
371 /***********************************************************************
372 * Main program
373 */
374 int
375 main(int argc, char *argv[])
376 {
377 InitCommonControls();
378
379 DialogBoxW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_GETFIREFOX), 0,
380 dlProc);
381
382 return 0;
383 }