Reputation: 494
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:
Upvotes: 6
Views: 18369
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
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:
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
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
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