c# Getting WinForm to acknowledge Process.StartInfo.WindowStyle when launched programmatically - c#

Microsoft Paint (mspaint.exe) will launch minimized with no problems. When launching a windows form I wrote in c# (myWinForm.exe) the Process.StartInfo.WindowStyle command gets ignored (always launched as normal window). Comments in code below detail this.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
LaunchProcess("mspaint.exe");
LaunchProcess("myWinForm.exe"); // this process will not acknowledge the StartInfo.WindowStyle command (always normal window)
}
private void LaunchProcess(string filename)
{
Process myProcess = new Process();
myProcess.StartInfo.FileName = filename;
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized; // how do I get a WinForm I wrote to acknowledge this line?
myProcess.Start();
}
}
How do I configure myWinForm to acknowledge ProcessWindowStyle when called from the Process.Start() command?

This must be taken care of in the program you launch, it is not automatic. The information is available from the Process.GetCurrentProcess().StartInfo property. It WindowState property contains the requested window state. Modify the project's Program.cs file similar to this:
using System.Diagnostics;
...
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var main = new Form1();
switch (Process.GetCurrentProcess().StartInfo.WindowStyle) {
case ProcessWindowStyle.Minimized: main.WindowState = FormWindowState.Minimized; break;
case ProcessWindowStyle.Maximized: main.WindowState = FormWindowState.Maximized; break;
}
Application.Run(main);
}

Related

Run Powershell script files step by step in WPF (C#)

I am a novice in C# and have a GUI in WPF where at some point it should automatically start executing Powershell scripts, but preferably one by one. As I see all methods run at once without waiting previous to finish, so my question is: what is better to use some kind of threads or async methods?
If I try to use task.WaitForExit(); then it freezes GUI, which is not acceptable. I have tried to use timer as well, but it looks like it doesn't see this it at all. Besides I have more ps1 files and several bat files, which need to be run one by one.
Could you tell please which method is better to use and how to combine it with active GUI in this case?
public partial class Start_deployment : Window
{
public Start_deployment()
{
InitializeComponent();
Run_scripts();
System.Windows.Application.Current.Shutdown();
}
public void Run_scripts()
{
var ps1File = #"C:\test\Install.ps1";
var startInfo = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = $"-ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -file \"{ps1File}\"",
UseShellExecute = false
};
var task = Process.Start(startInfo);
//task.WaitForExit();
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
}
}
Process.Start() returns Process instance, which has Exited event. Subscribe to that event to receive notification when it finished:
public partial class Start_deployment : Window
{
public Start_deployment()
{
InitializeComponent();
Run_scripts();
}
public void Run_scripts()
{
var ps1File = #"C:\test\Install.ps1";
var startInfo = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = $"-ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -file \"{ps1File}\"",
UseShellExecute = false
};
var proc = Process.Start(startInfo);
proc.Exited += OnProcessExited;
}
private void OnProcessExited(object sender, EventArgs eventArgs)
{
// todo, e.g.
// System.Windows.Application.Current.Shutdown();
}
}

C# form switch and vice versa

Assume that I have a C# Solution with 3 projects Main, Program1, Program2.
I want to have a "Main form", when I click on button "Program1" the main form will be hidden, Program1 will be showed, and when I close Program1, the Main form will return.
How can I do this?
I tried add Program1 and PRogram2 as Reference to Project Main and code like below in Main, it works for call Program1, but can't handle event Program1.closed() because when I try to reference Main to Program1, it error
---------------------------
Microsoft Visual Studio
---------------------------
A reference to 'Main' could not be added. Adding this project as a reference would cause a circular dependency.
---------------------------
OK
---------------------------
I searched Google and got nothing helpful!
using System;
using System.Windows.Forms;
namespace Switch
{
public partial class Main : Form
{
public Main()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Program1.Form1 pf1 = new Program1.Form1();
pf1.Show();
this.Hide();
}
}
}
As zcui93 commented you can use process to make it work. You can either have all 3 in same folder (when you deploy the app on client machine)
using System.Diagnostics;
...
Process process = new Process();
// Configure the process using the StartInfo properties.
process.StartInfo.FileName = "process.exe";
process.StartInfo.Arguments = "-n";
process.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
process.Start();
process.WaitForExit();// Waits here for the process to exit.
In C# you can use the Process.Exited event. This event doesn't work when someone close the app when someone kill the app from task manager.
Circular dependencies use to happen when the project arquitecture is not good.
In your case i think the problem migth be the program1 or program2 have Main as a reference.
Remove de Main reference from the program1 and program2.
The main project must have reference to the program1 and program2.
Thanks everyone for answers!
After confirmed with customer, they don't strictly need the "mainform" to be hidden, so I came with another easier solution:
1. For the "child form", I use ShowDiaglog() instead of Show()
private void btnChildForm1_Click(object sender, EventArgs e)
{
var frm = new ChildForm1();
frm.ShowDialog();
}
For the mainform, I use mutex to force it to be only 1 instance:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
[STAThread]
static void Main()
{
var mutex = new Mutex(true, "MainForm", out var result);
if (!result)
{
MessageBox.Show("Running!");
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
GC.KeepAlive(mutex);
}
}

