Get last active window: Get Previously active window - c#

I am working on an application which needs to get the last active window handle. Suppose my application is running then I want to get last active window handle that was just previously open just before my application.
#EDIT1: This is not the duplicate question. I need to get the handle of last active window not the current window.

This is similar to
alternate SO question, I would assume you would just track the active window and upon change you would then know the previously active
Edit, this is basically code copied from the question I linked that was looking for current active window but with logic to persist the lastHandle and identify when you have a new lastHandle. It's not a proven, compilable implementation:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
static IntPtr lastHandle = IntPtr.Zero;
//This will be called by your logic on when to check, I'm assuming you are using a Timer or similar technique.
IntPtr GetLastActive()
{
IntPtr curHandle = GetForeGroundWindow();
IntPtr retHandle = IntPtr.Zero;
if(curHandle != lastHandle)
{
//Keep previous for our check
retHandle = lastHandle;
//Always set last
lastHandle = curHandle;
if(retHandle != IntPtr.Zero)
return retHandle;
}
}

I needed the same thing of the last handle from the previous window I had open. The answer from Jamie Altizer was close, but I modified it to keep from overwriting the previous window when my application gets focus again. Here is the full class I made with the timer and everything.
static class ProcessWatcher
{
public static void StartWatch()
{
_timer = new Timer(100);
_timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
_timer.Start();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
setLastActive();
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
public static IntPtr LastHandle
{
get
{
return _previousToLastHandle;
}
}
private static void setLastActive()
{
IntPtr currentHandle = GetForegroundWindow();
if (currentHandle != _previousHandle)
{
_previousToLastHandle = _previousHandle;
_previousHandle = currentHandle;
}
}
private static Timer _timer;
private static IntPtr _previousHandle = IntPtr.Zero;
private static IntPtr _previousToLastHandle = IntPtr.Zero;
}

Related

Retrieving control information from another application from a MouseDown/Up event

I am working on building an application similar to Windows Steps Recorder (WSR) but with more features that are required by my company. I have pretty much done everything but one thing I am struggling on is retrieving the Text/ Names of controls clicked in other applications.
E.g. When using WSR if you click a button labelled OK on another application it can pick this up and automatically makes a comment on that step such as "User left click on OK"
Anyone know how I can retrieve this information using the window handle/ mouse pointer location (x, y)?
Another example I can give is from using the AutoIT Window Info tool
As you can see in the figure provided above AutoIt can retrieve the element information within applications using the Finder Tool.
If someone can give me a pointer towards how this is achieved using C# that would be great as currently I don't know where to start. All other examples I have found online are for returning control values from within the application opposed to background applications.
I am building my application in WinForms due to the fact that some of the namespaces I am using aren't compatible with WPF.
Would this be a case of using EnumWindows() and EnumChildWindows()??
Note: I do not need help with the mouse hooks etc. simply just the retrival of infromation from a control that has been clicked on.
Thanks,
Maisy
Hey guys I've managed to retrive the text information. It may not be the prettiest way of doing it but it works.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace EnumChildWinTest
{
public partial class Form1 : Form
{
public IntPtr windowHandle = IntPtr.Zero; // Default value
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")] private static extern int GetWindowText(int hWnd, StringBuilder title, int size);
StringBuilder title = new StringBuilder(256);
// Go Button
private void button1_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox1.AppendText($"Window Handle: {GetWindowHandle(textBox2.Text)} {Environment.NewLine}");
foreach (var child in GetChildWindows(windowHandle))
{
textBox1.AppendText($"Child window: {child.ToString()} {Environment.NewLine}");
GetWindowText(child.ToInt32(), title, 256);
textBox1.AppendText($"Title:{title}{Environment.NewLine}");
}
}
public IntPtr GetWindowHandle(string processName)
{
Process[] processes = Process.GetProcessesByName(processName);
foreach (Process p in processes)
{
windowHandle = p.MainWindowHandle;
}
return windowHandle;
}
public List<IntPtr> GetChildWindows(IntPtr handle)
{
var allChildWindows = new WindowHandleInfo(windowHandle).GetAllChildHandles();
return allChildWindows;
}
}
}
public class WindowHandleInfo
{
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
private IntPtr _MainHandle;
public WindowHandleInfo(IntPtr handle)
{
this._MainHandle = handle;
}
public List<IntPtr> GetAllChildHandles()
{
List<IntPtr> childHandles = new List<IntPtr>();
GCHandle gcChildhandlesList = GCHandle.Alloc(childHandles);
IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(this._MainHandle, childProc, pointerChildHandlesList);
}
finally
{
gcChildhandlesList.Free();
}
return childHandles;
}
private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
{
GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);
if (gcChildhandlesList == null || gcChildhandlesList.Target == null)
{
return false;
}
List<IntPtr> childHandles = gcChildhandlesList.Target as List<IntPtr>;
childHandles.Add(hWnd);
return true;
}
}

