I am trying to make a log using a C# windows form application. The goal here is to press a button to start a batch file (below) and get the text/data written to the command prompt, as it is written if possible, then send it to a listbox on my application. Think of it as a program for a server (which its not, its a discord bot.), my goal is just to have the "logs" sent to the application in real time.
Question: How can I create my own console inside my windows form application, example would be: If an echo said "Hello" I want it to display "Hello" in my listbox in realtime.
CMD File being Ran
#echo off
cd "C:\Users\gunzb\Desktop\Tarkov Bot\"
:loop
py bot.py
SET /A time=3
:timer
timeout /t 1 /nobreak>nul
echo Restarting in %time%
SET /A time-=1
IF %time% EQU 0 (goto skiploop) ELSE (goto timer)
:skiploop
goto loop
I have no idea where to start as when I search for this topic I get other languages or other methods that dont seem to either do it in real time or doesnt work at all. Thank you for any help given.
EDIT: The python script makes the writelines but I believe these can also be taken from the CMD process itself, not sure though.
EDIT:
public void StartBotBtn_Click(object sender, EventArgs e)
{
Process proc = new Process();
ProcessStartInfo si = new System.Diagnostics.ProcessStartInfo();
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.OutputDataReceived += ProcessOutputHandler;
proc.StartInfo.FileName = "C:\\Users\\gunzb\\Desktop\\Tarkov Bot\\start.bat";
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
processid = proc.Id;
}
private void StopBotBtn_Click(object sender, EventArgs e)
{
Array.ForEach(Process.GetProcessesByName("py"), x => x.Kill());
Array.ForEach(Process.GetProcessesByName("cmd"), x => x.Kill());
}
private void ProcessOutputHandler(object sender, DataReceivedEventArgs e)
{
this.listBox1.Items.Add(e.Data); //This is where I get confused.
}
Related
I'm trying to get a listbox of specific services (that my software uses) and then use buttons to "start" "stop" and "restart" in Visual C#.
Anyone can help?
Process[] processCollection = Process.GetProcesses();
private void ButtonOnClick(object seender, EventArgs e)
{
foreach (Process p in processCollection)
{
// make sure its a service 1st
if(!Environment.UserInteractive){
// iterate over processes and stuff into listbox
var exename = Path.GetFileName(p.MainModule.FileName)
listBoxVar.Items.Add(exename);
}
// start/restart a process
ProcessStartInfo startInfo = new ProcessStartInfo(exename);
Process.Start(startInfo);
// kill a process
p.Kill();
}
}
I want to create an auto restarter for my server. I have added a checkbox and made all required checks but I don't have any idea how to make that process restart upon crash.
Here is my code:
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
string world = textBox1.Text;
string auth = textBox2.Text;
if (checkBox1.Checked == true)
{
if (textBox1.Text.Trim().Length == 0 || textBox2.Text.Trim().Length == 0)
{
MessageBox.Show("Please check if you selected the path for worldserver and authserver");
}
else
{
//here i need something to restart those 2 processes after crash/close
}
}
}
The simplest way to start a process is to use the Start static method of the Process class:
Process.Start("yourapp.exe");
For access to more specific options, you can set up a ProcessStartInfo object instead:
var startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "yourapp.exe";
startInfo.Arguments = "-arg1 val1";
var exeProcess = Process.Start(startInfo);
exeProcess.Start();
To check whether the process in question is still running, you can use this:
var matchingProcesses = Process.GetProcessesByName("yourapp");
var isRunning = matchingProcesses.Length > 0;
And you can put that in a method and poll every few seconds or milliseconds (depending on how fast you want to respond):
var aTimer = new Timer();
aTimer.Elapsed += new ElapsedEventHandler(YourMethod);
aTimer.Interval = 1000;
aTimer.Enabled = true;
These classes are found in the System.Diagnostics and System.Timers namespaces, respectively.
Though it's not C# (but better, it works with almost any program), you can do an auto restarter in batch (or in bash, but I won't put the code here), and it will be enough for most cases:
#echo off
:start
myprogram.exe %*
if exist myprogam.lock goto start
inside your program:
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if(checkBox1.Checked)
{
using (System.IO.File.Create("myprogam.lock"));
}
else
{
System.IO.File.Delete("myprogam.lock")
}
}
you should also create the file in your main or init code.
bonus: you can delete the file if your program exits cleanly (or on some errors), and it won't restart.
to use, just put the first code in a .bat file you put in your program folder, and use this to start the program.
I have the following code for a button click event. This event should open the command window and execute the application:
private void start_Click(object sender, EventArgs e)
{
if (textBox1.Text == " " || textBox2.Text == " ")
{
MessageBox.Show("Header File or Executable Missing");
}
else
{
Process.Start(textBox1.Text);
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = textBox1.Text;
string filename = textBox1.Text;
int found = filename.LastIndexOf("\\");
int end = filename.Length;
string temp = filename.Substring(found);
startInfo.Arguments = temp + textBox2.Text;
Process.Start(startInfo);
}
}
The problem that I'm facing out here is that when I click the button, the command window does not persist and I don't know whether the command window displays an error message or not because it opens & closes in a flash. Can anybody tell me what is going wrong here and give me a few hints how to go about solving the issue?
If you want to start a new console application from your Windows Forms application you need to either pass in the path to such an application or to cmd.exe + the run command for that application. Make sure the code in your console application halts by asking for a Console.ReadKey(true) or similar.
When I start a new process, it automatically gets the focus. how can I prevent it from getting the focus or instead get back the focus to my application?
here is the code I'm using:
string path = #"c:\temp\myprocess.exe";
ProcessStartInfo info = new ProcessStartInfo(path);
info.WorkingDirectory = path;
Process p = Process.Start(info);
I just need the executed process not to get the focus.
Thank you very much,
Adi Barda
Maybe setting the WindowStyle property to Minimized can help.
If you don't need to show the process at all, try this:
string path = #"c:\temp\myprocess.exe";
ProcessStartInfo info = new ProcessStartInfo(path);
info.WorkingDirectory = path;
info.WindowStyle = ProcessWindowStyle.Hidden;
Or set WindowStyle to ProcessWindowStyle.Minimized if you want it visible but minimized, as Uwe Keim said.
can you do
myForm.Focus();
where myForm is the form on your main application
What i´ve done was to wait a little delay until the other application was succesfully loaded, then focus my application window.
//Test window
const string strCmdText = "/C cd C:\\sqlcipher";
Process.Start("CMD.exe", strCmdText);
//Delay
int liMilliseconds = 50;
Thread.Sleep(liMilliseconds);
//Code to bring window to front
this.WindowState = FormWindowState.Minimized;
this.Show();
this.WindowState = FormWindowState.Normal;
I apologize if this is a duplicate question, I searched a bit and couldn't find anything similar - I have a Python library that connects to my C# application via a socket in order to allow simple Python scripting (IronPython isn't an option right now for a couple of reasons). I would like to create a Windows Forms control that would be basically a graphical front-end for the Python interpreter, so that the user could run the interpreter without having to have a separate console window open.
I attached a simple demo of what I've tried so far below, but I haven't been able to get it to work. The DataReceived event handlers are never called, and when I try to write to the standard input nothing happens in the interpreter. Does anyone have any feedback about what I'm doing wrong, or if this is even possible?
public partial class Form1 : Form
{
Process _pythonProc;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ProcessStartInfo psi = new ProcessStartInfo()
{
FileName = #"C:\Python26\Python.exe",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
_pythonProc = new Process();
_pythonProc.OutputDataReceived += OutputDataReceived;
_pythonProc.ErrorDataReceived += ErrorDataReceived;
_pythonProc.StartInfo = psi;
_pythonProc.Start();
}
private void cmdExecute_Click(object sender, EventArgs e)
{
string cmd = textInput.Text;
_pythonProc.StandardInput.WriteLine(cmd);
_pythonProc.StandardInput.Flush();
textInput.Text = string.Empty;
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (!_pythonProc.HasExited)
_pythonProc.Kill();
}
private void OutputDataReceived(object sender, DataReceivedEventArgs args)
{
textOutput.Text += args.Data;
}
private void ErrorDataReceived(object sender, DataReceivedEventArgs args)
{
textOutput.Text += args.Data;
}
}
In case anyone else stumbles across this, I figured out the problem - by default, the Python interpreter only enters interactive mode if it detects that a TTY device is connected to standard input (which is normally only true if the program is run from the console). In order to redirect the standard IO streams, you have to set UseShellExecute in the ProcessStartInfo to false, which causes the interpreter to think that there is no TTY connected, meaning it immediately exits since it has nothing to do.
The solution is to run the Python interpreter with the "-i" command line argument, which forces the interpreter to interactive mode, regardless of whether there is a TTY connected to standard in. This makes the example above work correctly.
write in separate thread:
while(cond)
{
string s = _pythonProc.StandardOutput.ReadLine();
textOutput.Invoke( () => { textOutput.Text += s; } );
}