How to terminate a command issued to cmd.exe - c#

I created a cmd process in which I display the output to a window. I would like to be able to terminate the command like pressing Control-c in the command prompt.
new ProcessStartInfo("cmd.exe");
The only option I can think of is to terminate the process. Is this what pressing control-c does? The problem with this is some user settings will be lost. Two I can think of are prompt and the current directory. could there be any others? I can remember these and create a new process and reset them. Or is there another way to simulate the interruption?
enter image description here
You can start a process by calling the Start method. You can also end the process by calling the Kill method. All well and good. Now lets start a process by running cmd.exe and redirecting the input and output. So now assume we execute a command that takes a long time. It would be nice to cancel the command like we can do in a DOS window (Command Prompt) instead of forcing the user to close and reopen the app losing their history in the process.
I can provide more details if necessary.

The mechanism that cmd.exe uses1 is GenerateConsoleCtrlEvent, and it is not available when your Process.Start call created a new console, because of this restriction in the documentation:
Only those processes in the group that share the same console as the calling process receive the signal. In other words, if a process in the group creates a new console, that process does not receive the signal, nor do its descendants.
The option you have is to not launch cmd.exe directly, but start a console program that is in turn responsible both for starting cmd.exe in its shared console, and also keeping a communication link with your program open in order to know when to generate console control events.
Actually it should be the console subsystem detecting Ctrl+C and generating the console event, and it's received by both cmd.exe and any child process. cmd.exe has a complex handler that will cancel a running builtin command (like dir) and not exit. Child processes may also have logic to exit cleanly and save state when the console control eventis seen.

Related

Custom Powershell Host Invoke external program without console window

I'm writing an embedded powershell host in C# (windows application), and if there is an external program called in the pipeline the console window flashes as it's executed. Ping and netstat are examples of this as shown in the following code snippet
using (PowerShell PowerShellInstance = PowerShell.Create())
{
PowerShellInstance.AddScript("Get-Content test.txt; ls; ping www.google.com");
PowerShellInstance.Invoke();
# ...more code here to print output etc
}
Once the ping command is reached in the pipeline a console window will popup execute the command and return results. I would like to do this without the console window showing. I've searched and found examples of how to deal with this by starting a process for external commands and redirecting output.
I can do that of course, but then how would I test if a command in the pipeline is a call to an external program?
I would really like to be able to handle this generically if possible; meaning that I don't want to test for specific programs (e.g. ping, netstat, net) if I don't have to. The native powershell.exe does this so it's somehow possible.
It turns out that this is expected behavior of invoking console commands. In Windows 7 and above conhost.exe is responsible for handling calls to console programs. In this case, ping and netstat trigger an instance of conhost to be created, it handles the request, returns the results, and then remains open. conhost.exe starting up is what is causing the console flash I'm seeing. The fact that it remains open is why I was only seeing the console window flash once. Once conhost is connected to the calling process all subsequent console commands are handled by that same instance.
I'm marking this as an answer because a new question should be created to address conhost specifically.
Source. Windows Internals Part 1

How does the command prompt know when to wait for exit?

I was attempting to do a Windows command prompt re-code in C#. I was wondering how the command prompt knows when to wait for the process started to exit, and when not to wait for the called process to exit.
For example, if you type in the command prompt "notepad", Notepad will launch, but you can still execute other commands. However, if you open a utility such as more.com, ping.exe, or another utility, it will wait for the executing program to finish before letting you execute another command.
How does the command prompt know when to wait for exit, and how can this behavior be emulated in C#?
If the application is a Win32 GUI application, it will just run and command prompt won't wait for it to exit.
If the application is a console application, it will run in the command prompt and you'll need to wait for it to finish to get the command prompt back.
EDIT:
OK. It seems you need technical explanation. If you want to emulate the same feature in your application, you can check IMAGE_OPTIONAL_HEADER of EXE files here.
Inside IMAGE_OPTIONAL_HEADER, there is:
WORD Subsystem;
If SubSystem == 0x02 it means it's a GUI application.
If SubSystem == 0x03 it means it's a command prompt app.
EDIT 2:
If you want to see it in action:
Download http://www.ntcore.com/exsuite.php
Copy calc.exe or notepad.exe to your desktop
Open copied calc.exe in CFF Explorer
Navigate to Nt Headers -> Optional Headers
Change SubSystem from 0x002 to 0x003
Save it
Now run the new modified calc and you'll see the command prompt wait for it to be terminated.
The default from a command prompt is to spawn the GUI program in a separate process/fork.
However, you can run notepad (or other GUI program) inline with your command prompt / shell script:
start /w notepad.exe
This way, the command prompt / shell script only continues after the notepad.exe process has terminated.
Hope this helps, TW
When you start a new process, a GUI application in this context that actually works outside the boundaries of the prompt, the prompt will not wait. But, if you run a command that works entirely under the boundaries of the current instance of a prompt, it waits.
So, command notepad just starts the Notepad application and leaves control of application. While, command ipconfig runs under a domain (no this is not application domain), of the prompt.
To extremely generalize, when you use Process.Start in your C# equivalent, do not wait. It anyway will not.

