How can I access to the controls on another application's window?
I need to change the value of that controls (like textboxes) or click on them (like buttons).
I think I Should use API functions? But how?
See the SendKeys class and read this article, here is an example from the article:
// Get a handle to an application window.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
// Send a series of key presses to the Calculator application.
private void button1_Click(object sender, EventArgs e)
{
// Get a handle to the Calculator application. The window class
// and window name were obtained using the Spy++ tool.
IntPtr calculatorHandle = FindWindow("CalcFrame","Calculator");
// Verify that Calculator is a running process.
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("Calculator is not running.");
return;
}
// Make Calculator the foreground application and send it
// a set of calculations.
SetForegroundWindow(calculatorHandle);
SendKeys.SendWait("111");
SendKeys.SendWait("*");
SendKeys.SendWait("11");
SendKeys.SendWait("=");
}
Look for "Spy++": http://msdn.microsoft.com/en-us/library/dd460756.aspx
You can access controls on other windows with it.
you should use Windows APIs like EnumWindow or FindWindow then use EnumChildWindows API to find the controls in the target window, like the textbox you are looking for, then the API SetWindowText
have a look here for some ideas: Why is EnumChildWindows skipping children? also search for these APIs names here in Stack Overflow and you will find many examples...
Related
I've tried the following code:
[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr SetFocus(IntPtr hwnd);
void TakeFocus()
{
var process = Process.GetProcessesByName("myProcess").FirstOrDefault();
if (process != null)
{
// Tried each of the following:
ShowWindow(process.MainWindowHandle, 1);
ShowWindow(process.MainWindowHandle, 3);
ShowWindow(process.MainWindowHandle, 9);
ShowWindow(process.MainWindowHandle, 5);
SetFocus(process.MainWindowHandle);
SetForegroundWindow(process.MainWindowHandle);
}
}
I have a WPF companion app which runs in the background while a UWP app is running in the foreground. They communicate via WebSocket. I'm trying to create a method in the WPF app so it (or any other window) can steal focus from an activated UWP app, sending it into suspended state. Nothing I try seems to work, and there's no way to programatically make a UWP app suspend itself AFAIK without using the Launcher class (not an option for me, unless there's a way to call it without actually launching something-I haven't been able to do this). Normally I would assume it can't be done but I've seen programs that do it. Steam Big Picture Mode, for example, will steal focus from a UWP app when it is launched from a background process.
The supported way of suspending a UWP programmatically is available in the Spring 2018 update for Windows 10. It's already available in Insider builds/SDKs. This is the API to call:
https://learn.microsoft.com/en-us/uwp/api/windows.system.appresourcegroupinfo.startsuspendasync#Windows_System_AppResourceGroupInfo_StartSuspendAsync
IList<AppDiagnosticInfo> infos = await AppDiagnosticInfo.RequestInfoForAppAsync();
IList<AppResourceGroupInfo> resourceInfos = infos[0].GetResourceGroups();
await resourceInfos[0].StartSuspendAsync();
Here is a trivial sample app:
https://1drv.ms/u/s!AovTwKUMywTNoYQ3PrmBfZIGXmbULA
I can get handles using mouse location by clicking. But i need to find handles of all controls on a window using it's classname without clicking. I have to get them, while the window opened. Is it possible?
you can combine two popular API's:
[DllImport("user32.Dll")]
private static extern Boolean EnumChildWindows(int hWndParent, PChildCallBack lpEnumFunc, int lParam);
This function is for getting all "child" windows inside a window. The second one is
[DllImport("User32.Dll")]
private static extern void GetClassName(int hWnd, StringBuilder s, int nMaxCount);
Use this method to filter whether the enummed window has a specific class name.
Happy coding!
Yes, you need to use a variety of API calls, starting with EnumWindows and probably GetClassName as well.
I want to add a KeyPress event on Application level which checks certain key combination whenever it is pressed.
If keycombination is matched. I want to open a window on the current window that is executing.
How can I do this.
Edit
I want to add KeyPress event on Application class so that it can capture key pressed on all the windows.
One way to do is, I can go to every Window and add event on each window.
But what if number of windows is large enough. this is what my scenario is.
So I was trying to do something on Application class to do the same work.
How can I do
Use the PreviewKeyDown event. This is sent by each control before they process the key themselves.
As an alternative, you can use CommandBindings.
Maybe you can try to use Low-level Windows API hooks from C#
something like this:
http://www.codeproject.com/KB/system/CSLLKeyboard.aspx
this will involve code using System.Runtime.InteropServices and user32.dll
...
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
// and the code to create the event handler, etc... See more on the referred article.
...
As a clean and simple solution, maybe you could use something like this:
Instead of you manually add the event on every window, you make the computer do it for you.
private void AssignEventHandlers()
{
foreach (Window window in Application.Current.Windows)
{
//if (window != Application.Current.MainWindow)
window.KeyDown += new System.Windows.Input.KeyEventHandler(window_KeyDown);
}
}
void window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
// MessageBox.Show(e.Key.ToString());
if (System.Windows.Input.Keyboard.Modifiers == (System.Windows.Input.ModifierKeys.Control | System.Windows.Input.ModifierKeys.Alt)
&& e.Key == System.Windows.Input.Key.O)
{
MessageBox.Show(System.Windows.Input.Keyboard.Modifiers.ToString() + " " + e.Key.ToString());
}
}
Sources:
http://www.eggheadcafe.com/sample-code/SilverlightWPFandXAML/aeac920b-a64f-43b3-976b-2f7c91a5212b/wpf-get-all-windows-in-an-application.aspx
http://www.codegain.com/articles/wpf/miscellaneous/how-to-detect-ctrl-alt-key-combinations-in-wpf.aspx
I am trying to bring a window foreground. I am using this code. But its not working. Could someone please help?
ShowWindowAsync(wnd.hWnd, SW_SHOW);
SetForegroundWindow(wnd.hWnd);
// Code from Karl E. Peterson, www.mvps.org/vb/sample.htm
// Converted to Delphi by Ray Lischner
// Published in The Delphi Magazine 55, page 16
// Converted to C# by Kevin Gale
IntPtr foregroundWindow = GetForegroundWindow();
IntPtr Dummy = IntPtr.Zero;
uint foregroundThreadId = GetWindowThreadProcessId(foregroundWindow, Dummy);
uint thisThreadId = GetWindowThreadProcessId(wnd.hWnd, Dummy);
if (AttachThreadInput(thisThreadId, foregroundThreadId, true))
{
BringWindowToTop(wnd.hWnd); // IE 5.5 related hack
SetForegroundWindow(wnd.hWnd);
AttachThreadInput(thisThreadId, foregroundThreadId, false);
}
if (GetForegroundWindow() != wnd.hWnd)
{
// Code by Daniel P. Stasinski
// Converted to C# by Kevin Gale
IntPtr Timeout = IntPtr.Zero;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, Timeout, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Dummy, SPIF_SENDCHANGE);
BringWindowToTop(wnd.hWnd); // IE 5.5 related hack
SetForegroundWindow(wnd.hWnd);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Timeout, SPIF_SENDCHANGE);
}
Code Explained
Making a window the foreground window
requires more than just calling the
SetForegroundWindow API. You must
first determine the foreground thread
and attach it to your window, using
AttachThreadInput, then call
SetForegroundWindow. That way they can
share input states.
First I call GetForegroundWindow to
get the handle of the current
foreground window. Then a few calls to
GetWindowThreadProcessId retrieve the
threads associated with the current
foreground window and the window I
want to bring to the foreground. If
these threads are the same a simple
call to SetForegroundWindow is all
that is necessary. Otherwise, the
foreground thread is attached to the
window that I am bringing to the front
and detached from what was the current
foreground window. The
AttachThreadInput API handles this.
Content Taken from here
Thanks.
I've used this method before:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
Process[] processes = Process.GetProcessesByName("processname");
SetForegroundWindow(processes[0].MainWindowHandle);
More information: http://pinvoke.net/default.aspx/user32.SetForegroundWindow
This code restores and set focus to a window:
[DllImport("User32.dll")]
static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, Int32 lParam);
static Int32 WM_SYSCOMMAND = 0x0112;
static Int32 SC_RESTORE = 0xF120;
And use it like this:
var proc = Process.GetProcessesByName("YourProgram").FirstOrDefault();
if (proc != null)
{
var pointer = proc.MainWindowHandle;
SetForegroundWindow(pointer);
SendMessage(pointer, WM_SYSCOMMAND, SC_RESTORE, 0);
}
In order for SetForegroundWindow to work consistently, you have to meet a few criteria. The first is your process that would run the command must be in the foreground. Only foreground process can make another process foreground. In order to make your process foreground first, you have to bring the main window to the front, if it is not. You minimise it first and then SetForegroundWindow it, to make it foreground. Now find the target process and bring it to the front
The steps are
Minimise the current window
SetForegroundWindow it
Find the target process
SetForegroundWindow it
I've got an example, though it's a slightly different use case.
You should use SetForegroundWindow. Also it may be interesting for you C# Force Form Focus
I'll be brief: Form.BringToFront()
As of Windows 7 these features dont behave quite so well. If there is an application such as Excel in front of the application you want to bring to the front then Windows 7 blocks this and flashes the window. You can set a registry timeout setting ForegroundLockTimeout=0 in HKEY_CURRENT_USER\Control Panel\Desktop but these is known as stealing focus. To set the behaviour of how XP "should" behave and will behave in Windows 7 by default you can create/set the value to 0x00030D40 (200000ms).
I'd like to know what is the preferred solution for trusted Windows applications. eg. If I trust application B to take focus when I double click something in Application A, and some other app is obscuring the window of Application B.
I have a console application I'm using to run scheduled jobs through windows scheduler. All the communication to/from the application is in email, event logging, database logs. Is there any way I can suppress the console window from coming up?
Sure. Build it as a winforms app and never show your form.
Just be careful, because then it's not really a console app anymore, and there are some environments where you won't be able to use it.
Borrowed from MSDN (link text):
using System.Runtime.InteropServices;
...
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
...
//Sometimes System.Windows.Forms.Application.ExecutablePath works for the caption depending on the system you are running under.
IntPtr hWnd = FindWindow(null, "Your console windows caption"); //put your console window caption here
if(hWnd != IntPtr.Zero)
{
//Hide the window
ShowWindow(hWnd, 0); // 0 = SW_HIDE
}
if(hWnd != IntPtr.Zero)
{
//Show window again
ShowWindow(hWnd, 1); //1 = SW_SHOWNORMA
}
It's a hack, but the following blog post describes how you can hide the console window:
http://expsharing.blogspot.com/2008/03/hideshow-console-window-in-net-black.html
Schedule the task to run as a different user than your account and you won't get a window popping up . . .
Simply configure the Scheduled Task as "Run whether user is logged on or not".
Why don't you make the application a Windows Service?