如何在C#中隐藏/取消隐藏进程?

5

我试图在一个Visual C# 2010 - Windows Forms应用程序中启动一个外部进程。目标是将该进程作为隐藏窗口启动,并在稍后的时间将窗口显示出来。

我已经更新了我的进展:

//Initialization
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hwnd, bool enable);
[DllImport("user32.dll")]
private static extern bool MoveWindow(IntPtr handle, int x, int y, int width, 
int height, bool redraw);

SW_SHOW = 5;

以下代码被放置在我的主函数中:
ProcessStartInfo info = new ProcessStartInfo("process.exe");
info.WindowStyle = ProcessWindowStyle.Hidden;
Process p = Process.Start(info);

p.WaitForInputIdle();
IntPtr HWND = p.MainWindowHandle;

System.Threading.Thread.Sleep(1000);    

ShowWindow(HWND, SW_SHOW);
EnableWindow(HWND, true);
MoveWindow(HWND, 0, 0, 640, 480, true);

然而,由于窗口是以“隐藏”的方式启动的,p.MainWindowHandle = 0。我无法成功地显示窗口。我还尝试了HWND = p.Handle,但没有成功。
有没有办法为我的窗口提供一个新的句柄?这可能会解决我的问题。
参考资料: MSDN ShowWindow MSDN论坛 如何导入.dll文件

1
隐藏一个进程?(不可靠)- 还是隐藏一个窗体? - Marc Gravell
隐藏进程窗口。为了举例说明,假设它是Internet Explorer:ProcessStartInfo info = new ProcessStartInfo("iexplore"); - Matt Barr
CreateNoWindow仅适用于控制台模式应用程序。 Hidden需要GUI应用程序合作并注意Windows传递给其WinMain()函数的“nCmdShow”参数。 但是,这经常被忽略。 除了联系所有者之外,您无法做任何事情。 - Hans Passant
我已经更新了我的进展。请给予建议,感谢您的反馈。 - Matt Barr
4个回答

11

最终,这个过程已经正常运转。感谢你们的所有帮助,我想出了这个修复方法。

p.MainWindowHandle 的值为0,因此我需要使用user32的FindWindow()函数来获取窗口句柄。

//Initialization
int SW_SHOW = 5;

[DllImport("user32.dll",SetLastError=true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

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

[DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hwnd, bool enabled);

在我的主函数中:

ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "notepad";
info.UseShellExecute = true;
info.WindowStyle = ProcessWindowStyle.Hidden;

Process p = Process.Start(info);
p.WaitForInputIdle();
IntPtr HWND = FindWindow(null, "Untitled - Notepad");

System.Threading.Thread.Sleep(1000);

ShowWindow(HWND, SW_SHOW);
EnableWindow(HWND, true);

参考资料:

pinvoke.net: FindWindow()

编辑: 从dllImport声明中删除了WindowShowStyle:您可以将其定义为int。我定义了一个名为WindowShowStyle的枚举来定义此文章中概述的常量。对我来说,使用枚举定义比使用常量或硬编码值更好地适合我的编码模式。


嗨,Matt,谢谢分享。我知道现在有点晚了,但是当我尝试这段代码时,Visual Studio无法识别WindowShowStyle。我已经检查了你提供的所有链接,但没有找到任何关于这种类型的提及 - 你能告诉我这是从哪里来的吗?(我指的是ShowWindow导入声明中第二个参数的类型) - Bassie
非常抱歉回复晚了!希望你已经找到所需的内容。 - Matt Barr

2

取消窗口隐藏的示例代码:

int hWnd;
Process[] processRunning = Process.GetProcesses();
foreach (Process pr in processRunning)
{
    if (pr.ProcessName == "notepad")
    {
        hWnd = pr.MainWindowHandle.ToInt32();
        ShowWindow(hWnd, SW_HIDE);
    }
}

等我回家试一下,如果可以的话,我会接受它。难道没有查找窗口的方法吗? - Matt Barr
1
重新阅读后,我有进一步的担忧。没有办法知道pr是我的进程。例如,如果我的程序打开了两个记事本窗口,那该怎么办?我想知道是否有更好的方法来识别我打开的窗口。 - Matt Barr

1

请提供文档。测试表明,ProcessStartInfo.UseShellExecute = trueProcessWindowStyle.Hidden 生效的唯一方式。 - Matt Barr
1
在 MSDN 上查找 ProcessWindowStyle 是被假定的;但是我已经为您添加了链接。 - Peter Ritchie
谢谢。不幸的是,出于某种原因,在我的情况下它不起作用。如上所述,我已经测试了truefalse。在使用false时,窗口未能隐藏。 - Matt Barr

0
我在尝试最大化一个Windows应用程序(计算器)时遇到了这个问题,之前已经将其最小化了。将窗口置于前台是可以的(SetForegroundWindow),但是一旦窗口被最小化,计算器应用程序的窗口句柄就无法显示它了(ShowWindow)。
Windows应用程序的问题在于它们的实际顶级窗口是由ApplicationFrameHost进程拥有的。应用程序拥有的窗口只是它的“画布”,因此你无法通过Process.MainWindowHandle获取真正的句柄。如果你确信知道你要查找的窗口的标题,你可以枚举所有ApplicationFrameHost的窗口(EnumThreadWindows),并使用GetWindowText来找到具有正确标题的窗口。你也可以尝试使用FindWindow,但对我来说没有起作用。
我并不自信(不同的本地化!),但我也自己启动了应用程序。所以我记得在启动计算器应用程序之前,在ApplicationFrameHost中的窗口列表,并在一段时间后再次获取它们。然后我可以比较它们,看看哪个窗口是新的。这可能就是那个窗口!虽然不是100%安全,但目前似乎还可以工作。还有窗口标题MSCTFIME UI和Default IME多次出现(每个真实窗口都有一个),我忽略它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接