2

Below is my code. Here you can see that i am using constant for hide/show the window. Hide the other application from the another application in 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);
            }
        }
    }
Eugene
  • 2,965
  • 2
  • 34
  • 39

2 Answers2

2

When visible the MainWindowHandle is non-zero, after the Window is hidden the handle gets set to 0. I haven't found a way yet to get the required handle - maybe a work around would be to maintain a list of the windows you have hidden.

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

NOTE - rather than iterate through all processes returned by GetProcesses - you can use GetProcessesByName just to get the processes you are interested in.

There is an answer here based on other User32 functions - but seems quite complex : Unhide process by its process name?

A quick test with a WPF application showed multiple Window handles found using the code in the linked solution - the answer is to remove the return after the call to ShowWindow. I have added a modified version below to reopen multiple application instances if required.

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

NOTE that I have modified the ShowWindow definition to use an IntPtr as the type for the Window handle - this is the preferred type to use & it is the actual type of MainWindowHandle. In your hide method just change the code to be

IntPtr hWnd = pr.MainWindowHandle;

or the entire loop to

foreach (Process pr in processRunning)
{
  ShowWindow(pr.MainWindowHandle, SW_HIDE);
}
PaulF
  • 6,673
  • 2
  • 18
  • 29
  • Thank you PaulF. You solution is correct. But in my scenario, i want to close the first application after hiding the another application. And again when i start my first application, i want to show the hidden application. – Ankit Upadhyay Mar 06 '19 at 04:29
  • Unfortunately, once hidden the application has no window - so the applications MainWindowHandle is set to zero. The answer in the link I added should do the trick - getting the process ID & then a brute force search of all available windows to find the one attached to process matched by ID. – PaulF Mar 06 '19 at 11:53
  • i try as given in your link,it does not work also i try ShowWindow(handle, SW_RESTORE); // Restore Windows ShowWindow(handle, SW_SHOW); //Show Window SetForegroundWindow(handle); – Ankit Upadhyay Mar 06 '19 at 14:06
  • @AnkitUpadhyay: I have updated with code that works for me based on the original link code. – PaulF Mar 06 '19 at 14:41
  • I try on Notepad, that working good, My problem is in some condition the application is start without UI. So without load UI how can i show the UI? – Ankit Upadhyay Mar 07 '19 at 06:08
  • I don't think I can help on that particular problem - if the application starts up without a UI under normal conditions, how would you get it to display? What was the value of MainWindowHandle when you hid it - it may have been 0 if it had no main window? – PaulF Mar 07 '19 at 09:49
0

This is how Process.GetProcess() works.

Once you hide the main window of process its MainWindowHandle for next iteration over processes will become IntPtr.Zero. It has something to do with how MainWindowHandle is retrieved I guess.

Solutions:

  1. enumerate processes once
  2. store hWnd (e.g. in Dictionary<string, int>) and call ShowWindow() without retrieving processes again.
Sinatr
  • 20,892
  • 15
  • 90
  • 319