1 /* 2 * Advpack install functions 3 * 4 * Copyright 2006 James Hawkins 5 * 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. 10 * 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. 15 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 #include <stdlib.h> 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "winuser.h" 27 #include "winreg.h" 28 #include "winternl.h" 29 #include "winnls.h" 30 #include "setupapi.h" 31 #include "advpub.h" 32 #include "ole2.h" 33 #include "wine/debug.h" 34 #include "advpack_private.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(advpack); 37 38 #define SPAPI_ERROR 0xE0000000L 39 #define SPAPI_PREFIX 0x800F0000L 40 #define SPAPI_MASK 0xFFFFL 41 #define HRESULT_FROM_SPAPI(x) ((HRESULT)((x & SPAPI_MASK) | SPAPI_PREFIX)) 42 43 #define ADV_HRESULT(x) ((x & SPAPI_ERROR) ? HRESULT_FROM_SPAPI(x) : HRESULT_FROM_WIN32(x)) 44 45 #define ADV_SUCCESS 0 46 #define ADV_FAILURE 1 47 48 /* contains information about a specific install instance */ 49 typedef struct _ADVInfo 50 { 51 HINF hinf; 52 LPWSTR inf_path; 53 LPWSTR inf_filename; 54 LPWSTR install_sec; 55 LPWSTR working_dir; 56 DWORD flags; 57 BOOL need_reboot; 58 } ADVInfo; 59 60 typedef HRESULT (*iterate_fields_func)(HINF hinf, PCWSTR field, const void *arg); 61 62 /* Advanced INF commands */ 63 static const WCHAR CheckAdminRights[] = { 64 'C','h','e','c','k','A','d','m','i','n','R','i','g','h','t','s',0 65 }; 66 static const WCHAR DelDirs[] = {'D','e','l','D','i','r','s',0}; 67 static const WCHAR PerUserInstall[] = {'P','e','r','U','s','e','r','I','n','s','t','a','l','l',0}; 68 static const WCHAR RegisterOCXs[] = {'R','e','g','i','s','t','e','r','O','C','X','s',0}; 69 static const WCHAR RunPreSetupCommands[] = { 70 'R','u','n','P','r','e','S','e','t','u','p','C','o','m','m','a','n','d','s',0 71 }; 72 static const WCHAR RunPostSetupCommands[] = { 73 'R','u','n','P','o','s','t','S','e','t','u','p','C','o','m','m','a','n','d','s',0 74 }; 75 76 /* Advanced INF callbacks */ 77 static HRESULT del_dirs_callback(HINF hinf, PCWSTR field, const void *arg) 78 { 79 INFCONTEXT context; 80 HRESULT hr = S_OK; 81 DWORD size; 82 83 BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context); 84 85 for (; ok; ok = SetupFindNextLine(&context, &context)) 86 { 87 WCHAR directory[MAX_INF_STRING_LENGTH]; 88 89 if (!SetupGetLineTextW(&context, NULL, NULL, NULL, directory, 90 MAX_INF_STRING_LENGTH, &size)) 91 continue; 92 93 if (DelNodeW(directory, ADN_DEL_IF_EMPTY) != S_OK) 94 hr = E_FAIL; 95 } 96 97 return hr; 98 } 99 100 static HRESULT per_user_install_callback(HINF hinf, PCWSTR field, const void *arg) 101 { 102 PERUSERSECTIONW per_user; 103 INFCONTEXT context; 104 DWORD size; 105 106 static const WCHAR disp_name[] = {'D','i','s','p','l','a','y','N','a','m','e',0}; 107 static const WCHAR version[] = {'V','e','r','s','i','o','n',0}; 108 static const WCHAR is_installed[] = {'I','s','I','n','s','t','a','l','l','e','d',0}; 109 static const WCHAR comp_id[] = {'C','o','m','p','o','n','e','n','t','I','D',0}; 110 static const WCHAR guid[] = {'G','U','I','D',0}; 111 static const WCHAR locale[] = {'L','o','c','a','l','e',0}; 112 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0}; 113 114 per_user.bRollback = FALSE; 115 per_user.dwIsInstalled = 0; 116 117 SetupGetLineTextW(NULL, hinf, field, disp_name, per_user.szDispName, ARRAY_SIZE(per_user.szDispName), &size); 118 119 SetupGetLineTextW(NULL, hinf, field, version, per_user.szVersion, ARRAY_SIZE(per_user.szVersion), &size); 120 121 if (SetupFindFirstLineW(hinf, field, is_installed, &context)) 122 { 123 SetupGetIntField(&context, 1, (PINT)&per_user.dwIsInstalled); 124 } 125 126 SetupGetLineTextW(NULL, hinf, field, comp_id, per_user.szCompID, ARRAY_SIZE(per_user.szCompID), &size); 127 128 SetupGetLineTextW(NULL, hinf, field, guid, per_user.szGUID, ARRAY_SIZE(per_user.szGUID), &size); 129 130 SetupGetLineTextW(NULL, hinf, field, locale, per_user.szLocale, ARRAY_SIZE(per_user.szLocale), &size); 131 132 SetupGetLineTextW(NULL, hinf, field, stub_path, per_user.szStub, ARRAY_SIZE(per_user.szStub), &size); 133 134 return SetPerUserSecValuesW(&per_user); 135 } 136 137 static HRESULT register_ocxs_callback(HINF hinf, PCWSTR field, const void *arg) 138 { 139 HMODULE hm; 140 INFCONTEXT context; 141 HRESULT hr = S_OK; 142 143 BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context); 144 145 for (; ok; ok = SetupFindNextLine(&context, &context)) 146 { 147 WCHAR buffer[MAX_INF_STRING_LENGTH]; 148 149 /* get OCX filename */ 150 if (!SetupGetStringFieldW(&context, 1, buffer, ARRAY_SIZE(buffer), NULL)) 151 continue; 152 153 hm = LoadLibraryExW(buffer, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 154 if (hm) 155 { 156 if (do_ocx_reg(hm, TRUE, NULL, NULL) != S_OK) 157 hr = E_FAIL; 158 159 FreeLibrary(hm); 160 } 161 else 162 hr = E_FAIL; 163 164 if (FAILED(hr)) 165 { 166 /* FIXME: display a message box */ 167 break; 168 } 169 } 170 171 return hr; 172 } 173 174 static HRESULT run_setup_commands_callback(HINF hinf, PCWSTR field, const void *arg) 175 { 176 const ADVInfo *info = (const ADVInfo *)arg; 177 INFCONTEXT context; 178 HRESULT hr = S_OK; 179 DWORD size; 180 181 BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context); 182 183 for (; ok; ok = SetupFindNextLine(&context, &context)) 184 { 185 WCHAR buffer[MAX_INF_STRING_LENGTH]; 186 187 if (!SetupGetLineTextW(&context, NULL, NULL, NULL, buffer, 188 MAX_INF_STRING_LENGTH, &size)) 189 continue; 190 191 if (launch_exe(buffer, info->working_dir, NULL) != S_OK) 192 hr = E_FAIL; 193 } 194 195 return hr; 196 } 197 198 /* sequentially returns pointers to parameters in a parameter list 199 * returns NULL if the parameter is empty, e.g. one,,three */ 200 LPWSTR get_parameter(LPWSTR *params, WCHAR separator, BOOL quoted) 201 { 202 LPWSTR token = *params; 203 204 if (!*params) 205 return NULL; 206 207 if (quoted && *token == '"') 208 { 209 WCHAR *end = wcschr(token + 1, '"'); 210 if (end) 211 { 212 *end = 0; 213 *params = end + 1; 214 token = token + 1; 215 } 216 } 217 218 *params = wcschr(*params, separator); 219 if (*params) 220 *(*params)++ = '\0'; 221 222 if (!*token) 223 return NULL; 224 225 return token; 226 } 227 228 static BOOL is_full_path(LPCWSTR path) 229 { 230 const int MIN_PATH_LEN = 3; 231 232 if (!path || lstrlenW(path) < MIN_PATH_LEN) 233 return FALSE; 234 235 if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) 236 return TRUE; 237 238 return FALSE; 239 } 240 241 /* retrieves the contents of a field, dynamically growing the buffer if necessary */ 242 static WCHAR *get_field_string(INFCONTEXT *context, DWORD index, WCHAR *buffer, 243 const WCHAR *static_buffer, DWORD *size) 244 { 245 DWORD required; 246 247 if (SetupGetStringFieldW(context, index, buffer, *size, &required)) return buffer; 248 249 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 250 { 251 /* now grow the buffer */ 252 if (buffer != static_buffer) HeapFree(GetProcessHeap(), 0, buffer); 253 if (!(buffer = HeapAlloc(GetProcessHeap(), 0, required*sizeof(WCHAR)))) return NULL; 254 *size = required; 255 if (SetupGetStringFieldW(context, index, buffer, *size, &required)) return buffer; 256 } 257 258 if (buffer != static_buffer) HeapFree(GetProcessHeap(), 0, buffer); 259 return NULL; 260 } 261 262 /* iterates over all fields of a certain key of a certain section */ 263 static HRESULT iterate_section_fields(HINF hinf, PCWSTR section, PCWSTR key, 264 iterate_fields_func callback, void *arg) 265 { 266 WCHAR static_buffer[200]; 267 WCHAR *buffer = static_buffer; 268 DWORD size = ARRAY_SIZE(static_buffer); 269 INFCONTEXT context; 270 HRESULT hr = E_FAIL; 271 272 BOOL ok = SetupFindFirstLineW(hinf, section, key, &context); 273 while (ok) 274 { 275 UINT i, count = SetupGetFieldCount(&context); 276 277 for (i = 1; i <= count; i++) 278 { 279 if (!(buffer = get_field_string(&context, i, buffer, static_buffer, &size))) 280 goto done; 281 282 if ((hr = callback(hinf, buffer, arg)) != S_OK) 283 goto done; 284 } 285 286 ok = SetupFindNextMatchLineW(&context, key, &context); 287 } 288 289 hr = S_OK; 290 291 done: 292 if (buffer != static_buffer) HeapFree(GetProcessHeap(), 0, buffer); 293 return hr; 294 } 295 296 static HRESULT check_admin_rights(const ADVInfo *info) 297 { 298 INT check; 299 INFCONTEXT context; 300 HRESULT hr = S_OK; 301 302 if (!SetupFindFirstLineW(info->hinf, info->install_sec, 303 CheckAdminRights, &context)) 304 return S_OK; 305 306 if (!SetupGetIntField(&context, 1, &check)) 307 return S_OK; 308 309 if (check == 1) 310 hr = IsNTAdmin(0, NULL) ? S_OK : E_FAIL; 311 312 return hr; 313 } 314 315 /* performs a setupapi-level install of the INF file */ 316 static HRESULT spapi_install(const ADVInfo *info) 317 { 318 BOOL ret; 319 HRESULT res; 320 PVOID context; 321 322 context = SetupInitDefaultQueueCallbackEx(NULL, INVALID_HANDLE_VALUE, 0, 0, NULL); 323 if (!context) 324 return ADV_HRESULT(GetLastError()); 325 326 ret = SetupInstallFromInfSectionW(NULL, info->hinf, info->install_sec, 327 SPINST_FILES, NULL, info->working_dir, 328 SP_COPY_NEWER, SetupDefaultQueueCallbackW, 329 context, NULL, NULL); 330 if (!ret) 331 { 332 res = ADV_HRESULT(GetLastError()); 333 SetupTermDefaultQueueCallback(context); 334 335 return res; 336 } 337 338 SetupTermDefaultQueueCallback(context); 339 340 ret = SetupInstallFromInfSectionW(NULL, info->hinf, info->install_sec, 341 SPINST_INIFILES | SPINST_REGISTRY | SPINST_REGSVR, 342 HKEY_LOCAL_MACHINE, NULL, 0, 343 NULL, NULL, NULL, NULL); 344 if (!ret) 345 return ADV_HRESULT(GetLastError()); 346 347 return S_OK; 348 } 349 350 /* processes the Advanced INF commands */ 351 static HRESULT adv_install(ADVInfo *info) 352 { 353 HRESULT hr; 354 355 hr = check_admin_rights(info); 356 if (hr != S_OK) 357 return hr; 358 359 hr = iterate_section_fields(info->hinf, info->install_sec, RunPreSetupCommands, 360 run_setup_commands_callback, info); 361 if (hr != S_OK) 362 return hr; 363 364 OleInitialize(NULL); 365 hr = iterate_section_fields(info->hinf, info->install_sec, 366 RegisterOCXs, register_ocxs_callback, NULL); 367 OleUninitialize(); 368 if (hr != S_OK) 369 return hr; 370 371 hr = iterate_section_fields(info->hinf, info->install_sec, 372 PerUserInstall, per_user_install_callback, info); 373 if (hr != S_OK) 374 return hr; 375 376 hr = iterate_section_fields(info->hinf, info->install_sec, RunPostSetupCommands, 377 run_setup_commands_callback, info); 378 if (hr != S_OK) 379 return hr; 380 381 hr = iterate_section_fields(info->hinf, info->install_sec, 382 DelDirs, del_dirs_callback, info); 383 if (hr != S_OK) 384 return hr; 385 386 return hr; 387 } 388 389 /* determines the proper working directory for the INF file */ 390 static HRESULT get_working_dir(ADVInfo *info, LPCWSTR inf_filename, LPCWSTR working_dir) 391 { 392 WCHAR path[MAX_PATH]; 393 LPCWSTR ptr; 394 DWORD len; 395 396 static const WCHAR backslash[] = {'\\',0}; 397 static const WCHAR inf_dir[] = {'\\','I','N','F',0}; 398 399 if ((ptr = wcsrchr(inf_filename, '\\'))) 400 { 401 len = ptr - inf_filename + 1; 402 ptr = inf_filename; 403 } 404 else if (working_dir && *working_dir) 405 { 406 len = lstrlenW(working_dir) + 1; 407 ptr = working_dir; 408 } 409 else 410 { 411 GetCurrentDirectoryW(MAX_PATH, path); 412 lstrcatW(path, backslash); 413 lstrcatW(path, inf_filename); 414 415 /* check if the INF file is in the current directory */ 416 if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) 417 { 418 GetCurrentDirectoryW(MAX_PATH, path); 419 } 420 else 421 { 422 /* default to the windows\inf directory if all else fails */ 423 GetWindowsDirectoryW(path, MAX_PATH); 424 lstrcatW(path, inf_dir); 425 } 426 427 len = lstrlenW(path) + 1; 428 ptr = path; 429 } 430 431 info->working_dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 432 if (!info->working_dir) 433 return E_OUTOFMEMORY; 434 435 lstrcpynW(info->working_dir, ptr, len); 436 437 return S_OK; 438 } 439 440 /* loads the INF file and performs checks on it */ 441 static HRESULT install_init(LPCWSTR inf_filename, LPCWSTR install_sec, 442 LPCWSTR working_dir, DWORD flags, ADVInfo *info) 443 { 444 DWORD len; 445 HRESULT hr; 446 LPCWSTR ptr, path; 447 448 static const WCHAR backslash[] = {'\\',0}; 449 static const WCHAR default_install[] = { 450 'D','e','f','a','u','l','t','I','n','s','t','a','l','l',0 451 }; 452 453 if (!(ptr = wcsrchr(inf_filename, '\\'))) 454 ptr = inf_filename; 455 456 len = lstrlenW(ptr); 457 458 info->inf_filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 459 if (!info->inf_filename) 460 return E_OUTOFMEMORY; 461 462 lstrcpyW(info->inf_filename, ptr); 463 464 /* FIXME: determine the proper platform to install (NTx86, etc) */ 465 if (!install_sec || !*install_sec) 466 { 467 len = sizeof(default_install) - 1; 468 ptr = default_install; 469 } 470 else 471 { 472 len = lstrlenW(install_sec); 473 ptr = install_sec; 474 } 475 476 info->install_sec = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 477 if (!info->install_sec) 478 return E_OUTOFMEMORY; 479 480 lstrcpyW(info->install_sec, ptr); 481 482 hr = get_working_dir(info, inf_filename, working_dir); 483 if (FAILED(hr)) 484 return hr; 485 486 len = lstrlenW(info->working_dir) + lstrlenW(info->inf_filename) + 2; 487 info->inf_path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 488 if (!info->inf_path) 489 return E_OUTOFMEMORY; 490 491 lstrcpyW(info->inf_path, info->working_dir); 492 lstrcatW(info->inf_path, backslash); 493 lstrcatW(info->inf_path, info->inf_filename); 494 495 /* RunSetupCommand opens unmodified filename parameter */ 496 if (flags & RSC_FLAG_INF) 497 path = inf_filename; 498 else 499 path = info->inf_path; 500 501 info->hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL); 502 if (info->hinf == INVALID_HANDLE_VALUE) 503 return ADV_HRESULT(GetLastError()); 504 505 set_ldids(info->hinf, info->install_sec, info->working_dir); 506 507 /* FIXME: check that the INF is advanced */ 508 509 info->flags = flags; 510 info->need_reboot = FALSE; 511 512 return S_OK; 513 } 514 515 /* release the install instance information */ 516 static void install_release(const ADVInfo *info) 517 { 518 SetupCloseInfFile(info->hinf); 519 520 HeapFree(GetProcessHeap(), 0, info->inf_path); 521 HeapFree(GetProcessHeap(), 0, info->inf_filename); 522 HeapFree(GetProcessHeap(), 0, info->install_sec); 523 HeapFree(GetProcessHeap(), 0, info->working_dir); 524 } 525 526 /* this structure very closely resembles parameters of RunSetupCommand() */ 527 typedef struct 528 { 529 HWND hwnd; 530 LPCSTR title; 531 LPCSTR inf_name; 532 LPCSTR dir; 533 LPCSTR section_name; 534 } SETUPCOMMAND_PARAMS; 535 536 typedef struct 537 { 538 HWND hwnd; 539 LPCWSTR title; 540 LPCWSTR inf_name; 541 LPCWSTR dir; 542 LPCWSTR section_name; 543 } SETUPCOMMAND_PARAMSW; 544 545 /* internal: see DoInfInstall */ 546 static HRESULT DoInfInstallW(const SETUPCOMMAND_PARAMSW *setup) 547 { 548 ADVInfo info; 549 HRESULT hr; 550 551 TRACE("(%p)\n", setup); 552 553 ZeroMemory(&info, sizeof(ADVInfo)); 554 555 hr = install_init(setup->inf_name, setup->section_name, setup->dir, 0, &info); 556 if (hr != S_OK) 557 goto done; 558 559 hr = spapi_install(&info); 560 if (hr != S_OK) 561 goto done; 562 563 hr = adv_install(&info); 564 565 done: 566 install_release(&info); 567 568 return S_OK; 569 } 570 571 /*********************************************************************** 572 * DoInfInstall (ADVPACK.@) 573 * 574 * Install an INF section. 575 * 576 * PARAMS 577 * setup [I] Structure containing install information. 578 * 579 * RETURNS 580 * S_OK Everything OK 581 * HRESULT_FROM_WIN32(GetLastError()) Some other error 582 */ 583 HRESULT WINAPI DoInfInstall(const SETUPCOMMAND_PARAMS *setup) 584 { 585 UNICODE_STRING title, inf, section, dir; 586 SETUPCOMMAND_PARAMSW params; 587 HRESULT hr; 588 589 if (!setup) 590 return E_INVALIDARG; 591 592 RtlCreateUnicodeStringFromAsciiz(&title, setup->title); 593 RtlCreateUnicodeStringFromAsciiz(&inf, setup->inf_name); 594 RtlCreateUnicodeStringFromAsciiz(§ion, setup->section_name); 595 RtlCreateUnicodeStringFromAsciiz(&dir, setup->dir); 596 597 params.title = title.Buffer; 598 params.inf_name = inf.Buffer; 599 params.section_name = section.Buffer; 600 params.dir = dir.Buffer; 601 params.hwnd = setup->hwnd; 602 603 hr = DoInfInstallW(¶ms); 604 605 RtlFreeUnicodeString(&title); 606 RtlFreeUnicodeString(&inf); 607 RtlFreeUnicodeString(§ion); 608 RtlFreeUnicodeString(&dir); 609 610 return hr; 611 } 612 613 /*********************************************************************** 614 * ExecuteCabA (ADVPACK.@) 615 * 616 * See ExecuteCabW. 617 */ 618 HRESULT WINAPI ExecuteCabA(HWND hwnd, CABINFOA* pCab, LPVOID pReserved) 619 { 620 UNICODE_STRING cab, inf, section; 621 CABINFOW cabinfo; 622 HRESULT hr; 623 624 TRACE("(%p, %p, %p)\n", hwnd, pCab, pReserved); 625 626 if (!pCab) 627 return E_INVALIDARG; 628 629 if (pCab->pszCab) 630 { 631 RtlCreateUnicodeStringFromAsciiz(&cab, pCab->pszCab); 632 cabinfo.pszCab = cab.Buffer; 633 } 634 else 635 cabinfo.pszCab = NULL; 636 637 RtlCreateUnicodeStringFromAsciiz(&inf, pCab->pszInf); 638 RtlCreateUnicodeStringFromAsciiz(§ion, pCab->pszSection); 639 640 MultiByteToWideChar(CP_ACP, 0, pCab->szSrcPath, -1, cabinfo.szSrcPath, ARRAY_SIZE(cabinfo.szSrcPath)); 641 642 cabinfo.pszInf = inf.Buffer; 643 cabinfo.pszSection = section.Buffer; 644 cabinfo.dwFlags = pCab->dwFlags; 645 646 hr = ExecuteCabW(hwnd, &cabinfo, pReserved); 647 648 if (pCab->pszCab) 649 RtlFreeUnicodeString(&cab); 650 651 RtlFreeUnicodeString(&inf); 652 RtlFreeUnicodeString(§ion); 653 654 return hr; 655 } 656 657 /*********************************************************************** 658 * ExecuteCabW (ADVPACK.@) 659 * 660 * Installs the INF file extracted from a specified cabinet file. 661 * 662 * PARAMS 663 * hwnd [I] Handle to the window used for the display. 664 * pCab [I] Information about the cabinet file. 665 * pReserved [I] Reserved. Must be NULL. 666 * 667 * RETURNS 668 * Success: S_OK. 669 * Failure: E_FAIL. 670 */ 671 HRESULT WINAPI ExecuteCabW(HWND hwnd, CABINFOW* pCab, LPVOID pReserved) 672 { 673 ADVInfo info; 674 HRESULT hr; 675 676 TRACE("(%p, %p, %p)\n", hwnd, pCab, pReserved); 677 678 ZeroMemory(&info, sizeof(ADVInfo)); 679 680 if (pCab->pszCab && *pCab->pszCab) 681 FIXME("Cab archive not extracted!\n"); 682 683 hr = install_init(pCab->pszInf, pCab->pszSection, pCab->szSrcPath, pCab->dwFlags, &info); 684 if (hr != S_OK) 685 goto done; 686 687 hr = spapi_install(&info); 688 if (hr != S_OK) 689 goto done; 690 691 hr = adv_install(&info); 692 693 done: 694 install_release(&info); 695 696 return hr; 697 } 698 699 /*********************************************************************** 700 * LaunchINFSectionA (ADVPACK.@) 701 * 702 * See LaunchINFSectionW. 703 */ 704 INT WINAPI LaunchINFSectionA(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show) 705 { 706 UNICODE_STRING cmd; 707 HRESULT hr; 708 709 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show); 710 711 if (!cmdline) 712 return ADV_FAILURE; 713 714 RtlCreateUnicodeStringFromAsciiz(&cmd, cmdline); 715 716 hr = LaunchINFSectionW(hWnd, hInst, cmd.Buffer, show); 717 718 RtlFreeUnicodeString(&cmd); 719 720 return hr; 721 } 722 723 /*********************************************************************** 724 * LaunchINFSectionW (ADVPACK.@) 725 * 726 * Installs an INF section without BACKUP/ROLLBACK capabilities. 727 * 728 * PARAMS 729 * hWnd [I] Handle to parent window, NULL for desktop. 730 * hInst [I] Instance of the process. 731 * cmdline [I] Contains parameters in the order INF,section,flags,reboot. 732 * show [I] How the window should be shown. 733 * 734 * RETURNS 735 * Success: ADV_SUCCESS. 736 * Failure: ADV_FAILURE. 737 * 738 * NOTES 739 * INF - Filename of the INF to launch. 740 * section - INF section to install. 741 * flags - see advpub.h. 742 * reboot - smart reboot behavior 743 * 'A' Always reboot. 744 * 'I' Reboot if needed (default). 745 * 'N' No reboot. 746 */ 747 INT WINAPI LaunchINFSectionW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show) 748 { 749 ADVInfo info; 750 LPWSTR cmdline_copy, cmdline_ptr; 751 LPWSTR inf_filename, install_sec; 752 LPWSTR str_flags; 753 DWORD flags = 0; 754 HRESULT hr = S_OK; 755 756 TRACE("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_w(cmdline), show); 757 758 if (!cmdline) 759 return ADV_FAILURE; 760 761 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR)); 762 cmdline_ptr = cmdline_copy; 763 lstrcpyW(cmdline_copy, cmdline); 764 765 inf_filename = get_parameter(&cmdline_ptr, ',', TRUE); 766 install_sec = get_parameter(&cmdline_ptr, ',', TRUE); 767 768 str_flags = get_parameter(&cmdline_ptr, ',', TRUE); 769 if (str_flags) 770 { 771 DWORD inf_flags = wcstol(str_flags, NULL, 10); 772 if (inf_flags & LIS_QUIET) flags |= RSC_FLAG_QUIET; 773 if (inf_flags & LIS_NOGRPCONV) flags |= RSC_FLAG_NGCONV; 774 } 775 776 ZeroMemory(&info, sizeof(ADVInfo)); 777 778 hr = install_init(inf_filename, install_sec, NULL, flags, &info); 779 if (hr != S_OK) 780 goto done; 781 782 hr = spapi_install(&info); 783 if (hr != S_OK) 784 goto done; 785 786 hr = adv_install(&info); 787 788 done: 789 install_release(&info); 790 HeapFree(GetProcessHeap(), 0, cmdline_copy); 791 792 return SUCCEEDED(hr) ? ADV_SUCCESS : ADV_FAILURE; 793 } 794 795 /*********************************************************************** 796 * LaunchINFSectionExA (ADVPACK.@) 797 * 798 * See LaunchINFSectionExW. 799 */ 800 HRESULT WINAPI LaunchINFSectionExA(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show) 801 { 802 UNICODE_STRING cmd; 803 HRESULT hr; 804 805 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show); 806 807 if (!cmdline) 808 return ADV_FAILURE; 809 810 RtlCreateUnicodeStringFromAsciiz(&cmd, cmdline); 811 812 hr = LaunchINFSectionExW(hWnd, hInst, cmd.Buffer, show); 813 814 RtlFreeUnicodeString(&cmd); 815 816 return hr; 817 } 818 819 /*********************************************************************** 820 * LaunchINFSectionExW (ADVPACK.@) 821 * 822 * Installs an INF section with BACKUP/ROLLBACK capabilities. 823 * 824 * PARAMS 825 * hWnd [I] Handle to parent window, NULL for desktop. 826 * hInst [I] Instance of the process. 827 * cmdline [I] Contains parameters in the order INF,section,CAB,flags,reboot. 828 * show [I] How the window should be shown. 829 * 830 * RETURNS 831 * Success: ADV_SUCCESS. 832 * Failure: ADV_FAILURE. 833 * 834 * NOTES 835 * INF - Filename of the INF to launch. 836 * section - INF section to install. 837 * flags - see advpub.h. 838 * reboot - smart reboot behavior 839 * 'A' Always reboot. 840 * 'I' Reboot if needed (default). 841 * 'N' No reboot. 842 * 843 * BUGS 844 * Doesn't handle the reboot flag. 845 */ 846 HRESULT WINAPI LaunchINFSectionExW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show) 847 { 848 LPWSTR cmdline_copy, cmdline_ptr; 849 LPWSTR flags, ptr; 850 CABINFOW cabinfo; 851 HRESULT hr; 852 853 TRACE("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_w(cmdline), show); 854 855 if (!cmdline) 856 return ADV_FAILURE; 857 858 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR)); 859 cmdline_ptr = cmdline_copy; 860 lstrcpyW(cmdline_copy, cmdline); 861 862 cabinfo.pszInf = get_parameter(&cmdline_ptr, ',', TRUE); 863 cabinfo.pszSection = get_parameter(&cmdline_ptr, ',', TRUE); 864 cabinfo.pszCab = get_parameter(&cmdline_ptr, ',', TRUE); 865 *cabinfo.szSrcPath = '\0'; 866 867 flags = get_parameter(&cmdline_ptr, ',', TRUE); 868 if (flags) 869 cabinfo.dwFlags = wcstol(flags, NULL, 10); 870 871 if (!is_full_path(cabinfo.pszCab) && !is_full_path(cabinfo.pszInf)) 872 { 873 HeapFree(GetProcessHeap(), 0, cmdline_copy); 874 return E_INVALIDARG; 875 } 876 877 /* get the source path from the cab filename */ 878 if (cabinfo.pszCab && *cabinfo.pszCab) 879 { 880 if (!is_full_path(cabinfo.pszCab)) 881 lstrcpyW(cabinfo.szSrcPath, cabinfo.pszInf); 882 else 883 lstrcpyW(cabinfo.szSrcPath, cabinfo.pszCab); 884 885 ptr = wcsrchr(cabinfo.szSrcPath, '\\'); 886 *(++ptr) = '\0'; 887 } 888 889 hr = ExecuteCabW(hWnd, &cabinfo, NULL); 890 HeapFree(GetProcessHeap(), 0, cmdline_copy); 891 return SUCCEEDED(hr) ? ADV_SUCCESS : ADV_FAILURE; 892 } 893 894 HRESULT launch_exe(LPCWSTR cmd, LPCWSTR dir, HANDLE *phEXE) 895 { 896 STARTUPINFOW si; 897 PROCESS_INFORMATION pi; 898 899 if (phEXE) *phEXE = NULL; 900 901 ZeroMemory(&pi, sizeof(pi)); 902 ZeroMemory(&si, sizeof(si)); 903 si.cb = sizeof(si); 904 905 if (!CreateProcessW(NULL, (LPWSTR)cmd, NULL, NULL, FALSE, 906 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP, 907 NULL, dir, &si, &pi)) 908 { 909 return HRESULT_FROM_WIN32(GetLastError()); 910 } 911 912 CloseHandle(pi.hThread); 913 914 if (phEXE) 915 { 916 *phEXE = pi.hProcess; 917 return S_ASYNCHRONOUS; 918 } 919 920 /* wait for the child process to finish */ 921 WaitForSingleObject(pi.hProcess, INFINITE); 922 CloseHandle(pi.hProcess); 923 924 return S_OK; 925 } 926 927 /*********************************************************************** 928 * RunSetupCommandA (ADVPACK.@) 929 * 930 * See RunSetupCommandW. 931 */ 932 HRESULT WINAPI RunSetupCommandA(HWND hWnd, LPCSTR szCmdName, 933 LPCSTR szInfSection, LPCSTR szDir, 934 LPCSTR lpszTitle, HANDLE *phEXE, 935 DWORD dwFlags, LPVOID pvReserved) 936 { 937 UNICODE_STRING cmdname, infsec; 938 UNICODE_STRING dir, title; 939 HRESULT hr; 940 941 TRACE("(%p, %s, %s, %s, %s, %p, %d, %p)\n", 942 hWnd, debugstr_a(szCmdName), debugstr_a(szInfSection), 943 debugstr_a(szDir), debugstr_a(lpszTitle), 944 phEXE, dwFlags, pvReserved); 945 946 if (!szCmdName || !szDir) 947 return E_INVALIDARG; 948 949 RtlCreateUnicodeStringFromAsciiz(&cmdname, szCmdName); 950 RtlCreateUnicodeStringFromAsciiz(&infsec, szInfSection); 951 RtlCreateUnicodeStringFromAsciiz(&dir, szDir); 952 RtlCreateUnicodeStringFromAsciiz(&title, lpszTitle); 953 954 hr = RunSetupCommandW(hWnd, cmdname.Buffer, infsec.Buffer, dir.Buffer, 955 title.Buffer, phEXE, dwFlags, pvReserved); 956 957 RtlFreeUnicodeString(&cmdname); 958 RtlFreeUnicodeString(&infsec); 959 RtlFreeUnicodeString(&dir); 960 RtlFreeUnicodeString(&title); 961 962 return hr; 963 } 964 965 /*********************************************************************** 966 * RunSetupCommandW (ADVPACK.@) 967 * 968 * Executes an install section in an INF file or a program. 969 * 970 * PARAMS 971 * hWnd [I] Handle to parent window, NULL for quiet mode 972 * szCmdName [I] Inf or EXE filename to execute 973 * szInfSection [I] Inf section to install, NULL for DefaultInstall 974 * szDir [I] Path to extracted files 975 * szTitle [I] Title of all dialogs 976 * phEXE [O] Handle of EXE to wait for 977 * dwFlags [I] Flags; see include/advpub.h 978 * pvReserved [I] Reserved 979 * 980 * RETURNS 981 * S_OK Everything OK 982 * S_ASYNCHRONOUS OK, required to wait on phEXE 983 * ERROR_SUCCESS_REBOOT_REQUIRED Reboot required 984 * E_INVALIDARG Invalid argument given 985 * HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION) 986 * Not supported on this Windows version 987 * E_UNEXPECTED Unexpected error 988 * HRESULT_FROM_WIN32(GetLastError()) Some other error 989 */ 990 HRESULT WINAPI RunSetupCommandW(HWND hWnd, LPCWSTR szCmdName, 991 LPCWSTR szInfSection, LPCWSTR szDir, 992 LPCWSTR lpszTitle, HANDLE *phEXE, 993 DWORD dwFlags, LPVOID pvReserved) 994 { 995 ADVInfo info; 996 HRESULT hr; 997 998 TRACE("(%p, %s, %s, %s, %s, %p, %d, %p)\n", 999 hWnd, debugstr_w(szCmdName), debugstr_w(szInfSection), 1000 debugstr_w(szDir), debugstr_w(lpszTitle), 1001 phEXE, dwFlags, pvReserved); 1002 1003 if (dwFlags & RSC_FLAG_UPDHLPDLLS) 1004 FIXME("Unhandled flag: RSC_FLAG_UPDHLPDLLS\n"); 1005 1006 if (!szCmdName || !szDir) 1007 return E_INVALIDARG; 1008 1009 if (!(dwFlags & RSC_FLAG_INF)) 1010 return launch_exe(szCmdName, szDir, phEXE); 1011 1012 ZeroMemory(&info, sizeof(ADVInfo)); 1013 1014 hr = install_init(szCmdName, szInfSection, szDir, dwFlags, &info); 1015 if (hr != S_OK) 1016 goto done; 1017 1018 hr = spapi_install(&info); 1019 if (hr != S_OK) 1020 goto done; 1021 1022 hr = adv_install(&info); 1023 1024 done: 1025 install_release(&info); 1026 1027 return hr; 1028 } 1029