Force close all open popups from code - c#

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
}

Related

EnumWindows not finding Touch-Keyboard

I am trying to get the HWND of the On-Screen/Touch keyboard - the one that appears on the bottom of the screen. For that I first look for the Process ID according to the name, and then do EnumWindows to look through all windows and find one whose Process ID corresponds to the one I know:
doTheThing(int pid)
{
EnumWindows(new EnumWindowsProc(Report), (IntPtr)pid);
}
protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
protected static bool Report(IntPtr hwnd, IntPtr lParam)
{
IntPtr lpdwProcessId;
GetWindowThreadProcessId(hwnd, out lpdwProcessId);
if (lpdwProcessId == lParam)
{
MessageBox.Show("True: " + hwnd.ToString());
return false;
}
return true;
}
Now Report is called several times, but the thing never actually matches. If I take another process, it works, but it seems like the OnScreenkeyboard "System.Diagnostics.Process (WindowsInternal.ComposableShell.Experiences.TextInput.InputApp)" does not show up with EnumWindows.
Using FindWindow does not work as the window does not have a Title and its class is the generic ApplicationFrameHost.
In AHK I was able to get the HWND by hovering over the keyboard with MouseGetPos,,, WinUMID, so a HWND definitely exists.
Is there a possibility that some windows are ignored by the EnumWindows? If so, how can I prevent that? What other solutions are there?
As a sidenote, it also does not show up in the UI Automation verify tool.
Note: Windows now has two keyboards apparently. I mean the one you can open via the taskbar.
To clarify why I need this:
I have the following AHK-Script that can make the window I point my mouse over window semi-transparent:
MouseGetPos,,, WinUMID
WinSet, Transparent, 100, ahk_id %WinUMID%
I noticed that when I point it over the Touch-Keyboard, it will make it transparent and that effect stays even if the keyboard disappears, until I restart my system. If I save the WinUMID variable I can even change the transparency while the keyboard is not used.
Now I want to make the Keyboard semi-transparent in C#, and that works as long as I provide the HWND. But I can't figure out a way to get the HWND inside of C#, without the help of AHK.
process.MainWindowHandle returns 0.
I have also tried
ProcessThreadCollection threads = process.Threads;
foreach (ProcessThread thread in threads)
{
EnumThreadWindows((uint)thread.Id, new EnumThreadDelegate(EnumThreadCallback), IntPtr.Zero);
}
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
protected delegate bool EnumThreadDelegate(IntPtr hwnd, IntPtr lParam);
protected static bool EnumThreadCallback(IntPtr hwnd, IntPtr lParam)
{
MessageBox.Show("Try");
IntPtr lpdwProcessId;
GetWindowThreadProcessId(hwnd, out lpdwProcessId);
if (lpdwProcessId == lParam)
{
MessageBox.Show("True: " + hwnd.ToString());
makeTransparent(lParam);
return false;
} else
MessageBox.Show("False: " + hwnd.ToString());
return true;
}
EnumThreadCallback was never called though, even though it works for any other process.
Edit:
I found out that the Keyboard process was not actually creating the Keyboard. Instead, it seems like the keyboard-UI is created by explorer.
The following code does work:
Process[] processes = Process.GetProcesses();
IntPtr hWnd = IntPtr.Zero;
while ((hWnd = FindWindowEx(IntPtr.Zero, hWnd, "ApplicationFrameWindow", null)) != IntPtr.Zero)
{
IntPtr lpdwProcessId;
GetWindowThreadProcessId(hWnd, out lpdwProcessId);
foreach (Process process in processes)
{
if (process.ToString() == "System.Diagnostics.Process (explorer)")
{
if (process.Id == (int)lpdwProcessId)
{
doThing(hWnd);
}
}
}
}
However, multiple hWnds are used, and only one of them belongs to the keyboard. Now I need to find out how to filter out this specific one. There do not seem to be downsides to this method right now, but I don't feel comfortable releasing this without knowing if it can have any adverse effects because of this. Victim 1: The new Paste window.
Try this alternate solution:
var process = Process.GetProcessById(pid);
IntPtr hwnd = process.MainWindowHandle;

