Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/appwiz.cpl/addons.c
4396 views
1
/*
2
* Copyright 2006-2010 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 <stdarg.h>
20
#include <fcntl.h>
21
#include <stdio.h>
22
#include <errno.h>
23
24
#define COBJMACROS
25
#include "windef.h"
26
#include "winbase.h"
27
#include "winuser.h"
28
#include "cpl.h"
29
#include "winreg.h"
30
#include "ole2.h"
31
#include "commctrl.h"
32
#include "advpub.h"
33
#include "wininet.h"
34
#include "pathcch.h"
35
#include "shellapi.h"
36
#include "urlmon.h"
37
#include "msi.h"
38
#include "bcrypt.h"
39
40
#include "appwiz.h"
41
#include "res.h"
42
43
#include "wine/debug.h"
44
45
WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
46
47
#define GECKO_VERSION "2.47.4"
48
#ifdef __i386__
49
#define GECKO_ARCH "x86"
50
#define GECKO_SHA "26cecc47706b091908f7f814bddb074c61beb8063318e9efc5a7f789857793d6"
51
#elif defined(__x86_64__)
52
#define GECKO_ARCH "x86_64"
53
#define GECKO_SHA "e590b7d988a32d6aa4cf1d8aa3aa3d33766fdd4cf4c89c2dcc2095ecb28d066f"
54
#else
55
#define GECKO_ARCH ""
56
#define GECKO_SHA "???"
57
#endif
58
59
#define MONO_VERSION "10.2.0"
60
#if defined(__i386__) || defined(__x86_64__)
61
#define MONO_ARCH "x86"
62
#define MONO_SHA "4e1ed3f02e92d053133d03ddfbefcf6db4a4dc231a9aed3367b17117a88847d8"
63
#else
64
#define MONO_ARCH ""
65
#define MONO_SHA "???"
66
#endif
67
68
typedef struct {
69
const char *version;
70
const WCHAR *file_name;
71
const WCHAR *subdir_name;
72
const char *sha;
73
const char *url_default;
74
const WCHAR *config_key;
75
const WCHAR *url_config_key;
76
const WCHAR *dir_config_key;
77
LPCWSTR dialog_template;
78
} addon_info_t;
79
80
/* Download addon files over HTTP because Wine depends on an external library
81
* for TLS, so we can't be sure that HTTPS will work. The integrity of each file
82
* is checked with a hardcoded cryptographically secure hash. */
83
static const addon_info_t addons_info[] = {
84
{
85
GECKO_VERSION,
86
L"wine-gecko-" GECKO_VERSION "-" GECKO_ARCH ".msi",
87
L"gecko",
88
GECKO_SHA,
89
"http://source.winehq.org/winegecko.php",
90
L"MSHTML", L"GeckoUrl", L"GeckoCabDir",
91
MAKEINTRESOURCEW(ID_DWL_GECKO_DIALOG)
92
},
93
{
94
MONO_VERSION,
95
L"wine-mono-" MONO_VERSION "-" MONO_ARCH ".msi",
96
L"mono",
97
MONO_SHA,
98
"http://source.winehq.org/winemono.php",
99
L"Dotnet", L"MonoUrl", L"MonoCabDir",
100
MAKEINTRESOURCEW(ID_DWL_MONO_DIALOG)
101
}
102
};
103
104
static const addon_info_t *addon;
105
106
static HWND install_dialog = NULL;
107
static LPWSTR url = NULL;
108
static IBinding *dwl_binding;
109
static WCHAR *msi_file;
110
111
static const char * (CDECL *p_wine_get_version)(void);
112
113
static BOOL sha_check(const WCHAR *file_name)
114
{
115
const unsigned char *file_map;
116
HANDLE file, map;
117
DWORD size, i;
118
UCHAR sha[32];
119
char buf[1024];
120
BOOL ret = FALSE;
121
122
file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
123
if(file == INVALID_HANDLE_VALUE) {
124
WARN("Could not open file: %lu\n", GetLastError());
125
return FALSE;
126
}
127
128
size = GetFileSize(file, NULL);
129
130
map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
131
CloseHandle(file);
132
if(!map)
133
return FALSE;
134
135
file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
136
CloseHandle(map);
137
if(!file_map)
138
return FALSE;
139
140
if(!BCryptHash(BCRYPT_SHA256_ALG_HANDLE, NULL, 0, (UCHAR *)file_map, size, sha, sizeof(sha))) {
141
for(i=0; i < sizeof(sha); i++)
142
sprintf(buf + i * 2, "%02x", sha[i]);
143
144
ret = !strcmp(buf, addon->sha);
145
if(!ret)
146
WARN("Got %s, expected %s\n", buf, addon->sha);
147
}
148
149
UnmapViewOfFile(file_map);
150
return ret;
151
}
152
153
static void set_status(DWORD id)
154
{
155
HWND status = GetDlgItem(install_dialog, ID_DWL_STATUS);
156
WCHAR buf[64];
157
158
LoadStringW(hInst, id, buf, ARRAY_SIZE(buf));
159
SendMessageW(status, WM_SETTEXT, 0, (LPARAM)buf);
160
}
161
162
enum install_res {
163
INSTALL_OK = 0,
164
INSTALL_FAILED,
165
INSTALL_NEXT,
166
};
167
168
static enum install_res install_file(const WCHAR *file_name)
169
{
170
ULONG res;
171
172
res = MsiInstallProductW(file_name, NULL);
173
if(res == ERROR_PRODUCT_VERSION)
174
res = MsiInstallProductW(file_name, L"REINSTALL=ALL REINSTALLMODE=vomus");
175
if(res != ERROR_SUCCESS) {
176
ERR("MsiInstallProduct failed: %lu\n", res);
177
return INSTALL_FAILED;
178
}
179
180
return INSTALL_OK;
181
}
182
183
static enum install_res install_from_file(const WCHAR *dir, const WCHAR *subdir, const WCHAR *file_name)
184
{
185
WCHAR *path, *canonical_path;
186
enum install_res ret = INSTALL_NEXT;
187
DWORD len = lstrlenW( dir );
188
DWORD size = len + 1;
189
HANDLE file;
190
HRESULT hr;
191
192
size += lstrlenW( subdir ) + lstrlenW( file_name ) + 2;
193
if (!(path = malloc( size * sizeof(WCHAR) ))) return INSTALL_FAILED;
194
195
lstrcpyW( path, dir );
196
if (!wcsncmp( path, L"\\??\\", 4 )) path[1] = '\\'; /* change \??\ into \\?\ */
197
if (len && path[len-1] != '/' && path[len-1] != '\\') path[len++] = '\\';
198
199
lstrcpyW( path + len, subdir );
200
lstrcatW( path, L"\\" );
201
lstrcatW( path, file_name );
202
203
hr = PathAllocCanonicalize( path, PATHCCH_ALLOW_LONG_PATHS, &canonical_path );
204
if (FAILED( hr ))
205
{
206
ERR( "Failed to canonicalize %s, hr %#lx\n", debugstr_w(path), hr );
207
free( path );
208
return INSTALL_NEXT;
209
}
210
211
file = CreateFileW( canonical_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
212
NULL, OPEN_EXISTING, 0, 0 );
213
LocalFree( canonical_path );
214
if (file == INVALID_HANDLE_VALUE)
215
{
216
free( path );
217
return INSTALL_NEXT;
218
}
219
220
for (;;)
221
{
222
len = GetFinalPathNameByHandleW( file, path, size, VOLUME_NAME_DOS );
223
if (len <= size) break;
224
free( path );
225
size = len;
226
if (!(path = malloc( size * sizeof(WCHAR) ))) break;
227
}
228
CloseHandle( file );
229
if (!path) return INSTALL_FAILED;
230
if (len > 6) ret = install_file( (path[5] == ':') ? path + 4 : path ); /* remove '\\?\' */
231
free( path );
232
return ret;
233
}
234
235
static HKEY open_config_key(void)
236
{
237
HKEY hkey, ret;
238
DWORD res;
239
240
/* @@ Wine registry key: HKCU\Software\Wine\$config_key */
241
res = RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Wine", &hkey);
242
if(res != ERROR_SUCCESS)
243
return NULL;
244
245
res = RegOpenKeyW(hkey, addon->config_key, &ret);
246
RegCloseKey(hkey);
247
return res == ERROR_SUCCESS ? ret : NULL;
248
}
249
250
static enum install_res install_from_registered_dir(void)
251
{
252
static const WCHAR unix_prefix[8] = L"\\\\?\\unix";
253
WCHAR *package_dir, *new_package_dir;
254
HKEY hkey;
255
DWORD res, type, size = MAX_PATH * sizeof(WCHAR);
256
enum install_res ret;
257
258
hkey = open_config_key();
259
if(!hkey)
260
return INSTALL_NEXT;
261
262
package_dir = malloc(size + sizeof(unix_prefix));
263
res = RegGetValueW(hkey, NULL, addon->dir_config_key, RRF_RT_ANY, &type,
264
(PBYTE)package_dir + sizeof(unix_prefix), &size);
265
if(res == ERROR_MORE_DATA) {
266
new_package_dir = realloc(package_dir, size + sizeof(unix_prefix));
267
if(new_package_dir) {
268
package_dir = new_package_dir;
269
res = RegGetValueW(hkey, NULL, addon->dir_config_key, RRF_RT_ANY, &type,
270
(PBYTE)package_dir + sizeof(unix_prefix), &size);
271
}
272
}
273
RegCloseKey(hkey);
274
if(res == ERROR_FILE_NOT_FOUND) {
275
free(package_dir);
276
return INSTALL_NEXT;
277
} else if(res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) {
278
free(package_dir);
279
return INSTALL_FAILED;
280
}
281
282
memcpy( package_dir, unix_prefix, sizeof(unix_prefix) );
283
ret = install_from_file(package_dir, L"", addon->file_name);
284
285
free(package_dir);
286
return ret;
287
}
288
289
static enum install_res install_from_default_dir(void)
290
{
291
const WCHAR *package_dir;
292
WCHAR *dir_buf = NULL;
293
enum install_res ret = INSTALL_NEXT;
294
295
if ((package_dir = _wgetenv( L"WINEBUILDDIR" )))
296
{
297
dir_buf = malloc( wcslen(package_dir) * sizeof(WCHAR) + sizeof(L"\\..\\") );
298
lstrcpyW( dir_buf, package_dir );
299
lstrcatW( dir_buf, L"\\..\\" );
300
package_dir = dir_buf;
301
}
302
else package_dir = _wgetenv( L"WINEDATADIR" );
303
304
if (package_dir)
305
{
306
ret = install_from_file(package_dir, addon->subdir_name, addon->file_name);
307
free(dir_buf);
308
}
309
310
if (ret == INSTALL_NEXT)
311
ret = install_from_file(L"\\\\?\\unix" INSTALL_DATADIR "/wine/", addon->subdir_name, addon->file_name);
312
if (ret == INSTALL_NEXT && strcmp("" INSTALL_DATADIR, "/usr/share") != 0)
313
ret = install_from_file(L"\\\\?\\unix/usr/share/wine/", addon->subdir_name, addon->file_name);
314
if (ret == INSTALL_NEXT)
315
ret = install_from_file(L"\\\\?\\unix/opt/wine/", addon->subdir_name, addon->file_name);
316
return ret;
317
}
318
319
static WCHAR *get_cache_file_name(BOOL ensure_exists)
320
{
321
const WCHAR *xdg_dir;
322
const WCHAR *home_dir;
323
WCHAR *cache_dir=NULL, *ret;
324
size_t len, size;
325
326
xdg_dir = _wgetenv( L"XDG_CACHE_HOME" );
327
if (xdg_dir && *xdg_dir)
328
{
329
if (!(cache_dir = HeapAlloc( GetProcessHeap(), 0, wcslen(xdg_dir) * sizeof(WCHAR) + sizeof(L"\\\\?\\unix") ))) return NULL;
330
lstrcpyW( cache_dir, L"\\\\?\\unix" );
331
lstrcatW( cache_dir, xdg_dir );
332
TRACE("cache dir %s\n", debugstr_w(cache_dir));
333
}
334
else if ((home_dir = _wgetenv( L"WINEHOMEDIR" )))
335
{
336
if (!(cache_dir = HeapAlloc( GetProcessHeap(), 0, wcslen(home_dir) * sizeof(WCHAR) + sizeof(L"\\.cache") ))) return NULL;
337
lstrcpyW( cache_dir, home_dir );
338
lstrcatW( cache_dir, L"\\.cache" );
339
cache_dir[1] = '\\'; /* change \??\ into \\?\ */
340
}
341
else return NULL;
342
343
if (ensure_exists && !CreateDirectoryW( cache_dir, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
344
{
345
WARN( "%s does not exist and could not be created (%lu)\n", debugstr_w(cache_dir), GetLastError() );
346
HeapFree( GetProcessHeap(), 0, cache_dir );
347
return NULL;
348
}
349
350
size = lstrlenW( cache_dir ) + ARRAY_SIZE(L"\\wine") + lstrlenW( addon->file_name ) + 1;
351
if (!(ret = malloc( size * sizeof(WCHAR) )))
352
{
353
HeapFree( GetProcessHeap(), 0, cache_dir );
354
return NULL;
355
}
356
lstrcpyW( ret, cache_dir );
357
lstrcatW( ret, L"\\wine" );
358
HeapFree( GetProcessHeap(), 0, cache_dir );
359
360
if (ensure_exists && !CreateDirectoryW( ret, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
361
{
362
WARN( "%s does not exist and could not be created (%lu)\n", debugstr_w(ret), GetLastError() );
363
free( ret );
364
return NULL;
365
}
366
len = lstrlenW( ret );
367
ret[len++] = '\\';
368
lstrcpyW( ret + len, addon->file_name );
369
370
TRACE( "got %s\n", debugstr_w(ret) );
371
return ret;
372
}
373
374
static enum install_res install_from_cache(void)
375
{
376
WCHAR *cache_file_name;
377
enum install_res res;
378
379
cache_file_name = get_cache_file_name(FALSE);
380
if(!cache_file_name)
381
return INSTALL_NEXT;
382
383
if(!sha_check(cache_file_name)) {
384
WARN("could not validate checksum\n");
385
DeleteFileW(cache_file_name);
386
free(cache_file_name);
387
return INSTALL_NEXT;
388
}
389
390
res = install_file(cache_file_name);
391
free(cache_file_name);
392
return res;
393
}
394
395
static IInternetBindInfo InstallCallbackBindInfo;
396
397
static HRESULT WINAPI InstallCallback_QueryInterface(IBindStatusCallback *iface,
398
REFIID riid, void **ppv)
399
{
400
if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IBindStatusCallback, riid)) {
401
*ppv = iface;
402
return S_OK;
403
}
404
405
if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
406
TRACE("IID_IInternetBindInfo\n");
407
*ppv = &InstallCallbackBindInfo;
408
return S_OK;
409
}
410
411
return E_INVALIDARG;
412
}
413
414
static ULONG WINAPI InstallCallback_AddRef(IBindStatusCallback *iface)
415
{
416
return 2;
417
}
418
419
static ULONG WINAPI InstallCallback_Release(IBindStatusCallback *iface)
420
{
421
return 1;
422
}
423
424
static HRESULT WINAPI InstallCallback_OnStartBinding(IBindStatusCallback *iface,
425
DWORD dwReserved, IBinding *pib)
426
{
427
set_status(IDS_DOWNLOADING);
428
429
IBinding_AddRef(pib);
430
dwl_binding = pib;
431
432
return S_OK;
433
}
434
435
static HRESULT WINAPI InstallCallback_GetPriority(IBindStatusCallback *iface,
436
LONG *pnPriority)
437
{
438
return E_NOTIMPL;
439
}
440
441
static HRESULT WINAPI InstallCallback_OnLowResource(IBindStatusCallback *iface,
442
DWORD dwReserved)
443
{
444
return E_NOTIMPL;
445
}
446
447
static HRESULT WINAPI InstallCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
448
ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
449
{
450
HWND progress = GetDlgItem(install_dialog, ID_DWL_PROGRESS);
451
452
if(ulProgressMax)
453
SendMessageW(progress, PBM_SETRANGE32, 0, ulProgressMax);
454
if(ulProgress)
455
SendMessageW(progress, PBM_SETPOS, ulProgress, 0);
456
457
return S_OK;
458
}
459
460
static HRESULT WINAPI InstallCallback_OnStopBinding(IBindStatusCallback *iface,
461
HRESULT hresult, LPCWSTR szError)
462
{
463
WCHAR message[256];
464
465
if(dwl_binding) {
466
IBinding_Release(dwl_binding);
467
dwl_binding = NULL;
468
}
469
470
if(FAILED(hresult)) {
471
if(hresult == E_ABORT)
472
TRACE("Binding aborted\n");
473
else if (hresult == INET_E_DOWNLOAD_FAILURE)
474
{
475
if(LoadStringW(hInst, IDS_DOWNLOAD_FAILED, message, ARRAY_SIZE(message)))
476
MessageBoxW(install_dialog, message, NULL, MB_ICONERROR);
477
EndDialog(install_dialog, IDCANCEL);
478
}
479
else
480
ERR("Binding failed %08lx\n", hresult);
481
return S_OK;
482
}
483
484
if(!msi_file) {
485
ERR("No MSI file\n");
486
return E_FAIL;
487
}
488
489
set_status(IDS_INSTALLING);
490
EnableWindow(GetDlgItem(install_dialog, IDCANCEL), 0);
491
492
if(sha_check(msi_file)) {
493
WCHAR *cache_file_name;
494
495
install_file(msi_file);
496
497
cache_file_name = get_cache_file_name(TRUE);
498
if(cache_file_name) {
499
CopyFileW(msi_file, cache_file_name, FALSE);
500
free(cache_file_name);
501
}
502
}else {
503
if(LoadStringW(hInst, IDS_INVALID_SHA, message, ARRAY_SIZE(message)))
504
MessageBoxW(NULL, message, NULL, MB_ICONERROR);
505
}
506
507
DeleteFileW(msi_file);
508
free(msi_file);
509
msi_file = NULL;
510
511
EndDialog(install_dialog, 0);
512
return S_OK;
513
}
514
515
static HRESULT WINAPI InstallCallback_GetBindInfo(IBindStatusCallback *iface,
516
DWORD* grfBINDF, BINDINFO* pbindinfo)
517
{
518
TRACE("()\n");
519
520
*grfBINDF = BINDF_ASYNCHRONOUS;
521
return S_OK;
522
}
523
524
static HRESULT WINAPI InstallCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
525
DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
526
{
527
if(!msi_file) {
528
msi_file = wcsdup(pstgmed->lpszFileName);
529
TRACE("got file name %s\n", debugstr_w(msi_file));
530
}
531
532
return S_OK;
533
}
534
535
static HRESULT WINAPI InstallCallback_OnObjectAvailable(IBindStatusCallback *iface,
536
REFIID riid, IUnknown* punk)
537
{
538
ERR("\n");
539
return E_NOTIMPL;
540
}
541
542
static const IBindStatusCallbackVtbl InstallCallbackVtbl = {
543
InstallCallback_QueryInterface,
544
InstallCallback_AddRef,
545
InstallCallback_Release,
546
InstallCallback_OnStartBinding,
547
InstallCallback_GetPriority,
548
InstallCallback_OnLowResource,
549
InstallCallback_OnProgress,
550
InstallCallback_OnStopBinding,
551
InstallCallback_GetBindInfo,
552
InstallCallback_OnDataAvailable,
553
InstallCallback_OnObjectAvailable
554
};
555
556
static IBindStatusCallback InstallCallback = { &InstallCallbackVtbl };
557
558
static HRESULT WINAPI InstallCallbackBindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
559
{
560
return IBindStatusCallback_QueryInterface(&InstallCallback, riid, ppv);
561
}
562
563
static ULONG WINAPI InstallCallbackBindInfo_AddRef(IInternetBindInfo *iface)
564
{
565
return 2;
566
}
567
568
static ULONG WINAPI InstallCallbackBindInfo_Release(IInternetBindInfo *iface)
569
{
570
return 1;
571
}
572
573
static HRESULT WINAPI InstallCallbackBindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *bindf, BINDINFO *bindinfo)
574
{
575
ERR("\n");
576
return E_NOTIMPL;
577
}
578
579
static HRESULT WINAPI InstallCallbackBindInfo_GetBindString(IInternetBindInfo *iface, ULONG string_type,
580
WCHAR **strs, ULONG cnt, ULONG *fetched)
581
{
582
switch(string_type) {
583
case BINDSTRING_USER_AGENT:
584
TRACE("BINDSTRING_USER_AGENT\n");
585
586
*strs = CoTaskMemAlloc(sizeof(L"Wine Addon Downloader"));
587
if(!*strs)
588
return E_OUTOFMEMORY;
589
590
lstrcpyW(*strs, L"Wine Addon Downloader");
591
*fetched = 1;
592
return S_OK;
593
}
594
595
return E_NOTIMPL;
596
}
597
598
static const IInternetBindInfoVtbl InstallCallbackBindInfoVtbl = {
599
InstallCallbackBindInfo_QueryInterface,
600
InstallCallbackBindInfo_AddRef,
601
InstallCallbackBindInfo_Release,
602
InstallCallbackBindInfo_GetBindInfo,
603
InstallCallbackBindInfo_GetBindString
604
};
605
606
static IInternetBindInfo InstallCallbackBindInfo = { &InstallCallbackBindInfoVtbl };
607
608
static void append_url_params( WCHAR *url )
609
{
610
DWORD size = INTERNET_MAX_URL_LENGTH * sizeof(WCHAR);
611
DWORD len = lstrlenW(url);
612
613
lstrcpyW(url+len, L"?arch=");
614
len += lstrlenW(L"?arch=");
615
len += MultiByteToWideChar(CP_ACP, 0, GECKO_ARCH, sizeof(GECKO_ARCH),
616
url+len, size/sizeof(WCHAR)-len)-1;
617
lstrcpyW(url+len, L"&v=");
618
len += lstrlenW(L"&v=");
619
len += MultiByteToWideChar(CP_ACP, 0, addon->version, -1, url+len, size/sizeof(WCHAR)-len)-1;
620
lstrcpyW(url+len, L"&winev=");
621
len += lstrlenW(L"&winev=");
622
MultiByteToWideChar(CP_ACP, 0, p_wine_get_version ? p_wine_get_version() : 0, -1, url+len, size/sizeof(WCHAR)-len);
623
}
624
625
static LPWSTR get_url(void)
626
{
627
DWORD size = INTERNET_MAX_URL_LENGTH*sizeof(WCHAR);
628
WCHAR *url;
629
HKEY hkey;
630
DWORD res, type;
631
DWORD returned_size;
632
633
static const WCHAR httpW[] = {'h','t','t','p'};
634
635
url = malloc(size);
636
returned_size = size;
637
638
hkey = open_config_key();
639
if (hkey)
640
{
641
res = RegQueryValueExW(hkey, addon->url_config_key, NULL, &type, (LPBYTE)url, &returned_size);
642
RegCloseKey(hkey);
643
if(res == ERROR_SUCCESS && type == REG_SZ) goto found;
644
}
645
646
MultiByteToWideChar( CP_ACP, 0, addon->url_default, -1, url, size / sizeof(WCHAR) );
647
648
found:
649
if (returned_size > sizeof(httpW) && !memcmp(url, httpW, sizeof(httpW))) append_url_params( url );
650
651
TRACE("Got URL %s\n", debugstr_w(url));
652
return url;
653
}
654
655
static BOOL start_download(void)
656
{
657
IBindCtx *bind_ctx;
658
IMoniker *mon;
659
IUnknown *tmp;
660
HRESULT hres;
661
662
hres = CreateURLMoniker(NULL, url, &mon);
663
if(FAILED(hres))
664
return FALSE;
665
666
hres = CreateAsyncBindCtx(0, &InstallCallback, NULL, &bind_ctx);
667
if(SUCCEEDED(hres)) {
668
hres = IMoniker_BindToStorage(mon, bind_ctx, NULL, &IID_IUnknown, (void**)&tmp);
669
IBindCtx_Release(bind_ctx);
670
}
671
IMoniker_Release(mon);
672
if(FAILED(hres))
673
return FALSE;
674
675
if(tmp)
676
IUnknown_Release(tmp);
677
return TRUE;
678
}
679
680
static void run_winebrowser(const WCHAR *url)
681
{
682
PROCESS_INFORMATION pi;
683
STARTUPINFOW si;
684
WCHAR app[MAX_PATH];
685
LONG len, url_len;
686
WCHAR *args;
687
BOOL ret;
688
689
url_len = lstrlenW(url);
690
691
len = GetSystemDirectoryW(app, MAX_PATH - ARRAY_SIZE(L"\\winebrowser.exe"));
692
lstrcpyW(app+len, L"\\winebrowser.exe");
693
len += ARRAY_SIZE(L"\\winebrowser.exe") - 1;
694
695
args = malloc((len + 1 + url_len) * sizeof(WCHAR));
696
if(!args)
697
return;
698
699
memcpy(args, app, len*sizeof(WCHAR));
700
args[len++] = ' ';
701
memcpy(args+len, url, (url_len+1) * sizeof(WCHAR));
702
703
TRACE("starting %s\n", debugstr_w(args));
704
705
memset(&si, 0, sizeof(si));
706
si.cb = sizeof(si);
707
ret = CreateProcessW(app, args, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi);
708
free(args);
709
if (ret) {
710
CloseHandle(pi.hThread);
711
CloseHandle(pi.hProcess);
712
}
713
}
714
715
static INT_PTR CALLBACK installer_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
716
{
717
switch(msg) {
718
case WM_INITDIALOG:
719
ShowWindow(GetDlgItem(hwnd, ID_DWL_PROGRESS), SW_HIDE);
720
install_dialog = hwnd;
721
return TRUE;
722
723
case WM_NOTIFY:
724
switch (((NMHDR *)lParam)->code)
725
{
726
case NM_CLICK:
727
case NM_RETURN:
728
if (wParam == ID_DWL_STATUS)
729
run_winebrowser(((NMLINK*)lParam)->item.szUrl);
730
break;
731
}
732
break;
733
734
case WM_COMMAND:
735
switch(wParam) {
736
case IDCANCEL:
737
if(dwl_binding)
738
IBinding_Abort(dwl_binding);
739
EndDialog(hwnd, 0);
740
return FALSE;
741
742
case ID_DWL_INSTALL:
743
ShowWindow(GetDlgItem(hwnd, ID_DWL_PROGRESS), SW_SHOW);
744
EnableWindow(GetDlgItem(hwnd, ID_DWL_INSTALL), 0);
745
if(!start_download())
746
EndDialog(install_dialog, 0);
747
}
748
}
749
750
return FALSE;
751
}
752
753
BOOL install_addon(addon_t addon_type)
754
{
755
if(!*GECKO_ARCH)
756
return FALSE;
757
758
addon = addons_info+addon_type;
759
760
p_wine_get_version = (void *)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "wine_get_version");
761
762
/*
763
* Try to find addon .msi file in following order:
764
* - directory stored in $dir_config_key value of HKCU/Software/Wine/$config_key key
765
* - $datadir/$addon_subdir/
766
* - $INSTALL_DATADIR/wine/$addon_subdir/
767
* - /usr/share/wine/$addon_subdir/
768
* - /opt/wine/$addon_subdir/
769
* - download from URL stored in $url_config_key value of HKCU/Software/Wine/$config_key key
770
*/
771
if (install_from_registered_dir() == INSTALL_NEXT
772
&& install_from_default_dir() == INSTALL_NEXT
773
&& install_from_cache() == INSTALL_NEXT
774
&& (url = get_url()))
775
DialogBoxW(hInst, addon->dialog_template, 0, installer_proc);
776
777
free(url);
778
url = NULL;
779
return TRUE;
780
}
781
782