Changeset 45320 in vbox for trunk/src/VBox/Installer/win/Stub
- Timestamp:
- Apr 3, 2013 8:16:56 PM (12 years ago)
- Location:
- trunk/src/VBox/Installer/win/Stub
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Installer/win/Stub/Makefile.kmk
r43894 r45320 22 22 if "$(KBUILD_TARGET_ARCH)" == "x86" 23 23 24 TEMPLATE_VBOXSTUB = Drop the signing, we will sign it later.25 TEMPLATE_VBOXSTUB_EXTENDS = VBOXR3STATIC26 TEMPLATE_VBOXSTUB_POST_CMDS = $(NO_SUCH_VARIABLE)24 TEMPLATE_VBOXSTUB = Drop the signing, we will sign it later. 25 TEMPLATE_VBOXSTUB_EXTENDS = VBOXR3STATIC 26 TEMPLATE_VBOXSTUB_POST_CMDS = $(NO_SUCH_VARIABLE) 27 27 28 PROGRAMS.x86+= VBoxStub29 VBoxStub_TEMPLATE= VBOXSTUB30 VBoxStub_DEFS = _WIN32_WINNT=0x0501 IN_RT_R328 PROGRAMS += VBoxStub 29 VBoxStub_TEMPLATE= VBOXSTUB 30 VBoxStub_DEFS = _WIN32_WINNT=0x0501 IN_RT_R3 31 31 32 VBoxStub_SOURCES = \33 VBoxStub.cpp \34 VBoxStub.rc32 VBoxStub_SOURCES = \ 33 VBoxStub.cpp \ 34 VBoxStub.rc 35 35 36 VBoxStub_SDKS += \37 VBOX_NTDLL38 VBoxStub_LIBS = \39 $(VBOX_LIB_RUNTIME_STATIC) \40 $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Msi.lib36 VBoxStub_SDKS += \ 37 VBOX_NTDLL 38 VBoxStub_LIBS = \ 39 $(VBOX_LIB_RUNTIME_STATIC) \ 40 $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Msi.lib 41 41 42 VBoxStub.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)43 VBoxStub.cpp_DEPS = $(VBOX_SVN_REV_KMK)42 VBoxStub.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) 43 VBoxStub.cpp_DEPS = $(VBOX_SVN_REV_KMK) 44 44 45 # If signing mode is enabled, then add the possibility to46 # install public certificate automatically in /silent mode47 ifdef VBOX_SIGNING_MODE45 # If signing mode is enabled, then add the possibility to 46 # install public certificate automatically in /silent mode 47 ifdef VBOX_SIGNING_MODE 48 48 49 VBoxStub_SOURCES += VBoxStubCertUtil.cpp50 VBoxStub_LIBS += crypt32.lib51 VBoxStub.cpp_DEPS += $(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h52 VBoxStub.cpp_INCS += $(VBoxStub_0_OUTDIR)53 VBoxStub.cpp_DEFS += VBOX_SIGNING_MODE 49 VBoxStub_SOURCES += VBoxStubCertUtil.cpp 50 VBoxStub_LIBS += crypt32.lib 51 VBoxStub.cpp_DEPS += $(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h 52 VBoxStub.cpp_INCS += $(VBoxStub_0_OUTDIR) 53 VBoxStub.cpp_DEFS += VBOX_WITH_CODE_SIGNING 54 54 55 $$(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h: $(VBOX_BIN2C) $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer55 $$(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h: $(VBOX_BIN2C) $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer 56 56 $(VBOX_BIN2C) _VBoxStubPublicCert $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer $@ 57 57 58 endif58 endif 59 59 60 # The icon location is configurable.61 VBoxStub.rc_INCS += $(VBoxStub_0_OUTDIR)62 VBoxStub.rc_DEPS += \63 $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \64 $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc65 VBoxStub.rc_CLEAN = \66 $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \67 $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc60 # The icon location is configurable. 61 VBoxStub.rc_INCS += $(VBoxStub_0_OUTDIR) 62 VBoxStub.rc_DEPS += \ 63 $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \ 64 $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc 65 VBoxStub.rc_CLEAN = \ 66 $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \ 67 $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc 68 68 69 # Icon include file.70 $$(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc: $(VBOX_WINDOWS_ICON_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@)69 # Icon include file. 70 $$(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc: $(VBOX_WINDOWS_ICON_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@) 71 71 $(APPEND) -t $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ICON_FILE))"' 72 72 73 # Manifest.74 VBOX_STUB_MANIFEST_FILE := $(PATH_SUB_CURRENT)/VBoxStub.manifest75 $$(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc: $(VBOX_STUB_MANIFEST_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@)73 # Manifest. 74 VBOX_STUB_MANIFEST_FILE := $(PATH_SUB_CURRENT)/VBoxStub.manifest 75 $$(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc: $(VBOX_STUB_MANIFEST_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@) 76 76 $(APPEND) -t $@ 'APP_MANIFEST RT_MANIFEST "$(subst /,\\,$(VBOX_STUB_MANIFEST_FILE))"' 77 77 78 78 79 endif # x86 only -
trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp
r45318 r45320 49 49 #include "resource.h" 50 50 51 #ifdef VBOX_ SIGNING_MODE52 # include "VBoxStubCertUtil.h"53 # include "VBoxStubPublicCert.h"51 #ifdef VBOX_WITH_CODE_SIGNING 52 # include "VBoxStubCertUtil.h" 53 # include "VBoxStubPublicCert.h" 54 54 #endif 55 55 56 #ifndef _UNICODE 56 #ifndef _UNICODE /* Isn't this a little late? */ 57 57 #define _UNICODE 58 58 #endif … … 68 68 * Shows an error message box with a printf() style formatted string. 69 69 * 70 * @returns RTEXITCODE_FAILURE 70 71 * @param pszFmt Printf-style format string to show in the message box body. 71 72 * 72 73 */ 73 static voidShowError(const char *pszFmt, ...)74 static RTEXITCODE ShowError(const char *pszFmt, ...) 74 75 { 75 76 char *pszMsg; … … 88 89 AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt)); 89 90 va_end(va); 91 return RTEXITCODE_FAILURE; 90 92 } 91 93 … … 119 121 120 122 /** 121 * Reads data from a built-in resource. 122 * 123 * @returns iprt status code. 124 * 125 * @param hInst Instance to read the data from. 123 * Finds the specified in the resource section of the executable. 124 * 125 * @returns IPRT status code. 126 * 126 127 * @param pszDataName Name of resource to read. 127 * @param ppvResource Pointer to buffer which holds the read resource data.128 * @param pdwSize Pointer which holds the read data size.129 * 130 * /131 static int ReadData(HINSTANCE hInst, 132 128 * @param ppvResource Where to return the pointer to the data. 129 * @param pdwSize Where to return the size of the data (if found). 130 * Optional. 131 * 132 */ 133 static int FindData(const char *pszDataName, 133 134 PVOID *ppvResource, 134 135 DWORD *pdwSize) 135 136 { 136 137 AssertReturn(pszDataName, VERR_INVALID_PARAMETER); 138 HINSTANCE hInst = NULL; 137 139 138 140 /* Find our resource. */ … … 141 143 142 144 /* Get resource size. */ 143 *pdwSize = SizeofResource(hInst, hRsrc); 144 AssertReturn(*pdwSize > 0, VERR_NO_DATA); 145 DWORD cb = SizeofResource(hInst, hRsrc); 146 AssertReturn(cb > 0, VERR_NO_DATA); 147 if (pdwSize) 148 *pdwSize = cb; 145 149 146 150 /* Get pointer to resource. */ … … 156 160 157 161 /** 162 * Finds the header for the given package. 163 * 164 * @returns Pointer to the package header on success. On failure NULL is 165 * returned after ShowError has been invoked. 166 * @param iPackage The package number. 167 */ 168 static PVBOXSTUBPKG FindPackageHeader(unsigned iPackage) 169 { 170 char szHeaderName[32]; 171 RTStrPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", iPackage); 172 173 PVBOXSTUBPKG pPackage; 174 int rc = FindData(szHeaderName, (PVOID *)&pPackage, NULL); 175 if (RT_FAILURE(rc)) 176 { 177 ShowError("Internal error: Could not find package header #%u: %Rrc", iPackage, rc); 178 return NULL; 179 } 180 181 /** @todo validate it. */ 182 return pPackage; 183 } 184 185 186 187 /** 158 188 * Constructs a full temporary file path from the given parameters. 159 189 * … … 199 229 PVOID pvData = NULL; 200 230 DWORD dwDataSize = 0; 201 rc = ReadData(NULL,pszResourceName, &pvData, &dwDataSize);231 rc = FindData(pszResourceName, &pvData, &dwDataSize); 202 232 AssertMsgRCBreak(rc, ("Could not read resource data!\n")); 203 233 … … 298 328 299 329 /** 300 * Recursively copies a directory to another location. 301 * 302 * @returns iprt status code. 303 * 304 * @param pszDestDir Location to copy the source directory to. 305 * @param pszSourceDir The source directory to copy. 306 * 307 */ 308 int CopyDir(const char *pszDestDir, const char *pszSourceDir) 309 { 310 char szDest[RTPATH_MAX + 1]; 311 char szSource[RTPATH_MAX + 1]; 312 313 AssertStmt(pszDestDir, "Destination directory invalid!"); 314 AssertStmt(pszSourceDir, "Source directory invalid!"); 315 316 SHFILEOPSTRUCT s = {0}; 317 if ( RTStrPrintf(szDest, _MAX_PATH, "%s%c", pszDestDir, '\0') > 0 318 && RTStrPrintf(szSource, _MAX_PATH, "%s%c", pszSourceDir, '\0') > 0) 319 { 320 s.hwnd = NULL; 321 s.wFunc = FO_COPY; 322 s.pTo = szDest; 323 s.pFrom = szSource; 324 s.fFlags = FOF_SILENT 325 | FOF_NOCONFIRMATION 326 | FOF_NOCONFIRMMKDIR 327 | FOF_NOERRORUI; 328 } 329 return RTErrConvertFromWin32(SHFileOperation(&s)); 330 * Processes an MSI package. 331 * 332 * @returns Fully complained exit code. 333 * @param iPackage The package number. 334 * @param pszMsi The path to the MSI to process. 335 * @param pszMsiArgs Any additional installer (MSI) argument 336 * @param fLogging Whether to enable installer logging. 337 */ 338 static RTEXITCODE ProcessMsiPackage(unsigned iPackage, const char *pszMsi, const char *pszMsiArgs, bool fLogging) 339 { 340 int rc; 341 342 /* 343 * Set UI level. 344 */ 345 INSTALLUILEVEL enmDesiredUiLevel = g_fSilent ? INSTALLUILEVEL_NONE : INSTALLUILEVEL_FULL; 346 INSTALLUILEVEL enmRet = MsiSetInternalUI(enmDesiredUiLevel, NULL); 347 if (enmRet == INSTALLUILEVEL_NOCHANGE /* means error */) 348 return ShowError("Internal error: MsiSetInternalUI failed."); 349 350 /* 351 * Enable logging? 352 */ 353 if (fLogging) 354 { 355 char szLogFile[RTPATH_MAX]; 356 rc = RTStrCopy(szLogFile, sizeof(szLogFile), pszMsi); 357 if (RT_SUCCESS(rc)) 358 { 359 RTPathStripFilename(szLogFile); 360 rc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxInstallLog.txt"); 361 } 362 if (RT_FAILURE(rc)) 363 return ShowError("Internal error: Filename path too long."); 364 365 PRTUTF16 pwszLogFile; 366 rc = RTStrToUtf16(szLogFile, &pwszLogFile); 367 if (RT_FAILURE(rc)) 368 return ShowError("RTStrToUtf16 failed on '%s': %Rrc", szLogFile, rc); 369 370 UINT uLogLevel = MsiEnableLogW(INSTALLLOGMODE_VERBOSE, 371 pwszLogFile, 372 INSTALLLOGATTRIBUTES_FLUSHEACHLINE | (iPackage > 0 ? INSTALLLOGATTRIBUTES_APPEND : 0)); 373 RTUtf16Free(pwszLogFile); 374 if (uLogLevel != ERROR_SUCCESS) 375 return ShowError("MsiEnableLogW failed"); 376 } 377 378 /* 379 * Initialize the common controls (extended version). This is necessary to 380 * run the actual .MSI installers with the new fancy visual control 381 * styles (XP+). Also, an integrated manifest is required. 382 */ 383 INITCOMMONCONTROLSEX ccEx; 384 ccEx.dwSize = sizeof(INITCOMMONCONTROLSEX); 385 ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS | 386 ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | 387 ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES; 388 InitCommonControlsEx(&ccEx); /* Ignore failure. */ 389 390 /* 391 * Convert both strings to UTF-16 and start the installation. 392 */ 393 PRTUTF16 pwszMsi; 394 rc = RTStrToUtf16(pszMsi, &pwszMsi); 395 if (RT_FAILURE(rc)) 396 return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc); 397 PRTUTF16 pwszMsiArgs; 398 rc = RTStrToUtf16(pszMsiArgs, &pwszMsiArgs); 399 if (RT_FAILURE(rc)) 400 { 401 RTUtf16Free(pwszMsi); 402 return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc); 403 } 404 405 UINT uStatus = MsiInstallProductW(pwszMsi, pwszMsiArgs); 406 RTUtf16Free(pwszMsi); 407 RTUtf16Free(pwszMsiArgs); 408 409 if (uStatus == ERROR_SUCCESS) 410 return RTEXITCODE_SUCCESS; 411 if (uStatus == ERROR_SUCCESS_REBOOT_REQUIRED) 412 return RTEXITCODE_SUCCESS; /* we currently don't indicate this */ 413 414 /* 415 * Installation failed. Figure out what to say. 416 */ 417 switch (uStatus) 418 { 419 case ERROR_INSTALL_USEREXIT: 420 /* Don't say anything? */ 421 break; 422 423 case ERROR_INSTALL_PACKAGE_VERSION: 424 ShowError("This installation package cannot be installed by the Windows Installer service.\n" 425 "You must install a Windows service pack that contains a newer version of the Windows Installer service."); 426 break; 427 428 case ERROR_INSTALL_PLATFORM_UNSUPPORTED: 429 ShowError("This installation package is not supported on this platform."); 430 break; 431 432 default: 433 { 434 /* 435 * Try get windows to format the message. 436 */ 437 DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER 438 | FORMAT_MESSAGE_IGNORE_INSERTS 439 | FORMAT_MESSAGE_FROM_SYSTEM; 440 HMODULE hModule = NULL; 441 if (uStatus >= NERR_BASE && uStatus <= MAX_NERR) 442 { 443 hModule = LoadLibraryEx(TEXT("netmsg.dll"), 444 NULL, 445 LOAD_LIBRARY_AS_DATAFILE); 446 if (hModule != NULL) 447 dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE; 448 } 449 450 /** @todo this is totally WRONG wrt to string code pages. We expect UTF-8 451 * while the ANSI code page might be one of the special Chinese ones, 452 * IPRT is going to be so angry with us (and so will the users). */ 453 DWORD dwBufferLength; 454 LPSTR szMessageBuffer; 455 if (dwBufferLength = FormatMessageA(dwFormatFlags, 456 hModule, /* If NULL, load system stuff. */ 457 uStatus, 458 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 459 (LPSTR)&szMessageBuffer, 460 0, 461 NULL)) 462 { 463 ShowError("Installation failed! Error: %s", szMessageBuffer); 464 LocalFree(szMessageBuffer); 465 } 466 else /* If text lookup failed, show at least the error number. */ 467 ShowError("Installation failed! Error: %u", uStatus); 468 469 if (hModule) 470 FreeLibrary(hModule); 471 break; 472 } 473 } 474 475 return RTEXITCODE_FAILURE; 476 } 477 478 479 /** 480 * Processes a package. 481 * 482 * @returns Fully complained exit code. 483 * @param iPackage The package number. 484 * @param pszPkgDir The package directory (aka extraction dir). 485 * @param pszMsiArgs Any additional installer (MSI) argument 486 * @param fLogging Whether to enable installer logging. 487 */ 488 static RTEXITCODE ProcessPackage(unsigned iPackage, const char *pszPkgDir, const char *pszMsiArgs, bool fLogging) 489 { 490 /* 491 * Get the package header and check if it's needed. 492 */ 493 PVBOXSTUBPKG pPackage = FindPackageHeader(iPackage); 494 if (pPackage == NULL) 495 return RTEXITCODE_FAILURE; 496 497 if (!PackageIsNeeded(pPackage)) 498 return RTEXITCODE_SUCCESS; 499 500 /* 501 * Deal with the file based on it's extension. 502 */ 503 char *pszPkgFile = RTPathJoinA(pszPkgDir, pPackage->szFileName); 504 if (!pszPkgFile) 505 return ShowError("Out of memory on line #%u!", __LINE__); 506 RTPathChangeToDosSlashes(pszPkgFile, true /* Force conversion. */); /* paranoia */ 507 508 RTEXITCODE rcExit; 509 const char *pszExt = RTPathExt(pszPkgFile); 510 if (RTStrICmp(pszExt, ".msi") == 0) 511 rcExit = ProcessMsiPackage(iPackage, pszPkgFile, pszMsiArgs, fLogging); 512 else 513 rcExit = ShowError("Internal error: Do not know how to handle file '%s'.", pPackage->szFileName); 514 515 RTStrFree(pszPkgFile); 516 return rcExit; 517 } 518 519 520 #ifdef VBOX_WITH_CODE_SIGNING 521 /** 522 * Install the public certificate into TrustedPublishers so the installer won't 523 * prompt the user during silent installs. 524 * 525 * @returns Fully complained exit code. 526 */ 527 static RTEXITCODE InstallCertificate(void) 528 { 529 if (addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, 530 "TrustedPublisher", 531 g_ab_VBoxStubPublicCert, 532 sizeof(g_ab_VBoxStubPublicCert))) 533 return RTEXITCODE_SUCCESS; 534 return ShowError("Failed to construct install certificate."); 535 } 536 #endif /* VBOX_WITH_CODE_SIGNING */ 537 538 539 /** 540 * Copies the "<exepath>.custom" directory to the extraction path if it exists. 541 * 542 * This is used by the MSI packages from the resource section. 543 * 544 * @returns Fully complained exit code. 545 * @param pszDstDir The destination directory. 546 */ 547 static RTEXITCODE CopyCustomDir(const char *pszDstDir) 548 { 549 char szSrcDir[RTPATH_MAX]; 550 int rc = RTPathExecDir(szSrcDir, sizeof(szSrcDir) - 1); 551 if (RT_SUCCESS(rc)) 552 rc = RTPathAppend(szSrcDir, sizeof(szSrcDir) - 1, ".custom"); 553 if (RT_FAILURE(rc)) 554 return ShowError("Failed to construct '.custom' dir path: %Rrc", rc); 555 556 if (RTDirExists(szSrcDir)) 557 { 558 /* 559 * Use SHFileOperation w/ FO_COPY to do the job. This API requires an 560 * extra zero at the end of both source and destination paths. Thus 561 * the -1 above and below. 562 */ 563 size_t cwc; 564 RTUTF16 wszSrcDir[RTPATH_MAX + 2]; 565 PRTUTF16 pwszSrcDir = wszSrcDir; 566 rc = RTStrToUtf16Ex(szSrcDir, RTSTR_MAX, &pwszSrcDir, RTPATH_MAX, &cwc); 567 if (RT_FAILURE(rc)) 568 return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", szSrcDir, rc); 569 wszSrcDir[cwc] = '\0'; 570 571 RTUTF16 wszDstDir[RTPATH_MAX + 2]; 572 PRTUTF16 pwszDstDir = wszSrcDir; 573 rc = RTStrToUtf16Ex(pszDstDir, RTSTR_MAX, &pwszDstDir, RTPATH_MAX, &cwc); 574 if (RT_FAILURE(rc)) 575 return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", pszDstDir, rc); 576 wszDstDir[cwc] = '\0'; 577 578 SHFILEOPSTRUCTW FileOp; 579 RT_ZERO(FileOp); /* paranoia */ 580 FileOp.hwnd = NULL; 581 FileOp.wFunc = FO_COPY; 582 FileOp.pFrom = wszSrcDir; 583 FileOp.pTo = wszDstDir; 584 FileOp.fFlags = FOF_SILENT 585 | FOF_NOCONFIRMATION 586 | FOF_NOCONFIRMMKDIR 587 | FOF_NOERRORUI; 588 FileOp.fAnyOperationsAborted = FALSE; 589 FileOp.hNameMappings = NULL; 590 FileOp.lpszProgressTitle = NULL; 591 592 rc = SHFileOperationW(&FileOp); 593 if (rc != 0) /* Not a Win32 status code! */ 594 return ShowError("Copying the '.custom' dir failed: %#x", rc); 595 } 596 597 return RTEXITCODE_SUCCESS; 598 } 599 600 601 static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly) 602 { 603 int rc; 604 605 /* 606 * Make sure the directory exists. 607 */ 608 if (!RTDirExists(pszDstDir)) 609 { 610 rc = RTDirCreate(pszDstDir, 0700, 0); 611 if (RT_FAILURE(rc)) 612 return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc); 613 } 614 615 /* 616 * Extract files. 617 */ 618 for (unsigned k = 0; k < cPackages; k++) 619 { 620 PVBOXSTUBPKG pPackage = FindPackageHeader(k); 621 if (!pPackage) 622 return RTEXITCODE_FAILURE; /* Done complaining already. */ 623 624 if (fExtractOnly || PackageIsNeeded(pPackage)) 625 { 626 char *pszDstFile = RTPathJoinA(pszDstDir, pPackage->szFileName); 627 if (!pszDstFile) 628 return ShowError("Out of memory on line %u!", __LINE__); 629 630 rc = Extract(pPackage, pszDstFile); 631 RTStrFree(pszDstFile); 632 if (RT_FAILURE(rc)) 633 return ShowError("Error extracting package #%u: %Rrc", k, rc); 634 } 635 } 636 637 return RTEXITCODE_SUCCESS; 330 638 } 331 639 … … 363 671 bool fExtractOnly = false; 364 672 bool fEnableLogging = false; 365 #ifdef VBOX_ SIGNING_MODE673 #ifdef VBOX_WITH_CODE_SIGNING 366 674 bool fEnableSilentCert = true; 367 675 #endif … … 378 686 { "-silent", 's', RTGETOPT_REQ_NOTHING }, 379 687 { "/silent", 's', RTGETOPT_REQ_NOTHING }, 380 #ifdef VBOX_ SIGNING_MODE688 #ifdef VBOX_WITH_CODE_SIGNING 381 689 { "--no-silent-cert", 'c', RTGETOPT_REQ_NOTHING }, 382 690 { "-no-silent-cert", 'c', RTGETOPT_REQ_NOTHING }, … … 418 726 break; 419 727 420 #ifdef VBOX_ SIGNING_MODE728 #ifdef VBOX_WITH_CODE_SIGNING 421 729 case 'c': 422 730 fEnableSilentCert = false; … … 431 739 vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz); 432 740 if (RT_FAILURE(vrc)) 433 { 434 ShowError("Extraction path is too long."); 435 return RTEXITCODE_FAILURE; 436 } 741 return ShowError("Extraction path is too long."); 437 742 break; 438 743 … … 443 748 vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz); 444 749 if (RT_FAILURE(vrc)) 445 { 446 ShowError("MSI parameters are too long."); 447 return RTEXITCODE_FAILURE; 448 } 750 return ShowError("MSI parameters are too long."); 449 751 break; 450 752 … … 488 790 } 489 791 490 /** @todo The rest of this function should be done in smaller functions, 491 * we've lost the overview here! Too much state going around! */ 492 493 HRESULT hr = S_OK; 494 495 do /* break loop */ 496 { 497 /* 498 * Determine and create our temp path (only if not already set). 499 */ 500 if (szExtractPath[0] == '\0') 792 /* 793 * Determine the extration path if not given by the user, and gather some 794 * other bits we'll be needing later. 795 */ 796 if (szExtractPath[0] == '\0') 797 { 798 vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath)); 799 if (RT_SUCCESS(vrc)) 800 vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox"); 801 if (RT_FAILURE(vrc)) 802 return ShowError("Failed to determin extraction path (%Rrc)", vrc); 803 804 } 805 RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */ 806 807 /* Read our manifest. */ 808 PVBOXSTUBPKGHEADER pHeader; 809 vrc = FindData("MANIFEST", (PVOID *)&pHeader, NULL); 810 if (RT_FAILURE(vrc)) 811 return ShowError("Internal package error: Manifest not found (%Rrc)", vrc); 812 /** @todo If we could, we should validate the header. Only the magic isn't 813 * commonly defined, nor the version number... */ 814 815 /* 816 * Up to this point, we haven't done anything that requires any cleanup. 817 * From here on, we do everything in function so we can counter clean up. 818 */ 819 RTEXITCODE rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly); 820 if (rcExit == RTEXITCODE_SUCCESS) 821 { 822 if (fExtractOnly) 501 823 { 502 vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath)); 503 AssertMsgRCBreak(vrc, ("Could not retrieve temp directory!\n")); 504 505 vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox"); 506 AssertMsgRCBreak(vrc, ("Could not construct temp directory!\n")); 507 508 /* Convert slahes; this is necessary for MSI routines later! */ 509 RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); 824 if (!g_fSilent) 825 ShowInfo("Files were extracted to: %s", szExtractPath); 510 826 } 511 if (!RTDirExists(szExtractPath))827 else 512 828 { 513 vrc = RTDirCreate(szExtractPath, 0700, 0); 514 AssertMsgRCBreak(vrc, ("Could not create temp directory!\n")); 515 } 516 517 /* Get our executable path */ 518 char szPathExe[_MAX_PATH]; 519 vrc = RTPathExecDir(szPathExe, sizeof(szPathExe)); 520 /** @todo error checking */ 521 522 /* Read our manifest. */ 523 PVBOXSTUBPKGHEADER pHeader = NULL; 524 DWORD cbHeader = 0; 525 vrc = ReadData(NULL, "MANIFEST", (LPVOID*)&pHeader, &cbHeader); 526 AssertMsgRCBreak(vrc, ("Manifest not found!\n")); 527 528 /* Extract files. */ 529 for (BYTE k = 0; k < pHeader->byCntPkgs; k++) 530 { 531 PVBOXSTUBPKG pPackage = NULL; 532 DWORD cbPackage = 0; 533 char szHeaderName[RTPATH_MAX + 1] = {0}; 534 535 hr = ::StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k); 536 vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage); 537 AssertMsgRCBreak(vrc, ("Header not found!\n")); /** @todo include header name, how? */ 538 539 if (PackageIsNeeded(pPackage) || fExtractOnly) 829 rcExit = CopyCustomDir(szExtractPath); 830 #ifdef VBOX_WITH_CODE_SIGNING 831 if (rcExit == RTEXITCODE_SUCCESS && fEnableSilentCert && g_fSilent) 832 InstallCertificate(); 833 #endif 834 unsigned iPackage = 0; 835 while (iPackage < pHeader->byCntPkgs && rcExit == RTEXITCODE_SUCCESS) 540 836 { 541 char *pszTempFile = NULL; 542 vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile); 543 AssertMsgRCBreak(vrc, ("Could not create name for temporary extracted file!\n")); 544 vrc = Extract(pPackage, pszTempFile); 545 AssertMsgRCBreak(vrc, ("Could not extract file!\n")); 546 RTStrFree(pszTempFile); 837 rcExit = ProcessPackage(iPackage, szExtractPath, szMSIArgs, fEnableLogging); 838 iPackage++; 547 839 } 548 840 } 549 550 if (FALSE == fExtractOnly && !RT_FAILURE(vrc)) 551 { 552 /* 553 * Copy ".custom" directory into temp directory so that the extracted .MSI 554 * file(s) can use it. 555 */ 556 char *pszPathCustomDir = RTPathJoinA(szPathExe, ".custom"); 557 pszPathCustomDir = RTPathChangeToDosSlashes(pszPathCustomDir, true /* Force conversion. */); 558 if (pszPathCustomDir && RTDirExists(pszPathCustomDir)) 559 { 560 vrc = CopyDir(szExtractPath, pszPathCustomDir); 561 if (RT_FAILURE(vrc)) /* Don't fail if it's missing! */ 562 vrc = VINF_SUCCESS; 563 564 RTStrFree(pszPathCustomDir); 565 } 566 567 #ifdef VBOX_SIGNING_MODE 568 /* 569 * If --silent command line option is specified, do force public 570 * certificate install in background (i.e. completely prevent 571 * user interaction) 572 */ 573 if (TRUE == g_fSilent && TRUE == fEnableSilentCert) 574 { 575 if (!addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, 576 "TrustedPublisher", 577 g_ab_VBoxStubPublicCert, 578 sizeof(g_ab_VBoxStubPublicCert))) 579 { 580 /* Interrupt installation */ 581 vrc = VERR_NO_CHANGE; 582 break; 583 } 584 } 585 #endif 586 /* Do actions on files. */ 587 for (BYTE k = 0; k < pHeader->byCntPkgs; k++) 588 { 589 PVBOXSTUBPKG pPackage = NULL; 590 DWORD cbPackage = 0; 591 char szHeaderName[RTPATH_MAX] = {0}; 592 593 hr = StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k); 594 vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage); 595 AssertMsgRCBreak(vrc, ("Package not found!\n")); 596 597 if (PackageIsNeeded(pPackage)) 598 { 599 char *pszTempFile = NULL; 600 601 vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile); 602 AssertMsgRCBreak(vrc, ("Could not create name for temporary action file!\n")); 603 604 /* Handle MSI files. */ 605 if (RTStrICmp(RTPathExt(pszTempFile), ".msi") == 0) 606 { 607 /* Set UI level. */ 608 INSTALLUILEVEL UILevel = MsiSetInternalUI( g_fSilent 609 ? INSTALLUILEVEL_NONE 610 : INSTALLUILEVEL_FULL, 611 NULL); 612 AssertMsgBreak(UILevel != INSTALLUILEVEL_NOCHANGE, ("Could not set installer UI level!\n")); 613 614 /* Enable logging? */ 615 if (fEnableLogging) 616 { 617 char *pszLog = RTPathJoinA(szExtractPath, "VBoxInstallLog.txt"); 618 /* Convert slahes; this is necessary for MSI routines! */ 619 pszLog = RTPathChangeToDosSlashes(pszLog, true /* Force conversion. */); 620 AssertMsgBreak(pszLog, ("Could not construct path for log file!\n")); 621 UINT uLogLevel = MsiEnableLog(INSTALLLOGMODE_VERBOSE, 622 pszLog, INSTALLLOGATTRIBUTES_FLUSHEACHLINE); 623 RTStrFree(pszLog); 624 AssertMsgBreak(uLogLevel == ERROR_SUCCESS, ("Could not set installer logging level!\n")); 625 } 626 627 /* Initialize the common controls (extended version). This is necessary to 628 * run the actual .MSI installers with the new fancy visual control 629 * styles (XP+). Also, an integrated manifest is required. */ 630 INITCOMMONCONTROLSEX ccEx; 631 ccEx.dwSize = sizeof(INITCOMMONCONTROLSEX); 632 ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS | 633 ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | 634 ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES; 635 InitCommonControlsEx(&ccEx); /* Ignore failure. */ 636 637 UINT uStatus = ::MsiInstallProductA(pszTempFile, szMSIArgs); 638 if ( (uStatus != ERROR_SUCCESS) 639 && (uStatus != ERROR_SUCCESS_REBOOT_REQUIRED) 640 && (uStatus != ERROR_INSTALL_USEREXIT)) 641 { 642 switch (uStatus) 643 { 644 case ERROR_INSTALL_PACKAGE_VERSION: 645 ShowError("This installation package cannot be installed by the Windows Installer service.\n" 646 "You must install a Windows service pack that contains a newer version of the Windows Installer service."); 647 break; 648 649 case ERROR_INSTALL_PLATFORM_UNSUPPORTED: 650 ShowError("This installation package is not supported on this platform."); 651 break; 652 653 default: 654 { 655 DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER 656 | FORMAT_MESSAGE_IGNORE_INSERTS 657 | FORMAT_MESSAGE_FROM_SYSTEM; 658 HMODULE hModule = NULL; 659 if (uStatus >= NERR_BASE && uStatus <= MAX_NERR) 660 { 661 hModule = LoadLibraryEx(TEXT("netmsg.dll"), 662 NULL, 663 LOAD_LIBRARY_AS_DATAFILE); 664 if (hModule != NULL) 665 dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE; 666 } 667 668 DWORD dwBufferLength; 669 LPSTR szMessageBuffer; 670 if (dwBufferLength = FormatMessageA(dwFormatFlags, 671 hModule, /* If NULL, load system stuff. */ 672 uStatus, 673 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 674 (LPSTR)&szMessageBuffer, 675 0, 676 NULL)) 677 { 678 ShowError("Installation failed! Error: %s", szMessageBuffer); 679 LocalFree(szMessageBuffer); 680 } 681 else /* If text lookup failed, show at least the error number. */ 682 ShowError("Installation failed! Error: %u", uStatus); 683 if (hModule) 684 FreeLibrary(hModule); 685 /** @todo program exit code needs to be set */ 686 break; 687 } 688 } 689 690 vrc = VERR_NO_CHANGE; /* No change done to the system. */ 691 } 692 /** @todo program exit code needs to be for ERROR_INSTALL_USEREXIT. */ 693 } 694 RTStrFree(pszTempFile); 695 } /* Package needed? */ 696 } /* For all packages */ 697 } 841 } 842 843 844 845 do /* break loop */ 846 { 698 847 699 848 /* Clean up (only on success - prevent deleting the log). */ … … 712 861 } while (0); 713 862 714 if (RT_SUCCESS(vrc))715 {716 if ( fExtractOnly717 && !g_fSilent)718 {719 ShowInfo("Files were extracted to: %s", szExtractPath);720 }721 722 /** @todo Add more post installation stuff here if required. */723 }724 725 863 /* Release instance mutex. */ 726 864 if (hMutexAppRunning != NULL) … … 730 868 } 731 869 732 /*733 * Figure the exit code (not very difficult at the moment).734 */735 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;736 if (RT_FAILURE(vrc))737 rcExit = RTEXITCODE_FAILURE;738 870 return rcExit; 739 871 } -
trunk/src/VBox/Installer/win/Stub/resource.h
r44529 r45320 15 15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 16 16 */ 17 18 17 19 #define IDI_VIRTUALBOX 101 18 20 19 #define RT_MANIFEST 24 21 #ifndef RT_MANIFEST 22 # define RT_MANIFEST 24 23 #endif 20 24 #define APP_MANIFEST 1 21 25
Note:
See TracChangeset
for help on using the changeset viewer.