User32的ShowWindow没有按预期运行

时间:2023-01-28 07:29:42

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?

我使用User32的ShowWindow方法隐藏用户的窗口(cmd.exe)(主要是为了防止它们关闭它)。当用户打开表单时,进程启动并隐藏,然后当表单关闭时,进程被终止。但是,当窗体再次打开时,它不会隐藏窗口(有时不是第一次)有人可以帮我这个吗?

    [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;
        }
    }

2 个解决方案

#1


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);
    }

#2


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

你检查过p.MainWindowHandle是否是一个有效的句柄?它至少必须是非零的。尝试调用IsWindow进行确认。

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.

MSDN建议在检查MainWindowHandle之前调用WaitForInputIdle;您可能在新进程创建窗口之前访问该属性。不过,该属性本质上是不稳定的,因为进程实际上没有“主”窗口的概念。所有窗户都得到平等对待。 .Net框架只是将第一个窗口指定为主窗口,但该过程本身不需要考虑这种方式。

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.

另外,您是否考虑过最初只是隐藏进程,而不是启动它然后隐藏在事实之后?如Scotty2012演示的那样设置进程的StartInfo属性。

#1


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);
    }

#2


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

你检查过p.MainWindowHandle是否是一个有效的句柄?它至少必须是非零的。尝试调用IsWindow进行确认。

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.

MSDN建议在检查MainWindowHandle之前调用WaitForInputIdle;您可能在新进程创建窗口之前访问该属性。不过,该属性本质上是不稳定的,因为进程实际上没有“主”窗口的概念。所有窗户都得到平等对待。 .Net框架只是将第一个窗口指定为主窗口,但该过程本身不需要考虑这种方式。

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.

另外,您是否考虑过最初只是隐藏进程,而不是启动它然后隐藏在事实之后?如Scotty2012演示的那样设置进程的StartInfo属性。