FindWindow and SetForegroundWindow alternatives? - c#

I am searching for alternatives to the old User32.dll version of switching to a different application with FindWindow() and SetForegroundWindow().
I did find an alternative to the first with the usage of Process.GetProcessesByName() but I do not see the corresponding method to switch (set active/foreground) to that application.
Is there a way of doing that without using the old way with the User32.dll?
Thank you for your help.
EDIT
I accepted the answer of #Sorceri although it is not the answer I was looking for.

Answer: No.
But, to help the next wonderer looking to find a window and activate it from C# here's what you have to do:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
void ActivateApp(string processName)
{
Process[] p = Process.GetProcessesByName(processName);
// Activate the first application we find with this name
if (p.Count() > 0)
SetForegroundWindow(p[0].MainWindowHandle);
}
To bring notepad to the front, for example, you would call:
ActivateApp("notepad");
As a side note - for those of you who are trying to bring a window within your application to the foreground just call the Activate() method.

You could use SetActiveWindow as an alternative to SetForeGroundWindow. I'd say you should go through all the Windows Manipulation Api Functions and see if there's something you're missing out.
Also, note that you can obtain the handle of the System.Diagnostics.Process object via the Process.Handle property.

An alternative to SetForeGroundWindow is VisualBasic's AppActivate
Call it like this
Microsoft.VisualBasic.Interaction.AppActivate("WindowTitle")
Just because it is in the VisualBasic namespace doesn't mean you can't use it in C#.
Full Documentation here

You can use System.Diagnostics.Process Object for a FindWindow equivalent. There currently is no equivalent for SetForegroundWindow. You will want use Pinvoke with SetForgroundWindow.
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

Related

ShowWindowAsync not work in all case

ShowWindowAsync won't work in all case. It works when I try it with notepad, task managger, or visual studio, it's just do the job, restore them when they minimized, but when I try it with windows explorer or another external process, it won't work. In all case, the GetProcessesByName find them, just won't come back from minimized.
PInvokeFunctions class
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr WindowHandle);
Method
public static void FocusProcess(string procName)
{
Process[] objProcesses = Process.GetProcessesByName(procName);
if (objProcesses.Length > 0)
{
IntPtr hWnd = IntPtr.Zero;
hWnd = objProcesses[0].MainWindowHandle;
PInvokeFunctions.ShowWindowAsync(new HandleRef(null, hWnd), Constants.PInvokeConstants.SW_RESTORE); // SW_RESTORE = 9
PInvokeFunctions.SetForegroundWindow(hWnd);
}
}
What you want is actually not possible. You are trying to find the 'main window' of a process and that is an non-existing concept. The topic is discussed at length here: There can be more than one (or zero): Converting a process to a window
When you try to explain this to people, you sometimes get stuck in the Why won't you answer my question? cycle.
"I have a thread ID. How do I get the corresponding window?"
You can use the EnumThreadWindows function to get all the windows on the thread.
"Yes, I know about EnumThreadWindows, but how do I get the window that I want?"
Well, you haven't said what you wanted yet.
"I want the window that corresponds to the thread."
But which one? How will you decide among all the windows?
"That's what I'm asking you!"
But you haven't yet described what you want.
"I want the window corresponding to the thread. Why won't you answer my question?"
Note that saying, "I am looking for the top-level unowned window" is a step forward, but it still doesn't uniquely identify a window. There can be multiple top-level unowned windows in a process. For example, Explorer typically has lots of top-level unowned windows. There's the desktop, the taskbar, your open folder windows, and property sheets. If you ask for "the" top-level unowned window of Explorer, which one do you want?
And then Raymond ads the coup de grĂ¢ce:
Perhaps people are getting the idea that there is a way to uniquely specify "the" window for a process because the System.Diagnostics.Process object has a property called MainWindowHandle. The documentation for that property doesn't do anything to dispel the notion, either. I have no idea how that property decides among multiple top-level unowned windows.
So, as you see, you need to unask the question. What you want is fundamentally incorrect, since there is no 'main' window for a process like Chrome (remember, all modern browsers isolate browsing tabs in their own process). If you followed the discussion above, you'll know what to do.

manipulating the simple windows Calculator using win32 API in c#?

