// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Mba.Core
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
///
/// Default implementation of .
///
public sealed class BootstrapperCommand : IBootstrapperCommand
{
///
///
///
///
///
///
///
///
///
///
///
///
///
///
public BootstrapperCommand(
LaunchAction action,
Display display,
string commandLine,
int cmdShow,
ResumeType resume,
IntPtr splashScreen,
RelationType relation,
bool passthrough,
string layoutDirectory,
string bootstrapperWorkingFolder,
string bootstrapperApplicationDataPath)
{
this.Action = action;
this.Display = display;
this.CommandLine = commandLine;
this.CmdShow = cmdShow;
this.Resume = resume;
this.SplashScreen = splashScreen;
this.Relation = relation;
this.Passthrough = passthrough;
this.LayoutDirectory = layoutDirectory;
this.BootstrapperWorkingFolder = bootstrapperWorkingFolder;
this.BootstrapperApplicationDataPath = bootstrapperApplicationDataPath;
}
///
public LaunchAction Action { get; }
///
public Display Display { get; }
///
public string CommandLine { get; }
///
public int CmdShow { get; }
///
public ResumeType Resume { get; }
///
public IntPtr SplashScreen { get; }
///
public RelationType Relation { get; }
///
public bool Passthrough { get; }
///
public string LayoutDirectory { get; }
///
public string BootstrapperWorkingFolder { get; }
///
public string BootstrapperApplicationDataPath { get; }
///
public IMbaCommand ParseCommandLine()
{
var args = ParseCommandLineToArgs(this.CommandLine);
var unknownArgs = new List();
var variables = new List>();
var restart = Restart.Unknown;
foreach (var arg in args)
{
var unknownArg = false;
if (arg[0] == '-' || arg[0] == '/')
{
var parameter = arg.Substring(1).ToLowerInvariant();
switch (parameter)
{
case "norestart":
if (restart == Restart.Unknown)
{
restart = Restart.Never;
}
break;
case "forcerestart":
if (restart == Restart.Unknown)
{
restart = Restart.Always;
}
break;
default:
unknownArg = true;
break;
}
}
else
{
var index = arg.IndexOf('=');
if (index == -1)
{
unknownArg = true;
}
else
{
var name = arg.Substring(0, index);
var value = arg.Substring(index + 1);
variables.Add(new KeyValuePair(name, value));
}
}
if (unknownArg)
{
unknownArgs.Add(arg);
}
}
if (restart == Restart.Unknown)
{
restart = this.Display < Display.Full ? Restart.Automatic : Restart.Prompt;
}
return new MbaCommand
{
Restart = restart,
UnknownCommandLineArgs = unknownArgs.ToArray(),
Variables = variables.ToArray(),
};
}
///
/// Gets the command line arguments as a string array.
///
///
/// Array of command line arguments.
///
/// The command line could not be parsed into an array.
///
/// This method uses the same parsing as the operating system which handles quotes and spaces correctly.
///
public static string[] ParseCommandLineToArgs(string commandLine)
{
if (null == commandLine)
{
return new string[0];
}
// Parse the filtered command line arguments into a native array.
int argc = 0;
// CommandLineToArgvW tries to treat the first argument as the path to the process,
// which fails pretty miserably if your first argument is something like
// FOO="C:\Program Files\My Company". So give it something harmless to play with.
IntPtr argv = NativeMethods.CommandLineToArgvW("ignored " + commandLine, out argc);
if (IntPtr.Zero == argv)
{
// Throw an exception with the last error.
throw new Win32Exception();
}
// Marshal each native array pointer to a managed string.
try
{
// Skip "ignored" argument/hack.
string[] args = new string[argc - 1];
for (int i = 1; i < argc; ++i)
{
IntPtr argvi = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
args[i - 1] = Marshal.PtrToStringUni(argvi);
}
return args;
}
finally
{
NativeMethods.LocalFree(argv);
}
}
}
}