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};
62 /* Advanced INF callbacks */
63 static HRESULT
register_ocxs_callback(HINF hinf
, PCWSTR field
, void *arg
)
65 FIXME("Unhandled command: RegisterOCXs\n");
69 /* sequentially returns pointers to parameters in a parameter list
70 * returns NULL if the parameter is empty, e.g. one,,three */
71 LPWSTR
get_parameter(LPWSTR
*params
, WCHAR separator
)
73 LPWSTR token
= *params
;
78 *params
= strchrW(*params
, separator
);
88 static BOOL
is_full_path(LPWSTR path
)
90 const int MIN_PATH_LEN
= 3;
92 if (!path
|| lstrlenW(path
) < MIN_PATH_LEN
)
95 if (path
[1] == ':' || (path
[0] == '\\' && path
[1] == '\\'))
101 /* retrieves the contents of a field, dynamically growing the buffer if necessary */
102 static WCHAR
*get_field_string(INFCONTEXT
*context
, DWORD index
, WCHAR
*buffer
,
103 WCHAR
*static_buffer
, DWORD
*size
)
107 if (SetupGetStringFieldW(context
, index
, buffer
, *size
, &required
)) return buffer
;
109 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
111 /* now grow the buffer */
112 if (buffer
!= static_buffer
) HeapFree(GetProcessHeap(), 0, buffer
);
113 if (!(buffer
= HeapAlloc(GetProcessHeap(), 0, required
*sizeof(WCHAR
)))) return NULL
;
115 if (SetupGetStringFieldW(context
, index
, buffer
, *size
, &required
)) return buffer
;
118 if (buffer
!= static_buffer
) HeapFree(GetProcessHeap(), 0, buffer
);
122 /* iterates over all fields of a certain key of a certain section */
123 static HRESULT
iterate_section_fields(HINF hinf
, PCWSTR section
, PCWSTR key
,
124 iterate_fields_func callback
, void *arg
)
126 WCHAR static_buffer
[200];
127 WCHAR
*buffer
= static_buffer
;
128 DWORD size
= sizeof(static_buffer
) / sizeof(WCHAR
);
132 BOOL ok
= SetupFindFirstLineW(hinf
, section
, key
, &context
);
135 UINT i
, count
= SetupGetFieldCount(&context
);
137 for (i
= 1; i
<= count
; i
++)
139 if (!(buffer
= get_field_string(&context
, i
, buffer
, static_buffer
, &size
)))
142 if ((hr
= callback(hinf
, buffer
, arg
)) != S_OK
)
146 ok
= SetupFindNextMatchLineW(&context
, key
, &context
);
152 if (buffer
&& buffer
!= static_buffer
) HeapFree(GetProcessHeap(), 0, buffer
);
156 /* performs a setupapi-level install of the INF file */
157 static HRESULT
spapi_install(ADVInfo
*info
)
163 context
= SetupInitDefaultQueueCallbackEx(NULL
, INVALID_HANDLE_VALUE
, 0, 0, NULL
);
165 return ADV_HRESULT(GetLastError());
167 ret
= SetupInstallFromInfSectionW(NULL
, info
->hinf
, info
->install_sec
,
168 SPINST_FILES
, NULL
, info
->working_dir
,
169 SP_COPY_NEWER
, SetupDefaultQueueCallbackW
,
170 context
, NULL
, NULL
);
173 res
= ADV_HRESULT(GetLastError());
174 SetupTermDefaultQueueCallback(context
);
179 SetupTermDefaultQueueCallback(context
);
181 ret
= SetupInstallFromInfSectionW(NULL
, info
->hinf
, info
->install_sec
,
182 SPINST_INIFILES
| SPINST_REGISTRY
,
183 HKEY_LOCAL_MACHINE
, NULL
, 0,
184 NULL
, NULL
, NULL
, NULL
);
186 return ADV_HRESULT(GetLastError());
191 /* processes the Advanced INF commands */
192 static HRESULT
adv_install(ADVInfo
*info
)
196 hr
= iterate_section_fields(info
->hinf
, info
->install_sec
,
197 RegisterOCXs
, register_ocxs_callback
, NULL
);
202 /* loads the INF file and performs checks on it */
203 HRESULT
install_init(LPCWSTR inf_filename
, LPCWSTR install_sec
,
204 LPCWSTR working_dir
, DWORD flags
, ADVInfo
*info
)
209 static const WCHAR default_install
[] = {
210 'D','e','f','a','u','l','t','I','n','s','t','a','l','l',0
213 len
= lstrlenW(inf_filename
);
215 info
->inf_filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
216 if (!info
->inf_filename
)
217 return E_OUTOFMEMORY
;
219 lstrcpyW(info
->inf_filename
, inf_filename
);
221 /* FIXME: determine the proper platform to install (NTx86, etc) */
222 if (!install_sec
|| !*install_sec
)
224 len
= sizeof(default_install
) - 1;
225 ptr
= default_install
;
229 len
= lstrlenW(install_sec
);
233 info
->install_sec
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
234 if (!info
->install_sec
)
235 return E_OUTOFMEMORY
;
237 lstrcpyW(info
->install_sec
, ptr
);
239 /* FIXME: need to get the real working directory */
240 if (!working_dir
|| !*working_dir
)
242 ptr
= strrchrW(info
->inf_filename
, '\\');
243 len
= ptr
- info
->inf_filename
+ 1;
244 ptr
= info
->inf_filename
;
248 len
= lstrlenW(working_dir
);
252 info
->working_dir
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
253 if (!info
->working_dir
)
254 return E_OUTOFMEMORY
;
256 lstrcpynW(info
->working_dir
, ptr
, len
);
258 info
->hinf
= SetupOpenInfFileW(info
->inf_filename
, NULL
, INF_STYLE_WIN4
, NULL
);
259 if (info
->hinf
== INVALID_HANDLE_VALUE
)
260 return ADV_HRESULT(GetLastError());
262 set_ldids(info
->hinf
, info
->install_sec
, info
->working_dir
);
264 /* FIXME: check that the INF is advanced */
267 info
->need_reboot
= FALSE
;
272 /* release the install instance information */
273 void install_release(ADVInfo
*info
)
275 if (info
->hinf
&& info
->hinf
!= INVALID_HANDLE_VALUE
)
276 SetupCloseInfFile(info
->hinf
);
278 HeapFree(GetProcessHeap(), 0, info
->inf_filename
);
279 HeapFree(GetProcessHeap(), 0, info
->install_sec
);
280 HeapFree(GetProcessHeap(), 0, info
->working_dir
);
283 /* this structure very closely resembles parameters of RunSetupCommand() */
291 } SETUPCOMMAND_PARAMS
;
293 /***********************************************************************
294 * DoInfInstall (ADVPACK.@)
296 * Install an INF section.
299 * setup [I] Structure containing install information.
303 * HRESULT_FROM_WIN32(GetLastError()) Some other error
305 HRESULT WINAPI
DoInfInstall(const SETUPCOMMAND_PARAMS
*setup
)
309 void *callback_context
;
311 TRACE("(%p)\n", setup
);
313 hinf
= SetupOpenInfFileA(setup
->inf_name
, NULL
, INF_STYLE_WIN4
, NULL
);
314 if (hinf
== INVALID_HANDLE_VALUE
) return HRESULT_FROM_WIN32(GetLastError());
316 callback_context
= SetupInitDefaultQueueCallback(setup
->hwnd
);
318 ret
= SetupInstallFromInfSectionA(NULL
, hinf
, setup
->section_name
, SPINST_ALL
,
319 NULL
, NULL
, 0, SetupDefaultQueueCallbackA
,
320 callback_context
, NULL
, NULL
);
321 SetupTermDefaultQueueCallback(callback_context
);
322 SetupCloseInfFile(hinf
);
324 return ret
? S_OK
: HRESULT_FROM_WIN32(GetLastError());
327 /***********************************************************************
328 * ExecuteCabA (ADVPACK.@)
332 HRESULT WINAPI
ExecuteCabA(HWND hwnd
, CABINFOA
* pCab
, LPVOID pReserved
)
334 UNICODE_STRING cab
, inf
, section
;
338 TRACE("(%p, %p, %p)\n", hwnd
, pCab
, pReserved
);
345 RtlCreateUnicodeStringFromAsciiz(&cab
, pCab
->pszCab
);
346 cabinfo
.pszCab
= cab
.Buffer
;
349 cabinfo
.pszCab
= NULL
;
351 RtlCreateUnicodeStringFromAsciiz(&inf
, pCab
->pszInf
);
352 RtlCreateUnicodeStringFromAsciiz(§ion
, pCab
->pszSection
);
354 MultiByteToWideChar(CP_ACP
, 0, pCab
->szSrcPath
, -1, cabinfo
.szSrcPath
,
355 sizeof(cabinfo
.szSrcPath
) / sizeof(WCHAR
));
357 cabinfo
.pszInf
= inf
.Buffer
;
358 cabinfo
.pszSection
= section
.Buffer
;
359 cabinfo
.dwFlags
= pCab
->dwFlags
;
361 hr
= ExecuteCabW(hwnd
, &cabinfo
, pReserved
);
364 RtlFreeUnicodeString(&cab
);
366 RtlFreeUnicodeString(&inf
);
367 RtlFreeUnicodeString(§ion
);
372 /***********************************************************************
373 * ExecuteCabW (ADVPACK.@)
375 * Installs the INF file extracted from a specified cabinet file.
378 * hwnd [I] Handle to the window used for the display.
379 * pCab [I] Information about the cabinet file.
380 * pReserved [I] Reserved. Must be NULL.
389 HRESULT WINAPI
ExecuteCabW(HWND hwnd
, CABINFOW
* pCab
, LPVOID pReserved
)
391 FIXME("(%p, %p, %p): stub\n", hwnd
, pCab
, pReserved
);
395 /***********************************************************************
396 * LaunchINFSectionA (ADVPACK.@)
398 * See LaunchINFSectionW.
400 INT WINAPI
LaunchINFSectionA(HWND hWnd
, HINSTANCE hInst
, LPSTR cmdline
, INT show
)
405 TRACE("(%p, %p, %s, %i)\n", hWnd
, hInst
, debugstr_a(cmdline
), show
);
407 RtlCreateUnicodeStringFromAsciiz(&cmd
, cmdline
);
409 hr
= LaunchINFSectionW(hWnd
, hInst
, cmd
.Buffer
, show
);
411 RtlFreeUnicodeString(&cmd
);
416 /***********************************************************************
417 * LaunchINFSectionW (ADVPACK.@)
419 * Installs an INF section without BACKUP/ROLLBACK capabilities.
422 * hWnd [I] Handle to parent window, NULL for desktop.
423 * hInst [I] Instance of the process.
424 * cmdline [I] Contains parameters in the order INF,section,flags,reboot.
425 * show [I] How the window should be shown.
432 * INF - Filename of the INF to launch.
433 * section - INF section to install.
434 * flags - see advpub.h.
435 * reboot - smart reboot behavior
437 * 'I' Reboot if needed (default).
443 INT WINAPI
LaunchINFSectionW(HWND hWnd
, HINSTANCE hInst
, LPWSTR cmdline
, INT show
)
445 FIXME("(%p, %p, %s, %i): stub\n", hWnd
, hInst
, debugstr_w(cmdline
), show
);
449 /***********************************************************************
450 * LaunchINFSectionExA (ADVPACK.@)
452 * See LaunchINFSectionExW.
454 HRESULT WINAPI
LaunchINFSectionExA(HWND hWnd
, HINSTANCE hInst
, LPSTR cmdline
, INT show
)
459 TRACE("(%p, %p, %s, %i)\n", hWnd
, hInst
, debugstr_a(cmdline
), show
);
461 RtlCreateUnicodeStringFromAsciiz(&cmd
, cmdline
);
463 hr
= LaunchINFSectionExW(hWnd
, hInst
, cmd
.Buffer
, show
);
465 RtlFreeUnicodeString(&cmd
);
470 /***********************************************************************
471 * LaunchINFSectionExW (ADVPACK.@)
473 * Installs an INF section with BACKUP/ROLLBACK capabilities.
476 * hWnd [I] Handle to parent window, NULL for desktop.
477 * hInst [I] Instance of the process.
478 * cmdline [I] Contains parameters in the order INF,section,CAB,flags,reboot.
479 * show [I] How the window should be shown.
486 * INF - Filename of the INF to launch.
487 * section - INF section to install.
488 * flags - see advpub.h.
489 * reboot - smart reboot behavior
491 * 'I' Reboot if needed (default).
495 * Doesn't handle the reboot flag.
497 HRESULT WINAPI
LaunchINFSectionExW(HWND hWnd
, HINSTANCE hInst
, LPWSTR cmdline
, INT show
)
499 LPWSTR cmdline_copy
, cmdline_ptr
;
504 TRACE("(%p, %p, %s, %d)\n", hWnd
, hInst
, debugstr_w(cmdline
), show
);
509 cmdline_copy
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline
) + 1) * sizeof(WCHAR
));
510 cmdline_ptr
= cmdline_copy
;
511 lstrcpyW(cmdline_copy
, cmdline
);
513 cabinfo
.pszInf
= get_parameter(&cmdline_ptr
, ',');
514 cabinfo
.pszSection
= get_parameter(&cmdline_ptr
, ',');
515 cabinfo
.pszCab
= get_parameter(&cmdline_ptr
, ',');
517 flags
= get_parameter(&cmdline_ptr
, ',');
519 cabinfo
.dwFlags
= atolW(flags
);
521 /* get the source path from the cab filename */
522 if (cabinfo
.pszCab
&& *cabinfo
.pszCab
)
524 if (!is_full_path(cabinfo
.pszCab
))
527 lstrcpyW(cabinfo
.szSrcPath
, cabinfo
.pszCab
);
528 ptr
= strrchrW(cabinfo
.szSrcPath
, '\\');
532 hr
= ExecuteCabW(hWnd
, &cabinfo
, NULL
);
535 HeapFree(GetProcessHeap(), 0, cmdline_copy
);
540 HRESULT
launch_exe(LPCWSTR cmd
, LPCWSTR dir
, HANDLE
*phEXE
)
543 PROCESS_INFORMATION pi
;
545 if (phEXE
) *phEXE
= NULL
;
547 ZeroMemory(&pi
, sizeof(pi
));
548 ZeroMemory(&si
, sizeof(si
));
551 if (!CreateProcessW(NULL
, (LPWSTR
)cmd
, NULL
, NULL
, FALSE
,
552 CREATE_DEFAULT_ERROR_MODE
| CREATE_NEW_PROCESS_GROUP
,
553 NULL
, dir
, &si
, &pi
))
555 return HRESULT_FROM_WIN32(GetLastError());
558 CloseHandle(pi
.hThread
);
562 *phEXE
= pi
.hProcess
;
563 return S_ASYNCHRONOUS
;
566 /* wait for the child process to finish */
567 WaitForSingleObject(pi
.hProcess
, INFINITE
);
568 CloseHandle(pi
.hProcess
);
573 /***********************************************************************
574 * RunSetupCommandA (ADVPACK.@)
576 * See RunSetupCommandW.
578 HRESULT WINAPI
RunSetupCommandA(HWND hWnd
, LPCSTR szCmdName
,
579 LPCSTR szInfSection
, LPCSTR szDir
,
580 LPCSTR lpszTitle
, HANDLE
*phEXE
,
581 DWORD dwFlags
, LPVOID pvReserved
)
583 UNICODE_STRING cmdname
, infsec
;
584 UNICODE_STRING dir
, title
;
587 TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
588 hWnd
, debugstr_a(szCmdName
), debugstr_a(szInfSection
),
589 debugstr_a(szDir
), debugstr_a(lpszTitle
),
590 phEXE
, dwFlags
, pvReserved
);
592 if (!szCmdName
|| !szDir
)
595 RtlCreateUnicodeStringFromAsciiz(&cmdname
, szCmdName
);
596 RtlCreateUnicodeStringFromAsciiz(&infsec
, szInfSection
);
597 RtlCreateUnicodeStringFromAsciiz(&dir
, szDir
);
598 RtlCreateUnicodeStringFromAsciiz(&title
, lpszTitle
);
600 hr
= RunSetupCommandW(hWnd
, cmdname
.Buffer
, infsec
.Buffer
, dir
.Buffer
,
601 title
.Buffer
, phEXE
, dwFlags
, pvReserved
);
603 RtlFreeUnicodeString(&cmdname
);
604 RtlFreeUnicodeString(&infsec
);
605 RtlFreeUnicodeString(&dir
);
606 RtlFreeUnicodeString(&title
);
611 /***********************************************************************
612 * RunSetupCommandW (ADVPACK.@)
614 * Executes an install section in an INF file or a program.
617 * hWnd [I] Handle to parent window, NULL for quiet mode
618 * szCmdName [I] Inf or EXE filename to execute
619 * szInfSection [I] Inf section to install, NULL for DefaultInstall
620 * szDir [I] Path to extracted files
621 * szTitle [I] Title of all dialogs
622 * phEXE [O] Handle of EXE to wait for
623 * dwFlags [I] Flags; see include/advpub.h
624 * pvReserved [I] Reserved
628 * S_ASYNCHRONOUS OK, required to wait on phEXE
629 * ERROR_SUCCESS_REBOOT_REQUIRED Reboot required
630 * E_INVALIDARG Invalid argument given
631 * HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION)
632 * Not supported on this Windows version
633 * E_UNEXPECTED Unexpected error
634 * HRESULT_FROM_WIN32(GetLastError()) Some other error
637 * INF install unimplemented.
639 HRESULT WINAPI
RunSetupCommandW(HWND hWnd
, LPCWSTR szCmdName
,
640 LPCWSTR szInfSection
, LPCWSTR szDir
,
641 LPCWSTR lpszTitle
, HANDLE
*phEXE
,
642 DWORD dwFlags
, LPVOID pvReserved
)
647 TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
648 hWnd
, debugstr_w(szCmdName
), debugstr_w(szInfSection
),
649 debugstr_w(szDir
), debugstr_w(lpszTitle
),
650 phEXE
, dwFlags
, pvReserved
);
653 FIXME("Unhandled flags: 0x%08lx\n", dwFlags
);
655 if (!szCmdName
|| !szDir
)
658 if (!(dwFlags
& RSC_FLAG_INF
))
659 return launch_exe(szCmdName
, szDir
, phEXE
);
661 ZeroMemory(&info
, sizeof(ADVInfo
));
663 hr
= install_init(szCmdName
, szInfSection
, szDir
, dwFlags
, &info
);
667 hr
= spapi_install(&info
);
671 hr
= adv_install(&info
);
674 install_release(&info
);