C# Find and handle child processes of a process - c#

i need help finding the child processes (they are 2) of a process and handle them in order to set each of them foreground when needed.
The main process is Java Platform SE binary whose indicative name is javaw.
Using this code:
Process[] arrProcesses = Process.GetProcessesByName("javaw");
I can get the main process, so with:
IntPtr ipHwnd = arrProcesses[0].MainWindowHandle;
SetForegroundWindow(ipHwnd);
I can set it foreground.
My problem is that the handled process is the "last used" process...
Explaning better: on application bar of Windows I have 2 application(A, B) using java, if i click on A, when i use the code above, the application A gets foreground, insted, if i click on application B, with that code the B gets foreground.
What i want to do is decide which of two set foreground.
Anyone can help me?

Related

C# monitor external process state

I am making a launcher app in C# on windows. However the process isn't directly started by my C# application but it uses a url to start it e.g "steam://rungameid/xxxxxxx"
I need it to monitor a process by name (say XYZ.exe) in the following fashion:
Receive an event when XYZ.exe starts
Receive an event when XYZ.exe exits
I just want to minimise and restore the my C# application's form when the application is running and not running respectively
thanks
Make a timer (with your preferred timer method) and poll every 'n' milliseconds (find what's best for you... I'd say for minimizing/restoring from a game, 500 milliseconds could be a good start, but experiment), then you can use something like:
bool processRunning = false;
void timerTickMethod()
{
var procIsRunning = Process.GetProcessesByName("xyz.exe").Any();
if(procIsRunning && !processRunning)
ProcessIsStartedEvent(); // or directly minimize your app
else if(!procIsRuning && processRunning)
ProcessIsEndedEvent(); // or directly restore your app
processRunning = procIsRunning;
}
If you want to make sure it's your xyz.exe that is running, you can pass in the full path to GetProcessesByName (so that if there's other xyz.exe in your system, it won't confuse your app)
Update
I was writing from memory, so maybe GetProcessesByName only work for friendly names (with no exe, or path).
If that's the case (I haven't tried), and you need the full path you could do it like:
var procIsRunning = Process.GetProcesses().Any(x => x.MainModule.Filename == #"c:\your\full\path.exe");

user32 GetClassName isn't correct

I have a routine that get's all open windows (processes) and then searches for it's classname with the GetClassName method in user32. But when for example Teamviewer is on the classnames of all applications get the teamviewer classname.
Example: Notepad is open and TeamViewer on classname: 'TeamViewer_TitleBarButtonClass'
Notepad is open and TeamViewer off classname: 'Notepad'
I looked how this came and found out that Teamviewer puts a control on top of some application windows.
So how can i find the real classname of the applications and not from Teamviewer?
Process[] processes = Process.GetProcesses();
StringBuilder className = new StringBuilder(100);
For (int i = 0; i < processes.Length; i++)
{
if (processes[i].MainWindowHandle != IntPtr.Zero)
{
list.Add(processes[i]);
GetClassName(processes[i].MainWindowHandle, className, className.Capacity);
}
}
The heuristic that the Process class uses to guess which window is the "main" window is not perfect. There isn't any way for an app to mark the windows it creates as "this is the main one". So it punts at the best guess: the first window. This certainly can go wrong, you may find a hidden login window for example.
An alternative is to enumerate the threads in the process from Process.Threads, then for each thread to enumerate the windows it owns with EnumThreadWindows(), calling GetClassName() on each. You'll get to see all of the windows that way and should run across the one you are looking for. Using EnumWindows() is an alternative when can't be selective about the process. That also avoids the crash your current code suffers from when it happens to enumerate the "System" process too early.
The best to deal with intrusive software like this "TeamViewer" is to just uninstall it.

Send fast textinput to another process (Window)

I am writing a C# WPF program which sends text messages to another program's window. I have a macro program as part of my keyboard drivers (Logitech g15) which already does this, though it does not send keystrokes directly to the process, but to the currently focused window. It works well but i need to be able to send inputs from my program as well. There are other people using the process so the input text messages from my program needs to be fast enough so that my text does not interfere with their input.
The problem is that when I try to do this with a c# program I get too much delay. The macro program (Logitech G-Series Profiler) sends a command instantly. I have tried the following three commands for sending messages to process. (Listed by order of slowest to fastest)
SetForegroundWindow(_hWnd);
SendKeys.SendWait("{Enter}This is a keystroke input.{Enter}");
It is probably in the name, but this performs the command so slowly that I can actually follow with my eyes the text as it is input letter by letter. I have tried using the “SendKeys.Send” method but I get an error saying: “SendKeys cannot run inside this application because the application is not handling Windows messages.”
PostMessage((IntPtr)_hWnd, (uint)WMessages.WM_KEYUP, (int)key, (int)key);
PostMessage is a bit faster but still not fast enough for the purpose of my program. Besides the method returns before the message has been read by the process, which means two sequential PostMessage calls may not send sequential messages.
SendMessage(_hWnd, 0x100, (int) VKeys.VK_2, (int) VKeys.VK_2);
This is faster than the PostMessage but not nearly as fast as the macro program from Logitech. Also, the receiving program handles the input strangely, apparently not treating it the same way it does "genuine" input from the keyboard.
SetForegroundWindow(_hWnd);
const string text = "This is a keystroke input.";
IInputElement target = Keyboard.FocusedElement;
IInputElement target = InputManager.Current.PrimaryKeyboardDevice.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;
target.RaiseEvent(new TextCompositionEventArgs(InputManager.Current.PrimaryKeyboardDevice, new TextComposition(InputManager.Current, target, text)) { RoutedEvent = routedEvent });
This is the last thing I have tried. It seems instant with the way the text is sent to a process. However, I have only been able to send this to my own program since Keyboard.FocusedElement returns null when I have another program set as foreground window.
If someone can tell me how to get an IInputElement of another window I would sure like to know. Alternatively, if someone has a suggestion for a better method of sending input, I would dearly like to hear it.
Specs: Windows 7, 64bit
Visual Studio 2010, Framework 4
First of all, are you intentionally using WM_KEYDOWN (0x0100) instead of WM_KEYUP (0x0101) in your SendMessage example? This would just press the keys, and never release them, so the application would not process them properly.
Another way worth trying would be to send WM_SETTEXT, assuming the control interprets it correctly (like edit controls or combo boxes).
A last option would be to use SendInput which synthesizes keyboard and mouse input on a very low level, but similarly to you keyboard's macro program, this requires you to activate the correct window and set the focus, which can be quite painful.
Depending on your other's program window type, you could use UI Automation. See this example here:
Add Content to a Text Box Using UI Automation

Get Child window using ProcessID or Window Handle?

My program A launched program B (both are separate exe's). Now my program B need to find if A have any modal/child window open using A's processID.
Is there any way to do so?
Thanks a lot for your help.
You might be able to use some of the suggestions from this question (if you don't mind using Win32 calls).
I found the soln.
1. Get handle of parent window A.
PerformanceCounter perId = new PerformanceCounter("Process", "Creating Process ID", Process.GetCurrentProcess().ProcessName);
2. Use GetLastActivePopup method to get last active popup (Last popup works in my case :) ) .

.NET (C#): Getting child windows when you only have a process handle or PID?

Kind of a special case problem:
I start a process with System.Diagnostics.Process.Start(..)
The process opens a splash screen -- this splash screen becomes the main window.
The splash screen closes and the 'real' UI is shown. The main window (splash screen) is now invalid.
I still have the Process object, and I can query its handle, module, etc. But the main window handle is now invalid.
I need to get the process's UI (or UI handle) at this point. Assume I cannot change the behavior of the process to make this any easier (or saner).
I have looked around online but I'll admit I didn't look for more than an hour. Seemed like it should be somewhat trivial :-(
If you don't mind using the Windows API, you could use EnumWindowsProc, and check each of the handles that that turns up using GetWindowThreadProcessId (to see that it's in your process), and then maybe IsWindowVisible, GetWindowCaption and GetWindowTextLength to determine which hWnd in your process is the one you want.
Though if you haven't used those functions before that approach will be a real pain, so hopefully there's a simpler way.
#ageektrapped is on the right track, however FindWindow will not search child windows.
For that you will need to use FindWindowEx
Thank you for your answers. Thanks to you here, I figured out how to know if the main window of a process is in front or not:
N.B : of course this needs System.Diagnostic and System.Runtime.Interrop
public bool IsWindowActive(Int32 PID)
{
return IsWindowActive(Process.GetProcessById(PID));
}
[DllImport("user32.dll")]
private static extern
IntPtr GetForegroundWindow();
public bool IsWindowActive(Process proc)
{
proc.Refresh();
return proc.MainWindowHandle.Equals(GetForegroundWindow());
}
You may find that if you call .Refresh() that you get the new top-level window.
If you know the window's title, you can use the Win32 call, FindWindow, through P/Invoke.
You can find the signature here on pinvoke.net
From what I understand MainWindowHandle property of the process you are starting is not valid. If that's the case, you can use FindWindow function (from Win32 SDK) which returns the window handle you need. All you need is the class name of target application's main window. You can obtain it using Spy++ or Winspector. You also need to ensure you have the right window by checking that window's process id using GetWindowThreadProcessId.
At last, I have to say I am not an expert on Win32 and there might be a better solution for your case.
Use Process.GetProcessById(proc.Id); where proc was your splash screen.
Works for me.
Now, how do you get to main window properties in System.Windows.Forms to give it focus w/o using win32?
After all .net is supposed to be a one-stop solution - is it not?
Somewhere in the code, the "real" main window is created. You can just save the window handle at that time and then after the splash screen closes you can set Application.MainWindow to the real window.
The MainWindowHandle property is cached after it is first accessed which is why you don't see it changing even after the handle becomes invalid. GregUzelac's information is correct. Calling Proces.Refresh will causes the next call to Process.MainWindowHandle to re-do the logic to find a new main window handle. Michael's logic also works because the new Process doesn't have a cached version of the MainWindowHandle.

Categories

Resources