C# Copy-paste multiple times not working

In Visual C#, I'm trying to take text from multiple textboxes (one at a time) and paste them into Notepad. I do this by copying to the clipboard, alt-tabbing, and then pasting into notepad...then again for the other textboxes. This code represents this idea:
subBox1.SelectAll();
subBox1.Copy();
SendKeys.Send("%{TAB}"); // alt+tab
SendKeys.Send("^v"); // paste
SendKeys.Send("{TAB}"); // tab
subBox2.SelectAll();
subBox2.Copy();
SendKeys.Send("^v");
SendKeys.Send("{TAB}");
subBox3.SelectAll();
subBox3.Copy();
SendKeys.Send("^v");
SendKeys.Send("{TAB}");
As you can see, this copies and pastes from three textboxes (named subBox1, 2, and 3). But, for some reason, only the last textbox's contents are getting copied over. This also happens if I comment out the third box...in that case, only the second textbox's content gets copied over. I've tried using the SelectAll() and Copy() as you see here, as well as the Clipboard class. Both have the same issue.
For example, if the textbox contents are "asdf", "qwer", and "zxcv" respectively, all I see is "zxcv" three times.
Any idea why this is happening? I've been stuck on this for about an hour now and have no idea what's going on.
Thanks a ton!
SendKeys doesn't wait for the other application to process the keys you send, so by the time notepad gets around to processing your keypresses, your program has already copied subBox3's text over the top of the other texts.
You need to use SendWait instead.
As well, instead of sending Alt+Tab, you could use something like this:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
// ...
SetForegroundWindow(FindWindow(null, "Untitled - Notepad"));
I'd use SendMessage for more accurate results. To use SendMessage, you first need a valid window handle to the text area of Notepad. This can be done in a variety of ways, but I prefer just using my simple child lookup function.
You will need the following namespace imports and PInvoke declarations:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
//pinvoke
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hParent, delChildWndProc callback, IntPtr lpParam);
//delegate callback for EnumChildWindows:
[return:MarshalAs(UnmanagedType.Bool)]
private delegate bool delChildWndProc(IntPtr hWnd, IntPtr lParam);
Now, onto the child window lookup. Basically works similar to FindWindowEx, but I wanted to write my own, and it retrieves multiple windows which can be nice. It uses the following wrapper class to describe information between calls:
private class WindowLookup
{
public string LookupName { get; private set; }
public List<IntPtr> MatchedChildren { get; private set; }
public int Depth { get; set; }
public int MaxDepth { get; set; }
public WindowLookup(string lookup, int maxdepth)
{
this.MatchedChildren = new List<IntPtr>();
this.LookupName = lookup;
this.MaxDepth = maxdepth;
if (this.MaxDepth > 0)
this.MaxDepth++; //account for the depth past the parent control.
this.Depth = 0;
}
}
And then the following functions do all the work:
private static List<IntPtr> FindAllWindows(IntPtr hParent, string className, int maxdepth = 0)
{
var lookup = new WindowLookup(className, maxdepth);
var gcAlloc = GCHandle.Alloc(lookup);
try
{
LookupChildProc(hParent, GCHandle.ToIntPtr(gcAlloc));
}
finally
{
if (gcAlloc.IsAllocated)
gcAlloc.Free();
}
return lookup.MatchedChildren;
}
private static bool LookupChildProc(IntPtr hChild, IntPtr lParam)
{
var handle = GCHandle.FromIntPtr(lParam);
WindowLookup lookup = null;
if (handle.IsAllocated && (lookup = handle.Target as WindowLookup) != null)
{
if (lookup.Depth < lookup.MaxDepth || lookup.MaxDepth == 0)
{
lookup.Depth++;
var builder = new StringBuilder(256);
if (GetClassName(hChild, builder, builder.Capacity) && builder.ToString().ToLower() == lookup.LookupName.ToLower())
lookup.MatchedChildren.Add(hChild);
EnumChildWindows(hChild, LookupChildProc, lParam);
}
}
return true;
}
You don't need to worry about the implementation of these functions too much, they'll work as-is. The key thing is that using these functions, you can find the handle to notepad's Edit window (the text area you type in) very easily.
var notepads = Process.GetProcessesByName("notepad");
if (notepads.Length > 0)
{
foreach(var notepad in notepads) //iterate through all the running notepad processes. Of course, you can filter this by processId or whatever.
{
foreach(var edit in FindAllWindows(notepad.MainWindowHandle, "Edit"))
{
//next part of the code will go here, read on.
}
}
}
Now, where I left the code was in the middle of a loop through the "Edit" windows of each notepad process running at the time. Now that we have a valid window handle, we can use SendMessage to send stuff to it. In particular, appending text. I wrote the following function to handle appending text to a remote control:
private static void AppendWindowText(IntPtr hWnd, string text)
{
if (hWnd != IntPtr.Zero)
{
//for your reference, 0x0E (WM_GETTEXTLENGTH), 0xB1 (EM_SETSEL), 0xC2 (EM_REPLACESEL)
int len = SendMessage(hWnd, 0x000E, IntPtr.Zero, IntPtr.Zero).ToInt32();
var unmanaged = Marshal.StringToHGlobalAuto(text);
SendMessage(hWnd, 0x00B1, new IntPtr(len), new IntPtr(len));
SendMessage(hWnd, 0x00C2, IntPtr.Zero, unmanaged);
Marshal.FreeHGlobal(unmanaged);
}
}
Now that we have our AppendWindowText function, you can add a function call to it in the nested loop above (where I put the comment):
AppendWindowText(edit, "Some text here");
And there you have it. It's a bit of a wordy response, but in the end this method is far more reliable than using SendKeys and focusing the window etc. You never need to lose focus of your own application.
If you have any questions, feel free to comment and I'll answer as best I can.
Cheers,
J
EDIT: Some references:
SendMessage function (MSDN)
EnumChildWindows function (MSDN)
Appending text using SendMessage

