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
);
33 static const WCHAR ctxW
[] = {'c','t','x',0};
34 static const WCHAR cab_extW
[] = {'.','c','a','b',0};
35 static const WCHAR infW
[] = {'i','n','f',0};
36 static const WCHAR dllW
[] = {'d','l','l',0};
37 static const WCHAR ocxW
[] = {'o','c','x',0};
47 IBindStatusCallback
*callback
;
51 const WCHAR
*cache_file
;
53 const WCHAR
*file_name
;
54 enum install_type install_type
;
60 static void release_install_ctx(install_ctx_t
*ctx
)
63 IUri_Release(ctx
->uri
);
65 IBindStatusCallback_Release(ctx
->callback
);
66 heap_free(ctx
->install_file
);
70 static inline BOOL
file_exists(const WCHAR
*file_name
)
72 return GetFileAttributesW(file_name
) != INVALID_FILE_ATTRIBUTES
;
75 static HRESULT
extract_cab_file(install_ctx_t
*ctx
)
77 size_t path_len
, file_len
;
81 hres
= ExtractFilesW(ctx
->cache_file
, ctx
->tmp_dir
, 0, NULL
, NULL
, 0);
83 WARN("ExtractFilesW failed: %08x\n", hres
);
87 path_len
= strlenW(ctx
->tmp_dir
);
88 file_len
= strlenW(ctx
->file_name
);
89 ctx
->install_file
= heap_alloc((path_len
+file_len
+2)*sizeof(WCHAR
));
90 if(!ctx
->install_file
)
93 memcpy(ctx
->install_file
, ctx
->tmp_dir
, path_len
*sizeof(WCHAR
));
94 ctx
->install_file
[path_len
] = '\\';
95 memcpy(ctx
->install_file
+path_len
+1, ctx
->file_name
, (file_len
+1)*sizeof(WCHAR
));
97 /* NOTE: Assume that file_name contains ".cab" extension */
98 ptr
= ctx
->install_file
+path_len
+1+file_len
-3;
100 memcpy(ptr
, infW
, sizeof(infW
));
101 if(file_exists(ctx
->install_file
)) {
102 ctx
->install_type
= INSTALL_INF
;
106 memcpy(ptr
, dllW
, sizeof(dllW
));
107 if(file_exists(ctx
->install_file
)) {
108 ctx
->install_type
= INSTALL_DLL
;
112 memcpy(ptr
, ocxW
, sizeof(ocxW
));
113 if(file_exists(ctx
->install_file
)) {
114 ctx
->install_type
= INSTALL_DLL
;
118 FIXME("No known install file\n");
122 static HRESULT
setup_dll(install_ctx_t
*ctx
)
127 HRESULT (WINAPI
*reg_func
)(void);
129 module
= LoadLibraryW(ctx
->install_file
);
133 reg_func
= (void*)GetProcAddress(module
, "DllRegisterServer");
137 WARN("no DllRegisterServer function\n");
145 static void expand_command(install_ctx_t
*ctx
, const WCHAR
*cmd
, WCHAR
*buf
, size_t *size
)
147 const WCHAR
*ptr
= cmd
, *prev_ptr
= cmd
;
148 size_t len
= 0, len2
;
150 static const WCHAR expand_dirW
[] = {'%','E','X','T','R','A','C','T','_','D','I','R','%'};
152 while((ptr
= strchrW(ptr
, '%'))) {
154 memcpy(buf
+len
, prev_ptr
, ptr
-prev_ptr
);
157 if(!strncmpiW(ptr
, expand_dirW
, sizeof(expand_dirW
)/sizeof(WCHAR
))) {
158 len2
= strlenW(ctx
->tmp_dir
);
160 memcpy(buf
+len
, ctx
->tmp_dir
, len2
*sizeof(WCHAR
));
162 ptr
+= sizeof(expand_dirW
)/sizeof(WCHAR
);
164 FIXME("Can't expand %s\n", debugstr_w(ptr
));
175 strcpyW(buf
+len
, prev_ptr
);
176 *size
= len
+ strlenW(prev_ptr
) + 1;
179 static HRESULT
process_hook_section(install_ctx_t
*ctx
, const WCHAR
*sect_name
)
181 WCHAR buf
[2048], val
[2*MAX_PATH
];
186 static const WCHAR runW
[] = {'r','u','n',0};
188 len
= GetPrivateProfileStringW(sect_name
, NULL
, NULL
, buf
, sizeof(buf
)/sizeof(*buf
), ctx
->install_file
);
192 for(key
= buf
; *key
; key
+= strlenW(key
)+1) {
193 if(!strcmpiW(key
, runW
)) {
197 len
= GetPrivateProfileStringW(sect_name
, runW
, NULL
, val
, sizeof(val
)/sizeof(*val
), ctx
->install_file
);
199 TRACE("Run %s\n", debugstr_w(val
));
201 expand_command(ctx
, val
, NULL
, &size
);
203 cmd
= heap_alloc(size
*sizeof(WCHAR
));
207 expand_command(ctx
, val
, cmd
, &size
);
208 hres
= RunSetupCommandW(ctx
->hwnd
, cmd
, NULL
, ctx
->tmp_dir
, NULL
, NULL
, 0, NULL
);
213 FIXME("Unsupported hook %s\n", debugstr_w(key
));
221 static HRESULT
install_inf_file(install_ctx_t
*ctx
)
223 WCHAR buf
[2048], sect_name
[128];
224 BOOL default_install
= TRUE
;
229 static const WCHAR setup_hooksW
[] = {'S','e','t','u','p',' ','H','o','o','k','s',0};
230 static const WCHAR add_codeW
[] = {'A','d','d','.','C','o','d','e',0};
232 len
= GetPrivateProfileStringW(setup_hooksW
, NULL
, NULL
, buf
, sizeof(buf
)/sizeof(*buf
), ctx
->install_file
);
234 default_install
= FALSE
;
236 for(key
= buf
; *key
; key
+= strlenW(key
)+1) {
237 TRACE("[Setup Hooks] key: %s\n", debugstr_w(key
));
239 len
= GetPrivateProfileStringW(setup_hooksW
, key
, NULL
, sect_name
, sizeof(sect_name
)/sizeof(*sect_name
),
242 WARN("Could not get key value\n");
246 hres
= process_hook_section(ctx
, sect_name
);
252 len
= GetPrivateProfileStringW(add_codeW
, NULL
, NULL
, buf
, sizeof(buf
)/sizeof(*buf
), ctx
->install_file
);
254 FIXME("[Add.Code] section not supported\n");
256 /* Don't throw an error if we successfully ran setup hooks;
257 installation is likely to be complete enough */
262 if(default_install
) {
263 hres
= RunSetupCommandW(ctx
->hwnd
, ctx
->install_file
, NULL
, ctx
->tmp_dir
, NULL
, NULL
, RSC_FLAG_INF
, NULL
);
265 WARN("RunSetupCommandW failed: %08x\n", hres
);
273 static HRESULT
install_cab_file(install_ctx_t
*ctx
)
275 WCHAR tmp_path
[MAX_PATH
], tmp_dir
[MAX_PATH
];
276 BOOL res
= FALSE
, leave_temp
= FALSE
;
280 GetTempPathW(sizeof(tmp_path
)/sizeof(WCHAR
), tmp_path
);
282 for(i
=0; !res
&& i
< 100; i
++) {
283 GetTempFileNameW(tmp_path
, NULL
, GetTickCount() + i
*17037, tmp_dir
);
284 res
= CreateDirectoryW(tmp_dir
, NULL
);
289 ctx
->tmp_dir
= tmp_dir
;
291 TRACE("Using temporary directory %s\n", debugstr_w(tmp_dir
));
293 hres
= extract_cab_file(ctx
);
294 if(SUCCEEDED(hres
)) {
296 IBindStatusCallback_OnProgress(ctx
->callback
, 0, 0, BINDSTATUS_INSTALLINGCOMPONENTS
, ctx
->install_file
);
298 switch(ctx
->install_type
) {
300 hres
= install_inf_file(ctx
);
303 FIXME("Installing DLL, registering in temporary location\n");
304 hres
= setup_dll(ctx
);
314 RemoveDirectoryW(ctx
->tmp_dir
);
318 static void update_counter(install_ctx_t
*ctx
, HWND hwnd
)
322 if(--ctx
->counter
<= 0) {
325 KillTimer(hwnd
, ctx
->timer
);
326 LoadStringW(urlmon_instance
, IDS_AXINSTALL_INSTALL
, text
, sizeof(text
)/sizeof(WCHAR
));
328 button_hwnd
= GetDlgItem(hwnd
, ID_AXINSTALL_INSTALL_BTN
);
329 EnableWindow(button_hwnd
, TRUE
);
332 LoadStringW(urlmon_instance
, IDS_AXINSTALL_INSTALLN
, buf
, sizeof(buf
)/sizeof(WCHAR
));
333 sprintfW(text
, buf
, ctx
->counter
);
336 SetDlgItemTextW(hwnd
, ID_AXINSTALL_INSTALL_BTN
, text
);
339 static BOOL
init_warning_dialog(HWND hwnd
, install_ctx_t
*ctx
)
344 if(!SetPropW(hwnd
, ctxW
, ctx
))
347 hres
= IUri_GetDisplayUri(ctx
->uri
, &display_uri
);
351 SetDlgItemTextW(hwnd
, ID_AXINSTALL_LOCATION
, display_uri
);
352 SysFreeString(display_uri
);
354 SendDlgItemMessageW(hwnd
, ID_AXINSTALL_ICON
, STM_SETICON
,
355 (WPARAM
)LoadIconW(0, (const WCHAR
*)OIC_WARNING
), 0);
358 update_counter(ctx
, hwnd
);
359 ctx
->timer
= SetTimer(hwnd
, 1, 1000, NULL
);
363 static INT_PTR WINAPI
warning_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
366 case WM_INITDIALOG
: {
367 if(!init_warning_dialog(hwnd
, (install_ctx_t
*)lparam
))
373 case ID_AXINSTALL_INSTALL_BTN
: {
374 install_ctx_t
*ctx
= GetPropW(hwnd
, ctxW
);
385 update_counter(GetPropW(hwnd
, ctxW
), hwnd
);
392 static BOOL
install_warning(install_ctx_t
*ctx
)
394 IWindowForBindingUI
*window_iface
;
395 HWND parent_hwnd
= NULL
;
399 FIXME("no callback\n");
403 hres
= IBindStatusCallback_QueryInterface(ctx
->callback
, &IID_IWindowForBindingUI
, (void**)&window_iface
);
407 hres
= IWindowForBindingUI_GetWindow(window_iface
, &IID_ICodeInstall
, &ctx
->hwnd
);
408 IWindowForBindingUI_Release(window_iface
);
413 DialogBoxParamW(urlmon_instance
, MAKEINTRESOURCEW(ID_AXINSTALL_WARNING_DLG
), parent_hwnd
, warning_proc
, (LPARAM
)ctx
);
417 static HRESULT
install_file(install_ctx_t
*ctx
, const WCHAR
*cache_file
)
422 TRACE("%s\n", debugstr_w(cache_file
));
424 ctx
->cache_file
= cache_file
;
426 if(!install_warning(ctx
)) {
427 TRACE("Installation cancelled\n");
431 hres
= IUri_GetPath(ctx
->uri
, &path
);
432 if(SUCCEEDED(hres
)) {
433 const WCHAR
*ptr
, *ptr2
, *ext
;
435 ptr
= strrchrW(path
, '/');
441 ptr2
= strrchrW(ptr
, '\\');
445 ctx
->file_name
= ptr
;
446 ext
= strrchrW(ptr
, '.');
450 if(!strcmpW(ext
, cab_extW
)) {
451 hres
= install_cab_file(ctx
);
453 FIXME("Unsupported extension %s\n", debugstr_w(ext
));
462 static void failure_msgbox(install_ctx_t
*ctx
, HRESULT hres
)
464 WCHAR buf
[1024], fmt
[1024];
466 LoadStringW(urlmon_instance
, IDS_AXINSTALL_FAILURE
, fmt
, sizeof(fmt
)/sizeof(WCHAR
));
467 sprintfW(buf
, fmt
, hres
);
468 MessageBoxW(ctx
->hwnd
, buf
, NULL
, MB_OK
);
471 static HRESULT
distunit_on_stop(void *ctx
, const WCHAR
*cache_file
, HRESULT hresult
, const WCHAR
*error_str
)
473 install_ctx_t
*install_ctx
= ctx
;
475 TRACE("(%p %s %08x %s)\n", ctx
, debugstr_w(cache_file
), hresult
, debugstr_w(error_str
));
477 if(hresult
== S_OK
) {
478 hresult
= install_file(install_ctx
, cache_file
);
480 failure_msgbox(ctx
, hresult
);
483 if(install_ctx
->callback
)
484 IBindStatusCallback_OnStopBinding(install_ctx
->callback
, hresult
, error_str
);
486 if(install_ctx
->release_on_stop
)
487 release_install_ctx(install_ctx
);
491 /***********************************************************************
492 * AsyncInstallDistributionUnit (URLMON.@)
494 HRESULT WINAPI
AsyncInstallDistributionUnit(const WCHAR
*szDistUnit
, const WCHAR
*szTYPE
, const WCHAR
*szExt
,
495 DWORD dwFileVersionMS
, DWORD dwFileVersionLS
, const WCHAR
*szURL
, IBindCtx
*pbc
, void *pvReserved
, DWORD flags
)
500 TRACE("(%s %s %s %x %x %s %p %p %x)\n", debugstr_w(szDistUnit
), debugstr_w(szTYPE
), debugstr_w(szExt
),
501 dwFileVersionMS
, dwFileVersionLS
, debugstr_w(szURL
), pbc
, pvReserved
, flags
);
503 if(szDistUnit
|| szTYPE
|| szExt
)
504 FIXME("Unsupported arguments\n");
506 ctx
= heap_alloc_zero(sizeof(*ctx
));
508 return E_OUTOFMEMORY
;
510 hres
= CreateUri(szURL
, 0, 0, &ctx
->uri
);
513 return E_OUTOFMEMORY
;
516 ctx
->callback
= bsc_from_bctx(pbc
);
518 hres
= download_to_cache(ctx
->uri
, distunit_on_stop
, ctx
, ctx
->callback
);
519 if(hres
== MK_S_ASYNCHRONOUS
)
520 ctx
->release_on_stop
= TRUE
;
522 release_install_ctx(ctx
);