.Net - Windowstyle = Hidden VS. Createnowindow = True

.NET - WindowStyle = hidden vs. CreateNoWindow = true?

As Hans said, WindowStyle is a recommendation passed to the process, the application can choose to ignore it.

CreateNoWindow controls how the console works for the child process, but it doesn't work alone.

CreateNoWindow works in conjunction with UseShellExecute as follows:

To run the process without any window:

ProcessStartInfo info = new ProcessStartInfo(fileName, arg); 
info.CreateNoWindow = true;
info.UseShellExecute = false;
Process processChild = Process.Start(info);

To run the child process in its own window (new console)

ProcessStartInfo info = new ProcessStartInfo(fileName, arg); 
info.UseShellExecute = true; // which is the default value.
Process processChild = Process.Start(info); // separate window

To run the child process in the parent's console window

ProcessStartInfo info = new ProcessStartInfo(fileName, arg); 
info.UseShellExecute = false; // causes consoles to share window
Process processChild = Process.Start(info);

C# - Launch Invisible Process (CreateNoWindow & WindowStyle not working?)

Your usage of CreateNoWindow/WindowStyle works fine on my system with notepad.exe (e.g. it is hidden but running in the background), so it's probably something the WinForms app is doing. Some ideas:

Option 1: If you control the WinForms worker process, you can override Control.SetVisibleCore to always hide the form. If you don't want to always hide it, you can pass a command-line argument to it, e.g. /hide that will cause it to be hidden. Example (assuming there's already code-behind for the form):

public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
}

protected override void SetVisibleCore(bool value)
{
// You'd probably want to parse the command line.
if (Environment.CommandLine.Contains("/hide"))
base.SetVisibleCore(false);
else
base.SetVisibleCore(value);
}
}

With this, running MyForm.exe results in a process with a visible form. Running MyForm.exe /hide results in a process with a hidden form. You could pass the /hide argument from your master process, so then normal users running the application will still see it.

Option 2: You can hide the application after it starts by doing a P/Invoke to ShowWindow. More info on this here. This has the drawback that you can sometimes see the worker window flicker into existence before being hidden. Example:

class Program
{
public static void Main(string[] args)
{
ProcessStartInfo psi = new ProcessStartInfo()
{
FileName = @"C:\windows\system32\notepad.exe",
};

Process process = Process.Start(psi);

// Wait until the process has a main window handle.
while (process.MainWindowHandle == IntPtr.Zero)
{
process.Refresh();
}

ShowWindow(process.MainWindowHandle, SW_HIDE);
}

const int SW_HIDE = 0;

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}

C# I can't get CreateNoWindow to work - not even the msdn.com example

It makes most sense to first try from a cmd.exe

then from there understand the behaviour when running from visual studio

The word new in CreateNoNewWindow, is a bit misleading. It's more like it creates no window and even uses no window.

