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 :) ) .
Related
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?
I have two .NET applications:
parent-app.exe (WPF)
child-app.exe (WinForms)
The first application starts the second one
parent-app.exe → child-app.exe
by means of the class System.Diagnostics.Process.
When user clicks a button on the interface of the parent-app.exe, I start the process of child-app.exe immediately. Because child-app.exe is a .NET application, is takes some time before user could see the window (especially, on slow systems).
I want to show the user an intermediate (possibly dialog) window from parent-app.exe. This dialog window should say that user action is being processed and he should wait for the window of child-app.exe to show up.
Questions:
How can I check from parent-app.exe visibility state of the window of child-app.exe?
Here is the longer question. How would you implement this system of showing intermediate window by taking into account the restriction
that both programs use .NET?
As suggested here, you can try calling the Process.WaitForInputIdle method to wait for the MainWindowHandle to be created or periodically calling Process.Refresh and check if MainWindowHandle returns a valid handle. Perhaps this is enough for you, otherwise you can get additional information with the handle. In WinForms you could probably do something like this:
Form window = (Form)Control.FromHandle(process.MainWindowHandle);
I suspect there are similar solutions for other frameworks.
Update
I wrote this small sample, it is untested and I don't know if it works reliably (it may deadlock), but it should hint at some things you can try:
namespace SomeNS
{
using System.Diagnostics;
using System.Windows.Forms;
public static class SomeClass
{
static void SomeMethod()
{
Process process = Process.Start("child-app.exe");
// YourDialog is your dialog implementation inheriting from System.Windows.Window
YourDialog dlg = new YourDialog();
dlg.Loaded += (sender, e) =>
{
process.WaitForInputIdle();
Form window = (Form)Control.FromHandle(process.MainWindowHandle);
// Do something with the child app's window
dlg.Close();
};
dlg.ShowDialog();
}
}
}
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.
I managed to get the position (x,y) of mousse clicked event in windows with C# and Win32 API from the code at http://www.codeproject.com/KB/cs/globalhook.aspx (using Version 1 because I have a problem with version 2)
But I want to know what is clicked not the position on the screen.
For example, click the "Bold Button" in MS Word.
Is there a way to archive this?
Thanks in advance.
You can fetch a window handle from WindowFromPoint or ChildWindowFromPointEx, then query the window handle with GetWindowInfo etc. I don't think there's a trivial way to identify a button from Word, though.
Check out the AutomationElement.FromPoint() that's part of UI Automation - this suite of APIs is often used by automated test and accessibility apps that want to get information about the UI of other processes. For apps that support it (most of the UI in Windows and most MS apps), you can get information about the UI element, not just the outer window. This sample app prints out the name and type (eg 'button') of the item under the cursor.
It's not supported everywhere, may not work in many non-MS apps (though is supported by Firefox); but will at least get you better results than WindowFromPoint etc.
// Compile using: csc ItemAtPoint.cs /r:UIAutomationClient.dll /r:WindowsBase.dll
using System;
using System.Windows.Automation;
using System.Windows.Forms;
class ItemAtPoint
{
public static void Main()
{
Console.WriteLine("Place pointer over item and hit return...");
Console.ReadLine();
// Get the AutomationElement that represents the window handle...
System.Windows.Point point = new System.Windows.Point(Cursor.Position.X, Cursor.Position.Y);
AutomationElement el = AutomationElement.FromPoint(point);
// Print out the type of the item and its name
Console.WriteLine("item is a \"{0}\" with name \"{1}\"", el.Current.LocalizedControlType, el.Current.Name);
}
}
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.