Matt Barr
Matt Barr

Reputation: 494

How to hide / unhide a process in C#?

I am attempting to start an external process in a Visual C# 2010 - Windows Forms application. The goal is to start the process as a hidden window, and unhide the window at a later time.

I've updated my progress:

//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;

The following was placed in my main function:

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

However, because the window was started as "hidden," p.MainWindowHandle = 0. I am not able to successfully show the window. I have also tried HWND = p.Handle with no success.

Is there a way to provide a new handle to my window? This could potentially fix my problem.

References:

MSDN ShowWindow

MSDN Forums

How to Import .dll

Upvotes: 6

Views: 18369

Answers (4)

AyCe
AyCe

Reputation: 756

I had this problem trying to maximize a Windows App (calculator) again, after minimizing it. Getting the window to the front worked (SetForegroundWindow), but as soon as the window was minimized, the calculator app's window handle couldn't show it anymore (ShowWindow).

The problem with Windows Apps is that their actual top level windows are owned by the ApplicationFrameHost process. The window that the app has is just its "canvas", hence you cannot get the real handle via Process.MainWindowHandle. If you are confident that you know the title of the window you are looking for, you can enumerate all of ApplicationFrameHost's windows (EnumThreadWindows) and use GetWindowText to find the one that has the right title. You might also try your luck with FindWindow, though that didn't work for me.

I wasn't confident (different localizations!), but I also started the app myself. So I remember the list of windows in ApplicationFrameHost before launching the calculator app, and get it again a while later. Then I can compare them, to see which window is new. It's probably going to be that window! Not 100% safe, but seems to work so far. There are also the window titles MSCTFIME UI and Default IME multiple times (one for each real window), which I ignore.

Upvotes: 0

Matt Barr
Matt Barr

Reputation: 494

Finally, the process is operating properly. Thanks to all of your help, I came up with this fix.

The p.MainWindowHandle was 0, so I had to use the user32 FindWindow() function to get the window handle.

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

And in my main function:

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

References:

pinvoke.net: FindWindow()

Edit: Removed WindowShowStyle from the dllImport declaration: you can define this as an int instead. I defined an enum called WindowShowStyle to define the constants outlined in this article. It just better fits my coding patterns to have enums defined instead of using constant or hard-coded values.

Upvotes: 13

Peter Ritchie
Peter Ritchie

Reputation: 35881

The documention details that to use ProcessWindowStyle.Hidden you must also set ProcessStartInfo.UseShellExecute to false. http://msdn.microsoft.com/en-us/library/system.diagnostics.processwindowstyle.aspx

You would have to somehow know the window handle to unhide it later.

Upvotes: 1

Romil Kumar Jain
Romil Kumar Jain

Reputation: 20745

Sample code to unhide the window:

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

Upvotes: 2

Related Questions