views:

681

answers:

2

I am using the ShowWindow method from User32 to hide a window (cmd.exe) from the user (mainly to prevent them from closing it). When the user opens the form, the process is started, and hid, then when the form is closing the process is killed. However, when the form is opened again, it doesn't hide the window (and sometimes doesn't the first time) Can someone help me with this?

    [DllImport("User32")]
    private static extern int ShowWindow(int hwnd, int nCmdShow);   //this will allow me to hide a window

    public ConsoleForm(Process p) {
        this.p = p;
        p.Start();
        ShowWindow((int)p.MainWindowHandle, 0);   //0 means to hide the window. See User32.ShowWindow documentation SW_HIDE

        this.inStream = p.StandardInput;
        this.outStream = p.StandardOutput;
        this.errorStream = p.StandardError;

        InitializeComponent();

        wr = new watcherReader(watchProc);
        wr.BeginInvoke(this.outStream, this.txtOut, null, null);
        wr.BeginInvoke(this.errorStream, this.txtOut2, null, null);
    }

    private delegate void watcherReader(StreamReader sr, RichTextBox rtb);
    private void watchProc(StreamReader sr, RichTextBox rtb) {
        string line = sr.ReadLine();
        while (line != null && !stop && !p.WaitForExit(0)) {
            //Console.WriteLine(line);
            line = stripColors(line);
            rtb.Text += line + "\n";

            line = sr.ReadLine();
        }
    }

    public void start(string[] folders, string serverPath) {

        this.inStream.WriteLine("chdir C:\\cygwin\\bin");
        //this.inStream.WriteLine("bash --login -i");
        this.inStream.WriteLine("");
    }

    private void ConsoleForm_FormClosed(object sender, FormClosedEventArgs e) {
        this.stop = true;
        try {
            this.p.Kill();
            this.p.CloseMainWindow();
        } catch (InvalidOperationException) {
            return;
        }
    }
+3  A: 

It would be MUCH easier to this:

public ConsoleForm(Process p) {
        this.p = p;
        p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        p.StartInfo.CreateNoWindow = true;
        p.Start();

        this.inStream = p.StandardInput;
        this.outStream = p.StandardOutput;
        this.errorStream = p.StandardError;

        InitializeComponent();

        wr = new watcherReader(watchProc);
        wr.BeginInvoke(this.outStream, this.txtOut, null, null);
        wr.BeginInvoke(this.errorStream, this.txtOut2, null, null);
    }
scottm
Worked perfectly, thanks!
Malfist
A: 

Have you checked whether p.MainWindowHandle is a valid handle? It must be non-zero, at the very least. Try calling IsWindow to confirm.

MSDN suggests calling WaitForInputIdle before checking MainWindowHandle; you might be accessing the property before the new process has created its window. The property is inherently precarious anyway, though, because processes don't really have a notion of the "main" window. All windows are treated equally. The .Net framework simply designates the first window as the main one, but the process itself doesn't need to consider things that way.

Also, have you considered simply hiding the process initially, instead of starting it and then hiding after the fact? Set the process's StartInfo properties as Scotty2012 demonstrates.

Rob Kennedy