VirtualBox

source: vbox/trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp@ 45131

Last change on this file since 45131 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.2 KB
Line 
1/* $Id: VBoxStub.cpp 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 * VBoxStub - VirtualBox's Windows installer stub.
4 */
5
6/*
7 * Copyright (C) 2010-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <windows.h>
22#include <commctrl.h>
23#include <lmerr.h>
24#include <msiquery.h>
25#include <objbase.h>
26#include <shlobj.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#include <strsafe.h>
31
32#include <VBox/version.h>
33
34#include <iprt/assert.h>
35#include <iprt/dir.h>
36#include <iprt/file.h>
37#include <iprt/initterm.h>
38#include <iprt/getopt.h>
39#include <iprt/mem.h>
40#include <iprt/message.h>
41#include <iprt/path.h>
42#include <iprt/param.h>
43#include <iprt/stream.h>
44#include <iprt/string.h>
45#include <iprt/thread.h>
46
47#include "VBoxStub.h"
48#include "../StubBld/VBoxStubBld.h"
49#include "resource.h"
50
51#ifdef VBOX_SIGNING_MODE
52#include "VBoxStubCertUtil.h"
53#include "VBoxStubPublicCert.h"
54#endif
55
56#ifndef _UNICODE
57#define _UNICODE
58#endif
59
60
61/*******************************************************************************
62* Global Variables *
63*******************************************************************************/
64static bool g_fSilent = false;
65
66
67/**
68 * Shows an error message box with a printf() style formatted string.
69 *
70 * @param pszFmt Printf-style format string to show in the message box body.
71 *
72 */
73static void ShowError(const char *pszFmt, ...)
74{
75 char *pszMsg;
76 va_list va;
77
78 va_start(va, pszFmt);
79 if (RTStrAPrintfV(&pszMsg, pszFmt, va))
80 {
81 if (g_fSilent)
82 RTMsgError("%s", pszMsg);
83 else
84 MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR);
85 RTStrFree(pszMsg);
86 }
87 else /* Should never happen! */
88 AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
89 va_end(va);
90}
91
92
93/**
94 * Shows a message box with a printf() style formatted string.
95 *
96 * @param uType Type of the message box (see MSDN).
97 * @param pszFmt Printf-style format string to show in the message box body.
98 *
99 */
100static void ShowInfo(const char *pszFmt, ...)
101{
102 char *pszMsg;
103 va_list va;
104 va_start(va, pszFmt);
105 int rc = RTStrAPrintfV(&pszMsg, pszFmt, va);
106 va_end(va);
107 if (rc >= 0)
108 {
109 if (g_fSilent)
110 RTPrintf("%s\n", pszMsg);
111 else
112 MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION);
113 }
114 else /* Should never happen! */
115 AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
116 RTStrFree(pszMsg);
117}
118
119
120/**
121 * Reads data from a built-in resource.
122 *
123 * @returns iprt status code.
124 *
125 * @param hInst Instance to read the data from.
126 * @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 */
131static int ReadData(HINSTANCE hInst,
132 const char *pszDataName,
133 PVOID *ppvResource,
134 DWORD *pdwSize)
135{
136 do
137 {
138 AssertMsgBreak(pszDataName, ("Resource name is empty!\n"));
139
140 /* Find our resource. */
141 HRSRC hRsrc = FindResourceEx(hInst, RT_RCDATA, pszDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
142 AssertMsgBreak(hRsrc, ("Could not find resource!\n"));
143
144 /* Get resource size. */
145 *pdwSize = SizeofResource(hInst, hRsrc);
146 AssertMsgBreak(*pdwSize > 0, ("Size of resource is invalid!\n"));
147
148 /* Get pointer to resource. */
149 HGLOBAL hData = LoadResource(hInst, hRsrc);
150 AssertMsgBreak(hData, ("Could not load resource!\n"));
151
152 /* Lock resource. */
153 *ppvResource = LockResource(hData);
154 AssertMsgBreak(*ppvResource, ("Could not lock resource!\n"));
155 return VINF_SUCCESS;
156
157 } while (0);
158
159 return VERR_IO_GEN_FAILURE;
160}
161
162
163/**
164 * Constructs a full temporary file path from the given parameters.
165 *
166 * @returns iprt status code.
167 *
168 * @param pszTempPath The pure path to use for construction.
169 * @param pszTargetFileName The pure file name to use for construction.
170 * @param ppszTempFile Pointer to the constructed string. Must be freed
171 * using RTStrFree().
172 */
173static int GetTempFileAlloc(const char *pszTempPath,
174 const char *pszTargetFileName,
175 char **ppszTempFile)
176{
177 if (RTStrAPrintf(ppszTempFile, "%s\\%s", pszTempPath, pszTargetFileName) >= 0)
178 return VINF_SUCCESS;
179 return VERR_NO_STR_MEMORY;
180}
181
182
183/**
184 * Extracts a built-in resource to disk.
185 *
186 * @returns iprt status code.
187 *
188 * @param pszResourceName The resource name to extract.
189 * @param pszTempFile The full file path + name to extract the resource to.
190 *
191 */
192static int ExtractFile(const char *pszResourceName,
193 const char *pszTempFile)
194{
195 int rc;
196 RTFILE fh;
197 BOOL bCreatedFile = FALSE;
198
199 do
200 {
201 AssertMsgBreak(pszResourceName, ("Resource pointer invalid!\n"));
202 AssertMsgBreak(pszTempFile, ("Temp file pointer invalid!"));
203
204 /* Read the data of the built-in resource. */
205 PVOID pvData = NULL;
206 DWORD dwDataSize = 0;
207 rc = ReadData(NULL, pszResourceName, &pvData, &dwDataSize);
208 AssertMsgRCBreak(rc, ("Could not read resource data!\n"));
209
210 /* Create new (and replace an old) file. */
211 rc = RTFileOpen(&fh, pszTempFile,
212 RTFILE_O_CREATE_REPLACE
213 | RTFILE_O_WRITE
214 | RTFILE_O_DENY_NOT_DELETE
215 | RTFILE_O_DENY_WRITE);
216 AssertMsgRCBreak(rc, ("Could not open file for writing!\n"));
217 bCreatedFile = TRUE;
218
219 /* Write contents to new file. */
220 size_t cbWritten = 0;
221 rc = RTFileWrite(fh, pvData, dwDataSize, &cbWritten);
222 AssertMsgRCBreak(rc, ("Could not open file for writing!\n"));
223 AssertMsgBreak(dwDataSize == cbWritten, ("File was not extracted completely! Disk full?\n"));
224
225 } while (0);
226
227 if (RTFileIsValid(fh))
228 RTFileClose(fh);
229
230 if (RT_FAILURE(rc))
231 {
232 if (bCreatedFile)
233 RTFileDelete(pszTempFile);
234 }
235 return rc;
236}
237
238
239/**
240 * Extracts a built-in resource to disk.
241 *
242 * @returns iprt status code.
243 *
244 * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource.
245 * @param pszTempFile The full file path + name to extract the resource to.
246 *
247 */
248static int Extract(const PVBOXSTUBPKG pPackage,
249 const char *pszTempFile)
250{
251 return ExtractFile(pPackage->szResourceName,
252 pszTempFile);
253}
254
255
256/**
257 * Detects whether we're running on a 32- or 64-bit platform and returns the result.
258 *
259 * @returns TRUE if we're running on a 64-bit OS, FALSE if not.
260 *
261 */
262static BOOL IsWow64(void)
263{
264 BOOL bIsWow64 = TRUE;
265 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
266 if (NULL != fnIsWow64Process)
267 {
268 if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
269 {
270 /* Error in retrieving process type - assume that we're running on 32bit. */
271 return FALSE;
272 }
273 }
274 return bIsWow64;
275}
276
277
278/**
279 * Decides whether we need a specified package to handle or not.
280 *
281 * @returns TRUE if we need to handle the specified package, FALSE if not.
282 *
283 * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource.
284 *
285 */
286static BOOL PackageIsNeeded(PVBOXSTUBPKG pPackage)
287{
288 BOOL bIsWow64 = IsWow64();
289 if ((bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_AMD64)) /* 64bit Windows. */
290 {
291 return TRUE;
292 }
293 else if ((!bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_X86)) /* 32bit. */
294 {
295 return TRUE;
296 }
297 else if (pPackage->byArch == VBOXSTUBPKGARCH_ALL)
298 {
299 return TRUE;
300 }
301 return FALSE;
302}
303
304
305/**
306 * Recursively copies a directory to another location.
307 *
308 * @returns iprt status code.
309 *
310 * @param pszDestDir Location to copy the source directory to.
311 * @param pszSourceDir The source directory to copy.
312 *
313 */
314int CopyDir(const char *pszDestDir, const char *pszSourceDir)
315{
316 char szDest[RTPATH_MAX + 1];
317 char szSource[RTPATH_MAX + 1];
318
319 AssertStmt(pszDestDir, "Destination directory invalid!");
320 AssertStmt(pszSourceDir, "Source directory invalid!");
321
322 SHFILEOPSTRUCT s = {0};
323 if ( RTStrPrintf(szDest, _MAX_PATH, "%s%c", pszDestDir, '\0') > 0
324 && RTStrPrintf(szSource, _MAX_PATH, "%s%c", pszSourceDir, '\0') > 0)
325 {
326 s.hwnd = NULL;
327 s.wFunc = FO_COPY;
328 s.pTo = szDest;
329 s.pFrom = szSource;
330 s.fFlags = FOF_SILENT
331 | FOF_NOCONFIRMATION
332 | FOF_NOCONFIRMMKDIR
333 | FOF_NOERRORUI;
334 }
335 return RTErrConvertFromWin32(SHFileOperation(&s));
336}
337
338
339int WINAPI WinMain(HINSTANCE hInstance,
340 HINSTANCE hPrevInstance,
341 char *lpCmdLine,
342 int nCmdShow)
343{
344 char **argv = __argv;
345 int argc = __argc;
346
347 /* Check if we're already running and jump out if so. */
348 /* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
349 HANDLE hMutexAppRunning = CreateMutex(NULL, FALSE, "VBoxStubInstaller");
350 if ( (hMutexAppRunning != NULL)
351 && (GetLastError() == ERROR_ALREADY_EXISTS))
352 {
353 /* Close the mutex for this application instance. */
354 CloseHandle(hMutexAppRunning);
355 hMutexAppRunning = NULL;
356 return 1;
357 }
358
359 /* Init IPRT. */
360 int vrc = RTR3InitExe(argc, &argv, 0);
361 if (RT_FAILURE(vrc))
362 return vrc;
363
364 /*
365 * Parse arguments.
366 */
367
368 /* Parameter variables. */
369 bool fExtractOnly = false;
370 bool fEnableLogging = false;
371#ifdef VBOX_SIGNING_MODE
372 bool fEnableSilentCert = true;
373#endif
374 char szExtractPath[RTPATH_MAX] = {0};
375 char szMSIArgs[4096] = {0};
376
377 /* Parameter definitions. */
378 static const RTGETOPTDEF s_aOptions[] =
379 {
380 { "--extract", 'x', RTGETOPT_REQ_NOTHING },
381 { "-extract", 'x', RTGETOPT_REQ_NOTHING },
382 { "/extract", 'x', RTGETOPT_REQ_NOTHING },
383 { "--silent", 's', RTGETOPT_REQ_NOTHING },
384 { "-silent", 's', RTGETOPT_REQ_NOTHING },
385 { "/silent", 's', RTGETOPT_REQ_NOTHING },
386#ifdef VBOX_SIGNING_MODE
387 { "--no-silent-cert", 'c', RTGETOPT_REQ_NOTHING },
388 { "-no-silent-cert", 'c', RTGETOPT_REQ_NOTHING },
389 { "/no-silent-cert", 'c', RTGETOPT_REQ_NOTHING },
390#endif
391 { "--logging", 'l', RTGETOPT_REQ_NOTHING },
392 { "-logging", 'l', RTGETOPT_REQ_NOTHING },
393 { "/logging", 'l', RTGETOPT_REQ_NOTHING },
394 { "--path", 'p', RTGETOPT_REQ_STRING },
395 { "-path", 'p', RTGETOPT_REQ_STRING },
396 { "/path", 'p', RTGETOPT_REQ_STRING },
397 { "--msiparams", 'm', RTGETOPT_REQ_STRING },
398 { "-msiparams", 'm', RTGETOPT_REQ_STRING },
399 { "--version", 'V', RTGETOPT_REQ_NOTHING },
400 { "-version", 'V', RTGETOPT_REQ_NOTHING },
401 { "/version", 'V', RTGETOPT_REQ_NOTHING },
402 { "-v", 'V', RTGETOPT_REQ_NOTHING },
403 { "--help", 'h', RTGETOPT_REQ_NOTHING },
404 { "-help", 'h', RTGETOPT_REQ_NOTHING },
405 { "/help", 'h', RTGETOPT_REQ_NOTHING },
406 { "/?", 'h', RTGETOPT_REQ_NOTHING },
407 };
408
409 /* Parse the parameters. */
410 int ch;
411 RTGETOPTUNION ValueUnion;
412 RTGETOPTSTATE GetState;
413 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
414 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
415 {
416 switch (ch)
417 {
418 case 'x':
419 fExtractOnly = true;
420 break;
421
422 case 's':
423 g_fSilent = true;
424 break;
425
426#ifdef VBOX_SIGNING_MODE
427 case 'c':
428 fEnableSilentCert = false;
429 break;
430#endif
431
432 case 'l':
433 fEnableLogging = true;
434 break;
435
436 case 'p':
437 vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz);
438 if (RT_FAILURE(vrc))
439 {
440 ShowError("Extraction path is too long.");
441 return RTEXITCODE_FAILURE;
442 }
443 break;
444
445 case 'm':
446 if (szMSIArgs[0])
447 vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), " ");
448 if (RT_SUCCESS(vrc))
449 vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz);
450 if (RT_FAILURE(vrc))
451 {
452 ShowError("MSI parameters are too long.");
453 return RTEXITCODE_FAILURE;
454 }
455 break;
456
457 case 'V':
458 ShowInfo("Version: %d.%d.%d.%d",
459 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
460 return VINF_SUCCESS;
461
462 case 'h':
463 ShowInfo("-- %s v%d.%d.%d.%d --\n"
464 "Command Line Parameters:\n\n"
465 "--extract - Extract file contents to temporary directory\n"
466 "--silent - Enables silent mode installation\n"
467 "--no-silent-cert - Do not install VirtualBox Certificate automatically when --silent option is specified\n"
468 "--path - Sets the path of the extraction directory\n"
469 "--msiparams <parameters> - Specifies extra parameters for the MSI installers\n"
470 "--logging - Enables installer logging\n"
471 "--help - Print this help and exit\n"
472 "--version - Print version number and exit\n\n"
473 "Examples:\n"
474 "%s --msiparams INSTALLDIR=C:\\VBox\n"
475 "%s --extract -path C:\\VBox",
476 VBOX_STUB_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
477 argv[0], argv[0]);
478 return VINF_SUCCESS;
479
480 default:
481 if (g_fSilent)
482 return RTGetOptPrintError(ch, &ValueUnion);
483 if (ch == VINF_GETOPT_NOT_OPTION || ch == VERR_GETOPT_UNKNOWN_OPTION)
484 ShowError("Unknown option \"%s\"!\n"
485 "Please refer to the command line help by specifying \"/?\"\n"
486 "to get more information.", ValueUnion.psz);
487 else
488 ShowError("Parameter parsing error: %Rrc\n"
489 "Please refer to the command line help by specifying \"/?\"\n"
490 "to get more information.", ch);
491 return RTEXITCODE_SYNTAX;
492
493 }
494 }
495
496 HRESULT hr = S_OK;
497
498 do /* break loop */
499 {
500 /* Get/create our temp path (only if not already set). */
501 if (szExtractPath[0] == '\0')
502 {
503 vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
504 AssertMsgRCBreak(vrc, ("Could not retrieve temp directory!\n"));
505
506 vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox");
507 AssertMsgRCBreak(vrc, ("Could not construct temp directory!\n"));
508
509 /* Convert slahes; this is necessary for MSI routines later! */
510 RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */);
511 }
512 if (!RTDirExists(szExtractPath))
513 {
514 vrc = RTDirCreate(szExtractPath, 0700, 0);
515 AssertMsgRCBreak(vrc, ("Could not create temp directory!\n"));
516 }
517
518 /* Get our executable path */
519 char szPathExe[_MAX_PATH];
520 vrc = RTPathExecDir(szPathExe, sizeof(szPathExe));
521 /** @todo error checking */
522
523 /* Read our manifest. */
524 PVBOXSTUBPKGHEADER pHeader = NULL;
525 DWORD cbHeader = 0;
526 vrc = ReadData(NULL, "MANIFEST", (LPVOID*)&pHeader, &cbHeader);
527 AssertMsgRCBreak(vrc, ("Manifest not found!\n"));
528
529 /* Extract files. */
530 for (BYTE k = 0; k < pHeader->byCntPkgs; k++)
531 {
532 PVBOXSTUBPKG pPackage = NULL;
533 DWORD cbPackage = 0;
534 char szHeaderName[RTPATH_MAX + 1] = {0};
535
536 hr = ::StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k);
537 vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage);
538 AssertMsgRCBreak(vrc, ("Header not found!\n")); /** @todo include header name, how? */
539
540 if (PackageIsNeeded(pPackage) || fExtractOnly)
541 {
542 char *pszTempFile = NULL;
543 vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile);
544 AssertMsgRCBreak(vrc, ("Could not create name for temporary extracted file!\n"));
545 vrc = Extract(pPackage, pszTempFile);
546 AssertMsgRCBreak(vrc, ("Could not extract file!\n"));
547 RTStrFree(pszTempFile);
548 }
549 }
550
551 if (FALSE == fExtractOnly && !RT_FAILURE(vrc))
552 {
553 /*
554 * Copy ".custom" directory into temp directory so that the extracted .MSI
555 * file(s) can use it.
556 */
557 char *pszPathCustomDir = RTPathJoinA(szPathExe, ".custom");
558 pszPathCustomDir = RTPathChangeToDosSlashes(pszPathCustomDir, true /* Force conversion. */);
559 if (pszPathCustomDir && RTDirExists(pszPathCustomDir))
560 {
561 vrc = CopyDir(szExtractPath, pszPathCustomDir);
562 if (RT_FAILURE(vrc)) /* Don't fail if it's missing! */
563 vrc = VINF_SUCCESS;
564
565 RTStrFree(pszPathCustomDir);
566 }
567
568#ifdef VBOX_SIGNING_MODE
569 /*
570 * If --silent command line option is specified, do force public
571 * certificate install in background (i.e. completely prevent
572 * user interaction)
573 */
574 if (TRUE == g_fSilent && TRUE == fEnableSilentCert)
575 {
576 if (!addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE,
577 "TrustedPublisher",
578 g_ab_VBoxStubPublicCert,
579 sizeof(g_ab_VBoxStubPublicCert)))
580 {
581 /* Interrupt installation */
582 vrc = VERR_NO_CHANGE;
583 break;
584 }
585 }
586#endif
587 /* Do actions on files. */
588 for (BYTE k = 0; k < pHeader->byCntPkgs; k++)
589 {
590 PVBOXSTUBPKG pPackage = NULL;
591 DWORD cbPackage = 0;
592 char szHeaderName[RTPATH_MAX] = {0};
593
594 hr = StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k);
595 vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage);
596 AssertMsgRCBreak(vrc, ("Package not found!\n"));
597
598 if (PackageIsNeeded(pPackage))
599 {
600 char *pszTempFile = NULL;
601
602 vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile);
603 AssertMsgRCBreak(vrc, ("Could not create name for temporary action file!\n"));
604
605 /* Handle MSI files. */
606 if (RTStrICmp(RTPathExt(pszTempFile), ".msi") == 0)
607 {
608 /* Set UI level. */
609 INSTALLUILEVEL UILevel = MsiSetInternalUI( g_fSilent
610 ? INSTALLUILEVEL_NONE
611 : INSTALLUILEVEL_FULL,
612 NULL);
613 AssertMsgBreak(UILevel != INSTALLUILEVEL_NOCHANGE, ("Could not set installer UI level!\n"));
614
615 /* Enable logging? */
616 if (fEnableLogging)
617 {
618 char *pszLog = RTPathJoinA(szExtractPath, "VBoxInstallLog.txt");
619 /* Convert slahes; this is necessary for MSI routines! */
620 pszLog = RTPathChangeToDosSlashes(pszLog, true /* Force conversion. */);
621 AssertMsgBreak(pszLog, ("Could not construct path for log file!\n"));
622 UINT uLogLevel = MsiEnableLog(INSTALLLOGMODE_VERBOSE,
623 pszLog, INSTALLLOGATTRIBUTES_FLUSHEACHLINE);
624 RTStrFree(pszLog);
625 AssertMsgBreak(uLogLevel == ERROR_SUCCESS, ("Could not set installer logging level!\n"));
626 }
627
628 /* Initialize the common controls (extended version). This is necessary to
629 * run the actual .MSI installers with the new fancy visual control
630 * styles (XP+). Also, an integrated manifest is required. */
631 INITCOMMONCONTROLSEX ccEx;
632 ccEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
633 ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS |
634 ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES |
635 ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES;
636 InitCommonControlsEx(&ccEx); /* Ignore failure. */
637
638 UINT uStatus = ::MsiInstallProductA(pszTempFile, szMSIArgs);
639 if ( (uStatus != ERROR_SUCCESS)
640 && (uStatus != ERROR_SUCCESS_REBOOT_REQUIRED)
641 && (uStatus != ERROR_INSTALL_USEREXIT))
642 {
643 switch (uStatus)
644 {
645 case ERROR_INSTALL_PACKAGE_VERSION:
646 ShowError("This installation package cannot be installed by the Windows Installer service.\n"
647 "You must install a Windows service pack that contains a newer version of the Windows Installer service.");
648 break;
649
650 case ERROR_INSTALL_PLATFORM_UNSUPPORTED:
651 ShowError("This installation package is not supported on this platform.");
652 break;
653
654 default:
655 {
656 DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER
657 | FORMAT_MESSAGE_IGNORE_INSERTS
658 | FORMAT_MESSAGE_FROM_SYSTEM;
659 HMODULE hModule = NULL;
660 if (uStatus >= NERR_BASE && uStatus <= MAX_NERR)
661 {
662 hModule = LoadLibraryEx(TEXT("netmsg.dll"),
663 NULL,
664 LOAD_LIBRARY_AS_DATAFILE);
665 if (hModule != NULL)
666 dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
667 }
668
669 DWORD dwBufferLength;
670 LPSTR szMessageBuffer;
671 if (dwBufferLength = FormatMessageA(dwFormatFlags,
672 hModule, /* If NULL, load system stuff. */
673 uStatus,
674 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
675 (LPSTR)&szMessageBuffer,
676 0,
677 NULL))
678 {
679 ShowError("Installation failed! Error: %s", szMessageBuffer);
680 LocalFree(szMessageBuffer);
681 }
682 else /* If text lookup failed, show at least the error number. */
683 ShowError("Installation failed! Error: %u", uStatus);
684 if (hModule)
685 FreeLibrary(hModule);
686 break;
687 }
688 }
689
690 vrc = VERR_NO_CHANGE; /* No change done to the system. */
691 }
692 }
693 RTStrFree(pszTempFile);
694 } /* Package needed? */
695 } /* For all packages */
696 }
697
698 /* Clean up (only on success - prevent deleting the log). */
699 if ( !fExtractOnly
700 && RT_SUCCESS(vrc))
701 {
702 for (int i=0; i<5; i++)
703 {
704 vrc = RTDirRemoveRecursive(szExtractPath, 0 /*fFlags*/);
705 if (RT_SUCCESS(vrc))
706 break;
707 RTThreadSleep(3000 /* Wait 3 seconds.*/);
708 }
709 }
710
711 } while (0);
712
713 if (RT_SUCCESS(vrc))
714 {
715 if ( fExtractOnly
716 && !g_fSilent)
717 {
718 ShowInfo("Files were extracted to: %s", szExtractPath);
719 }
720
721 /** @todo Add more post installation stuff here if required. */
722 }
723
724 /* Release instance mutex. */
725 if (hMutexAppRunning != NULL)
726 {
727 CloseHandle(hMutexAppRunning);
728 hMutexAppRunning = NULL;
729 }
730
731 /* Set final exit (return) code (error level). */
732 if (RT_FAILURE(vrc))
733 {
734 switch(vrc)
735 {
736 case VERR_NO_CHANGE:
737 default:
738 vrc = 1;
739 }
740 }
741 else /* Always set to (VINF_SUCCESS), even if we got something else (like a VWRN etc). */
742 vrc = VINF_SUCCESS;
743 return vrc;
744}
745
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette