wined3d: Implement more GLSL instructions and a little cleanup.
[wine] / dlls / mshtml / install.c
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "ole2.h"
32 #include "commctrl.h"
33 #include "advpub.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 #include "mshtml_private.h"
39 #include "resource.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
42
43 static HWND install_dialog = NULL;
44 static LPWSTR tmp_file_name = NULL;
45 static HANDLE tmp_file = INVALID_HANDLE_VALUE;
46 static LPWSTR url = NULL;
47
48 static void clean_up(void)
49 {
50     if(tmp_file != INVALID_HANDLE_VALUE)
51         CloseHandle(tmp_file);
52
53     if(tmp_file_name) {
54         DeleteFileW(tmp_file_name);
55         HeapFree(GetProcessHeap(), 0, tmp_file_name);
56         tmp_file_name = NULL;
57     }
58
59     if(tmp_file != INVALID_HANDLE_VALUE) {
60         CloseHandle(tmp_file);
61         tmp_file = INVALID_HANDLE_VALUE;
62     }
63
64     if(install_dialog)
65         EndDialog(install_dialog, 0);
66 }
67
68 static void set_status(DWORD id)
69 {
70     HWND status = GetDlgItem(install_dialog, ID_DWL_STATUS);
71     WCHAR buf[64];
72
73     LoadStringW(hInst, id, buf, sizeof(buf)/sizeof(WCHAR));
74     SendMessageW(status, WM_SETTEXT, 0, (LPARAM)buf);
75 }
76
77 static void set_registry(LPCSTR install_dir)
78 {
79     LPWSTR gecko_path;
80     HKEY hkey;
81     DWORD res, len, size;
82
83     static const WCHAR wszMshtmlKey[] = {
84         'S','o','f','t','w','a','r','e','\\','W','i','n','e',
85         '\\','M','S','H','T','M','L',0};
86     static const WCHAR wszGeckoPath[] = {'G','e','c','k','o','P','a','t','h',0};
87     static const WCHAR wszWineGecko[] = {'w','i','n','e','_','g','e','c','k','o',0};
88
89     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */
90     res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey);
91     if(res != ERROR_SUCCESS) {
92         ERR("Faild to open MSHTML key: %ld\n", res);
93         return;
94     }
95
96     len = MultiByteToWideChar(CP_ACP, 0, install_dir, -1, NULL, 0)-1;
97     gecko_path = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)+sizeof(wszWineGecko));
98     MultiByteToWideChar(CP_ACP, 0, install_dir, -1, gecko_path, -1);
99     memcpy(gecko_path+len, wszWineGecko, sizeof(wszWineGecko));
100
101     size = len*sizeof(WCHAR)+sizeof(wszWineGecko);
102     res = RegSetValueExW(hkey, wszGeckoPath, 0, REG_SZ, (LPVOID)gecko_path,
103                        len*sizeof(WCHAR)+sizeof(wszWineGecko));
104     HeapFree(GetProcessHeap(), 0, gecko_path);
105     RegCloseKey(hkey);
106     if(res != ERROR_SUCCESS)
107         ERR("Failed to set GeckoPath value: %08lx\n", res);
108 }
109
110 static HRESULT WINAPI InstallCallback_QueryInterface(IBindStatusCallback *iface,
111                                                      REFIID riid, void **ppv)
112 {
113     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IBindStatusCallback, riid)) {
114         *ppv = iface;
115         return S_OK;
116     }
117
118     return E_INVALIDARG;
119 }
120
121 static ULONG WINAPI InstallCallback_AddRef(IBindStatusCallback *iface)
122 {
123     return 2;
124 }
125
126 static ULONG WINAPI InstallCallback_Release(IBindStatusCallback *iface)
127 {
128     return 1;
129 }
130
131 static HRESULT WINAPI InstallCallback_OnStartBinding(IBindStatusCallback *iface,
132         DWORD dwReserved, IBinding *pib)
133 {
134     WCHAR tmp_dir[MAX_PATH];
135
136     set_status(IDS_DOWNLOADING);
137
138     GetTempPathW(sizeof(tmp_dir)/sizeof(WCHAR), tmp_dir);
139
140     tmp_file_name = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR));
141     GetTempFileNameW(tmp_dir, NULL, 0, tmp_file_name);
142
143     TRACE("creating temp file %s\n", debugstr_w(tmp_file_name));
144
145     tmp_file = CreateFileW(tmp_file_name, GENERIC_WRITE, 0, NULL, 
146                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
147
148     if(tmp_file == INVALID_HANDLE_VALUE) {
149         ERR("Could not create file: %ld\n", GetLastError());
150         clean_up();
151         return E_FAIL;
152     }
153
154     return S_OK;
155 }
156
157 static HRESULT WINAPI InstallCallback_GetPriority(IBindStatusCallback *iface,
158         LONG *pnPriority)
159 {
160     return E_NOTIMPL;
161 }
162
163 static HRESULT WINAPI InstallCallback_OnLowResource(IBindStatusCallback *iface,
164        DWORD dwReserved)
165 {
166     return E_NOTIMPL;
167 }
168
169 static HRESULT WINAPI InstallCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
170         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
171 {
172     HWND progress = GetDlgItem(install_dialog, ID_DWL_PROGRESS);
173
174     if(ulProgressMax)
175         SendMessageW(progress, PBM_SETRANGE32, 0, ulProgressMax);
176     if(ulProgress)
177         SendMessageW(progress, PBM_SETPOS, ulProgress, 0);
178
179     return S_OK;
180 }
181
182 static HRESULT WINAPI InstallCallback_OnStopBinding(IBindStatusCallback *iface,
183         HRESULT hresult, LPCWSTR szError)
184 {
185     LPSTR file_name;
186     DWORD len;
187     HMODULE advpack;
188     char program_files[MAX_PATH];
189     typeof(ExtractFilesA) *pExtractFilesA;
190     HRESULT hres;
191
192     static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
193
194     if(FAILED(hresult)) {
195         ERR("Binding failed %08lx\n", hresult);
196         clean_up();
197         return S_OK;
198     }
199
200     CloseHandle(tmp_file);
201     tmp_file = INVALID_HANDLE_VALUE;
202
203     set_status(IDS_INSTALLING);
204
205     advpack = LoadLibraryW(wszAdvpack);
206     pExtractFilesA = (typeof(ExtractFilesA)*)GetProcAddress(advpack, "ExtractFiles");
207
208     len = WideCharToMultiByte(CP_ACP, 0, tmp_file_name, -1, NULL, 0, NULL, NULL);
209     file_name = HeapAlloc(GetProcessHeap(), 0, len);
210     WideCharToMultiByte(CP_ACP, 0, tmp_file_name, -1, file_name, -1, NULL, NULL);
211
212     GetEnvironmentVariableA("ProgramFiles", program_files, sizeof(program_files));
213
214     /* FIXME: Use unicode version (not yet implemented) */
215     hres = pExtractFilesA(file_name, program_files, 0, NULL, NULL, 0);
216     FreeLibrary(advpack);
217     HeapFree(GetProcessHeap(), 0, file_name);
218     if(FAILED(hres)) {
219         ERR("Could not extract package: %08lx\n", hres);
220         clean_up();
221     }
222
223     set_registry(program_files);
224     clean_up();
225
226     return S_OK;
227 }
228
229 static HRESULT WINAPI InstallCallback_GetBindInfo(IBindStatusCallback *iface,
230         DWORD* grfBINDF, BINDINFO* pbindinfo)
231 {
232     /* FIXME */
233     *grfBINDF = 0;
234     return S_OK;
235 }
236
237 static HRESULT WINAPI InstallCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
238         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
239 {
240     IStream *str = pstgmed->u.pstm;
241     BYTE buf[1024];
242     DWORD size;
243     HRESULT hres;
244
245     do {
246         size = 0;
247         hres = IStream_Read(str, buf, sizeof(buf), &size);
248         if(size)
249             WriteFile(tmp_file, buf, size, NULL, NULL);
250     }while(hres == S_OK);
251
252     return S_OK;
253 }
254
255 static HRESULT WINAPI InstallCallback_OnObjectAvailable(IBindStatusCallback *iface,
256         REFIID riid, IUnknown* punk)
257 {
258     ERR("\n");
259     return E_NOTIMPL;
260 }
261
262 static IBindStatusCallbackVtbl InstallCallbackVtbl = {
263     InstallCallback_QueryInterface,
264     InstallCallback_AddRef,
265     InstallCallback_Release,
266     InstallCallback_OnStartBinding,
267     InstallCallback_GetPriority,
268     InstallCallback_OnLowResource,
269     InstallCallback_OnProgress,
270     InstallCallback_OnStopBinding,
271     InstallCallback_GetBindInfo,
272     InstallCallback_OnDataAvailable,
273     InstallCallback_OnObjectAvailable
274 };
275
276 static IBindStatusCallback InstallCallback = { &InstallCallbackVtbl };
277
278 static LPWSTR get_url(void)
279 {
280     HKEY hkey;
281     DWORD res, type;
282     DWORD size = 512*sizeof(WCHAR);
283     LPWSTR url;
284
285     static const WCHAR wszMshtmlKey[] = {
286         'S','o','f','t','w','a','r','e','\\','W','i','n','e',
287         '\\','M','S','H','T','M','L',0};
288     static const WCHAR wszGeckoUrl[] = {'G','e','c','k','o','U','r','l',0};
289
290     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */
291     res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey);
292     if(res != ERROR_SUCCESS)
293         return NULL;
294
295     url = HeapAlloc(GetProcessHeap(), 0, size);
296
297     res = RegQueryValueExW(hkey, wszGeckoUrl, NULL, &type, (LPBYTE)url, &size);
298     RegCloseKey(hkey);
299     if(res != ERROR_SUCCESS || type != REG_SZ) {
300         HeapFree(GetProcessHeap(), 0, url);
301         return NULL;
302     }
303
304     return url;
305 }
306
307 static DWORD WINAPI download_proc(PVOID arg)
308 {
309     IMoniker *mon;
310     IBindCtx *bctx;
311     IStream *str = NULL;
312     HRESULT hres;
313
314     CreateURLMoniker(NULL, url, &mon);
315     HeapFree(GetProcessHeap(), 0, url);
316     url = NULL;
317
318     CreateAsyncBindCtx(0, &InstallCallback, 0, &bctx);
319
320     hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&str);
321     IBindCtx_Release(bctx);
322     if(FAILED(hres)) {
323         ERR("BindToStorage failed: %08lx\n", hres);
324         return 0;
325     }
326
327     if(str)
328         IStream_Release(str);
329
330     return 0;
331 }
332
333 static INT_PTR CALLBACK installer_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
334 {
335     switch(msg) {
336     case WM_INITDIALOG:
337         install_dialog = hwnd;
338         return TRUE;
339
340     case WM_COMMAND:
341         switch(wParam) {
342         case IDCANCEL:
343             EndDialog(hwnd, 0);
344             return FALSE;
345
346         case ID_DWL_INSTALL:
347             EnableWindow(GetDlgItem(hwnd, ID_DWL_INSTALL), 0);
348             EnableWindow(GetDlgItem(hwnd, IDCANCEL), 0); /* FIXME */
349             CreateThread(NULL, 0, download_proc, NULL, 0, NULL);
350             return FALSE;
351         }
352     }
353
354     return FALSE;
355 }
356
357 void install_wine_gecko(void)
358 {
359     HANDLE hsem;
360
361     SetLastError(ERROR_SUCCESS);
362     hsem = CreateSemaphoreA( NULL, 0, 1, "mshtml_install_semaphore");
363
364     if(GetLastError() == ERROR_ALREADY_EXISTS) {
365         WaitForSingleObject(hsem, INFINITE);
366     }else {
367         if((url = get_url()))
368            DialogBoxW(hInst, MAKEINTRESOURCEW(ID_DWL_DIALOG), 0, installer_proc);
369     }
370
371     ReleaseSemaphore(hsem, 1, NULL);
372     CloseHandle(hsem);
373 }