Console application not starting processes when scheduled in Windows

I have a simple .NET console app in C#, that runs an external process "pscp" (putty secure copy). This works great when I just run the .exe.
However, when I schedule the application in windows scheduled tasks, the application does not seem to open the external process pscp.exe. Normally it should pop up an extra console screen and open pscp.exe there. This works, just not when scheduled.
I start the process like this:
pscp.FileName = "pscp.exe";
Process p = Process.Start(pscp);
p.WaitForExit();
Any ideas on how to fix this?
Starting cmd with the /c argument runs "your exe" in a new cmd window.
The scheduled task runs under a different identity. Make sure that's working. Also, make sure you wrap the call to your exe with a cmd /c "your exe".

C# program parameters from the command line?

I'm trying to start a C# program running, and then give it command from the cmd.exe after it's started running. For instance, suppose I started my .exe from the command line (C://FILEPATH/my_program.exe). I'd then like to have that program continue running, and then have me be able to pass commands to it that it is capable of handling. In my ideal world this would be something like "C://FILEPATH/my_program.exe run_my_command()" which would execute the run_my_command function, or "C://FILEPATH/my_program.exe k", which would do something in response to the char k that I'd pre-programmed in. I know that, as I've typed, would start a new copy of my_program.exe. I'd only like to have one running while I pass something like that in.
Does anyone know how to do this? Sample code would be wonderfully appreciated. Thanks!!
The simplest solution would be for your second instance of "my_program.exe" to look for an existing instance that's already running, "pass" the message over to it and then exit immediately.
The usual way this is implemented is via named pipes (System.IO.Pipes in .NET 3.5+). When your program starts up, listen on a named pipe with a given name. If there's something else already listening on that pipe, send the message to it and exit.
You are describing a typical service and command tool. The service (demon) runs in the background and executes commands. The command tool takes user commands and passes them to the service. See Windows Service Applications. Having a service instead of starting several processes takes care of some issues your approach has, like security isolation between the processes (eg. one user starts the a command, another user starts another command and gets executed in the context of the first user) and process lifetime issues (user launches a command and then closes his session).
The command tool would communicate with the process via classic IPC (local RPC, pipes, shared memory, etc).

C# - Close OpenVPN Cleanly

We have written an application that sits in the tray controlling OpenVPN as an extension to a bigger application.
If you run openvpn.exe on command line, you can press F4 to close it. We need to do send the same keypress from C#, but you can only send string values to StandardInput.
We have been forced to kill OpenVpn to close it, and this seems to be causing BSOD every now and then on Vista...
Here is a link to my post on MSDN that also describes the issue: MSDN Forums
Does anyone know how to send special keystrokes to a Process with StandardInput?
Or maybe a workaround to close OpenVPN more cleanly?
UPDATE:
The following do not work when passed to StandardInput.Write(), F1 key is in this example:
ConsoleKey.F1
"\x70" (Hex value for F1)
Convert.ToChar((int)ConsoleKey.F1)
We already properly redirect the input/output, because we can successfully pass username/password to OpenVPN with no problem.
UPDATE 2: Found this on some command line option documentation for OpenVPN:
--service exit-event [0|1]
Should be used when OpenVPN is being automatically executed by another program in such a context that no interaction with the user via display or keyboard is possible. In general, end-users should never need to explicitly use this option, as it is automatically added by the OpenVPN service wrapper when a given OpenVPN configuration is being run as a service.
exit-event is the name of a Windows global event object, and OpenVPN will continuously monitor the state of this event object and exit when it becomes signaled.
The second parameter indicates the initial state of exit-event and normally defaults to 0.
Multiple OpenVPN processes can be simultaneously executed with the same exit-event parameter. In any case, the controlling process can signal exit-event, causing all such OpenVPN processes to exit.
How would I use this in C#? Is the "exit-event" signaling they are mentioning a Mutex?
If I run OpenVPN as the following:
"openvpn.exe --config PathToMyConfig.ovpn --service MyEventName 0"
Then the following C# code causes OpenVPN to exit cleanly:
EventWaitHandle resetEvent = EventWaitHandle.OpenExisting("MyEventName");
resetEvent.Set();
Props to consultutah, his comments helped quite a bit.
StandardInput.Write(ConsoleKey.F4);
Obviously you have to get StandardIn for the process.

Categories

Resources