im trying to get the name of each window i click on. I have working code but its using system timers instead of timers on the form. i will post code so its eaiser to see what im doing wrong. its also not letting me refer back to my text box, i think i need to bring it into the function.
heres the Dll imports and variables
private static string LastActiveWindow = "";
private static string ActiveWindowName = "";
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWind, StringBuilder lpString, int nMaxCount);
and then i have my timer running 10 times a second which will run the active window function:
private void TimerActiveWindow_Tick(object sender, EventArgs e)
{
ActiveWindow();
}
private static void ActiveWindow(object Obj, EventArgs e)
{
IntPtr hwnd = GetForegroundWindow();
const int Capacity = 512;
var text = new StringBuilder(Capacity);
try
{
if (GetWindowText(hwnd, text, Capacity) > 0)
{
if (ActiveWindowName != text.ToString())
{
if (!LastActiveWindow.Equals(text.ToString()))
{
// TxtBody.text += "<br><font color = purple> Current Window - [" + text.ToString() + "]</font><br>";
LastActiveWindow = text.ToString();
MessageBox.Show(text.ToString());
}
}
}
}
catch { }
}
The only difference is the timer which on my program which uses the system timer looks like this
System.Timers.Timer TimerActiveWindow = new System.Timers.Timer();
TimerActiveWindow.Elapsed += new ElapsedEventHandler(Program.ActiveWindow);
TimerActiveWindow.AutoReset = true;
TimerActiveWindow.Interval = 100;
Related
I am using the code posted in this question with some minor changes:
Embed Unity3D app inside WPF *without* having it take up the whole window
This approach worked great, but when I am looking at my task manager processes. My main WPF executable name is removed from the process when I exit the page running the unity player and load another page. The application still works just fine. Task Manager just shows an icon with no process name next to it. This is only an issue because I have another background service that monitor my WPF application and starts and stops it remotely based on its name. Any suggestion?
Page Code Shown Below.
public System.Windows.Forms.Integration.WindowsFormsHost host = new System.Windows.Forms.Integration.WindowsFormsHost();
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private Process process;
private IntPtr unityHWND = IntPtr.Zero;
private const int WM_ACTIVATE = 0x0006;
private readonly IntPtr WA_ACTIVE = new IntPtr(1);
private readonly IntPtr WA_INACTIVE = new IntPtr(0);
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
bool initialized = false;
public UnityPlayer()
{
InitializeComponent();
if (this.grid1.Children.Count == 0)
{
this.grid1.Children.Add(host);
}
dispatcherTimer.Tick += attemptInit;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
void attemptInit(object sender, EventArgs e)
{
if (process != null)
{
if (process.HasExited)
{
Thread.Sleep(1000);
FSC.GoHome();
}
}
if (initialized)
return;
HwndSource source = (HwndSource)HwndSource.FromVisual(host);
Console.WriteLine("attempting to get handle...");
if (source == null)
{
Console.WriteLine("Failed to get handle source");
return;
}
IntPtr hWnd = source.Handle;
try
{
process = new Process();
process.StartInfo.FileName = "Block Breaker.exe";
process.StartInfo.Arguments = "-parentHWND " + hWnd.ToInt32() + " " + Environment.CommandLine;
process.StartInfo.UseShellExecute = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForInputIdle();
// Doesn't work for some reason ?!
//unityHWND = process.MainWindowHandle;
EnumChildWindows(host.Handle, WindowEnum, IntPtr.Zero);
//unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8");
Console.WriteLine("Unity HWND: 0x" + unityHWND.ToString("X8"));
panel1_Resize(this, EventArgs.Empty);
initialized = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ".\nCheck if Container.exe is placed next to UnityGame.exe.");
}
}
private void ActivateUnityWindow()
{
SendMessage(unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero);
}
private void DeactivateUnityWindow()
{
SendMessage(unityHWND, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero);
}
private int WindowEnum(IntPtr hwnd, IntPtr lparam)
{
unityHWND = hwnd;
ActivateUnityWindow();
return 0;
}
private void panel1_Resize(object sender, EventArgs e)
{
MoveWindow(unityHWND, 0, 0, (int)host.Width, (int)host.Height, true);
Console.WriteLine("RESIZED UNITY WINDOW TO: " + (int)host.Width + "x" + (int)host.Height);
ActivateUnityWindow();
}
private void Page_Unloaded(object sender, RoutedEventArgs e)
{
dispatcherTimer.Stop();
dispatcherTimer = null;
host.Dispose();
}
Image Show Process Before the pages loads
Image show Process While the page is running
Image show Process After the pages exits and loads new page
I am getting the automation element on windows using mouse cordinates(x &y)
static Rect m_bRect = new Rect(0, 0, 0, 0);
AutomationElement element = AutomationElement.FromPoint(new Point((double)Cursor.Position.X, (double)Cursor.Position.Y));
m_bRect = element.Current.BoundingRectangle;
i want to achieve one functionality that if user cursor position is not inside element Boundingrectangle then Block the input calls using API user32.dll, for that i have written below code on mouse down operation.
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern void BlockInput([In, MarshalAs(UnmanagedType.Bool)]bool fBlockIt);
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetCursorPos(ref POINT p);
private void HookManager_MouseDown(object sender, MouseEventArgs e)
{
POINT l_objPoint = new POINT();
bool l_bretVal = GetCursorPos(ref l_objPoint);
while (!m_bRect .Contains(l_objPoint.X, l_objPoint.Y)
{
BlockInput(true);
break;
}
}
But above code is not working as expected, it takes user clicks even if user cursor is not inside automation element boundingrectangle.
I have also tried another approach using timer tick please check below code but here Automationelement is not captured correctly.
private void OnHovering()
{
System.Windows.Forms.Timer _timerOnHover = new System.Windows.Forms.Timer();
_timerOnHover.Tick += new EventHandler(_timerOnHovering_Tick);
_timerOnHover.Interval = 100;
_timerOnHover.Start();
}
private void _timerOnHovering_Tick(object sender, EventArgs e)
{
POINT currentPoint = new POINT();
bool l_bretVal = GetCursorPos(ref currentPoint);
if (!l_bretVal)
{
return;
}
if (!m_bRect.Contains(currentPoint.X, currentPoint.Y && !ISmouseMove)
{
BlockInput(true);
}
else
{
BlockInput(false);
}
}
}
I've created some global Hot keys for my application and I want them to work only if my application is active. (It should not work if my application is not the active form).
So how can I check if my C# winform application is the active form among all the other windows applications?
I tried
if(this.Focused)
//Do somthing
But it's not working
Try this:
[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);
public static bool Activates()
{
var x = GetForegroundWindow();
if (x == IntPtr.Zero) {
return false;
}
var y = Process.GetCurrentProcess().Id;
int i;
GetWindowThreadProcessId(x, out i);
return i == y;
}
You can also refer: C#: Detecting which application has focus
You can use Windows API function GetForegroundWindow and GetWindowText.
GetForegroundWindow :
The GetForegroundWindow function returns a handle to the window with which the user is currently working.
GetWindowText:
The GetWindowText function copies the text of the specified window's title bar (if it has one) into a buffer.
Add below code to declare API functions :
[ DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[ DllImport("user32.dll") ]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
Start a timer :
private void timer1_Tick(object sender, System.EventArgs e)
{
GetActiveWindow();
}
Active window function :
private void GetActiveWindow()
{
const int nChars = 256;
int handle = 0;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
if ( GetWindowText(handle, Buff, nChars) > 0 )
{
this.captionWindowLabel.Text = Buff.ToString();
this.IDWindowLabel.Text = handle.ToString();
}
}
what i need to do is that I need to control another application installed on the same machine using my custom application. For example if i needed to use the standard windows calculator I would simply send the input events to the calculator. I have used some code snippets to make this possible and I have now triggered both mouse and keyboard events. but the problem is that i can be sure that the keyboard event will hit the target application because it has the process handle. but i cannot be sure about the mouse. and also if the target application goes into background, i cannot initiate mouse clicks on it. I need help to find a way to make sure that the mouse click is done on the application only.
I need to send mouse co-ordinates and click as well. for example "sendMouseClick("Notepad", 100, 400); which will send a click to Notepad, even though it stays minimized.
IMPORTANT NOTE
A similar question is answered previously but that is in reference to first finding the state of the other application and then sending the inputs either keyboard or mouse, what i need to do is to send an application a set of instructions that must work whether the application is in foreground or not.
For "The other Guys":: if you dont want to help or cant help, thats okay but please do know that i havent stolen the question or anything. I simply want to achieve this task in C#.
The code I have to simulate keyboard key Press is:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;
namespace SimulateKeyPress
{
partial class Form1 : Form
{
private Button button1 = new Button();
private Button button2 = new Button();
private Button button3 = new Button();
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
public Form1()
{
button1.Location = new Point(10, 10);
button1.TabIndex = 1;
button1.Text = "Click to automate Calculator";
button1.AutoSize = true;
button1.Click += new EventHandler(button1_Click);
button2.Location = new Point(150, 140);
button2.TabIndex = 0;
button2.Text = "Click to Exit Calculator";
button2.AutoSize = true;
button2.Location = new Point(80, 80);
button2.TabIndex = 2;
button2.Text = "Click to Run Calculator";
button2.AutoSize = true;
button2.Click += new EventHandler(button2_Click);
this.DoubleClick += new EventHandler(Form1_DoubleClick);
this.Controls.Add(button1);
this.Controls.Add(button2);
// this.Controls.Add(button3);
}
// 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");
//Process firstProc = new Process();
//firstProc.StartInfo.FileName = "calc.exe";
//firstProc.EnableRaisingEvents = true;
//firstProc.Start();
// 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("1024");
SendKeys.SendWait("*");
SendKeys.SendWait("32");
SendKeys.SendWait("=");
}
private void button2_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start("calc.exe");
}
private void button3_Click(object sender,EventArgs e)
{
Process [] proc =Process.GetProcessesByName("Calculator");
proc[0].Kill();
}
// Send a key to the button when the user double-clicks anywhere
// on the form.
private void Form1_DoubleClick(object sender, EventArgs e)
{
// Send the enter key to the button, which raises the click
// event for the button. This works because the tab stop of
// the button is 0.
SendKeys.Send("{ENTER}");
}
}
}
the previous help on stack overflow, msdn and other sites provides the code to simulate a mouse click in the same application. But i need to send mouse hits to another application.
Maybe this could help you
Code
The task
Getting the mouse's current position
Sending the mouse event
Windows forms
...
using System.Runtime.InteropServices;
namespace yournamespace
{
public partial class yourclassname
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
int X = Cursor.Position.X;
int Y = Cursor.Position.Y;
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}
}
WPF
Things are a bit harder in WPF
double mousePointX;
double mousePointY;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out POINT lpPoint);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
private void WritePoint(object sender, RoutedEventArgs e)
{
POINT p;
if (GetCursorPos(out p))
{
System.Console.WriteLine(Convert.ToString(p.X) + ";" + Convert.ToString(p.Y));
}
}
[DllImport("User32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
private Point ConvertPixelsToUnits(int x, int y)
{
// get the system DPI
IntPtr dDC = GetDC(IntPtr.Zero); // Get desktop DC
int dpi = GetDeviceCaps(dDC, 88);
bool rv = ReleaseDC(IntPtr.Zero, dDC);
// WPF's physical unit size is calculated by taking the
// "Device-Independant Unit Size" (always 1/96)
// and scaling it by the system DPI
double physicalUnitSize = (1d / 96d) * (double)dpi;
Point wpfUnits = new Point(physicalUnitSize * (double)x,
physicalUnitSize * (double)y);
return wpfUnits;
}
private void WriteMouseCoordinatesInWPFUnits()
{
POINT p;
if (GetCursorPos(out p))
{
Point wpfPoint = ConvertPixelsToUnits(p.X, p.Y);
System.Console.WriteLine(Convert.ToString(wpfPoint.X) + ";" + Convert.ToString(wpfPoint.Y));
mousePointY = wpfPoint.Y;
mousePointX = wpfPoint.X
}
}
Now the most important part of the code
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
...
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, Convert.ToUInt32(mousePointX), Convert.ToUInt32(mousePointY), 0, 0);
...
Warning
The code is tested
The code is not a "copy & paste code
I have a problem with getting scrollbar positions. Is it possible to get the scrollbar position of another process for example Notepad. I wrote small app where i tested and always get 0 0 as a position of scrollbars.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll")]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
private void Form1_Load(object sender, EventArgs e)
{
this.SuspendLayout();
Process notepad = new Process();
ProcessStartInfo psi = new ProcessStartInfo(#"c:\list1.txt");
psi.WindowStyle = ProcessWindowStyle.Normal;
notepad.StartInfo = psi;
notepad.Start();
this.ResumeLayout();
notepad.WaitForInputIdle(3000);
IntPtr old = SetParent(notepad.MainWindowHandle, this.Handle);
SetWindowLong(notepad.MainWindowHandle, GWL_STYLE, WS_VISIBLE + WS_MAXIMIZE);
MoveWindow(notepad.MainWindowHandle, 100, 100, 400, 400, true);
SetActiveWindow(notepad.MainWindowHandle);
SwitchToThisWindow(notepad.MainWindowHandle, true);
}
I have button which send PGDN event to notepad and it works great but after pgdn event position of scrollbar also is 0 0
private void PGDN_Click(object sender, EventArgs e)
{
Process[] procs = Process.GetProcessesByName("Notepad");
IntPtr hwnd = procs[0].MainWindowHandle;
SetActiveWindow(hwnd);
SwitchToThisWindow(hwnd, true);
Thread.Sleep(2000);
SendKeys.SendWait("{PGDN}");
Thread.Sleep(2000);
label1.Text = "OK";
label1.Text = "";
label1.Text = HScrollPos().ToString() + " " + VScrollPos().ToString(); }
Here are the HScrollPos and VScrollPos functions :
public int VScrollPos()
{
Process[] procs = Process.GetProcessesByName("Notepad");
IntPtr hwnd = procs[0].MainWindowHandle;
if (procs.Length != 0)
{
return GetScrollPos(hwnd , SB_VERT);
}
else
{
MessageBox.Show("Notepad Nor Running");
return 0;
}
}
public int HScrollPos()
{
Process[] procs = Process.GetProcessesByName("Notepad");
IntPtr hwnd = procs[0].MainWindowHandle;
if (procs.Length != 0)
{
return GetScrollPos(hwnd , SB_HORZ);
}
else
{
MessageBox.Show("Notepad Nor Running");
return 0;
}
}
Maybe there is another way to get Scrollbar Position of another process/window in windows? Please Help. Thx for granted.
And here is the Working Code based on Answer. Thx
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
private void button4_Click(object sender, EventArgs e)
{
string lpszParentClass = "Notepad";
string lpszParentWindow = "Untitled - Notepad";
string lpszClass = "Edit";
IntPtr ParenthWnd = new IntPtr(0);
IntPtr hWnd = new IntPtr(0);
ParenthWnd = FindWindow(lpszParentClass, lpszParentWindow);
if (ParenthWnd.Equals(IntPtr.Zero))
MessageBox.Show("Notepad Not Running");
else
{
hWnd = FindWindowEx(ParenthWnd, hWnd, lpszClass, "");
if (hWnd.Equals(IntPtr.Zero))
MessageBox.Show("Notepad doesn't have an edit component ?");
else
{
MessageBox.Show("Notepad Window: " + ParenthWnd.ToString());
MessageBox.Show("Edit Control: " + hWnd.ToString());
}
}
SetActiveWindow(ParenthWnd);
label5.Text = GetScrollPos(hWnd, SB_VERT) + " " + GetScrollPos(hWnd, SB_HORZ);
}
I suspect the problem is that you are using the main window handle, you should be using the handle of the Edit control, which is a child of the main window.
Using the main window hwnd you can enumrate the child windows to find the hWnd of the edit control and then use that hWnd in your call to get the scroll bar position.
SendKeys is working because it is sending the key stroke to the window that has input focus which in this case is the Edit control.
Here is an answer to a question I provided sometime back that will help with the interop for EnumChildWindows if you need, there is a lot more there but it might help.