Bring another application to front

I have built a C# Windows Form application. When the form loads, it's full screen. The form has icons on it that launch other applications (not forms). I'm trying to accomplish determining whether the application is already running or not and if it's not, start it, otherwise bring it to the front. I have accomplished determining whether the application is running or not and if it's not, to start it, I just can't figure out how to bring it to the front if it is. I have read other results on Google and Stack Overflow, but haven't been able to get them to work.
Any help is greatly appreciated!
My code, so far, is:
private void button4_Click(object sender, EventArgs e)
{
Process[] processName = Process.GetProcessesByName("ProgramName");
if (processName.Length == 0)
{
//Start application here
Process.Start("C:\\bin\\ProgramName.exe");
}
else
{
//Set foreground window
?
}
}
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
private IntPtr handle;
private void button4_Click(object sender, EventArgs e)
{
Process[] processName = Process.GetProcessesByName("ProgramName");
if (processName.Length == 0)
{
//Start application here
Process.Start("C:\\bin\\ProgramName.exe");
}
else
{
//Set foreground window
handle = processName[0].MainWindowHandle;
SetForegroundWindow(handle);
}
}
If you also wish to show the window even if it is minimized, use:
if (IsIconic(handle))
ShowWindow(handle, SW_RESTORE);
Although several answers here are marked as working, they did not work in my case. I found correct code, which worked for me on blog of Joseph Gozlan. I'm repeating here this awesome code for convenience. Notice slight but very important difference with async call, compared to other answers. All credits to original code author.
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr WindowHandle);
public const int SW_RESTORE = 9;
private void FocusProcess(string procName)
{
Process[] objProcesses = System.Diagnostics.Process.GetProcessesByName(procName);
if (objProcesses.Length > 0)
{
IntPtr hWnd = IntPtr.Zero;
hWnd = objProcesses[0].MainWindowHandle;
ShowWindowAsync(new HandleRef(null,hWnd), SW_RESTORE);
SetForegroundWindow(objProcesses[0].MainWindowHandle);
}
}

How to set focus back to form after opening up a process (Notepad)?

