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) + 1;
313 info->working_dir = HeapAlloc(GetProcessHeap(), 0, len * 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).
520 INT WINAPI LaunchINFSectionW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
523 LPWSTR cmdline_copy, cmdline_ptr;
524 LPWSTR inf_filename, install_sec;
529 TRACE("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_w(cmdline), show);
534 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
535 cmdline_ptr = cmdline_copy;
536 lstrcpyW(cmdline_copy, cmdline);
538 inf_filename = get_parameter(&cmdline_ptr, ',');
539 install_sec = get_parameter(&cmdline_ptr, ',');
541 str_flags = get_parameter(&cmdline_ptr, ',');
543 flags = atolW(str_flags);
545 ZeroMemory(&info, sizeof(ADVInfo));
547 hr = install_init(inf_filename, install_sec, NULL, flags, &info);
551 hr = spapi_install(&info);
555 hr = adv_install(&info);
558 install_release(&info);
559 HeapFree(GetProcessHeap(), 0, cmdline_copy);
564 /***********************************************************************
565 * LaunchINFSectionExA (ADVPACK.@)
567 * See LaunchINFSectionExW.
569 HRESULT WINAPI LaunchINFSectionExA(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
574 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
576 RtlCreateUnicodeStringFromAsciiz(&cmd, cmdline);
578 hr = LaunchINFSectionExW(hWnd, hInst, cmd.Buffer, show);
580 RtlFreeUnicodeString(&cmd);
585 /***********************************************************************
586 * LaunchINFSectionExW (ADVPACK.@)
588 * Installs an INF section with BACKUP/ROLLBACK capabilities.
591 * hWnd [I] Handle to parent window, NULL for desktop.
592 * hInst [I] Instance of the process.
593 * cmdline [I] Contains parameters in the order INF,section,CAB,flags,reboot.
594 * show [I] How the window should be shown.
601 * INF - Filename of the INF to launch.
602 * section - INF section to install.
603 * flags - see advpub.h.
604 * reboot - smart reboot behavior
606 * 'I' Reboot if needed (default).
610 * Doesn't handle the reboot flag.
612 HRESULT WINAPI LaunchINFSectionExW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
614 LPWSTR cmdline_copy, cmdline_ptr;
619 TRACE("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_w(cmdline), show);
624 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
625 cmdline_ptr = cmdline_copy;
626 lstrcpyW(cmdline_copy, cmdline);
628 cabinfo.pszInf = get_parameter(&cmdline_ptr, ',');
629 cabinfo.pszSection = get_parameter(&cmdline_ptr, ',');
630 cabinfo.pszCab = get_parameter(&cmdline_ptr, ',');
631 *cabinfo.szSrcPath = '\0';
633 flags = get_parameter(&cmdline_ptr, ',');
635 cabinfo.dwFlags = atolW(flags);
637 /* get the source path from the cab filename */
638 if (cabinfo.pszCab && *cabinfo.pszCab)
640 if (!is_full_path(cabinfo.pszCab))
643 lstrcpyW(cabinfo.szSrcPath, cabinfo.pszCab);
644 ptr = strrchrW(cabinfo.szSrcPath, '\\');
648 hr = ExecuteCabW(hWnd, &cabinfo, NULL);
651 HeapFree(GetProcessHeap(), 0, cmdline_copy);
656 HRESULT launch_exe(LPCWSTR cmd, LPCWSTR dir, HANDLE *phEXE)
659 PROCESS_INFORMATION pi;
661 if (phEXE) *phEXE = NULL;
663 ZeroMemory(&pi, sizeof(pi));
664 ZeroMemory(&si, sizeof(si));
667 if (!CreateProcessW(NULL, (LPWSTR)cmd, NULL, NULL, FALSE,
668 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP,
669 NULL, dir, &si, &pi))
671 return HRESULT_FROM_WIN32(GetLastError());
674 CloseHandle(pi.hThread);
678 *phEXE = pi.hProcess;
679 return S_ASYNCHRONOUS;
682 /* wait for the child process to finish */
683 WaitForSingleObject(pi.hProcess, INFINITE);
684 CloseHandle(pi.hProcess);
689 /***********************************************************************
690 * RunSetupCommandA (ADVPACK.@)
692 * See RunSetupCommandW.
694 HRESULT WINAPI RunSetupCommandA(HWND hWnd, LPCSTR szCmdName,
695 LPCSTR szInfSection, LPCSTR szDir,
696 LPCSTR lpszTitle, HANDLE *phEXE,
697 DWORD dwFlags, LPVOID pvReserved)
699 UNICODE_STRING cmdname, infsec;
700 UNICODE_STRING dir, title;
703 TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
704 hWnd, debugstr_a(szCmdName), debugstr_a(szInfSection),
705 debugstr_a(szDir), debugstr_a(lpszTitle),
706 phEXE, dwFlags, pvReserved);
708 if (!szCmdName || !szDir)
711 RtlCreateUnicodeStringFromAsciiz(&cmdname, szCmdName);
712 RtlCreateUnicodeStringFromAsciiz(&infsec, szInfSection);
713 RtlCreateUnicodeStringFromAsciiz(&dir, szDir);
714 RtlCreateUnicodeStringFromAsciiz(&title, lpszTitle);
716 hr = RunSetupCommandW(hWnd, cmdname.Buffer, infsec.Buffer, dir.Buffer,
717 title.Buffer, phEXE, dwFlags, pvReserved);
719 RtlFreeUnicodeString(&cmdname);
720 RtlFreeUnicodeString(&infsec);
721 RtlFreeUnicodeString(&dir);
722 RtlFreeUnicodeString(&title);
727 /***********************************************************************
728 * RunSetupCommandW (ADVPACK.@)
730 * Executes an install section in an INF file or a program.
733 * hWnd [I] Handle to parent window, NULL for quiet mode
734 * szCmdName [I] Inf or EXE filename to execute
735 * szInfSection [I] Inf section to install, NULL for DefaultInstall
736 * szDir [I] Path to extracted files
737 * szTitle [I] Title of all dialogs
738 * phEXE [O] Handle of EXE to wait for
739 * dwFlags [I] Flags; see include/advpub.h
740 * pvReserved [I] Reserved
744 * S_ASYNCHRONOUS OK, required to wait on phEXE
745 * ERROR_SUCCESS_REBOOT_REQUIRED Reboot required
746 * E_INVALIDARG Invalid argument given
747 * HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION)
748 * Not supported on this Windows version
749 * E_UNEXPECTED Unexpected error
750 * HRESULT_FROM_WIN32(GetLastError()) Some other error
753 * INF install unimplemented.
755 HRESULT WINAPI RunSetupCommandW(HWND hWnd, LPCWSTR szCmdName,
756 LPCWSTR szInfSection, LPCWSTR szDir,
757 LPCWSTR lpszTitle, HANDLE *phEXE,
758 DWORD dwFlags, LPVOID pvReserved)
763 TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
764 hWnd, debugstr_w(szCmdName), debugstr_w(szInfSection),
765 debugstr_w(szDir), debugstr_w(lpszTitle),
766 phEXE, dwFlags, pvReserved);
769 FIXME("Unhandled flags: 0x%08lx\n", dwFlags);
771 if (!szCmdName || !szDir)
774 if (!(dwFlags & RSC_FLAG_INF))
775 return launch_exe(szCmdName, szDir, phEXE);
777 ZeroMemory(&info, sizeof(ADVInfo));
779 hr = install_init(szCmdName, szInfSection, szDir, dwFlags, &info);
783 hr = spapi_install(&info);
787 hr = adv_install(&info);
790 install_release(&info);