About C# Process Class:I can start some processes but another can not open [duplicate]

This question already has answers here:
How do I start a process from C#?
(13 answers)
Closed 6 years ago.
Can anyone help me? O(∩_∩)O
Today I meet a question that I want to use a program maybe a player and I need log the data(BCI EEG) from the user.So I try to use the Process Class to Start a ConsoleApplication in an WindowsApplication.
I create a Simple WindowsApplication to have a try my idea.
But it not works,I also try to use the Process Class to Start other Application It' Ok.When I Start my own program that is a ConsoleApplication it not works.
public partial class Form1 : Form
{
Process myProcess = new Process();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
myProcess.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
myProcess.StartInfo.FileName = "D:\\EEG\\Emotiv Xavier TestBench v3.0.0.41\\EmotivXavierTestBench.exe";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
//System.Console.WriteLine("Hello World!");
//MessageBox.Show("button1.Click was raised.");
}
This TestBench program can open .But why the program I create doesn't work?
D:\temp\EmotivConnection\Debug\EmotivConnection.exe
So you've run the application, but don't allow to create any console window by
myProcess.StartInfo.CreateNoWindow = true;
And so you see nothing (the application runs however). Probably, you want to re-direct the output (and show it in, say, MyTextBox instead of console window)
private void button1_Click(object sender, EventArgs e) {
// Process is IDisposable, so wrap it into using
using (Process myProcess = new Process()) {
myProcess.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
myProcess.StartInfo.FileName =
//"cmd.exe"; // <- standard test
"D:\\EEG\\Emotiv Xavier TestBench v3.0.0.41\\EmotivXavierTestBench.exe";
myProcess.StartInfo.CreateNoWindow = true;
// Crucial: we want to see the output in MyTextBox,
// not in the standard console (which is hidden by "CreateNoWindow = true")
myProcess.StartInfo.RedirectStandardOutput = true;
// You may want this as well
//myProcess.StartInfo.RedirectStandardError = true;
myProcess.Start();
myProcess.WaitForExit();
// Do not forget to put MyTextBox on the form
// Read the output ("Hello World") in the MyTextBox
MyTextBox.Text = myProcess.StandardOutput.ReadToEnd();
}
}
You are calling
myProcess.StartInfo.CreateNoWindow = true;
have you checked, if your task manager contains your program?
I assume it is actually running but in the same window as your current app.
About CreateNoWindow:
"true if the process should be started without creating a new window to contain it; otherwise, false. The default is false."
Source: MSDN
This could help you aswell:
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
.NET - WindowStyle = hidden vs. CreateNoWindow = true?

Waiting for commands to be complete

