d3d11: Remove null dxgi object checks.
[wine.git] / dlls / urlmon / axinstall.c
blob9d5e99ccc7d3f6959cc1b606dd6815941489cd19
1 /*
2 * Copyright 2012 Jacek Caban for CodeWeavers
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.
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.
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
19 #define OEMRESOURCE
21 #include <assert.h>
23 #include "urlmon_main.h"
24 #include "resource.h"
26 #include "advpub.h"
27 #include "fdi.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
33 enum install_type {
34 INSTALL_UNKNOWN,
35 INSTALL_DLL,
36 INSTALL_INF
39 typedef struct {
40 IUri *uri;
41 IBindStatusCallback *callback;
42 BOOL release_on_stop;
43 BOOL cancel;
44 WCHAR *install_file;
45 const WCHAR *cache_file;
46 const WCHAR *tmp_dir;
47 const WCHAR *file_name;
48 enum install_type install_type;
49 HWND hwnd;
50 int counter;
51 INT_PTR timer;
52 } install_ctx_t;
54 static void release_install_ctx(install_ctx_t *ctx)
56 if(ctx->uri)
57 IUri_Release(ctx->uri);
58 if(ctx->callback)
59 IBindStatusCallback_Release(ctx->callback);
60 heap_free(ctx->install_file);
61 heap_free(ctx);
64 static inline BOOL file_exists(const WCHAR *file_name)
66 return GetFileAttributesW(file_name) != INVALID_FILE_ATTRIBUTES;
69 static HRESULT extract_cab_file(install_ctx_t *ctx)
71 size_t path_len, file_len;
72 WCHAR *ptr;
73 HRESULT hres;
75 hres = ExtractFilesW(ctx->cache_file, ctx->tmp_dir, 0, NULL, NULL, 0);
76 if(FAILED(hres)) {
77 WARN("ExtractFilesW failed: %08lx\n", hres);
78 return hres;
81 path_len = lstrlenW(ctx->tmp_dir);
82 file_len = lstrlenW(ctx->file_name);
83 ctx->install_file = heap_alloc((path_len+file_len+2)*sizeof(WCHAR));
84 if(!ctx->install_file)
85 return E_OUTOFMEMORY;
87 memcpy(ctx->install_file, ctx->tmp_dir, path_len*sizeof(WCHAR));
88 ctx->install_file[path_len] = '\\';
89 memcpy(ctx->install_file+path_len+1, ctx->file_name, (file_len+1)*sizeof(WCHAR));
91 /* NOTE: Assume that file_name contains ".cab" extension */
92 ptr = ctx->install_file+path_len+1+file_len-3;
94 memcpy(ptr, L"inf", sizeof(L"inf"));
95 if(file_exists(ctx->install_file)) {
96 ctx->install_type = INSTALL_INF;
97 return S_OK;
100 memcpy(ptr, L"dll", sizeof(L"dll"));
101 if(file_exists(ctx->install_file)) {
102 ctx->install_type = INSTALL_DLL;
103 return S_OK;
106 memcpy(ptr, L"ocx", sizeof(L"ocx"));
107 if(file_exists(ctx->install_file)) {
108 ctx->install_type = INSTALL_DLL;
109 return S_OK;
112 FIXME("No known install file\n");
113 return E_NOTIMPL;
116 static HRESULT setup_dll(install_ctx_t *ctx)
118 HMODULE module;
119 HRESULT hres;
121 HRESULT (WINAPI *reg_func)(void);
123 module = LoadLibraryW(ctx->install_file);
124 if(!module)
125 return E_FAIL;
127 reg_func = (void*)GetProcAddress(module, "DllRegisterServer");
128 if(reg_func) {
129 hres = reg_func();
130 }else {
131 WARN("no DllRegisterServer function\n");
132 hres = E_FAIL;
135 FreeLibrary(module);
136 return hres;
139 static void expand_command(install_ctx_t *ctx, const WCHAR *cmd, WCHAR *buf, size_t *size)
141 const WCHAR *ptr = cmd, *prev_ptr = cmd;
142 size_t len = 0, len2;
144 static const WCHAR expand_dirW[] = {'%','E','X','T','R','A','C','T','_','D','I','R','%'};
146 while((ptr = wcschr(ptr, '%'))) {
147 if(buf)
148 memcpy(buf+len, prev_ptr, ptr-prev_ptr);
149 len += ptr-prev_ptr;
151 if(!wcsnicmp(ptr, expand_dirW, ARRAY_SIZE(expand_dirW))) {
152 len2 = lstrlenW(ctx->tmp_dir);
153 if(buf)
154 memcpy(buf+len, ctx->tmp_dir, len2*sizeof(WCHAR));
155 len += len2;
156 ptr += ARRAY_SIZE(expand_dirW);
157 }else {
158 FIXME("Can't expand %s\n", debugstr_w(ptr));
159 if(buf)
160 buf[len] = '%';
161 len++;
162 ptr++;
165 prev_ptr = ptr;
168 if(buf)
169 lstrcpyW(buf+len, prev_ptr);
170 *size = len + lstrlenW(prev_ptr) + 1;
173 static HRESULT process_hook_section(install_ctx_t *ctx, const WCHAR *sect_name)
175 WCHAR buf[2048], val[2*MAX_PATH];
176 const WCHAR *key;
177 DWORD len;
178 HRESULT hres;
180 len = GetPrivateProfileStringW(sect_name, NULL, NULL, buf, ARRAY_SIZE(buf), ctx->install_file);
181 if(!len)
182 return S_OK;
184 for(key = buf; *key; key += lstrlenW(key)+1) {
185 if(!wcsicmp(key, L"run")) {
186 WCHAR *cmd;
187 size_t size;
189 len = GetPrivateProfileStringW(sect_name, L"run", NULL, val, ARRAY_SIZE(val), ctx->install_file);
191 TRACE("Run %s\n", debugstr_w(val));
193 expand_command(ctx, val, NULL, &size);
195 cmd = heap_alloc(size*sizeof(WCHAR));
196 if(!cmd)
197 return E_OUTOFMEMORY;
199 expand_command(ctx, val, cmd, &size);
200 hres = RunSetupCommandW(ctx->hwnd, cmd, NULL, ctx->tmp_dir, NULL, NULL, 0, NULL);
201 heap_free(cmd);
202 if(FAILED(hres))
203 return hres;
204 }else {
205 FIXME("Unsupported hook %s\n", debugstr_w(key));
206 return E_NOTIMPL;
210 return S_OK;
213 static HRESULT install_inf_file(install_ctx_t *ctx)
215 WCHAR buf[2048], sect_name[128];
216 BOOL default_install = TRUE;
217 const WCHAR *key;
218 DWORD len;
219 HRESULT hres;
221 len = GetPrivateProfileStringW(L"Setup Hooks", NULL, NULL, buf, ARRAY_SIZE(buf), ctx->install_file);
222 if(len) {
223 default_install = FALSE;
225 for(key = buf; *key; key += lstrlenW(key)+1) {
226 TRACE("[Setup Hooks] key: %s\n", debugstr_w(key));
228 len = GetPrivateProfileStringW(L"Setup Hooks", key, NULL, sect_name, ARRAY_SIZE(sect_name),
229 ctx->install_file);
230 if(!len) {
231 WARN("Could not get key value\n");
232 return E_FAIL;
235 hres = process_hook_section(ctx, sect_name);
236 if(FAILED(hres))
237 return hres;
241 len = GetPrivateProfileStringW(L"Add.Code", NULL, NULL, buf, ARRAY_SIZE(buf), ctx->install_file);
242 if(len) {
243 default_install = FALSE;
245 for(key = buf; *key; key += lstrlenW(key)+1) {
246 TRACE("[Add.Code] key: %s\n", debugstr_w(key));
248 len = GetPrivateProfileStringW(L"Add.Code", key, NULL, sect_name, ARRAY_SIZE(sect_name),
249 ctx->install_file);
250 if(!len) {
251 WARN("Could not get key value\n");
252 return E_FAIL;
255 hres = RunSetupCommandW(ctx->hwnd, ctx->install_file, sect_name,
256 ctx->tmp_dir, NULL, NULL, RSC_FLAG_INF, NULL);
257 if(FAILED(hres)) {
258 WARN("RunSetupCommandW failed: %08lx\n", hres);
259 return hres;
264 if(default_install) {
265 hres = RunSetupCommandW(ctx->hwnd, ctx->install_file, NULL, ctx->tmp_dir, NULL, NULL, RSC_FLAG_INF, NULL);
266 if(FAILED(hres)) {
267 WARN("RunSetupCommandW failed: %08lx\n", hres);
268 return hres;
272 return S_OK;
275 static HRESULT install_cab_file(install_ctx_t *ctx)
277 WCHAR tmp_path[MAX_PATH], tmp_dir[MAX_PATH];
278 BOOL res = FALSE, leave_temp = FALSE;
279 DWORD i;
280 HRESULT hres;
282 GetTempPathW(ARRAY_SIZE(tmp_path), tmp_path);
284 for(i=0; !res && i < 100; i++) {
285 GetTempFileNameW(tmp_path, NULL, GetTickCount() + i*17037, tmp_dir);
286 res = CreateDirectoryW(tmp_dir, NULL);
288 if(!res)
289 return E_FAIL;
291 ctx->tmp_dir = tmp_dir;
293 TRACE("Using temporary directory %s\n", debugstr_w(tmp_dir));
295 hres = extract_cab_file(ctx);
296 if(SUCCEEDED(hres)) {
297 if(ctx->callback)
298 IBindStatusCallback_OnProgress(ctx->callback, 0, 0, BINDSTATUS_INSTALLINGCOMPONENTS, ctx->install_file);
300 switch(ctx->install_type) {
301 case INSTALL_INF:
302 hres = install_inf_file(ctx);
303 break;
304 case INSTALL_DLL:
305 FIXME("Installing DLL, registering in temporary location\n");
306 hres = setup_dll(ctx);
307 if(SUCCEEDED(hres))
308 leave_temp = TRUE;
309 break;
310 default:
311 assert(0);
315 if(!leave_temp)
316 RemoveDirectoryW(ctx->tmp_dir);
317 return hres;
320 static void update_counter(install_ctx_t *ctx, HWND hwnd)
322 WCHAR text[100];
324 if(--ctx->counter <= 0) {
325 HWND button_hwnd;
327 KillTimer(hwnd, ctx->timer);
328 LoadStringW(urlmon_instance, IDS_AXINSTALL_INSTALL, text, ARRAY_SIZE(text));
330 button_hwnd = GetDlgItem(hwnd, ID_AXINSTALL_INSTALL_BTN);
331 EnableWindow(button_hwnd, TRUE);
332 }else {
333 WCHAR buf[100];
334 LoadStringW(urlmon_instance, IDS_AXINSTALL_INSTALLN, buf, ARRAY_SIZE(buf));
335 swprintf(text, ARRAY_SIZE(text), buf, ctx->counter);
338 SetDlgItemTextW(hwnd, ID_AXINSTALL_INSTALL_BTN, text);
341 static BOOL init_warning_dialog(HWND hwnd, install_ctx_t *ctx)
343 BSTR display_uri;
344 HRESULT hres;
346 if(!SetPropW(hwnd, L"ctx", ctx))
347 return FALSE;
349 hres = IUri_GetDisplayUri(ctx->uri, &display_uri);
350 if(FAILED(hres))
351 return FALSE;
353 SetDlgItemTextW(hwnd, ID_AXINSTALL_LOCATION, display_uri);
354 SysFreeString(display_uri);
356 SendDlgItemMessageW(hwnd, ID_AXINSTALL_ICON, STM_SETICON,
357 (WPARAM)LoadIconW(0, (const WCHAR*)OIC_WARNING), 0);
359 ctx->counter = 4;
360 update_counter(ctx, hwnd);
361 ctx->timer = SetTimer(hwnd, 1, 1000, NULL);
362 return TRUE;
365 static INT_PTR WINAPI warning_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
367 switch(msg) {
368 case WM_INITDIALOG: {
369 if(!init_warning_dialog(hwnd, (install_ctx_t*)lparam))
370 EndDialog(hwnd, 0);
371 return TRUE;
373 case WM_COMMAND:
374 switch(wparam) {
375 case ID_AXINSTALL_INSTALL_BTN: {
376 install_ctx_t *ctx = GetPropW(hwnd, L"ctx");
377 if(ctx)
378 ctx->cancel = FALSE;
379 EndDialog(hwnd, 0);
380 return FALSE;
382 case IDCANCEL:
383 EndDialog(hwnd, 0);
384 return FALSE;
386 case WM_TIMER:
387 update_counter(GetPropW(hwnd, L"ctx"), hwnd);
388 return TRUE;
391 return FALSE;
394 static BOOL install_warning(install_ctx_t *ctx)
396 IWindowForBindingUI *window_iface;
397 HWND parent_hwnd = NULL;
398 HRESULT hres;
400 if(!ctx->callback) {
401 FIXME("no callback\n");
402 return FALSE;
405 hres = IBindStatusCallback_QueryInterface(ctx->callback, &IID_IWindowForBindingUI, (void**)&window_iface);
406 if(FAILED(hres))
407 return FALSE;
409 hres = IWindowForBindingUI_GetWindow(window_iface, &IID_ICodeInstall, &ctx->hwnd);
410 IWindowForBindingUI_Release(window_iface);
411 if(FAILED(hres))
412 return FALSE;
414 ctx->cancel = TRUE;
415 DialogBoxParamW(urlmon_instance, MAKEINTRESOURCEW(ID_AXINSTALL_WARNING_DLG), parent_hwnd, warning_proc, (LPARAM)ctx);
416 return !ctx->cancel;
419 static HRESULT install_file(install_ctx_t *ctx, const WCHAR *cache_file)
421 BSTR path;
422 HRESULT hres;
424 TRACE("%s\n", debugstr_w(cache_file));
426 ctx->cache_file = cache_file;
428 if(!install_warning(ctx)) {
429 TRACE("Installation cancelled\n");
430 return S_OK;
433 hres = IUri_GetPath(ctx->uri, &path);
434 if(SUCCEEDED(hres)) {
435 const WCHAR *ptr, *ptr2, *ext;
437 ptr = wcsrchr(path, '/');
438 if(!ptr)
439 ptr = path;
440 else
441 ptr++;
443 ptr2 = wcsrchr(ptr, '\\');
444 if(ptr2)
445 ptr = ptr2+1;
447 ctx->file_name = ptr;
448 ext = wcsrchr(ptr, '.');
449 if(!ext)
450 ext = ptr;
452 if(!wcsicmp(ext, L".cab")) {
453 hres = install_cab_file(ctx);
454 }else {
455 FIXME("Unsupported extension %s\n", debugstr_w(ext));
456 hres = E_NOTIMPL;
458 SysFreeString(path);
461 return hres;
464 static void failure_msgbox(install_ctx_t *ctx, HRESULT hres)
466 WCHAR buf[1024], fmt[1024];
468 LoadStringW(urlmon_instance, IDS_AXINSTALL_FAILURE, fmt, ARRAY_SIZE(fmt));
469 swprintf(buf, ARRAY_SIZE(buf), fmt, hres);
470 MessageBoxW(ctx->hwnd, buf, NULL, MB_OK);
473 static HRESULT distunit_on_stop(void *ctx, const WCHAR *cache_file, HRESULT hresult, const WCHAR *error_str)
475 install_ctx_t *install_ctx = ctx;
477 TRACE("(%p %s %08lx %s)\n", ctx, debugstr_w(cache_file), hresult, debugstr_w(error_str));
479 if(hresult == S_OK) {
480 hresult = install_file(install_ctx, cache_file);
481 if(FAILED(hresult))
482 failure_msgbox(ctx, hresult);
485 if(install_ctx->callback)
486 IBindStatusCallback_OnStopBinding(install_ctx->callback, hresult, error_str);
488 if(install_ctx->release_on_stop)
489 release_install_ctx(install_ctx);
490 return S_OK;
493 /***********************************************************************
494 * AsyncInstallDistributionUnit (URLMON.@)
496 HRESULT WINAPI AsyncInstallDistributionUnit(const WCHAR *szDistUnit, const WCHAR *szTYPE, const WCHAR *szExt,
497 DWORD dwFileVersionMS, DWORD dwFileVersionLS, const WCHAR *szURL, IBindCtx *pbc, void *pvReserved, DWORD flags)
499 install_ctx_t *ctx;
500 HRESULT hres;
502 TRACE("(%s %s %s %lx %lx %s %p %p %lx)\n", debugstr_w(szDistUnit), debugstr_w(szTYPE), debugstr_w(szExt),
503 dwFileVersionMS, dwFileVersionLS, debugstr_w(szURL), pbc, pvReserved, flags);
505 if(szDistUnit || szTYPE || szExt)
506 FIXME("Unsupported arguments\n");
508 ctx = heap_alloc_zero(sizeof(*ctx));
509 if(!ctx)
510 return E_OUTOFMEMORY;
512 hres = CreateUri(szURL, 0, 0, &ctx->uri);
513 if(FAILED(hres)) {
514 heap_free(ctx);
515 return E_OUTOFMEMORY;
518 ctx->callback = bsc_from_bctx(pbc);
520 hres = download_to_cache(ctx->uri, distunit_on_stop, ctx, ctx->callback);
521 if(hres == MK_S_ASYNCHRONOUS)
522 ctx->release_on_stop = TRUE;
523 else
524 release_install_ctx(ctx);
526 return hres;