隐藏Windows表单后无法将其显示回来

时间:2019-03-05 13:29:06

标签: c# .net

下面是我的代码。在这里您可以看到我使用常量来隐藏/显示窗口。在C#.net中的另一个应用程序中隐藏另一个应用程序。

    private const int SW_HIDE = 0;
    private const int SW_SHOW = 5;

    [DllImport("User32")]
    private static extern int ShowWindow(int hwnd, int nCmdShow);

    private void btnHide_Click(object sender, EventArgs e){

        Process[] processRunning = Process.GetProcesses();
        foreach (Process pr in processRunning){

            if (pr.ProcessName == FileName){
                hWnd = pr.MainWindowHandle.ToInt32();
                ShowWindow(hWnd, SW_HIDE);
            }
        }
    }

    private void btnShow_Click(object sender, EventArgs e){

        Process[] processRunning = Process.GetProcesses();

        foreach (Process pr in processRunning){
            if (pr.ProcessName == FileName){

                hWnd = pr.MainWindowHandle.ToInt32();
                ShowWindow(hWnd, SW_SHOW);
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

当可见的MainWindowHandle不为零时,在隐藏窗口之后,将句柄设置为0。我还没有找到获取所需句柄的方法-可能的解决方法是维护列表隐藏的窗户。

List<int> HiddenWindows = new List<int>();

private void btnHide_Click(object sender, RoutedEventArgs e)
{
  Process[] processRunning = Process.GetProcessesByName(FileName);
  foreach (Process pr in processRunning)
  {
    int hWnd = pr.MainWindowHandle.ToInt32();
    if (hWnd == 0)
      continue;
    ShowWindow(hWnd, SW_HIDE);
    HiddenWindows.Add(hWnd);
  }
}

private void btnShow_Click(object sender, RoutedEventArgs e)
{
  foreach (int hWnd in HiddenWindows)
  {
    ShowWindow(hWnd, SW_SHOW);
  }
  HiddenWindows.Clear();
}

注意-您可以使用GetProcessesByName来获取您感兴趣的进程,而不是遍历GetProcesses返回的所有进程。

这里有一个基于其他User32函数的答案-但看起来很复杂:Unhide process by its process name?

使用WPF应用程序进行的快速测试显示,使用链接的解决方案中的代码找到了多个Window句柄-答案是删除对ShowWindow的调用后的返回值。我在下面添加了修改后的版本,以便在需要时重新打开多个应用程序实例。

private const int SW_SHOW = 5;
private String FileName = "notepad";

[DllImport("User32")]
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("User32.dll")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string strClassName, string strWindowName);

[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);

private void btnShow2_Click(object sender, RoutedEventArgs e)
{
  //an array of all processes with name "processName"
  Process[] localAll = Process.GetProcessesByName(FileName);

  foreach (var pr in localAll)
  {
    IntPtr hWnd = IntPtr.Zero;
    int prcsId = 0;

    //check all open windows (not only the process we are looking) begining from the
    //child of the desktop, handle = IntPtr.Zero initialy.
    do
    {
      //get child handle of window who's handle is "handle".
      hWnd = FindWindowEx(IntPtr.Zero, hWnd, null, null);
      GetWindowThreadProcessId(hWnd, out prcsId); //get ProcessId from "handle"

      //if it matches what we are looking
      //Note there maybe multiple Windows found - so try all of them
      if (prcsId == pr.Id)
        ShowWindow(hWnd, SW_SHOW); //Show Window
    } while (hWnd != IntPtr.Zero);
  }
}

请注意,我已经修改了ShowWindow定义以将IntPtr用作Window句柄的类型-这是首选的类型,并且它是MainWindowHandle的实际类型。在您的hide方法中,只需将代码更改为 是

IntPtr hWnd = pr.MainWindowHandle;

或整个循环

foreach (Process pr in processRunning)
{
  ShowWindow(pr.MainWindowHandle, SW_HIDE);
}

答案 1 :(得分:0)

Process.GetProcess()的工作方式。

隐藏进程的主窗口后,其MainWindowHandle的下一次迭代将变为IntPtr.Zero。我猜这与如何检索MainWindowHandle有关。

解决方案:

  1. 枚举一次进程
  2. 存储hWnd(例如,在Dictionary<string, int>中)并调用ShowWindow(),而无需再次检索进程。