2 * Advpack install functions
4 * Copyright 2006 James Hawkins
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "advpack_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(advpack
);
39 #define SPAPI_ERROR 0xE0000000L
40 #define SPAPI_PREFIX 0x800F0000L
41 #define SPAPI_MASK 0xFFFFL
42 #define HRESULT_FROM_SPAPI(x) ((x & SPAPI_MASK) | SPAPI_PREFIX)
44 #define ADV_HRESULT(x) ((x & SPAPI_ERROR) ? HRESULT_FROM_SPAPI(x) : HRESULT_FROM_WIN32(x))
46 /* contains information about a specific install instance */
47 typedef struct _ADVInfo
57 typedef HRESULT (*iterate_fields_func
)(HINF hinf
, PCWSTR field
, void *arg
);
59 /* Advanced INF commands */
60 static const WCHAR RegisterOCXs
[] = {'R','e','g','i','s','t','e','r','O','C','X','s',0};
61 static const WCHAR RunPostSetupCommands
[] = {
62 'R','u','n','P','o','s','t','S','e','t','u','p','C','o','m','m','a','n','d','s',0
65 /* Advanced INF callbacks */
66 static HRESULT
register_ocxs_callback(HINF hinf
, PCWSTR field
, void *arg
)
72 BOOL ok
= SetupFindFirstLineW(hinf
, field
, NULL
, &context
);
74 for (; ok
; ok
= SetupFindNextLine(&context
, &context
))
76 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
78 /* get OCX filename */
79 if (!SetupGetStringFieldW(&context
, 1, buffer
,
80 sizeof(buffer
) / sizeof(WCHAR
), NULL
))
83 hm
= LoadLibraryExW(buffer
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
);
90 if (do_ocx_reg(hm
, TRUE
))
99 static HRESULT
run_post_setup_commands_callback(HINF hinf
, PCWSTR field
, void *arg
)
101 ADVInfo
*info
= (ADVInfo
*)arg
;
106 BOOL ok
= SetupFindFirstLineW(hinf
, field
, NULL
, &context
);
108 for (; ok
; ok
= SetupFindNextLine(&context
, &context
))
110 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
112 if (!SetupGetLineTextW(&context
, NULL
, NULL
, NULL
, buffer
,
113 MAX_INF_STRING_LENGTH
, &size
))
116 if (launch_exe(buffer
, info
->working_dir
, NULL
))
123 /* sequentially returns pointers to parameters in a parameter list
124 * returns NULL if the parameter is empty, e.g. one,,three */
125 LPWSTR
get_parameter(LPWSTR
*params
, WCHAR separator
)
127 LPWSTR token
= *params
;
132 *params
= strchrW(*params
, separator
);
142 static BOOL
is_full_path(LPWSTR path
)
144 const int MIN_PATH_LEN
= 3;
146 if (!path
|| lstrlenW(path
) < MIN_PATH_LEN
)
149 if (path
[1] == ':' || (path
[0] == '\\' && path
[1] == '\\'))
155 /* retrieves the contents of a field, dynamically growing the buffer if necessary */
156 static WCHAR
*get_field_string(INFCONTEXT
*context
, DWORD index
, WCHAR
*buffer
,
157 WCHAR
*static_buffer
, DWORD
*size
)
161 if (SetupGetStringFieldW(context
, index
, buffer
, *size
, &required
)) return buffer
;
163 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
165 /* now grow the buffer */
166 if (buffer
!= static_buffer
) HeapFree(GetProcessHeap(), 0, buffer
);
167 if (!(buffer
= HeapAlloc(GetProcessHeap(), 0, required
*sizeof(WCHAR
)))) return NULL
;
169 if (SetupGetStringFieldW(context
, index
, buffer
, *size
, &required
)) return buffer
;
172 if (buffer
!= static_buffer
) HeapFree(GetProcessHeap(), 0, buffer
);
176 /* iterates over all fields of a certain key of a certain section */
177 static HRESULT
iterate_section_fields(HINF hinf
, PCWSTR section
, PCWSTR key
,
178 iterate_fields_func callback
, void *arg
)
180 WCHAR static_buffer
[200];
181 WCHAR
*buffer
= static_buffer
;
182 DWORD size
= sizeof(static_buffer
) / sizeof(WCHAR
);
186 BOOL ok
= SetupFindFirstLineW(hinf
, section
, key
, &context
);
189 UINT i
, count
= SetupGetFieldCount(&context
);
191 for (i
= 1; i
<= count
; i
++)
193 if (!(buffer
= get_field_string(&context
, i
, buffer
, static_buffer
, &size
)))
196 if ((hr
= callback(hinf
, buffer
, arg
)) != S_OK
)
200 ok
= SetupFindNextMatchLineW(&context
, key
, &context
);
206 if (buffer
&& buffer
!= static_buffer
) HeapFree(GetProcessHeap(), 0, buffer
);
210 /* performs a setupapi-level install of the INF file */
211 static HRESULT
spapi_install(ADVInfo
*info
)
217 context
= SetupInitDefaultQueueCallbackEx(NULL
, INVALID_HANDLE_VALUE
, 0, 0, NULL
);
219 return ADV_HRESULT(GetLastError());
221 ret
= SetupInstallFromInfSectionW(NULL
, info
->hinf
, info
->install_sec
,
222 SPINST_FILES
, NULL
, info
->working_dir
,
223 SP_COPY_NEWER
, SetupDefaultQueueCallbackW
,
224 context
, NULL
, NULL
);
227 res
= ADV_HRESULT(GetLastError());
228 SetupTermDefaultQueueCallback(context
);
233 SetupTermDefaultQueueCallback(context
);
235 ret
= SetupInstallFromInfSectionW(NULL
, info
->hinf
, info
->install_sec
,
236 SPINST_INIFILES
| SPINST_REGISTRY
,
237 HKEY_LOCAL_MACHINE
, NULL
, 0,
238 NULL
, NULL
, NULL
, NULL
);
240 return ADV_HRESULT(GetLastError());
245 /* processes the Advanced INF commands */
246 static HRESULT
adv_install(ADVInfo
*info
)
250 hr
= iterate_section_fields(info
->hinf
, info
->install_sec
,
251 RegisterOCXs
, register_ocxs_callback
, NULL
);
255 hr
= iterate_section_fields(info
->hinf
, info
->install_sec
, RunPostSetupCommands
,
256 run_post_setup_commands_callback
, info
);
263 /* loads the INF file and performs checks on it */
264 HRESULT
install_init(LPCWSTR inf_filename
, LPCWSTR install_sec
,
265 LPCWSTR working_dir
, DWORD flags
, ADVInfo
*info
)
270 static const WCHAR default_install
[] = {
271 'D','e','f','a','u','l','t','I','n','s','t','a','l','l',0
274 len
= lstrlenW(inf_filename
);
276 info
->inf_filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
277 if (!info
->inf_filename
)
278 return E_OUTOFMEMORY
;
280 lstrcpyW(info
->inf_filename
, inf_filename
);
282 /* FIXME: determine the proper platform to install (NTx86, etc) */
283 if (!install_sec
|| !*install_sec
)
285 len
= sizeof(default_install
) - 1;
286 ptr
= default_install
;
290 len
= lstrlenW(install_sec
);
294 info
->install_sec
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
295 if (!info
->install_sec
)
296 return E_OUTOFMEMORY
;
298 lstrcpyW(info
->install_sec
, ptr
);
300 /* FIXME: need to get the real working directory */
301 if (!working_dir
|| !*working_dir
)
303 ptr
= strrchrW(info
->inf_filename
, '\\');
304 len
= ptr
- info
->inf_filename
+ 1;
305 ptr
= info
->inf_filename
;
309 len
= lstrlenW(working_dir
);
313 info
->working_dir
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
314 if (!info
->working_dir
)
315 return E_OUTOFMEMORY
;
317 lstrcpynW(info
->working_dir
, ptr
, len
);
319 info
->hinf
= SetupOpenInfFileW(info
->inf_filename
, NULL
, INF_STYLE_WIN4
, NULL
);
320 if (info
->hinf
== INVALID_HANDLE_VALUE
)
321 return ADV_HRESULT(GetLastError());
323 set_ldids(info
->hinf
, info
->install_sec
, info
->working_dir
);
325 /* FIXME: check that the INF is advanced */
328 info
->need_reboot
= FALSE
;
333 /* release the install instance information */
334 void install_release(ADVInfo
*info
)
336 if (info
->hinf
&& info
->hinf
!= INVALID_HANDLE_VALUE
)
337 SetupCloseInfFile(info
->hinf
);
339 HeapFree(GetProcessHeap(), 0, info
->inf_filename
);
340 HeapFree(GetProcessHeap(), 0, info
->install_sec
);
341 HeapFree(GetProcessHeap(), 0, info
->working_dir
);
344 /* this structure very closely resembles parameters of RunSetupCommand() */
352 } SETUPCOMMAND_PARAMS
;
354 /***********************************************************************
355 * DoInfInstall (ADVPACK.@)
357 * Install an INF section.
360 * setup [I] Structure containing install information.
364 * HRESULT_FROM_WIN32(GetLastError()) Some other error
366 HRESULT WINAPI
DoInfInstall(const SETUPCOMMAND_PARAMS
*setup
)
370 void *callback_context
;
372 TRACE("(%p)\n", setup
);
374 hinf
= SetupOpenInfFileA(setup
->inf_name
, NULL
, INF_STYLE_WIN4
, NULL
);
375 if (hinf
== INVALID_HANDLE_VALUE
) return HRESULT_FROM_WIN32(GetLastError());
377 callback_context
= SetupInitDefaultQueueCallback(setup
->hwnd
);
379 ret
= SetupInstallFromInfSectionA(NULL
, hinf
, setup
->section_name
, SPINST_ALL
,
380 NULL
, NULL
, 0, SetupDefaultQueueCallbackA
,
381 callback_context
, NULL
, NULL
);
382 SetupTermDefaultQueueCallback(callback_context
);
383 SetupCloseInfFile(hinf
);
385 return ret
? S_OK
: HRESULT_FROM_WIN32(GetLastError());
388 /***********************************************************************
389 * ExecuteCabA (ADVPACK.@)
393 HRESULT WINAPI
ExecuteCabA(HWND hwnd
, CABINFOA
* pCab
, LPVOID pReserved
)
395 UNICODE_STRING cab
, inf
, section
;
399 TRACE("(%p, %p, %p)\n", hwnd
, pCab
, pReserved
);
406 RtlCreateUnicodeStringFromAsciiz(&cab
, pCab
->pszCab
);
407 cabinfo
.pszCab
= cab
.Buffer
;
410 cabinfo
.pszCab
= NULL
;
412 RtlCreateUnicodeStringFromAsciiz(&inf
, pCab
->pszInf
);
413 RtlCreateUnicodeStringFromAsciiz(§ion
, pCab
->pszSection
);
415 MultiByteToWideChar(CP_ACP
, 0, pCab
->szSrcPath
, -1, cabinfo
.szSrcPath
,
416 sizeof(cabinfo
.szSrcPath
) / sizeof(WCHAR
));
418 cabinfo
.pszInf
= inf
.Buffer
;
419 cabinfo
.pszSection
= section
.Buffer
;
420 cabinfo
.dwFlags
= pCab
->dwFlags
;
422 hr
= ExecuteCabW(hwnd
, &cabinfo
, pReserved
);
425 RtlFreeUnicodeString(&cab
);
427 RtlFreeUnicodeString(&inf
);
428 RtlFreeUnicodeString(§ion
);
433 /***********************************************************************
434 * ExecuteCabW (ADVPACK.@)
436 * Installs the INF file extracted from a specified cabinet file.
439 * hwnd [I] Handle to the window used for the display.
440 * pCab [I] Information about the cabinet file.
441 * pReserved [I] Reserved. Must be NULL.
447 HRESULT WINAPI
ExecuteCabW(HWND hwnd
, CABINFOW
* pCab
, LPVOID pReserved
)
452 TRACE("(%p, %p, %p)\n", hwnd
, pCab
, pReserved
);
454 ZeroMemory(&info
, sizeof(ADVInfo
));
456 if (pCab
->pszCab
&& *pCab
->pszCab
)
457 FIXME("Cab archive not extracted!\n");
459 hr
= install_init(pCab
->pszInf
, pCab
->pszSection
, pCab
->szSrcPath
, pCab
->dwFlags
, &info
);
463 hr
= spapi_install(&info
);
467 hr
= adv_install(&info
);
470 install_release(&info
);
475 /***********************************************************************
476 * LaunchINFSectionA (ADVPACK.@)
478 * See LaunchINFSectionW.
480 INT WINAPI
LaunchINFSectionA(HWND hWnd
, HINSTANCE hInst
, LPSTR cmdline
, INT show
)
485 TRACE("(%p, %p, %s, %i)\n", hWnd
, hInst
, debugstr_a(cmdline
), show
);
487 RtlCreateUnicodeStringFromAsciiz(&cmd
, cmdline
);
489 hr
= LaunchINFSectionW(hWnd
, hInst
, cmd
.Buffer
, show
);
491 RtlFreeUnicodeString(&cmd
);
496 /***********************************************************************
497 * LaunchINFSectionW (ADVPACK.@)
499 * Installs an INF section without BACKUP/ROLLBACK capabilities.
502 * hWnd [I] Handle to parent window, NULL for desktop.
503 * hInst [I] Instance of the process.
504 * cmdline [I] Contains parameters in the order INF,section,flags,reboot.
505 * show [I] How the window should be shown.
512 * INF - Filename of the INF to launch.
513 * section - INF section to install.
514 * flags - see advpub.h.
515 * reboot - smart reboot behavior
517 * 'I' Reboot if needed (default).
523 INT WINAPI
LaunchINFSectionW(HWND hWnd
, HINSTANCE hInst
, LPWSTR cmdline
, INT show
)
525 FIXME("(%p, %p, %s, %i): stub\n", hWnd
, hInst
, debugstr_w(cmdline
), show
);
529 /***********************************************************************
530 * LaunchINFSectionExA (ADVPACK.@)
532 * See LaunchINFSectionExW.
534 HRESULT WINAPI
LaunchINFSectionExA(HWND hWnd
, HINSTANCE hInst
, LPSTR cmdline
, INT show
)
539 TRACE("(%p, %p, %s, %i)\n", hWnd
, hInst
, debugstr_a(cmdline
), show
);
541 RtlCreateUnicodeStringFromAsciiz(&cmd
, cmdline
);
543 hr
= LaunchINFSectionExW(hWnd
, hInst
, cmd
.Buffer
, show
);
545 RtlFreeUnicodeString(&cmd
);
550 /***********************************************************************
551 * LaunchINFSectionExW (ADVPACK.@)
553 * Installs an INF section with BACKUP/ROLLBACK capabilities.
556 * hWnd [I] Handle to parent window, NULL for desktop.
557 * hInst [I] Instance of the process.
558 * cmdline [I] Contains parameters in the order INF,section,CAB,flags,reboot.
559 * show [I] How the window should be shown.
566 * INF - Filename of the INF to launch.
567 * section - INF section to install.
568 * flags - see advpub.h.
569 * reboot - smart reboot behavior
571 * 'I' Reboot if needed (default).
575 * Doesn't handle the reboot flag.
577 HRESULT WINAPI
LaunchINFSectionExW(HWND hWnd
, HINSTANCE hInst
, LPWSTR cmdline
, INT show
)
579 LPWSTR cmdline_copy
, cmdline_ptr
;
584 TRACE("(%p, %p, %s, %d)\n", hWnd
, hInst
, debugstr_w(cmdline
), show
);
589 cmdline_copy
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline
) + 1) * sizeof(WCHAR
));
590 cmdline_ptr
= cmdline_copy
;
591 lstrcpyW(cmdline_copy
, cmdline
);
593 cabinfo
.pszInf
= get_parameter(&cmdline_ptr
, ',');
594 cabinfo
.pszSection
= get_parameter(&cmdline_ptr
, ',');
595 cabinfo
.pszCab
= get_parameter(&cmdline_ptr
, ',');
597 flags
= get_parameter(&cmdline_ptr
, ',');
599 cabinfo
.dwFlags
= atolW(flags
);
601 /* get the source path from the cab filename */
602 if (cabinfo
.pszCab
&& *cabinfo
.pszCab
)
604 if (!is_full_path(cabinfo
.pszCab
))
607 lstrcpyW(cabinfo
.szSrcPath
, cabinfo
.pszCab
);
608 ptr
= strrchrW(cabinfo
.szSrcPath
, '\\');
612 hr
= ExecuteCabW(hWnd
, &cabinfo
, NULL
);
615 HeapFree(GetProcessHeap(), 0, cmdline_copy
);
620 HRESULT
launch_exe(LPCWSTR cmd
, LPCWSTR dir
, HANDLE
*phEXE
)
623 PROCESS_INFORMATION pi
;
625 if (phEXE
) *phEXE
= NULL
;
627 ZeroMemory(&pi
, sizeof(pi
));
628 ZeroMemory(&si
, sizeof(si
));
631 if (!CreateProcessW(NULL
, (LPWSTR
)cmd
, NULL
, NULL
, FALSE
,
632 CREATE_DEFAULT_ERROR_MODE
| CREATE_NEW_PROCESS_GROUP
,
633 NULL
, dir
, &si
, &pi
))
635 return HRESULT_FROM_WIN32(GetLastError());
638 CloseHandle(pi
.hThread
);
642 *phEXE
= pi
.hProcess
;
643 return S_ASYNCHRONOUS
;
646 /* wait for the child process to finish */
647 WaitForSingleObject(pi
.hProcess
, INFINITE
);
648 CloseHandle(pi
.hProcess
);
653 /***********************************************************************
654 * RunSetupCommandA (ADVPACK.@)
656 * See RunSetupCommandW.
658 HRESULT WINAPI
RunSetupCommandA(HWND hWnd
, LPCSTR szCmdName
,
659 LPCSTR szInfSection
, LPCSTR szDir
,
660 LPCSTR lpszTitle
, HANDLE
*phEXE
,
661 DWORD dwFlags
, LPVOID pvReserved
)
663 UNICODE_STRING cmdname
, infsec
;
664 UNICODE_STRING dir
, title
;
667 TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
668 hWnd
, debugstr_a(szCmdName
), debugstr_a(szInfSection
),
669 debugstr_a(szDir
), debugstr_a(lpszTitle
),
670 phEXE
, dwFlags
, pvReserved
);
672 if (!szCmdName
|| !szDir
)
675 RtlCreateUnicodeStringFromAsciiz(&cmdname
, szCmdName
);
676 RtlCreateUnicodeStringFromAsciiz(&infsec
, szInfSection
);
677 RtlCreateUnicodeStringFromAsciiz(&dir
, szDir
);
678 RtlCreateUnicodeStringFromAsciiz(&title
, lpszTitle
);
680 hr
= RunSetupCommandW(hWnd
, cmdname
.Buffer
, infsec
.Buffer
, dir
.Buffer
,
681 title
.Buffer
, phEXE
, dwFlags
, pvReserved
);
683 RtlFreeUnicodeString(&cmdname
);
684 RtlFreeUnicodeString(&infsec
);
685 RtlFreeUnicodeString(&dir
);
686 RtlFreeUnicodeString(&title
);
691 /***********************************************************************
692 * RunSetupCommandW (ADVPACK.@)
694 * Executes an install section in an INF file or a program.
697 * hWnd [I] Handle to parent window, NULL for quiet mode
698 * szCmdName [I] Inf or EXE filename to execute
699 * szInfSection [I] Inf section to install, NULL for DefaultInstall
700 * szDir [I] Path to extracted files
701 * szTitle [I] Title of all dialogs
702 * phEXE [O] Handle of EXE to wait for
703 * dwFlags [I] Flags; see include/advpub.h
704 * pvReserved [I] Reserved
708 * S_ASYNCHRONOUS OK, required to wait on phEXE
709 * ERROR_SUCCESS_REBOOT_REQUIRED Reboot required
710 * E_INVALIDARG Invalid argument given
711 * HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION)
712 * Not supported on this Windows version
713 * E_UNEXPECTED Unexpected error
714 * HRESULT_FROM_WIN32(GetLastError()) Some other error
717 * INF install unimplemented.
719 HRESULT WINAPI
RunSetupCommandW(HWND hWnd
, LPCWSTR szCmdName
,
720 LPCWSTR szInfSection
, LPCWSTR szDir
,
721 LPCWSTR lpszTitle
, HANDLE
*phEXE
,
722 DWORD dwFlags
, LPVOID pvReserved
)
727 TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
728 hWnd
, debugstr_w(szCmdName
), debugstr_w(szInfSection
),
729 debugstr_w(szDir
), debugstr_w(lpszTitle
),
730 phEXE
, dwFlags
, pvReserved
);
733 FIXME("Unhandled flags: 0x%08lx\n", dwFlags
);
735 if (!szCmdName
|| !szDir
)
738 if (!(dwFlags
& RSC_FLAG_INF
))
739 return launch_exe(szCmdName
, szDir
, phEXE
);
741 ZeroMemory(&info
, sizeof(ADVInfo
));
743 hr
= install_init(szCmdName
, szInfSection
, szDir
, dwFlags
, &info
);
747 hr
= spapi_install(&info
);
751 hr
= adv_install(&info
);
754 install_release(&info
);