Crabwise Studios logo

Using CommandWrap

Commands have many other attributes and methods that are helpful. For example, we can take the messages written to standard out by the process by accessing the StandardOutput field of our object. We can also view the state of the command, for example, if the command has finished running, by calling querying HasExecuted.


Creating a simple Command object

Any Command that uses our library is a subclass of, and must extend, our Command class. Command classes are tagged with the [CommandSyntax] attribute which contains the syntax of the command without arguments. All arguments are tagged with the [ParameterSyntax] attribute, containing the syntax for a particular parameter of the command.

As a simple example, we can create a Command called NetstatCommand object for the windows netstat command. First, we must tag the class definition with the attribute [CommandSyntax("netstat")]. Secondly, we can implement the parameters of the netstat command. If we wanted to implement the -o flag, we can create a boolean field and tag it with ParameterSyntax("-o")].

Next, we can implement the interval parameter. Since this is a numeric value, the field of our NetstatCommand class would be an int. This is also a user-defined value, and not a flag, so we must tag the field with the attribute [CommandSyntax("{arg}")]. The CommandWrap library will take the user-defined argument, and substitute it in for {arg}. The library also handles many other types, as well as Collections, which is explained in greater detail below.


namespace CommandWrapExamples
{
    using Crabwise.CommandWrap;
         
    [CommandSyntax("netstat")]
    public class NetstatCommand : Command
    {
        [ParameterSyntax("-o")]
        public bool? ShowOwningProcess { get; set; }
            
        [ParameterSyntax("{arg}")]
        public int? Interval { get; set; }
    } 
}

Using the simple Command Object

Now that we have a basic command class created, let's use it. Create an instance of the NetstatCommand class. We can run a process using this command object by calling its Execute() method inherited from its super class. Commands have many other attributes and methods that are helpful. For example, we can take the messages written to standard out by the process by accessing the StandardOutput field of our object. We can also view the state of the command, for example, if the command has finished running, by querying HasExecuted.


public void RunBasicExample()
{
    NetstatCommand netcmd = new NetstatCommand();
    netcmd.ShowOwningProcess = true;

    int ret = netcmd.Execute();

    Console.WriteLine(netcmd.StandardOutput);
    Console.WriteLine("Has cmd executed?: " + netcmd.HasExecuted);

    Console.ReadLine();
}

Defining how a Command starts

Not all processes can be run from any location on the machine without special parameters, and sometimes we want to launch a process with more specific information, for example, a specific location. Much of this can be done by creating a CommandStartInfo object.

Let's create a new class, CalcCommand, that simply defines the CommandSyntax attribute as calc.exe. We can try to create this object and run it, but chances are that we have to specify the location of calc.exe.


namespace CommandWrapExamples
{
    using Crabwise.CommandWrap;
         
    [CommandSyntax("calc.exe")]
    public class CalcCommand : Command
    {
    }
}

Now we can create a new CommandStartInfo object before our instance of CalcCommand. One of the many fields of this object is Path, which we can set to be the location of calc.exe, %windir%\system32\. Now, we can call the Execute() method on our instance of CalcCommand, giving it our instance of CommandStartInfo.


public void RunCalcExample()
{
    CommandStartInfo calcInfo = new CommandStartInfo();
    calcInfo.Path = "%windir%\\system32\\";
    CalcCommand calccmd = new CalcCommand();
    calccmd.Execute(calcInfo);
}

Defining Parameters - Defining {arg}

As mentioned before, the argument of a command parameter may be anything from a boolean to a collection of strings. Let's create a subclass of Command called ZipCommand, which could be used with an imaginary zip process. Our imaginary process has the following syntax: zip files -- [files], where [files] is a list of file paths to zip. This parameter is required.

To do this, we can instantiate a collection of strings in the class, allowing the user to add files however they see fit in other modules. We can then make a parameter for our Command called Files of type Collection<String>. For this, we would tag the parameter with the following attribute: [ParameterSyntax("files -- {arg}", Required = true)]. This will allow access to the underlying collection of strings, and then when the Command is executed, it will replace {args} in the Files parameter with the contents of the collection.


class ZipCommand : Command
{
    Collection<string> filesToZip;

    [ParameterSyntax("files -- {arg}", Required = true)]
    public Collection<string> Files
    {
        get { return this.filesToZip; }
    }
}

Defining Parameters - Specifying Order

To continue with ZipCommand, let's imagine that the process also requires a destination path for the resulting zip. This turns the syntax to zip files -- [files] dest -- [dest]. The destination parameter must appear after the list of files to zip.

The CommandWrap library allows us to specify a position of the parameters for any particular Command, the first parameter being 0. Parameters with the same position value will appear in an arbitrary order.

To do this, all that needs to be done is set the Position value (this value is set at default to 0). Since our dest parameter must appear after the files parameter, let's set the dest parameter's position to 1 by tagging it with the following attribute: [ParameterSyntax("dest -- {arg}", Required = true, Position = 1)].


class ZipCommand : Command
{
    Collection<string> filesToZip;

    [ParameterSyntax("files -- {arg}", Required = true)]
    public Collection<string> Files
    {
        get { return this.filesToZip; }
    }

    [ParameterSyntax("dest -- {arg}", Required = true, Position = 1)]
    public string Destination { get; set; }
}