How to capture data in a window

I have a desktop application installed on my machine. When I start a program some kind of window gets open. let's say, something like this (just example):
So, I want to write an application in C# that will find this window and capture some data from it.
What tools should I look at? I want to go with a path of least resistance.
I need to capture images, text from textboxes, and also find controls by text and click on them.
I suggest you use the cool but little-known UI Automation API for this work.
For this, the first thing to test is launch the associated UISpy tool. It will display a tree of all accessible windows on screen. It also is able to run some actions like pressing a menu, selecting an item, etc. This is using what's called UI Automation Control Patterns, which provide a way to categorize and expose a control's functionality independent of the control type or the appearance of the control.
So, if you can automate this application with UI Spy, you also can do the exact same thing using .NET code (UISpy is itself simply using the underlying API).
Here is an interesting tutorial article about UI automation programming: The Microsoft UI Automation Library
You should start enumerating handles of all windows for that process :
https://stackoverflow.com/a/2584672/351383
Then for each handle get information about text and position, with position infomation you can take screenshots of desktop on that position to get images AFAIK there is no other way to get images from a window of running application.
When you got screen positions of the controls then use from link below to simulate left mouse click, search windows for some text and then click on some point inside control, here is the method that will click a point :
https://stackoverflow.com/a/10355905/351383
I put toghether quick class to gather that data for process :
public static class ProcessSpy
{
public static List<ProcessSpyData> GetDataForProcess(string processName)
{
var result = new List<ProcessSpyData>();
Process myProc = Process.GetProcessesByName(processName).FirstOrDefault();
if (myProc != null)
{
var myHandles = EnumerateProcessWindowHandles(myProc);
foreach (IntPtr wndHandle in myHandles)
{
result.Add(new ProcessSpyData(wndHandle));
}
}
return result;
}
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
static IEnumerable<IntPtr> EnumerateProcessWindowHandles(Process prc)
{
var handles = new List<IntPtr>();
foreach (ProcessThread thread in prc.Threads)
EnumThreadWindows(thread.Id, (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
return handles;
}
}
public class ProcessSpyData
{
private const uint WM_GETTEXT = 0x000D;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
[DllImport("user32.dll")]
private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
int left, top, right, bottom;
public Rectangle ToRectangle()
{
return new Rectangle(left, top, right - left, bottom - top);
}
}
[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
public IntPtr WindowHandle { get; private set; }
public string WindowText { get; private set; }
public Rectangle ClientRect { get; private set; }
public Rectangle ScreenPos { get; private set; }
public ProcessSpyData(IntPtr windowHandle)
{
this.WindowHandle = windowHandle;
GetWindowText();
GetWindowSize();
}
private void GetWindowText()
{
StringBuilder message = new StringBuilder(1024);
SendMessage(this.WindowHandle, WM_GETTEXT, message.Capacity, message);
this.WindowText = message.ToString();
}
private void GetWindowSize()
{
var nativeRect = new RECT();
GetClientRect(this.WindowHandle, out nativeRect);
this.ClientRect = nativeRect.ToRectangle();
Point loc = this.ClientRect.Location;
ClientToScreen(this.WindowHandle, ref loc);
this.ScreenPos = new Rectangle(loc, this.ClientRect.Size);
}
}
That should get you started, but you have to be aware if app is using non standard controls then there is no way to get text out of it with this method, and for images maybe you will get better results looking at executable resources.
UPDATE
Geting controls text for various control types (MFC, winforms, Delphi VCL etc.) would be very hard task, but for winforms see excelent Managed Windows API, they even have some sort of spy application in tools, look at that.
What kind of data are you trying to capture?
You may try listening to windows messages or reading the memory.
Depending on how much of these type of tasks you are going to be doing in the future (or how important this one is) you could try investing in something like Ranorex Spy (Ranorex studio is ott).
Link: http://www.ranorex.com/product/tools/ranorex-spy.html
there is no other way than to inject the application you want to inspect. This is how UISpy actually runs. This is also why UISpy should be run with Administrative credential.

Determine if current application is activated (has focus)

Note: There's a very similar question, but it's WPF-specific; this one is not.
How can I determine if the current application is activated (i.e. has focus)?
This works:
/// <summary>Returns true if the current application has focus, false otherwise</summary>
public static bool ApplicationIsActivated()
{
var activatedHandle = GetForegroundWindow();
if (activatedHandle == IntPtr.Zero) {
return false; // No window is currently activated
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
return activeProcId == procId;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
It has the advantage of being thread-safe, not requiring the main form (or its handle) and is not WPF or WinForms specific. It will work with child windows (even independent ones created on a separate thread). Also, there's zero setup required.
The disadvantage is that it uses a little P/Invoke, but I can live with that :-)
since it's likely that some element in your UI has contain focus for the form to be active try:
this.ContainsFocus
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.containsfocus(v=vs.110).aspx
The solution I found which requires neither native calls nor requires handling events is to check Form.ActiveForm. In my tests, that was null when no window in the application was focused and otherwise non-null.
var windowInApplicationIsFocused = Form.ActiveForm != null;
Ah, this is specific to winforms. But that applies to my situation ;-).
You can subscribe to Main Window's Activated event
First get the handle either using:
IntPtr myWindowHandle;
myWindowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
or
HwndSource source = (HwndSource)HwndSource.FromVisual(this);
myWindowHandle = source.Handle;
Then compare whethers it is the ForeGroundWindow:
if (myWindowHandle == GetForegroundWindow())
{
// Do stuff!
}
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
Handle the Activated event of your main application Form.
In WPF the easiest way to check if a window is active is:
if(this.IsActive)
{
//the window is active
}

Keep window on top and steal focus in WinForms

I realize that this would be COMPLETELY bad practice in normal situations, but this is just for a test app that needs to be taking input from a bar code scanner (emulating a keyboard). The problem is that I need to start up some scripts while scanning, so I need the window to regain focus directly after I click the script to run it. I've tried using Activate(), BringToFront(), Focus() as well as some Win32 calls like SetForegroundWindow(), Setcapture() and SetActiveWindow()... however the best I can get any of them to do is to make the taskbar item start blinking to tell me that it wants to have focus, but something is stopping it. BTW, I'm running this on XP SP2 and using .NET 2.0.
Is this possible?
Edit: To clarify, I am running the scripts by double-clicking on them in explorer. So I need it to steal focus back from explorer and to the test app.
I struggled with a similar problem for quite a while. After much experimentation and guessing, this is how I solved it:
// Get the window to the front.
this.TopMost = true;
this.TopMost = false;
// 'Steal' the focus.
this.Activate();
Visibility
Make the window a "Top-Most" window. This is the way the Task-Manager can remain on top of other windows. This is a property of a Form and you make the form top-most (floating above other windows) by setting the value to true.
You shouldn't need to override any of the "Active window" behaviour with the top-most setting.
Focus
I asked a similar question previously here on StackOverflow and the answer would solve your problem. You can make the application use a low-level input hook and get notification of the key-codes coming from the scanner. This way, your application always gets these keys even though the application does not have focus.
You may need to enhance the solution to squash the key-codes so that they are not transmitted to the "in-focus" application (e.g. notepad).
Since Windows 2000, there is no official mechanism for an application to grab focus without direct intervention of the user. Peeking at the input streams through the RawInputDevices hook is the only sensible way to go.
A number of articles may help (C# implementations)
RawInput article on CodeProject
MSDN documentation of RawInput
I had a similar problem and found the following to do the trick. Adapted to C# from here
// force window to have focus
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const uint SW_SHOW = 5;
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(form.Handle);
ShowWindow(form.Handle, SW_SHOW);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(form.Handle);
ShowWindow(form.Handle, SW_SHOW);
}
form.Activate();
EDIT: Here are the necessary PInvoke definitions for C#:
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
/// <summary>The GetForegroundWindow function returns a handle to the foreground window.</summary>
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(HandleRef hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
The way I approached this problem was to spawn another thread whose only purpose was to ensure the Form is TopMost and has focus at all times. This code will make all other applications unusable while it is running, which is what I needed for my specific applications. You can add in a Sleep in keepFocus or have some other event trigger it.
using System.Threading; // be sure to include the System.Threading namespace
//Delegates for safe multi-threading.
delegate void DelegateGetFocus();
private DelegateGetFocus m_getFocus;
//Constructor.
myForm()
{
m_getFocus = new DelegateGetFocus(this.getFocus); // initialise getFocus
InitializeComponent();
spawnThread(keepFocus); // call spawnThread method
}
//Spawns a new Thread.
private void spawnThread(ThreadStart ts)
{
try
{
Thread newThread = new Thread(ts);
newThread.IsBackground = true;
newThread.Start();
}
catch(Exception e)
{
MessageBox.Show(e.Message, "Exception!", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
//Continuously call getFocus.
private void keepFocus()
{
while(true)
{
getFocus();
}
}
//Keeps Form on top and gives focus.
private void getFocus()
{
//If we need to invoke this call from another thread.
if (this.InvokeRequired)
{
try
{
this.Invoke(m_getFocus, new object[] { });
}
catch (System.ObjectDisposedException e)
{
// Window was destroyed. No problem but terminate application.
Application.Exit();
}
}
//Otherwise, we're safe.
else
{
this.TopMost = true;
this.Activate();
}
}
}
You might try focusing on a specific input, or try the setting .TopMost property to true (and then unsetting it again).
But I suspect your problem is that these methods all just place messages in the windows event queue, and your program has to wait for all existing events to finish processing before it will handle that one and focus the app.

Categories

Resources