If you have CreateNoNewWindow=false (the default), then it will run that child cmd in the parent window. (that may seem strange but if you compare it to what happens when CreateNoNewWindow=true then it's not so strange). When you run the program you'll see it says the cmd banner with Copyright e.t.c. that's from the child cmd running in the parent window.

If you have CreateNoNewWindow=true and you run your program then it will output nothing. Task manager will still show the second cmd.exe that is because it is running the child cmd.exe but not in any cmd window at all.

Now for the behaviour within visual studio.

With Visual studio console applications when you click play, visual studio will pop up its cmd window which disappears once the program has completed, but any spawned processes would live on.

With visual studio, If you have CreateNoNewWindow set to true (i.e. use no window at all), then it will pop up its cmd window, spawn the second cmd in no window, so it's invisible, then the parent cmd window will close and the spawned child cmd.exe will continue to show in task manager but will have no window. So task manager will show one cmd.exe, and you'll see no window.

As a test before testing the paragraph below, you can create a cmd window, sdfsdfds so you have something in command history accessible with up arrow so you can see whether you're in the parenet command or not. Then start a child process. type cmd<ENTER>. Now kill the parent. The child is still there.

With visual studio, if you have CreateNoNewWindow set to false(i.e. use the parent window), (this, as we have seen, is possible even after a parent process has been killed, if the child was created and using that window, before the parent was killed) then click play, then visual studio will flick up its cmd window as it does, and it will spawn a child cmd.exe process and task manager only shows one cmd.exe process but in a window, and the play button shows as active again, so the program must have completed execution, and the parent process was completed. So visual studio closed the parent cmd.exe but the child is still there still using the parent's window as it was prior to the parent cmd.exe being completed.

That's for when a visual studio project is set to console application, where a console will always at least flick up.

But for a project that isn't created as a console application e.g. for a winforms application, the console can be set to hide, and no console would flick up or need to be run at all even for the main program.

Note here- UseShellExecute and CreateNoWindow are being set to their non default values. UseShellExecute is by default true, and we set it to false because when UseShellExecute is true then CreateNoWindow ignores the value of itself(CreateNoWindow), and a new window is created(even if CreateNoWindow is set to true). CreateNoWindow is by default false, and we set it to true. If you are going to use CreateNoWindow, then the only non superfluous and working use case would be UseShellExecute=false and CreateNoWindow=true. (If UseShellExecute=true(default) then you should use process window style hidden.. ) Also bear in mind these things work for cmd.exe but fail for some other things like calc.exe

ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
Process.Start(psi);

Hiding the process window, why isn't it working?

In my experience, the following works whenever I fire up "cmd.exe".

info.CreateNoWindow = true;
info.UseShellExecute = false;

It doesn't seem to work with "notepad.exe". It fails with other apps too, like "excel.exe" and "winword.exe".

This works, however:

ProcessStartInfo info = new ProcessStartInfo("notepad.exe");

info.WindowStyle = ProcessWindowStyle.Hidden;

Process proc = Process.Start(info);

From MSDN:

A window can be either visible or hidden. The system displays a hidden window by not drawing it. If a window is hidden, it is effectively disabled. A hidden window can process messages from the system or from other windows, but it cannot process input from the user or display output. Frequently, an application may keep a new window hidden while it customizes the window's appearance, and then make the window style Normal. To use ProcessWindowStyle.Hidden, the ProcessStartInfo.UseShellExecute property must be false.

When I tested it, I didn't have to set UseShellExecute = false.

C# - Command window appears a tenth of a second before disappear

For the Code Blocks as shown in your question, the behavior is normal.

Let's have a look at them...

//[...]
procInfo.CreateNoWindow = false; //That's not what you meant
procInfo.UseShellExecute = false;
process.Start(); //Will show up the console window
process.CloseMainWindow(); //Will close the main window (probably also the whole application)

Between process.Start(); and process.CloseMainWindow(); is a short time frame, where the application is visible.

Like described by @BugFinder, it should be enough to edit the CreateNoWindow Value from false to true.

Check if that works.

Your second try is getting you further away:

process.Start();
while (process.MainWindowHandle == IntPtr.Zero)
{
process.Refresh(); //Let's do this as long as there is no window...
}
var handle = process.MainWindowHandle; //This occurs, when there is *already* a window.
ShowWindow(handle, 0) //ShowWindow from user32.dll

The idea of using Shell Functions is basically not bad, but this code is doing the same like the code above (and is also unmanaged).

Let's try a different way and take the C# Sample from PInvoke.Net: (not more managed than ShowWindow()...)

public static void StartupNotepad()
{
const uint NORMAL_PRIORITY_CLASS = 0x0020;
const uint STARTF_USESHOWWINDOW = 0x1; //IMPORTANT for you
bool retValue;
string Application = Environment.GetEnvironmentVariable("windir") + @"\Notepad.exe";
string CommandLine = @" c:\boot.ini"; //Funny
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
STARTUPINFO sInfo = new STARTUPINFO();
sInfo.wShowWindow = 0; //IMPORTANT for you - See http://pinvoke.net/default.aspx/Enums/ShowWindowCommand.html
sInfo.dwFlags = STARTF_USESHOWWINDOW; //IMPORTANT for you
SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
retValue = CreateProcess(Application,CommandLine,
ref pSec,ref tSec,false,NORMAL_PRIORITY_CLASS,
IntPtr.Zero,null,ref sInfo,out pInfo);

Console.WriteLine("Process ID (PID): " + pInfo.dwProcessId);
Console.WriteLine("Process Handle : " + pInfo.hProcess);
}

This example demonstrates the use of CreateProcess (MSDN Link at the bottom) in a very static manner.

I suggest you to write a more dynamic function and play around with it. The PROCESS_INFORMATION structure allows you to manipulate the newly created process later in your application. If your problem still persists using the CreateProcess() Call, it's to check whether the started application does some tricky stuff on itself. And last but not least whether the problem occurs not only on your computer...

Here are some more references:

  • SO: WindowStyle.Hidden vs. CreateNoWindow = True
  • SO: How to call CreateProcess() with STARTUPINFOEX from C# and re-parent the child
  • SO: winapi: CreateProcess but hide the process' window?
  • MSDN: ProcessStartInfo.CreateNoWindow Property
  • MSDN: CreateProcess() Function
  • MSDN: STARTUPINFO Structure

EDIT:

Probably a workaround, but if your 3rd party App is designed to show a Window and tries to ignore your requests, STARTUPINFO also has dwX and dwY, which sets the Window's position if dwFlags specifies STARTF_USEPOSITION. Same for dwXSize and dwYSize.

If all else fails, you could give it a try and pass positions and sizes, which make the proces appear invisible. Cheers.

what is the difference between ProcessStartInfo's UseShellExecute and CreateNoWindow?

It plays no role. The rule is that CreateNoWindow will only have an effect when:

  1. You use UseShellExecute = false so that the CreateProcess() winapi is used to start the program
  2. The program you start is a console mode application.

If the app is a native Windows GUI app that creates it own window then you can ask it to not create a visible window with WindowStyle = ProcessWindowStyle.Hidden. There are however a lot of programs that ignore this request. They should, only way to stop it is through Task Manager. Next reasonable choice is ProcessWindowStyle.Minimized



Related Topics



Leave a reply



Submit