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 #include "urlmon_main.h"
25 static const WCHAR ctxW
[] = {'c','t','x',0};
26 static const WCHAR cab_extW
[] = {'.','c','a','b',0};
27 static const WCHAR infW
[] = {'i','n','f',0};
28 static const WCHAR dllW
[] = {'d','l','l',0};
29 static const WCHAR ocxW
[] = {'o','c','x',0};
39 IBindStatusCallback
*callback
;
43 const WCHAR
*cache_file
;
45 const WCHAR
*file_name
;
46 enum install_type install_type
;
52 static void release_install_ctx(install_ctx_t
*ctx
)
55 IUri_Release(ctx
->uri
);
57 IBindStatusCallback_Release(ctx
->callback
);
58 heap_free(ctx
->install_file
);
62 static inline BOOL
file_exists(const WCHAR
*file_name
)
64 return GetFileAttributesW(file_name
) != INVALID_FILE_ATTRIBUTES
;
67 static HRESULT
extract_cab_file(install_ctx_t
*ctx
)
69 size_t path_len
, file_len
;
73 hres
= ExtractFilesW(ctx
->cache_file
, ctx
->tmp_dir
, 0, NULL
, NULL
, 0);
75 WARN("ExtractFilesW failed: %08x\n", hres
);
79 path_len
= strlenW(ctx
->tmp_dir
);
80 file_len
= strlenW(ctx
->file_name
);
81 ctx
->install_file
= heap_alloc((path_len
+file_len
+2)*sizeof(WCHAR
));
82 if(!ctx
->install_file
)
85 memcpy(ctx
->install_file
, ctx
->tmp_dir
, path_len
*sizeof(WCHAR
));
86 ctx
->install_file
[path_len
] = '\\';
87 memcpy(ctx
->install_file
+path_len
+1, ctx
->file_name
, (file_len
+1)*sizeof(WCHAR
));
89 /* NOTE: Assume that file_name contains ".cab" extension */
90 ptr
= ctx
->install_file
+path_len
+1+file_len
-3;
92 memcpy(ptr
, infW
, sizeof(infW
));
93 if(file_exists(ctx
->install_file
)) {
94 ctx
->install_type
= INSTALL_INF
;
98 memcpy(ptr
, dllW
, sizeof(dllW
));
99 if(file_exists(ctx
->install_file
)) {
100 ctx
->install_type
= INSTALL_DLL
;
104 memcpy(ptr
, ocxW
, sizeof(ocxW
));
105 if(file_exists(ctx
->install_file
)) {
106 ctx
->install_type
= INSTALL_DLL
;
110 FIXME("No known install file\n");
114 static HRESULT
setup_dll(install_ctx_t
*ctx
)
119 HRESULT (WINAPI
*reg_func
)(void);
121 module
= LoadLibraryW(ctx
->install_file
);
125 reg_func
= (void*)GetProcAddress(module
, "DllRegisterServer");
129 WARN("no DllRegisterServer function\n");
137 static void expand_command(install_ctx_t
*ctx
, const WCHAR
*cmd
, WCHAR
*buf
, size_t *size
)
139 const WCHAR
*ptr
= cmd
, *prev_ptr
= cmd
;
140 size_t len
= 0, len2
;
142 static const WCHAR expand_dirW
[] = {'%','E','X','T','R','A','C','T','_','D','I','R','%'};
144 while((ptr
= strchrW(ptr
, '%'))) {
146 memcpy(buf
+len
, prev_ptr
, ptr
-prev_ptr
);
149 if(!strncmpiW(ptr
, expand_dirW
, sizeof(expand_dirW
)/sizeof(WCHAR
))) {
150 len2
= strlenW(ctx
->tmp_dir
);
152 memcpy(buf
+len
, ctx
->tmp_dir
, len2
*sizeof(WCHAR
));
154 ptr
+= sizeof(expand_dirW
)/sizeof(WCHAR
);
156 FIXME("Can't expand %s\n", debugstr_w(ptr
));
167 strcpyW(buf
+len
, prev_ptr
);
168 *size
= len
+ strlenW(prev_ptr
) + 1;
171 static HRESULT
process_hook_section(install_ctx_t
*ctx
, const WCHAR
*sect_name
)
173 WCHAR buf
[2048], val
[2*MAX_PATH
];
178 static const WCHAR runW
[] = {'r','u','n',0};
180 len
= GetPrivateProfileStringW(sect_name
, NULL
, NULL
, buf
, sizeof(buf
)/sizeof(*buf
), ctx
->install_file
);
184 for(key
= buf
; *key
; key
+= strlenW(key
)+1) {
185 if(!strcmpiW(key
, runW
)) {
189 len
= GetPrivateProfileStringW(sect_name
, runW
, NULL
, val
, sizeof(val
)/sizeof(*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
));
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 static const WCHAR setup_hooksW
[] = {'S','e','t','u','p',' ','H','o','o','k','s',0};
222 static const WCHAR add_codeW
[] = {'A','d','d','.','C','o','d','e',0};
224 len
= GetPrivateProfileStringW(setup_hooksW
, NULL
, NULL
, buf
, sizeof(buf
)/sizeof(*buf
), ctx
->install_file
);
226 default_install
= FALSE
;
228 for(key
= buf
; *key
; key
+= strlenW(key
)+1) {
229 TRACE("[Setup Hooks] key: %s\n", debugstr_w(key
));
231 len
= GetPrivateProfileStringW(setup_hooksW
, key
, NULL
, sect_name
, sizeof(sect_name
)/sizeof(*sect_name
),
234 WARN("Could not get key value\n");
238 hres
= process_hook_section(ctx
, sect_name
);
244 len
= GetPrivateProfileStringW(add_codeW
, NULL
, NULL
, buf
, sizeof(buf
)/sizeof(*buf
), ctx
->install_file
);
246 FIXME("[Add.Code] section not supported\n");
248 /* Don't throw an error if we successfully ran setup hooks;
249 installation is likely to be complete enough */
254 if(default_install
) {
255 hres
= RunSetupCommandW(ctx
->hwnd
, ctx
->install_file
, NULL
, ctx
->tmp_dir
, NULL
, NULL
, RSC_FLAG_INF
, NULL
);
257 WARN("RunSetupCommandW failed: %08x\n", hres
);
265 static HRESULT
install_cab_file(install_ctx_t
*ctx
)
267 WCHAR tmp_path
[MAX_PATH
], tmp_dir
[MAX_PATH
];
268 BOOL res
= FALSE
, leave_temp
= FALSE
;
272 GetTempPathW(sizeof(tmp_path
)/sizeof(WCHAR
), tmp_path
);
274 for(i
=0; !res
&& i
< 100; i
++) {
275 GetTempFileNameW(tmp_path
, NULL
, GetTickCount() + i
*17037, tmp_dir
);
276 res
= CreateDirectoryW(tmp_dir
, NULL
);
281 ctx
->tmp_dir
= tmp_dir
;
283 TRACE("Using temporary directory %s\n", debugstr_w(tmp_dir
));
285 hres
= extract_cab_file(ctx
);
286 if(SUCCEEDED(hres
)) {
288 IBindStatusCallback_OnProgress(ctx
->callback
, 0, 0, BINDSTATUS_INSTALLINGCOMPONENTS
, ctx
->install_file
);
290 switch(ctx
->install_type
) {
292 hres
= install_inf_file(ctx
);
295 FIXME("Installing DLL, registering in temporary location\n");
296 hres
= setup_dll(ctx
);
306 RemoveDirectoryW(ctx
->tmp_dir
);
310 static void update_counter(install_ctx_t
*ctx
, HWND hwnd
)
314 if(--ctx
->counter
<= 0) {
317 KillTimer(hwnd
, ctx
->timer
);
318 LoadStringW(urlmon_instance
, IDS_AXINSTALL_INSTALL
, text
, sizeof(text
)/sizeof(WCHAR
));
320 button_hwnd
= GetDlgItem(hwnd
, ID_AXINSTALL_INSTALL_BTN
);
321 EnableWindow(button_hwnd
, TRUE
);
324 LoadStringW(urlmon_instance
, IDS_AXINSTALL_INSTALLN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
325 sprintfW(text
, buf
, ctx
->counter
);
328 SetDlgItemTextW(hwnd
, ID_AXINSTALL_INSTALL_BTN
, text
);
331 static BOOL
init_warning_dialog(HWND hwnd
, install_ctx_t
*ctx
)
336 if(!SetPropW(hwnd
, ctxW
, ctx
))
339 hres
= IUri_GetDisplayUri(ctx
->uri
, &display_uri
);
343 SetDlgItemTextW(hwnd
, ID_AXINSTALL_LOCATION
, display_uri
);
344 SysFreeString(display_uri
);
346 SendDlgItemMessageW(hwnd
, ID_AXINSTALL_ICON
, STM_SETICON
,
347 (WPARAM
)LoadIconW(0, (const WCHAR
*)OIC_WARNING
), 0);
350 update_counter(ctx
, hwnd
);
351 ctx
->timer
= SetTimer(hwnd
, 1, 1000, NULL
);
355 static INT_PTR WINAPI
warning_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
358 case WM_INITDIALOG
: {
359 if(!init_warning_dialog(hwnd
, (install_ctx_t
*)lparam
))
365 case ID_AXINSTALL_INSTALL_BTN
: {
366 install_ctx_t
*ctx
= GetPropW(hwnd
, ctxW
);
377 update_counter(GetPropW(hwnd
, ctxW
), hwnd
);
384 static BOOL
install_warning(install_ctx_t
*ctx
)
386 IWindowForBindingUI
*window_iface
;
387 HWND parent_hwnd
= NULL
;
391 FIXME("no callback\n");
395 hres
= IBindStatusCallback_QueryInterface(ctx
->callback
, &IID_IWindowForBindingUI
, (void**)&window_iface
);
399 hres
= IWindowForBindingUI_GetWindow(window_iface
, &IID_ICodeInstall
, &ctx
->hwnd
);
400 IWindowForBindingUI_Release(window_iface
);
405 DialogBoxParamW(urlmon_instance
, MAKEINTRESOURCEW(ID_AXINSTALL_WARNING_DLG
), parent_hwnd
, warning_proc
, (LPARAM
)ctx
);
409 static HRESULT
install_file(install_ctx_t
*ctx
, const WCHAR
*cache_file
)
414 TRACE("%s\n", debugstr_w(cache_file
));
416 ctx
->cache_file
= cache_file
;
418 if(!install_warning(ctx
)) {
419 TRACE("Installation cancelled\n");
423 hres
= IUri_GetPath(ctx
->uri
, &path
);
424 if(SUCCEEDED(hres
)) {
425 const WCHAR
*ptr
, *ptr2
, *ext
;
427 ptr
= strrchrW(path
, '/');
433 ptr2
= strrchrW(ptr
, '\\');
437 ctx
->file_name
= ptr
;
438 ext
= strrchrW(ptr
, '.');
442 if(!strcmpiW(ext
, cab_extW
)) {
443 hres
= install_cab_file(ctx
);
445 FIXME("Unsupported extension %s\n", debugstr_w(ext
));
454 static void failure_msgbox(install_ctx_t
*ctx
, HRESULT hres
)
456 WCHAR buf
[1024], fmt
[1024];
458 LoadStringW(urlmon_instance
, IDS_AXINSTALL_FAILURE
, fmt
, sizeof(fmt
)/sizeof(WCHAR
));
459 sprintfW(buf
, fmt
, hres
);
460 MessageBoxW(ctx
->hwnd
, buf
, NULL
, MB_OK
);
463 static HRESULT
distunit_on_stop(void *ctx
, const WCHAR
*cache_file
, HRESULT hresult
, const WCHAR
*error_str
)
465 install_ctx_t
*install_ctx
= ctx
;
467 TRACE("(%p %s %08x %s)\n", ctx
, debugstr_w(cache_file
), hresult
, debugstr_w(error_str
));
469 if(hresult
== S_OK
) {
470 hresult
= install_file(install_ctx
, cache_file
);
472 failure_msgbox(ctx
, hresult
);
475 if(install_ctx
->callback
)
476 IBindStatusCallback_OnStopBinding(install_ctx
->callback
, hresult
, error_str
);
478 if(install_ctx
->release_on_stop
)
479 release_install_ctx(install_ctx
);
483 /***********************************************************************
484 * AsyncInstallDistributionUnit (URLMON.@)
486 HRESULT WINAPI
AsyncInstallDistributionUnit(const WCHAR
*szDistUnit
, const WCHAR
*szTYPE
, const WCHAR
*szExt
,
487 DWORD dwFileVersionMS
, DWORD dwFileVersionLS
, const WCHAR
*szURL
, IBindCtx
*pbc
, void *pvReserved
, DWORD flags
)
492 TRACE("(%s %s %s %x %x %s %p %p %x)\n", debugstr_w(szDistUnit
), debugstr_w(szTYPE
), debugstr_w(szExt
),
493 dwFileVersionMS
, dwFileVersionLS
, debugstr_w(szURL
), pbc
, pvReserved
, flags
);
495 if(szDistUnit
|| szTYPE
|| szExt
)
496 FIXME("Unsupported arguments\n");
498 ctx
= heap_alloc_zero(sizeof(*ctx
));
500 return E_OUTOFMEMORY
;
502 hres
= CreateUri(szURL
, 0, 0, &ctx
->uri
);
505 return E_OUTOFMEMORY
;
508 ctx
->callback
= bsc_from_bctx(pbc
);
510 hres
= download_to_cache(ctx
->uri
, distunit_on_stop
, ctx
, ctx
->callback
);
511 if(hres
== MK_S_ASYNCHRONOUS
)
512 ctx
->release_on_stop
= TRUE
;
514 release_install_ctx(ctx
);