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
23 #include "urlmon_main.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(urlmon
);
41 IBindStatusCallback
*callback
;
45 const WCHAR
*cache_file
;
47 const WCHAR
*file_name
;
48 enum install_type install_type
;
54 static void release_install_ctx(install_ctx_t
*ctx
)
57 IUri_Release(ctx
->uri
);
59 IBindStatusCallback_Release(ctx
->callback
);
60 heap_free(ctx
->install_file
);
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
;
75 hres
= ExtractFilesW(ctx
->cache_file
, ctx
->tmp_dir
, 0, NULL
, NULL
, 0);
77 WARN("ExtractFilesW failed: %08x\n", 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
)
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
;
100 memcpy(ptr
, L
"dll", sizeof(L
"dll"));
101 if(file_exists(ctx
->install_file
)) {
102 ctx
->install_type
= INSTALL_DLL
;
106 memcpy(ptr
, L
"ocx", sizeof(L
"ocx"));
107 if(file_exists(ctx
->install_file
)) {
108 ctx
->install_type
= INSTALL_DLL
;
112 FIXME("No known install file\n");
116 static HRESULT
setup_dll(install_ctx_t
*ctx
)
121 HRESULT (WINAPI
*reg_func
)(void);
123 module
= LoadLibraryW(ctx
->install_file
);
127 reg_func
= (void*)GetProcAddress(module
, "DllRegisterServer");
131 WARN("no DllRegisterServer function\n");
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
, '%'))) {
148 memcpy(buf
+len
, prev_ptr
, ptr
-prev_ptr
);
151 if(!wcsnicmp(ptr
, expand_dirW
, ARRAY_SIZE(expand_dirW
))) {
152 len2
= lstrlenW(ctx
->tmp_dir
);
154 memcpy(buf
+len
, ctx
->tmp_dir
, len2
*sizeof(WCHAR
));
156 ptr
+= ARRAY_SIZE(expand_dirW
);
158 FIXME("Can't expand %s\n", debugstr_w(ptr
));
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
];
180 len
= GetPrivateProfileStringW(sect_name
, NULL
, NULL
, buf
, ARRAY_SIZE(buf
), ctx
->install_file
);
184 for(key
= buf
; *key
; key
+= lstrlenW(key
)+1) {
185 if(!wcsicmp(key
, L
"run")) {
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
));
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
);
205 FIXME("Unsupported hook %s\n", debugstr_w(key
));
213 static HRESULT
install_inf_file(install_ctx_t
*ctx
)
215 WCHAR buf
[2048], sect_name
[128];
216 BOOL default_install
= TRUE
;
221 len
= GetPrivateProfileStringW(L
"Setup Hooks", NULL
, NULL
, buf
, ARRAY_SIZE(buf
), ctx
->install_file
);
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
),
231 WARN("Could not get key value\n");
235 hres
= process_hook_section(ctx
, sect_name
);
241 len
= GetPrivateProfileStringW(L
"Add.Code", NULL
, NULL
, buf
, ARRAY_SIZE(buf
), ctx
->install_file
);
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
),
251 WARN("Could not get key value\n");
255 hres
= RunSetupCommandW(ctx
->hwnd
, ctx
->install_file
, sect_name
,
256 ctx
->tmp_dir
, NULL
, NULL
, RSC_FLAG_INF
, NULL
);
258 WARN("RunSetupCommandW failed: %08x\n", hres
);
264 if(default_install
) {
265 hres
= RunSetupCommandW(ctx
->hwnd
, ctx
->install_file
, NULL
, ctx
->tmp_dir
, NULL
, NULL
, RSC_FLAG_INF
, NULL
);
267 WARN("RunSetupCommandW failed: %08x\n", hres
);
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
;
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
);
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
)) {
298 IBindStatusCallback_OnProgress(ctx
->callback
, 0, 0, BINDSTATUS_INSTALLINGCOMPONENTS
, ctx
->install_file
);
300 switch(ctx
->install_type
) {
302 hres
= install_inf_file(ctx
);
305 FIXME("Installing DLL, registering in temporary location\n");
306 hres
= setup_dll(ctx
);
316 RemoveDirectoryW(ctx
->tmp_dir
);
320 static void update_counter(install_ctx_t
*ctx
, HWND hwnd
)
324 if(--ctx
->counter
<= 0) {
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
);
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
)
346 if(!SetPropW(hwnd
, L
"ctx", ctx
))
349 hres
= IUri_GetDisplayUri(ctx
->uri
, &display_uri
);
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);
360 update_counter(ctx
, hwnd
);
361 ctx
->timer
= SetTimer(hwnd
, 1, 1000, NULL
);
365 static INT_PTR WINAPI
warning_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
368 case WM_INITDIALOG
: {
369 if(!init_warning_dialog(hwnd
, (install_ctx_t
*)lparam
))
375 case ID_AXINSTALL_INSTALL_BTN
: {
376 install_ctx_t
*ctx
= GetPropW(hwnd
, L
"ctx");
387 update_counter(GetPropW(hwnd
, L
"ctx"), hwnd
);
394 static BOOL
install_warning(install_ctx_t
*ctx
)
396 IWindowForBindingUI
*window_iface
;
397 HWND parent_hwnd
= NULL
;
401 FIXME("no callback\n");
405 hres
= IBindStatusCallback_QueryInterface(ctx
->callback
, &IID_IWindowForBindingUI
, (void**)&window_iface
);
409 hres
= IWindowForBindingUI_GetWindow(window_iface
, &IID_ICodeInstall
, &ctx
->hwnd
);
410 IWindowForBindingUI_Release(window_iface
);
415 DialogBoxParamW(urlmon_instance
, MAKEINTRESOURCEW(ID_AXINSTALL_WARNING_DLG
), parent_hwnd
, warning_proc
, (LPARAM
)ctx
);
419 static HRESULT
install_file(install_ctx_t
*ctx
, const WCHAR
*cache_file
)
424 TRACE("%s\n", debugstr_w(cache_file
));
426 ctx
->cache_file
= cache_file
;
428 if(!install_warning(ctx
)) {
429 TRACE("Installation cancelled\n");
433 hres
= IUri_GetPath(ctx
->uri
, &path
);
434 if(SUCCEEDED(hres
)) {
435 const WCHAR
*ptr
, *ptr2
, *ext
;
437 ptr
= wcsrchr(path
, '/');
443 ptr2
= wcsrchr(ptr
, '\\');
447 ctx
->file_name
= ptr
;
448 ext
= wcsrchr(ptr
, '.');
452 if(!wcsicmp(ext
, L
".cab")) {
453 hres
= install_cab_file(ctx
);
455 FIXME("Unsupported extension %s\n", debugstr_w(ext
));
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 %08x %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
);
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
);
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
)
502 TRACE("(%s %s %s %x %x %s %p %p %x)\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
));
510 return E_OUTOFMEMORY
;
512 hres
= CreateUri(szURL
, 0, 0, &ctx
->uri
);
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
;
524 release_install_ctx(ctx
);