I am working with a winform that runs a cmd in the background, redirecting input and output asynchronously.
Currently, the winform iterating through an array of commands, writing each to the cmd via the StreamWriter the StandardInput is redirected to. How can I force the loop to wait until the present command is complete in the cmd before writing the next line in?
EDIT: I took out all of my actual project code, and replaced it with this, a stripped down version of what I'm trying to do, only including components of my project relevant to my question.
public partial class Form1 : Form
{
public delegate void WriteToConsoleMethod(string text);
Process _process;
string[] _commands =
{
"echo hello world",
"echo my name is T.K.",
"echo Here is a list of commands"
};
public Form1()
{
InitializeComponent();
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd")
{
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
_process = Process.Start(processStartInfo);
_process.OutputDataReceived += new DataReceivedEventHandler(new DataReceivedEventHandler(DataReceived_EventHandler));
_process.ErrorDataReceived += new DataReceivedEventHandler(new DataReceivedEventHandler(DataReceived_EventHandler));
_process.BeginErrorReadLine();
_process.BeginOutputReadLine();
}
private void DataReceived_EventHandler(object sender, DataReceivedEventArgs e)
{
IAsyncResult result = this.BeginInvoke(new WriteToConsoleMethod(writeToConsole), new object[] { e.Data + Environment.NewLine });
this.EndInvoke(result);
}
private void writeToConsole(string output)
{
txtbxConsole.AppendText(output);
}
private void btnBegin_Click(object sender, EventArgs e)
{
foreach (string command in _commands)
{
_process.StandardInput.WriteLine(command);
// I want a way to pause here until the cmd has finished processing the command.
}
}
}
I don't think there is anything built-in that will support that. However you could send your own special command and then wait until you see this in the output for example ,
something like :
const string Separator= "---Command Completed--\xE3\xE2\xE1\xE0\xE3";
// Has to be something that won't occur in normal output.
volatile bool finished = false;
private void button1_Click(object sender, EventArgs e)
{
foreach (string command in _commands)
Run(command);
}
private void writeToConsole(string output)
{
if (output.IndexOf(Separator) >= 0)
finished = true;
else
richTextBox1.AppendText(output);
}
private void Run(string command)
{
finished = false;
_process.StandardInput.WriteLine(command);
_process.StandardInput.WriteLine("#echo " + Seperator);
while (!finished)
{
Application.DoEvents();
System.Threading.Thread.Sleep(100);
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
finished = true;
}
Assuming you are using System.Diagnostics.Process, then you probably need something like
ProcessStartInfo pi = new ProcessStartInfo(cmd);
pi.Arguments = ...
pi.WorkingDirectory = ...
Process myProcess = Process.Start(pi);
myProcess.WaitForExit();
I ended up solving this problem by wrapping my interaction with the command prompt into a separate class and instead of maintaining one prompt for all of the actions, I started up another prompt for each call. Then I take advantage of WaitForExit() to synchronize my threads.
After each command, I write in an exit command to close the process. I scan the output for exit calls, and when I find one, I use the context of that line to save the workspace so that the prompt for the next command will be made from the same working directory. I also had to hook up a DataRecievedEventHandler to parse out the header and exit calls before forwarding the EventHandlers to the winform.
The thing that's nagging me about this solution is that if the output of whatever process I'm running prints out exit, output scanner will behave as though it found the original exit. I employed the same solution sgmoore had in his answer - I write in exit [UNIQUE STRING] to the prompt, and scan the output for that, but I'm sure that's far from best practice.

Suppress command window from started command-line application with .NET

I have a module that needs to run a small .Net command-line program to check for updates. Everything is working great, however I am having trouble suppressing the Command Prompt output from being shown.
The app has it's own Windows Form that it pops up if it detected an update. Updating needs to run as a seperate app due to the fact that it requires a different execution context from the DLL it is launched from.
string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\" + AUTO_UPDATE_EXENAME;
updater.StartInfo.FileName = path;
updater.StartInfo.Arguments = AUTO_UPDATE_PARAMETERS;
updater.StartInfo.CreateNoWindow = false;
updater.StartInfo.UseShellExecute = false;
updater.StartInfo.RedirectStandardOutput = true;
updater.StartInfo.WorkingDirectory = path;
updater.Start();
I have tried most all of the different working combinations of CreateNoWindow, UseShellExecute, and RedirectStandardOutput and each of them results in that annoying black box popping up. The app does write to stdout but I only use that for debugging and the user shouldn't really see the text that it generates.
Supposedly CreateNoWindow and/or RedirectStandardOutput should prevent the box from popping up, but it does no matter how I set these variables.
Set the command-line application to a Winforms Application, but don't open a form when it executes, like you usually would.
You can hide the window on startup like this:
using System.Runtime.InteropServices;
namespace MyConsoleApp {
class Program {
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[STAThread()]
static void Main(string[] args)
{
Console.Title = "MyConsoleApp";
if (args.StartWith("-w"))
{
// hide the console window
setConsoleWindowVisibility(false, Console.Title);
// open your form
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run( new frmMain() );
}
// else don't do anything as the console window opens by default
}
public static void setConsoleWindowVisibility(bool visible, string title)
{
//Sometimes System.Windows.Forms.Application.ExecutablePath works
// for the caption depending on the system you are running under.
IntPtr hWnd = FindWindow(null, title);
if (hWnd != IntPtr.Zero)
{
if (!visible)
//Hide the window
ShowWindow(hWnd, 0); // 0 = SW_HIDE
else
//Show window again
ShowWindow(hWnd, 1); //1 = SW_SHOWNORMA
}
}
}
}
http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/ea8b0fd5-a660-46f9-9dcb-d525cc22dcbd
Here's an example code that interrogates the MAC on the active connection, this is a console application, no need to make this a Windows form...
public class TestARP
{
private StringBuilder sbRedirectedOutput = new StringBuilder();
public string OutputData
{
get { return this.sbRedirectedOutput.ToString(); }
}
// Asynchronous!
public void Run()
{
System.Diagnostics.ProcessStartInfo ps = new System.Diagnostics.ProcessStartInfo();
ps.FileName = "arp";
ps.ErrorDialog = false;
ps.Arguments = "-a";
ps.CreateNoWindow = true; // comment this out
ps.UseShellExecute = false; // true
ps.RedirectStandardOutput = true; // false
ps.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // comment this out
using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
{
proc.StartInfo = ps;
proc.Exited += new EventHandler(proc_Exited);
proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(proc_OutputDataReceived);
proc.Start();
proc.WaitForExit();
proc.BeginOutputReadLine(); // Comment this out
}
}
void proc_Exited(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("proc_Exited: Process Ended");
}
void proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
if (e.Data != null) this.sbRedirectedOutput.Append(e.Data + Environment.NewLine);
}
}
Now, look at the Run method, that is in Asynchronous mode, and runs as a single console window - in fact a normal console application with no extra window popping up, notice the comments, if you were to change those lines, it becomes a synchronous process shelling out, very quickly, you will notice that this console will create another window with the output of the command arp. Because it is in Asynchronous mode, the output gets redirected to an event handler which stuffs the data into the StringBuilder instance for further processing...
Hope this helps,
Best regards,
Tom.

Categories