wine/dlls/appwiz.cpl/addons.c
Vincent Povirk 619b7e07d7 mscoree: Update Wine Mono to 4.7.1.
This has some bug fixes from Mono, and it no longer ships
debug symbols for the whole managed class library, which were
accidentally included in 4.7.0.

Signed-off-by: Vincent Povirk <vincent@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2017-08-01 23:03:46 +02:00

801 lines
22 KiB
C

/*
* Copyright 2006-2010 Jacek Caban for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#define COBJMACROS
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "cpl.h"
#include "winreg.h"
#include "ole2.h"
#include "commctrl.h"
#include "advpub.h"
#include "wininet.h"
#include "shellapi.h"
#include "urlmon.h"
#include "msi.h"
#include "bcrypt.h"
#include "appwiz.h"
#include "res.h"
#include "wine/debug.h"
#include "wine/library.h"
WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
#define GECKO_VERSION "2.47"
#ifdef __i386__
#define ARCH_STRING "x86"
#define GECKO_SHA "3b8a361f5d63952d21caafd74e849a774994822fb96c5922b01d554f1677643a"
#elif defined(__x86_64__)
#define ARCH_STRING "x86_64"
#define GECKO_SHA "c565ea25e50ea953937d4ab01299e4306da4a556946327d253ea9b28357e4a7d"
#else
#define ARCH_STRING ""
#define GECKO_SHA "???"
#endif
#define MONO_VERSION "4.7.1"
#define MONO_SHA "2c8d5db7f833c3413b2519991f5af1f433d59a927564ec6f38a3f1f8b2c629aa"
typedef struct {
const char *version;
const char *file_name;
const char *subdir_name;
const char *sha;
const char *url_default;
const char *config_key;
const char *url_config_key;
const char *dir_config_key;
LPCWSTR dialog_template;
} addon_info_t;
static const addon_info_t addons_info[] = {
{
GECKO_VERSION,
"wine_gecko-" GECKO_VERSION "-" ARCH_STRING ".msi",
"gecko",
GECKO_SHA,
"http://source.winehq.org/winegecko.php",
"MSHTML", "GeckoUrl", "GeckoCabDir",
MAKEINTRESOURCEW(ID_DWL_GECKO_DIALOG)
},
{
MONO_VERSION,
"wine-mono-" MONO_VERSION ".msi",
"mono",
MONO_SHA,
"http://source.winehq.org/winemono.php",
"Dotnet", "MonoUrl", "MonoCabDir",
MAKEINTRESOURCEW(ID_DWL_MONO_DIALOG)
}
};
static const addon_info_t *addon;
static HWND install_dialog = NULL;
static LPWSTR url = NULL;
static IBinding *dwl_binding;
static WCHAR *msi_file;
static WCHAR * (CDECL *p_wine_get_dos_file_name)(const char*);
static const WCHAR kernel32_dllW[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
static BOOL sha_check(const WCHAR *file_name)
{
const unsigned char *file_map;
HANDLE file, map;
DWORD size, i;
BCRYPT_HASH_HANDLE hash = NULL;
BCRYPT_ALG_HANDLE alg = NULL;
UCHAR sha[32];
char buf[1024];
BOOL ret = FALSE;
file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if(file == INVALID_HANDLE_VALUE) {
WARN("Could not open file: %u\n", GetLastError());
return FALSE;
}
size = GetFileSize(file, NULL);
map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
CloseHandle(file);
if(!map)
return FALSE;
file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
CloseHandle(map);
if(!file_map)
return FALSE;
if(BCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))
goto end;
if(BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0))
goto end;
if(BCryptHashData(hash, (UCHAR *)file_map, size, 0))
goto end;
if(BCryptFinishHash(hash, sha, sizeof(sha), 0))
goto end;
for(i=0; i < sizeof(sha); i++)
sprintf(buf + i * 2, "%02x", sha[i]);
ret = !strcmp(buf, addon->sha);
if(!ret)
WARN("Got %s, expected %s\n", buf, addon->sha);
end:
UnmapViewOfFile(file_map);
if(hash) BCryptDestroyHash(hash);
if(alg) BCryptCloseAlgorithmProvider(alg, 0);
return ret;
}
static void set_status(DWORD id)
{
HWND status = GetDlgItem(install_dialog, ID_DWL_STATUS);
WCHAR buf[64];
LoadStringW(hInst, id, buf, sizeof(buf)/sizeof(WCHAR));
SendMessageW(status, WM_SETTEXT, 0, (LPARAM)buf);
}
enum install_res {
INSTALL_OK = 0,
INSTALL_FAILED,
INSTALL_NEXT,
};
static enum install_res install_file(const WCHAR *file_name)
{
ULONG res;
res = MsiInstallProductW(file_name, NULL);
if(res != ERROR_SUCCESS) {
ERR("MsiInstallProduct failed: %u\n", res);
return INSTALL_FAILED;
}
return INSTALL_OK;
}
static enum install_res install_from_unix_file(const char *dir, const char *subdir, const char *file_name)
{
LPWSTR dos_file_name;
char *file_path;
int fd, len;
enum install_res ret;
len = strlen(dir);
file_path = heap_alloc(len+strlen(subdir)+strlen(file_name)+3);
if(!file_path)
return INSTALL_FAILED;
memcpy(file_path, dir, len);
if(len && file_path[len-1] != '/' && file_path[len-1] != '\\')
file_path[len++] = '/';
if(*subdir) {
strcpy(file_path+len, subdir);
len += strlen(subdir);
file_path[len++] = '/';
}
strcpy(file_path+len, file_name);
fd = open(file_path, O_RDONLY);
if(fd == -1) {
TRACE("%s not found\n", debugstr_a(file_path));
heap_free(file_path);
return INSTALL_NEXT;
}
close(fd);
if(p_wine_get_dos_file_name) { /* Wine UNIX mode */
dos_file_name = p_wine_get_dos_file_name(file_path);
if(!dos_file_name) {
ERR("Could not get dos file name of %s\n", debugstr_a(file_path));
heap_free(file_path);
return INSTALL_FAILED;
}
} else { /* Windows mode */
UINT res;
WARN("Could not get wine_get_dos_file_name function, calling install_cab directly.\n");
res = MultiByteToWideChar( CP_ACP, 0, file_path, -1, 0, 0);
dos_file_name = heap_alloc (res*sizeof(WCHAR));
MultiByteToWideChar( CP_ACP, 0, file_path, -1, dos_file_name, res);
}
heap_free(file_path);
ret = install_file(dos_file_name);
heap_free(dos_file_name);
return ret;
}
static HKEY open_config_key(void)
{
HKEY hkey, ret;
DWORD res;
static const WCHAR wine_keyW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e',0};
/* @@ Wine registry key: HKCU\Software\Wine\$config_key */
res = RegOpenKeyW(HKEY_CURRENT_USER, wine_keyW, &hkey);
if(res != ERROR_SUCCESS)
return NULL;
res = RegOpenKeyA(hkey, addon->config_key, &ret);
RegCloseKey(hkey);
return res == ERROR_SUCCESS ? ret : NULL;
}
static enum install_res install_from_registered_dir(void)
{
char *package_dir;
HKEY hkey;
DWORD res, type, size = MAX_PATH;
enum install_res ret;
hkey = open_config_key();
if(!hkey)
return INSTALL_NEXT;
package_dir = heap_alloc(size);
res = RegGetValueA(hkey, NULL, addon->dir_config_key, RRF_RT_ANY, &type, (PBYTE)package_dir, &size);
if(res == ERROR_MORE_DATA) {
package_dir = heap_realloc(package_dir, size);
res = RegGetValueA(hkey, NULL, addon->dir_config_key, RRF_RT_ANY, &type, (PBYTE)package_dir, &size);
}
RegCloseKey(hkey);
if(res == ERROR_FILE_NOT_FOUND) {
heap_free(package_dir);
return INSTALL_NEXT;
} else if(res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) {
heap_free(package_dir);
return INSTALL_FAILED;
}
TRACE("Trying %s/%s\n", debugstr_a(package_dir), debugstr_a(addon->file_name));
ret = install_from_unix_file(package_dir, "", addon->file_name);
heap_free(package_dir);
return ret;
}
static enum install_res install_from_default_dir(void)
{
const char *data_dir, *package_dir;
char *dir_buf = NULL;
int len;
enum install_res ret;
if((data_dir = wine_get_data_dir())) {
package_dir = data_dir;
}else if((data_dir = wine_get_build_dir())) {
len = strlen(data_dir);
dir_buf = heap_alloc(len + sizeof("/../"));
memcpy(dir_buf, data_dir, len);
strcpy(dir_buf+len, "/../");
package_dir = dir_buf;
}else {
return INSTALL_NEXT;
}
ret = install_from_unix_file(package_dir, addon->subdir_name, addon->file_name);
heap_free(dir_buf);
if (ret == INSTALL_NEXT)
ret = install_from_unix_file(INSTALL_DATADIR "/wine/", addon->subdir_name, addon->file_name);
if (ret == INSTALL_NEXT && strcmp(INSTALL_DATADIR, "/usr/share"))
ret = install_from_unix_file("/usr/share/wine/", addon->subdir_name, addon->file_name);
return ret;
}
static WCHAR *get_cache_file_name(BOOL ensure_exists)
{
const char *home_dir = NULL, *xdg_cache_dir;
size_t len, size = strlen(addon->file_name) + 7; /* strlen("/wine/"), '\0' */
char *cache_file_name;
WCHAR *ret;
/* non-Wine (eg. Windows) cache is currently not supported */
if(!p_wine_get_dos_file_name)
return NULL;
xdg_cache_dir = getenv("XDG_CACHE_HOME");
if(xdg_cache_dir && *xdg_cache_dir) {
size += strlen(xdg_cache_dir);
}else {
home_dir = getenv("HOME");
if(!home_dir)
return NULL;
size += strlen(home_dir) + 8; /* strlen("/.cache/") */
}
cache_file_name = heap_alloc(size);
if(!cache_file_name)
return NULL;
if(xdg_cache_dir && *xdg_cache_dir) {
len = strlen(xdg_cache_dir);
if(len > 1 && xdg_cache_dir[len-1] == '/')
len--;
memcpy(cache_file_name, xdg_cache_dir, len);
cache_file_name[len] = 0;
}else {
len = strlen(home_dir);
memcpy(cache_file_name, home_dir, len);
strcpy(cache_file_name+len, "/.cache");
len += 7;
}
if(ensure_exists && mkdir(cache_file_name, 0777) && errno != EEXIST) {
WARN("%s does not exist and could not be created: %s\n", cache_file_name, strerror(errno));
heap_free(cache_file_name);
return NULL;
}
strcpy(cache_file_name+len, "/wine");
len += 5;
if(ensure_exists && mkdir(cache_file_name, 0777) && errno != EEXIST) {
WARN("%s does not exist and could not be created: %s\n", cache_file_name, strerror(errno));
return NULL;
}
cache_file_name[len++] = '/';
strcpy(cache_file_name+len, addon->file_name);
ret = p_wine_get_dos_file_name(cache_file_name);
TRACE("%s -> %s\n", cache_file_name, debugstr_w(ret));
heap_free(cache_file_name);
return ret;
}
static enum install_res install_from_cache(void)
{
WCHAR *cache_file_name;
enum install_res res;
cache_file_name = get_cache_file_name(FALSE);
if(!cache_file_name)
return INSTALL_NEXT;
if(!sha_check(cache_file_name)) {
WARN("could not validate checksum\n");
DeleteFileW(cache_file_name);
heap_free(cache_file_name);
return INSTALL_NEXT;
}
res = install_file(cache_file_name);
heap_free(cache_file_name);
return res;
}
static IInternetBindInfo InstallCallbackBindInfo;
static HRESULT WINAPI InstallCallback_QueryInterface(IBindStatusCallback *iface,
REFIID riid, void **ppv)
{
if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IBindStatusCallback, riid)) {
*ppv = iface;
return S_OK;
}
if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
TRACE("IID_IInternetBindInfo\n");
*ppv = &InstallCallbackBindInfo;
return S_OK;
}
return E_INVALIDARG;
}
static ULONG WINAPI InstallCallback_AddRef(IBindStatusCallback *iface)
{
return 2;
}
static ULONG WINAPI InstallCallback_Release(IBindStatusCallback *iface)
{
return 1;
}
static HRESULT WINAPI InstallCallback_OnStartBinding(IBindStatusCallback *iface,
DWORD dwReserved, IBinding *pib)
{
set_status(IDS_DOWNLOADING);
IBinding_AddRef(pib);
dwl_binding = pib;
return S_OK;
}
static HRESULT WINAPI InstallCallback_GetPriority(IBindStatusCallback *iface,
LONG *pnPriority)
{
return E_NOTIMPL;
}
static HRESULT WINAPI InstallCallback_OnLowResource(IBindStatusCallback *iface,
DWORD dwReserved)
{
return E_NOTIMPL;
}
static HRESULT WINAPI InstallCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
{
HWND progress = GetDlgItem(install_dialog, ID_DWL_PROGRESS);
if(ulProgressMax)
SendMessageW(progress, PBM_SETRANGE32, 0, ulProgressMax);
if(ulProgress)
SendMessageW(progress, PBM_SETPOS, ulProgress, 0);
return S_OK;
}
static HRESULT WINAPI InstallCallback_OnStopBinding(IBindStatusCallback *iface,
HRESULT hresult, LPCWSTR szError)
{
if(dwl_binding) {
IBinding_Release(dwl_binding);
dwl_binding = NULL;
}
if(FAILED(hresult)) {
if(hresult == E_ABORT)
TRACE("Binding aborted\n");
else
ERR("Binding failed %08x\n", hresult);
return S_OK;
}
if(!msi_file) {
ERR("No MSI file\n");
return E_FAIL;
}
set_status(IDS_INSTALLING);
EnableWindow(GetDlgItem(install_dialog, IDCANCEL), 0);
if(sha_check(msi_file)) {
WCHAR *cache_file_name;
install_file(msi_file);
cache_file_name = get_cache_file_name(TRUE);
if(cache_file_name) {
MoveFileW(msi_file, cache_file_name);
heap_free(cache_file_name);
}
}else {
WCHAR message[256];
if(LoadStringW(hInst, IDS_INVALID_SHA, message, sizeof(message)/sizeof(WCHAR)))
MessageBoxW(NULL, message, NULL, MB_ICONERROR);
}
DeleteFileW(msi_file);
heap_free(msi_file);
msi_file = NULL;
EndDialog(install_dialog, 0);
return S_OK;
}
static HRESULT WINAPI InstallCallback_GetBindInfo(IBindStatusCallback *iface,
DWORD* grfBINDF, BINDINFO* pbindinfo)
{
TRACE("()\n");
*grfBINDF = BINDF_ASYNCHRONOUS;
return S_OK;
}
static HRESULT WINAPI InstallCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
{
if(!msi_file) {
msi_file = heap_strdupW(pstgmed->u.lpszFileName);
TRACE("got file name %s\n", debugstr_w(msi_file));
}
return S_OK;
}
static HRESULT WINAPI InstallCallback_OnObjectAvailable(IBindStatusCallback *iface,
REFIID riid, IUnknown* punk)
{
ERR("\n");
return E_NOTIMPL;
}
static const IBindStatusCallbackVtbl InstallCallbackVtbl = {
InstallCallback_QueryInterface,
InstallCallback_AddRef,
InstallCallback_Release,
InstallCallback_OnStartBinding,
InstallCallback_GetPriority,
InstallCallback_OnLowResource,
InstallCallback_OnProgress,
InstallCallback_OnStopBinding,
InstallCallback_GetBindInfo,
InstallCallback_OnDataAvailable,
InstallCallback_OnObjectAvailable
};
static IBindStatusCallback InstallCallback = { &InstallCallbackVtbl };
static HRESULT WINAPI InstallCallbackBindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
{
return IBindStatusCallback_QueryInterface(&InstallCallback, riid, ppv);
}
static ULONG WINAPI InstallCallbackBindInfo_AddRef(IInternetBindInfo *iface)
{
return 2;
}
static ULONG WINAPI InstallCallbackBindInfo_Release(IInternetBindInfo *iface)
{
return 1;
}
static HRESULT WINAPI InstallCallbackBindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *bindf, BINDINFO *bindinfo)
{
ERR("\n");
return E_NOTIMPL;
}
static HRESULT WINAPI InstallCallbackBindInfo_GetBindString(IInternetBindInfo *iface, ULONG string_type,
WCHAR **strs, ULONG cnt, ULONG *fetched)
{
static const WCHAR wine_addon_downloaderW[] =
{'W','i','n','e',' ','A','d','d','o','n',' ','D','o','w','n','l','o','a','d','e','r',0};
switch(string_type) {
case BINDSTRING_USER_AGENT:
TRACE("BINDSTRING_USER_AGENT\n");
*strs = CoTaskMemAlloc(sizeof(wine_addon_downloaderW));
if(!*strs)
return E_OUTOFMEMORY;
memcpy(*strs, wine_addon_downloaderW, sizeof(wine_addon_downloaderW));
*fetched = 1;
return S_OK;
}
return E_NOTIMPL;
}
static const IInternetBindInfoVtbl InstallCallbackBindInfoVtbl = {
InstallCallbackBindInfo_QueryInterface,
InstallCallbackBindInfo_AddRef,
InstallCallbackBindInfo_Release,
InstallCallbackBindInfo_GetBindInfo,
InstallCallbackBindInfo_GetBindString
};
static IInternetBindInfo InstallCallbackBindInfo = { &InstallCallbackBindInfoVtbl };
static void append_url_params( WCHAR *url )
{
static const WCHAR arch_formatW[] = {'?','a','r','c','h','='};
static const WCHAR v_formatW[] = {'&','v','='};
static const WCHAR winevW[] = {'&','w','i','n','e','v','='};
DWORD size = INTERNET_MAX_URL_LENGTH * sizeof(WCHAR);
DWORD len = strlenW(url);
memcpy(url+len, arch_formatW, sizeof(arch_formatW));
len += sizeof(arch_formatW)/sizeof(WCHAR);
len += MultiByteToWideChar(CP_ACP, 0, ARCH_STRING, sizeof(ARCH_STRING),
url+len, size/sizeof(WCHAR)-len)-1;
memcpy(url+len, v_formatW, sizeof(v_formatW));
len += sizeof(v_formatW)/sizeof(WCHAR);
len += MultiByteToWideChar(CP_ACP, 0, addon->version, -1, url+len, size/sizeof(WCHAR)-len)-1;
memcpy(url+len, winevW, sizeof(winevW));
len += sizeof(winevW)/sizeof(WCHAR);
MultiByteToWideChar(CP_ACP, 0, PACKAGE_VERSION, -1, url+len, size/sizeof(WCHAR)-len);
}
static LPWSTR get_url(void)
{
DWORD size = INTERNET_MAX_URL_LENGTH*sizeof(WCHAR);
WCHAR *url, *config_key;
HKEY hkey;
DWORD res, type;
DWORD returned_size;
static const WCHAR httpW[] = {'h','t','t','p'};
url = heap_alloc(size);
returned_size = size;
hkey = open_config_key();
if (hkey)
{
config_key = heap_strdupAtoW(addon->url_config_key);
res = RegQueryValueExW(hkey, config_key, NULL, &type, (LPBYTE)url, &returned_size);
heap_free(config_key);
RegCloseKey(hkey);
if(res == ERROR_SUCCESS && type == REG_SZ) goto found;
}
MultiByteToWideChar( CP_ACP, 0, addon->url_default, -1, url, size / sizeof(WCHAR) );
found:
if (returned_size > sizeof(httpW) && !memcmp(url, httpW, sizeof(httpW))) append_url_params( url );
TRACE("Got URL %s\n", debugstr_w(url));
return url;
}
static BOOL start_download(void)
{
IBindCtx *bind_ctx;
IMoniker *mon;
IUnknown *tmp;
HRESULT hres;
hres = CreateURLMoniker(NULL, url, &mon);
if(FAILED(hres))
return FALSE;
hres = CreateAsyncBindCtx(0, &InstallCallback, NULL, &bind_ctx);
if(SUCCEEDED(hres)) {
hres = IMoniker_BindToStorage(mon, bind_ctx, NULL, &IID_IUnknown, (void**)&tmp);
IBindCtx_Release(bind_ctx);
}
IMoniker_Release(mon);
if(FAILED(hres))
return FALSE;
if(tmp)
IUnknown_Release(tmp);
return TRUE;
}
static void run_winebrowser(const WCHAR *url)
{
PROCESS_INFORMATION pi;
STARTUPINFOW si;
WCHAR app[MAX_PATH];
LONG len, url_len;
WCHAR *args;
BOOL ret;
static const WCHAR winebrowserW[] = {'\\','w','i','n','e','b','r','o','w','s','e','r','.','e','x','e',0};
url_len = strlenW(url);
len = GetSystemDirectoryW(app, MAX_PATH-sizeof(winebrowserW)/sizeof(WCHAR));
memcpy(app+len, winebrowserW, sizeof(winebrowserW));
len += sizeof(winebrowserW)/sizeof(WCHAR) -1;
args = heap_alloc((len+1+url_len)*sizeof(WCHAR));
if(!args)
return;
memcpy(args, app, len*sizeof(WCHAR));
args[len++] = ' ';
memcpy(args+len, url, (url_len+1) * sizeof(WCHAR));
TRACE("starting %s\n", debugstr_w(args));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
ret = CreateProcessW(app, args, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi);
heap_free(args);
if (ret) {
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
}
static INT_PTR CALLBACK installer_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg) {
case WM_INITDIALOG:
ShowWindow(GetDlgItem(hwnd, ID_DWL_PROGRESS), SW_HIDE);
install_dialog = hwnd;
return TRUE;
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code)
{
case NM_CLICK:
case NM_RETURN:
if (wParam == ID_DWL_STATUS)
run_winebrowser(((NMLINK*)lParam)->item.szUrl);
break;
}
break;
case WM_COMMAND:
switch(wParam) {
case IDCANCEL:
if(dwl_binding)
IBinding_Abort(dwl_binding);
EndDialog(hwnd, 0);
return FALSE;
case ID_DWL_INSTALL:
ShowWindow(GetDlgItem(hwnd, ID_DWL_PROGRESS), SW_SHOW);
EnableWindow(GetDlgItem(hwnd, ID_DWL_INSTALL), 0);
if(!start_download())
EndDialog(install_dialog, 0);
}
}
return FALSE;
}
BOOL install_addon(addon_t addon_type)
{
if(!*ARCH_STRING)
return FALSE;
addon = addons_info+addon_type;
p_wine_get_dos_file_name = (void*)GetProcAddress(GetModuleHandleW(kernel32_dllW), "wine_get_dos_file_name");
/*
* Try to find addon .msi file in following order:
* - directory stored in $dir_config_key value of HKCU/Software/Wine/$config_key key
* - $datadir/$addon_subdir/
* - $INSTALL_DATADIR/wine/$addon_subdir/
* - /usr/share/wine/$addon_subdir/
* - download from URL stored in $url_config_key value of HKCU/Software/Wine/$config_key key
*/
if (install_from_registered_dir() == INSTALL_NEXT
&& install_from_default_dir() == INSTALL_NEXT
&& install_from_cache() == INSTALL_NEXT
&& (url = get_url()))
DialogBoxW(hInst, addon->dialog_template, 0, installer_proc);
heap_free(url);
url = NULL;
return TRUE;
}