I open up a notepad from my program using Process.Start() but the new opened notepad covers the screen. But I do want my application to maintain its focus.
I similarly (using the same Process.Start) open up MS Excel and Word but to get focus back to my form all I need to write is:
this.Focus();
But quirk with Notepad: I open notepad (and all other processes like this)
Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.EnableRaisingEvents = true;
process.StartInfo.FileName = #"abc.log";
process.Start();
Now notepad takes the focus.
I tried these:
this.Activate(), this.Focus(), needless to mention
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr SetFocus(HandleRef hWnd);
{
IntPtr hWnd = myProcess.Handle;
SetFocus(new HandleRef(null, hWnd));
}
[DllImport("User32")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[DllImportAttribute("User32.DLL")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_RESTORE = 9;
{
ShowWindow(Process.GetCurrentProcess().MainWindowHandle, SW_RESTORE);
SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle);
}
Another lengthier solution got from here.
All which still keeps the focus on notepad. Why is it so difficult to merely get focus to a window, that too application's own window?
EDIT: At best I can open the notepad minimized, but it still wouldn't give the focus to the form after trying all the above codes. Notepad opens minimized, but focus will be still on notepad (something that sometimes we see in windows xp) and form will be out of focused.
I tried almost everything on internet (so sure about it :)). At best I could get my form on top of all other forms, but without focus (going by #Hans Passant's method). Going by heavy blocks of codes all over, I somehow felt this aint gonna be easy. So I always used SetForegroundWindow() with chunks of other code. Never thought merely SetForegroundWindow() would do the trick.
This worked.
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
Process process = new Process();
process.StartInfo.FileName = #...\abc.log";
process.Start();
process.WaitForInputIdle(); //this is the key!!
SetForegroundWindow(this.Handle);
}
At times this method yields in a focus on the parent form (in cases where my desired form is a modal child form of its parent form); in such cases, just add this.Focus() to the last line..
Even this worked:
Microsoft.VisualBasic.Interaction.Shell(#"notepad.exe D:\abc.log",
Microsoft.VisualBasic.AppWinStyle.NormalNoFocus);
Solution provided by here
I had the same problem, i eventually wound up with programmatically calling alt-tab:
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private void alttab()
{
uint WM_SYSCOMMAND = 0x0112;
int SC_PREVWINDOW = 0xF050;
PostMessage(Process.GetCurrentProcess().MainWindowHandle, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
}
//EDIT: You should use process.MainWindowHandle instead ofcourse
If you want to start a process and focus back to the form, then start that process with minimized state, like this:
Dim psi As New ProcessStartInfo("notepad")
psi.WindowStyle = ProcessWindowStyle.Minimized
Process.Start(psi)
Windows prevents apps from shoving their window into the user's face, you are seeing this at work. The exact rules when an app may steal the focus are documented in the MSDN docs for AllowSetForegroundWindow().
A back-door around this restriction is the AttachThreadInput() function. This code worked well, I did take a shortcut on finding the thread ID for the thread that owns the foreground window. Good enough for Notepad, possibly not for other apps. Do beware that Raymond Chen does not approve of this kind of hack.
private void button1_Click(object sender, EventArgs e) {
var prc = Process.Start("notepad.exe");
prc.WaitForInputIdle();
int tid = GetCurrentThreadId();
int tidTo = prc.Threads[0].Id;
if (!AttachThreadInput(tid, tidTo, true)) throw new Win32Exception();
this.BringToFront();
AttachThreadInput(tid, tidTo, false);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool AttachThreadInput(int tid, int tidTo, bool attach);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
Try this:
public partial class MainForm : Form
{
private ShowForm showForm;
public MainForm()
{
InitializeComponent();
}
private void showButton_Click(object sender, EventArgs e)
{
this.showForm = new ShowForm();
this.showForm.FormClosed += showForm_FormClosed;
this.showForm.Show(this);
}
private void showForm_FormClosed(object sender, FormClosedEventArgs e)
{
this.Focus();
}
}

Performing a mouse click without moving cursor

I couldn't find any solution except moving the cursor by Cursor class, clicking with mouse_event then moving the cursor to its old position. I am playing with SendInput function right now but still no chance for a good solution. Any advice?
You should use Win32 API.
Use pInvoked SendMessage from user32.dll
pInvoked Function
Then read about mouse events:
Mouse Input on msdn
And then read about: System events and Mouse Mess.......
Also there is lots of info:
Info
Here's an example following the approach Hooch suggested.
I created a form which contains 2 buttons. When you click upon the first button, the position of the second button is resolved (screen coördinates). Then a handle for this button is retrieved. Finally the SendMessage(...) (PInvoke) function is used to send a click event without moving the mouse.
public partial class Form1 : Form
{
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg,
IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "WindowFromPoint",
CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr WindowFromPoint(Point point);
private const int BM_CLICK = 0x00F5;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Specify the point you want to click
var screenPoint = this.PointToScreen(new Point(button2.Left,
button2.Top));
// Get a handle
var handle = WindowFromPoint(screenPoint);
// Send the click message
if (handle != IntPtr.Zero)
{
SendMessage( handle, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
}
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("Hi", "There");
}
}

Force close all open popups from code

I want to cause all open popups (with StaysOpen == false) to close from code. Basically I want to simulate the user clicking the mouse (which would close the popups) from code.
I don't need to actually simulate the click, I just need the resulting behavior. I've thought about just going through the visual tree looking for popups and closing each one, but that doesn't seem like the cleanest approach.
Thanks in advance for any help or opinions.
A WPF popup actually creates a new window (a Win32 window, not a WPF Window instance). So you can't find it in the Application.Windows collection, but you can probably find it using a Win32 API like EnumChildWindows.
Once you have the handle, you can retrieve the associated HwndSource. I think the RootVisual of the HwndSource is the Popup (didn't check, you might have to look deeper in the visual tree).
So the code should be similar to this (completely untested):
public static class PopupCloser
{
public static void CloseAllPopups()
{
foreach(Window window in Application.Current.Windows)
{
CloseAllPopups(window);
}
}
public static void CloseAllPopups(Window window)
{
IntPtr handle = new WindowInteropHelper(window).Handle;
EnumChildWindows(handle, ClosePopup, IntPtr.Zero);
}
private static bool ClosePopup(IntPtr hwnd, IntPtr lParam)
{
HwndSource source = HwndSource.FromHwnd(hwnd);
if (source != null)
{
Popup popup = source.RootVisual as Popup;
if (popup != null)
{
popup.IsOpen = false;
}
}
return true; // to continue enumeration
}
private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
}
Going through the visual tree is the way to do it that isn't dependent in any way on how you've created them in the first place. There may be much cleaner ways of doing it, but they all really depend on your implementation.
For instance, all of the Popups in my application are bound to view model objects that expose some kind of IsOpen property that the Popup binds to. If I needed to implement this functionality in my project, I'd just maintain a collection of these objects (or a generator method) that I could iterate over, and set IsOpen to false on each. This obviously won't work if you aren't building your UI the way I am, though.
The accepted answer (https://stackoverflow.com/a/3886139/12885902) wasn't doing the trick for me, because source.RootVisual was never of type Popup but of the internal type PopupRoot. The following tweak got the code to work:
private void CloseAllPopups()
{
foreach (Window window in Application.Current.Windows)
{
IntPtr handle = new WindowInteropHelper(window).Handle;
EnumThreadWindows(handle, ClosePopup, IntPtr.Zero);
}
}
private static bool ClosePopup(IntPtr hwnd, IntPtr lParam)
{
HwndSource source = HwndSource.FromHwnd(hwnd);
if (source?.RootVisual?.GetType().Name == "PopupRoot")
{
if (LogicalTreeHelper.GetParent(source.RootVisual) is Popup popup)
{
popup.IsOpen = false;
}
}
return true; // to continue enumeration
}
private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumThreadWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
Please also keep in mind that the CloseAllPopups() method has to be called by the main UI thread (e.g. Application.Current.Dispatcher.Invoke())!
My previous answer was also not working all the time. It only worked when the Visual Studio debugger was attached to the process. What ended up working in any case is the following:
Application.Current.Dispatcher.Invoke(() =>
{
PresentationSource.CurrentSources.OfType<HwndSource>()
.Select(h => h.RootVisual)
.OfType<FrameworkElement>()
.Select(f => f.Parent)
.OfType<Popup>()
.Where(popup => popup.IsOpen)
.ToList()
.ForEach(popup => popup.SetCurrentValue(Popup.IsOpenProperty, false));
});
Declare somewhere static array of opened popups:
static List<Popup> openedPopups = new List<Popup>();
Before open popup close all previsiously opened popups:
private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// close all before opene popup
openedPopups.ForEach(p => p.IsOpen = false);
openedPopups.Clear(); // clear opened popus's collection, because they were closed
Popup1.IsOpen = true; // open popup I need open now
openedPopups.Add(Popup1); // remember it for future close
}

Categories

Resources