Here is a good question for the CodeProject poll. How many of us have wanted to write an interpreter for a language of our own? I'm sure that would include most of us. All of us who actually tried to write one would have written it as a command line application. What if I wanted to embed it in a Windows application? Out of that question was born this control, which I call the
ShellControl. It has nothing to do with the OS shell, although it can be used as a UI for one. In fact, the sample application does just that, it gets commands from the user, uses cmd.exe to run it, and displays the results in the UI. Think of it as the command tool window in Visual Studio.
What it is?
ShellControl is a .NET User Control that you can embed directly in your Windows Forms applications. It emulates a command line UI, like the DOS shell. It is pretty basic in functionality. It provides the following features:
- Prompt - It provides a prompt, which can be changed anytime. It works like the prompt we are used to see in the DOS shell, i.e., it can't be erased out.
- Command History - It maintains a history of the commands executed so far. The up/down arrow keys can be used to move up/down the history just like the DOS shell.
- Autocompletion - It provides auto completion for the last command. The right arrow key can be used for this purpose.
- All other features of a standard
TextBox, because the
ShellControl in reality is just a modified
TextBox, it provides all the normal functionality of the standard Windows
TextBox. This includes using the mouse to select text, copy/paste, undo/redo etc.
How to use it?
Pretty simple. Add the control like any normal User Control (Right click on the ToolBox, click Add/Remove Items and Browse to ShellControl.dll). Subscribe to the
CommandEnteredEvent. Do whatever you want with the command text passed in as part of the
CommandEnteredEventArgs object. Here is some sample code:
shellControl1.CommandEntered += new
void shellControl1_CommandEntered(object sender,
string command = e.Command;
ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe");
startInfo.Arguments = "/C " + e.Command;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process p = Process.Start(startInfo);
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
if (output.Length != 0)
else if (error.Length != 0)
The code above gets the command text and executes it by starting a new cmd.exe process. It then writes back the result to the control. It can't get any simpler, can it?
Other Properties And Methods
Besides the event, the control exposes the following properties and methods:
Prompt - Use it to get/set the prompt displayed in the control.
ShellTextForeColor - Set/Get the color of the foreground text.
ShellTextBackColor - Set/Get the background color.
ShellTextFont - Set/Get the font of the console text.
WriteText(string text) - Use it to write text to the
ShellControl. You need to remember that the control writes the prompt on the display after every call to
WriteText, so if you are writing multiple lines, be sure to append them to a single string before calling
Clear - Clears the console, leaving just the prompt.
GetCommandHistory - Returns a string array of the commands entered so far.
How it works?
ShellControl is a class derived from
UserControl. All it does is wrap
ShellTextBox, which derives from
TextBox. Two questions here.
- Why not directly expose
Because that would expose all properties of the
MaxLength etc. And that would be disastrous because the
ShellControl needs to tightly control the addition of text to make sure that nothing funny happens. For e.g., the
ShellControl needs to make sure that you can't modify text that's above the current line, it needs to ensure that you can't erase the prompt and so on..
- Why derive from
TextBox, why not aggregate it?
ShellTextBox needs to override
WndProc. And that's necessary to make sure that Cut/Paste/Clear from the Context menu don't do anything silly.
WndProc looks like this:
protected override void WndProc(ref Message m)
case 0x0302: case 0x0300: case 0x000C: if (!IsCaretAtWritablePosition())
case 0x0303: return;
As you can see,
WM_CLEAR has no effect, while Cut/Paste are made to operate on the text currently at the prompt.
For controlling key presses, the
ShellTextBox subscribes to the
KeyDown events of the
KeyPress event handler handles backspace and Enter keys while other keys are handled by the
KeyDown event handler. A utility class,
CommandHistory, maintains the list of commands entered as well as the current position in that list. The up/down arrow keys use information in that list to display the command history. That section looks like this:
private void ShellControl_KeyDown(object sender, KeyEventArgs e)
if (!IsCaretAtWritablePosition() &&
!(e.Control || IsTerminatorKey(e.KeyCode)))
if (e.KeyCode == Keys.Left && IsCaretJustBeforePrompt())
e.Handled = true;
else if (e.KeyCode == Keys.Down)
e.Handled = true;
else if (e.KeyCode == Keys.Up )
e.Handled = true;
When the enter key is pressed, the
ShellTextBox gets the text currently at the prompt and calls
ShellTextControl, which in turn fires the
CommandEntered event. That's all there is to it.
Although I'm fairly comfortable in C#, this is my first attempt at creating UserControls. I know this is not going to be the most downloaded control in CodeProject, but I feel it's still useful for certain situations where you want to emulate the command line.
Feedback, comments are welcome.
Feb 17 2005 - Initial submission.