SetForegroundWindow if child process has focus - c#

I've developed an application that starts external processes (e.g. like the notepad etc.) and displays the main window of the process inside a panel in my application. (Like described in this thread)
The problem is that I get a lot of focus problems with that. E.g. when a window is over my application's window and I click on the window of the sub process, the main window does not come to the foreground.
I've tried to solve this problem by calling SetForegroundWindow from the main application when the child process receives focus, but as this and this thread describes this only works if the process is being debugged or if it is the foreground process. There is a workaround by calling AttachThreadInput, but that doesn't work 100% reliable.
SetForegroundWindow should also work if "The process was started by the foreground process", but in my case it is the other way arround. (The foreground process was started by the process)
Is there a way to get the right to set the foreground window if the focussed window is a child process of my process?

SetForegroundWindow sets the thread that created the specified window into the foreground.
BringWindowToTop brings the specified window to the top of the Z order.

Related

How to distinguish between a program’s GUI and Console window?

I have written a code in c# that gets processes by name, activates the window of the desired process and sends some hotkeys to this process. The problem is that the desired process has two windows, a console window and a GUI window, as a result sometimes the GUI window is activated and everything works fine, but sometimes the console window is activated and nothing happens. So my question is, is there a way to distinguish between that process’ GUI and console window, so by program won’t get confused and only activate the GUI window ?
(By activating I mean bringing this process’ window to the foreground in order for the sending hotkeys to work. I have no access to the code of the desired process so I cannot change the way it starts up).

Get Active Subwindow

I want to check in an foreign application if a defined subwindow is opened and in foreground.
If I check it using winapi GetForegroundWindow I get the handle of the main window, instead of the actual active subwindow.
I can enumerate with winapi EnumWindows through all windows matching the title, but this will only provide the information, that the subwindow is open, but not if it is in foreground.
Howto merge both things?
Find the foreground window with GetForegroundWindow.
Find the thread that owns that window with GetWindowThreadProcessId.
Find the GUI info (active window, focus window, capture window etc.) for that thread with GetGUIThreadInfo.

Process does not kill on form close

I have just built version one of my testing application using Windows Forms. I have noticed that when running the application, it runs completely fine no hitches, exactly like the debug view. When it comes to closing the application I have noticed that the actual executable/process name hangs within Task manager and does not correctly close.
Upon further inspection I have noticed that when calling another form without hiding the previous form, a new process is spawned (kinda expected). When closing the new form (containing a few text boxes, labels and a DataGridView) the newly spawned process does not kill it's self, but remains. Then closing the main window the window disappears from the taskbar/view, but still, the processes remain active using 8,268k - 8,308k Memory
private void ClientSearch_Click(object sender, EventArgs e)
{
ClientSearch Clientsearch = new ClientSearch();
Clientsearch.Show();
}
Standard explanations for this behavior:
Hiding your main window when you display another window and forgetting to unhide it. There is no visible window anymore, nor can the user do anything to unhide it, but your app keeps motoring of course.
Starting a thread and not making sure that it is terminated when the main window closes. Setting the thread's IsBackground property to true is a workaround for that.
Calling Application.DoEvents() in your code. A very dangerous method that permits you to close the user interface but doesn't stop the loop in which it was called so the main thread of your app does not exit either.
This kind of problem is readily visible as well when you debug your app. You might have gotten in the habit of using the red rectangle on the toolbar (aka Debug + Stop Debugging) to force the debugger to quit. The Debug + Windows + Threads debugger window can provide insight into the cause of the last two bullets. Or you can use Tools + Attach to Process to attach the debugger to a zombie process.
Call
Application.Exit();
on form close/closing.
Your applications should only be creating one process per run. A new form should not be creating a new process.

Focus Windows Explorer From C# App In Task Bar

Our company has application that runs as a task bar icon - there is no UI besides the task bar icon.
Certain events cause the task bar to launch a explorer.exe to show a directory. User interaction does not cause this, so our application does not have focus.
I am able to show the directory in windows explorer using code like this:
Process.Start("explorer.exe", "c:\somedirectory");
The problem is, the folder launches in the background and I can't seem to give it focus.
Part of the problem is that the explorer.exe process exits immediately, launching the explorer.exe process separately. I am able to find the launched window using Process.processes() and looking at the window title and start time of the process.
Once I finally get a handle on the process (and wait for it to open), I'm trying to focus it. Here's what I've tried:
//trying to bring the application to the front
form.TopMost = true;
form.Activate();
form.BringToFront();
form.Focus();
Process process = ...;
ShowWindow(process.Handle, WindowShowStyle.ShowNormal);
SetForegroundWindow(process.Handle);
SwitchToThisWindow(process.Handle, true);
ShowWindow(process.MainWindowHandle, WindowShowStyle.ShowNormal);
SetForegroundWindow(process.MainWindowHandle);
SwitchToThisWindow(process.MainWindowHandle, true);
This makes the window blink in the task bar, but it still isn't focused.
How can I get the window to come to the front of the screen?
You could use the Shell.Application scripting interface to ask Explorer to create and show a new window. I believe this is also possible using a typed interface, but the exact one escapes me at the moment.
var shellApplication = Type.GetTypeFromProgID("Shell.Application");
dynamic shell = Activator.CreateInstance(shellApplication);
shell.Open(#"C:\drop\");
This seems open the window with focus (Tested on Win 8.1 using a timer which opens after 30 seconds, then navigating around in a focused web browser until the timer fires).
To focus explorer.exe, the application itself needed focus. WinForms intentionally makes this difficult since it could be abused.
Here's how you can steal focus in WinForms. Keep in mind that it may have bad consequences.
Once your application has focus, you can focus another process:
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
SetForegroundWindow(otherProcess.MainWindowHandle);
Here's how I found the explorer process. Like I said, the explorer.exe seems to launch another process and close, so the best option seemed to be to find the most recently launched explorer.exe process:
public static Process GetExplorerProcess()
{
var all = Process.GetProcessesByName("explorer");
Process process = null;
foreach (var p in all)
if (process == null || p.StartTime > process.StartTime)
process = p;
return process;
}
Another option that wouldn't require stealing focus is to show a message from your tray icon. Then you can setup a click handler to open/focus the folder. The application would naturally have focus from the click.
trayIcon.ShowBalloonTip(3000, "", msg, ToolTipIcon.Info);
This falls more in line with "don't annoy the user" but in my case the user is far more annoyed at having to click the bubble.
Update
Finding the explorer process requires admin privileges for your app. I've found that if you focus your own application first, then launch the folder, then the folder is automatically focused. In other words, there is no need to search through the current processes and call SetForegroundWindow.

Intercept Opening Window - C#

Is there some way to watch for / intercept a window opening in Windows and then to block said window from opening? This would be for an application that's already running and I wouldn't want to stop the process, just close the popup window it spawns.
Update:
A process is already running (e.g. it's in Task Manager) but has no visible windows.
At some random time, that process will popup a window
I manually close the window (click "OK").
The process continues to run at this point and will, again, popup a window a bit later (repeating these steps).
I want to automate step #3, where I have to manually close the popup, by intercepting that window opening and closing it or hiding it or never letting it open in the first place. I don't want to do this by polling the open windows. I want to receive some event that a window is about to open.
I do not control this other application, so I can't otherwise change it. And I don't want to kill the process, itself.
If you're trying to do what I asked (allow only one instance of a program to run at a time), here is an elegant solution using a Mutex. You can probably copy and paste most of that code to achieve what you want.

Categories

Resources