VirtualBox

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

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

Installer/win/Stub/VBoxStub.cpp: Fixed broken parameter handling by rewriting it to use RTGetOpt. -msiparam didn't work and had to be at the end of the parameter list. More than one -path would concatenate with instead of overwrite the previous values. Returning 0 (success) on syntax error. Poping up message boxes on errors in silent mode.

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

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