Well, I've tried my best to look at code examples and posts all over the web on how to do this, but I haven't been able to make any headway in a few months using windows API to interact with another program that's already running. I'm not the greatest programmer and some of this stuff is beyond me.
The most I've been able to do is find the Calculator process and its handle, and use that with SetWindowText to change the title. What I'd really like to learn how to do is make my program use the windows user32 (I think this must be the correct library) to enter some numbers by actually pressing the number key buttons on the software calculator to do a simple calculation.
I don't really have a use for this program, it's just a goal I'm trying to reach to learn how to use the windows API past my very beginner level SPECIFICALLY in C#. If no one has the code for this, or even if you do, I'd most appreciate some suggestions for books or resources on the web I should be reading to learn how to do this.
Since you say you're using C# you should be using the System.Windows.Automation namespace, whose entire purpose in life is to allow you to control other programs via automation.
You didn't give details as to what you wanted, but here's a program that pushes "7" in the calculator.
using System.Windows.Automation;
class Program
{
public static void Main()
{
var calcWindow = AutomationElement.RootElement.FindFirst(
TreeScope.Children,
new PropertyCondition(AutomationElement.NameProperty, "Calculator"));
if (calcWindow == null) return;
var sevenButton = calcWindow.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "7"));
var invokePattern = sevenButton.GetCurrentPattern(InvokePattern.Pattern)
as InvokePattern;
invokePattern.Invoke();
}
}
You are entering the fun world of platform invoking (P/Invoke). Your best friend in this world is www.pinvoke.net, which contains c# (and vb.net) signatures for a great number of winapi functions.
For example, SendMessage:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
and this list of message codes.
You'll notice that all p/invoke methods use the DllImport attribute, found in the System.Runtime.InteropServices namespace.
They also have an extern modifier in the method signature. This means that the code is found outside of the current assembly.
You can then use SendMessage to send messages to the handle of the calculator.
As Jonathan mentioned in his comment, you should use Spy++ to detect which messages are being sent that result in the actions you want to replicate.
For good measure, here is an article with more introductory information on P/Invoke.

Find and activate an application's window

Assume that notepad.exe is opening and the it's window is inactive. I will write an application to activate it. How to make?
Update: The window title is undefined. So, I don't like to use to FindWindow which based on window's title.
My application is Winform C# 2.0. Thanks.
You'll need to P/invoke SetForegroundWindow(). Process.MainWindowHandle can give you the handle you'll need. For example:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
var prc = Process.GetProcessesByName("notepad");
if (prc.Length > 0) {
SetForegroundWindow(prc[0].MainWindowHandle);
}
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
}
Note the ambiguity if you've got more than one copy of Notepad running.
You'd need to PInvoke the Windows API calls such as FindWindow and or EnumWindows and GetWindowText (for the title). Ideally you might also want to use GeWindowThreadProcessId so you can tie it down to the actual process.
You have to use combination of these -
Toggle Process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden at runtime
and
Bring another processes Window to foreground when it has ShowInTaskbar = false
You need to find the class of the window and do a search on it. Read more about it here.
Just for info, Notepad's class name is "Notepad" (without quotes). You can verify it using Spy++.
Note: You cannot activate a window of an app if it was run with no window. Read more options in API here.

Create window as child in third party application

I'm trying to get my C# form to be parented correctly in a third party app, I have the handle to the control that I would like my form parented to but just can't seem to get it to work.
alt text http://img693.imageshack.us/img693/8871/examplec.jpg
I would like to create my form so that it is part of the MDIClient, handle 005E0ED6. Just like Window 01D7157D.
Is this possible? If so can it be done in C#?
How have you tried doing it? Did you try SetParent? See the following StackOverflow question to see if it helps. Embedding HWND into external process using SetParent
This code seems to work:
[DllImport("user32.dll")]
private static extern
IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
private static extern
IntPtr AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, int fAttach);
WinAPI.SetParent(this.Handle, otherappshandle);
IntPtr otherprocessID = GetWindowThreadProcessId(otherappshandle, new IntPtr(0));
IntPtr threadID = new IntPtr(AppDomain.GetCurrentThreadId());
AttachThreadInput(threadID , otherprocessID , 1);
Good luck. I've gone down that road, and found that there's enough little irritating gotchas that I eventually gave up on it.
SetParent() and the like will get you part of the way there, but there's a bunch of little gotchas to watch as far as the overall system (message pump blocking etc.) that just make it a time sink.
With WinForms, especially, I'd highly recommend just running your UI in the main process (if you can), and if you want to isolate your processing in another process do that instead.

.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