views:

364

answers:

3

I have 2 programs (.exe) which I've created in .NET. We'll call them the Master and the Worker. The Master starts 1 or more Workers. The Worker will not be interacted with by the user, but it is a WinForms app that receives commands and runs WinForms components based on the commands it receives from the Master.

I want the Worker app to run completely hidden (except showing up in the Task Manager of course). I thought that I could accomplish this with the StartInfo.CreateNoWindow and StartInfo.WindowStyle properties, but I still see the Client.exe window and components in the form. However, it doesn't show up in the taskbar.

   Process process = new Process
      {
          EnableRaisingEvents = true,
          StartInfo =
              {
                  CreateNoWindow = true,
                  WindowStyle = ProcessWindowStyle.Hidden

                  FileName = "Client.exe",
                  UseShellExecute = false,
                  ErrorDialog = false,
              }
      };

What do I need to do to let Client.exe run, but not show up?

+1  A: 

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);
}
Chris Schmich
Chris, thanks so much for the suggestions. I'll give both a try and report back. I too figure it's some problem with what I have in the WinForms, but the MSDN docs don't imply that anything can override or disable those options.
Chad
Chad
@Chad: You are doing the `ShowWindow` from the master process and the `SetVisibleCore` in the worker process, correct? Have you tried putting a breakpoint in `SetVisibleCore`? Does it get hit? You could also try handling some Form events (see http://msdn.microsoft.com/en-us/library/system.windows.forms.form_events.aspx), e.g. `Load`, `GotFocus`, `VisibleChanged`, or `Activated`, and then try changing the visibility there. Are you using `System.Windows.Forms.WebBrowser`? I was able to hide a form hosting that control by using the `SetVisibleCore` method.
Chris Schmich
@Chris: Yes, ShowWindow is in the Master and SetVisibleCore is in the Worker. I printed out Form.Visible in the Worker and it is "false" in the form's constructor. Now, I'll look at the events to see if the visibility is changing elsewhere. My component:internal class FlashWebBrowser : WebBrowser{protected override void WndProc(ref Message m){ switch (m.Msg) { case 0x021: case 0x201: case 0x204: case 0x207: base.DefWndProc(ref m); return; } base.WndProc(ref m);}}via: http://tiredblogger.wordpress.com/2008/01/03/flash-and-proxy-support-on-net-webbrowser-controls/
Chad
@Chris: So, I tried intercepting VisibleChanged and setting Visible = false whenever it is triggered. This works almost 100%. I still see a small flicker when the Worker loads. For now, I can live with that and get back to more important features. Thanks for all your help - you got the answer.
Chad
A: 

If you dont want to show the window form, then why are you going for WinForms, why dont you go for a Windows Service?

Chinjoo
I wish I could! Unfortunately, out of necessity, my WinForms has a WebBrowser control.
Chad
then probably you can check this link: http://www.daniweb.com/forums/thread19672.html
Chinjoo
A: 

The problem is with UseShellExecute = false, set this to true and the process will be started as hidden. Using the shell to start the process understands how to make the application hidden, where as starting the process directly with UseShellExecute = false starts the process directly, and as Chris Schmich mentioned, you'd have to handle hiding the window from inside the client application. This might be more desirable if you want the option of running the application manually for debugging or testing purposes.

Jeff Schumacher
Jeff, thanks for your comments. Unfortunately, this also didn't work for me. I'm thinking it must have something to do with the components on my form, but I don't know why that would be the problem. Can you explain more how "Using the shell to start the process understands how to make the application hidden, where as starting the process directly with UseShellExecute = false starts the process directly"? Thanks.
Chad