aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Mba.Core/BootstrapperCommand.cs
blob: bbd10e1d526822c6cee0406092053027290ee500 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// 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.BootstrapperCore
{
    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;

    public sealed class BootstrapperCommand : IBootstrapperCommand
    {
        private readonly string commandLine;

        public BootstrapperCommand(
            LaunchAction action,
            Display display,
            Restart restart,
            string commandLine,
            int cmdShow,
            ResumeType resume,
            IntPtr splashScreen,
            RelationType relation,
            bool passthrough,
            string layoutDirectory)
        {
            this.Action = action;
            this.Display = display;
            this.Restart = restart;
            this.commandLine = commandLine;
            this.CmdShow = cmdShow;
            this.Resume = resume;
            this.SplashScreen = splashScreen;
            this.Relation = relation;
            this.Passthrough = passthrough;
            this.LayoutDirectory = layoutDirectory;
        }

        public LaunchAction Action { get; }

        public Display Display { get; }

        public Restart Restart { get; }

        public string[] CommandLineArgs => GetCommandLineArgs(this.commandLine);

        public int CmdShow { get; }

        public ResumeType Resume { get; }

        public IntPtr SplashScreen { get; }

        public RelationType Relation { get; }

        public bool Passthrough { get; }

        public string LayoutDirectory { get; }

        /// <summary>
        /// Gets the command line arguments as a string array.
        /// </summary>
        /// <returns>
        /// Array of command line arguments.
        /// </returns>
        /// <exception type="Win32Exception">The command line could not be parsed into an array.</exception>
        /// <remarks>
        /// This method uses the same parsing as the operating system which handles quotes and spaces correctly.
        /// </remarks>
        public static string[] GetCommandLineArgs(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);
            }
        }
    }
}