I have the following code:
The using statements are
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
Before the Main I have
// import the function in your
[DllImport("User32.dll")]
static extern int SetForegroundWindow(IntPtr point);
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
[STAThreadAttribute]
static void **Main**(string[] args)
Within the Main I have
// Get the Processes
Process[] p = Process.GetProcesses();
string processName = "";
// Loop through the processes list
for (int i = 0; i < p.Length; i++)
{
// Find myProcessName
if (p[i].ProcessName == "myProcessName")
{
Console.WriteLine("PID: " + p[i].Id);
processName = p[i].ProcessName;
}
}
// Set the process/window to the foreground
Process p = Process.GetProcessesByName(processName)[0];
if (p != null)
{
// Get the process handle
IntPtr h = p.MainWindowHandle;
// Set the window to the foreground
SetForegroundWindow(h);
// Wait to get idle
p.WaitForInputIdle();
// Set the Active window
SetActiveWindow(h);
// Wait to get idle
p.WaitForInputIdle();
}
// Select the Text
MouseOperations.SetCursorPosition(1269, 218);
MouseOperations.MouseEvent(MouseOperations.MouseEventFlags.LeftDown);
MouseOperations.MouseEvent(MouseOperations.MouseEventFlags.LeftUp);
MouseOperations.SetCursorPosition(123, 310);
MouseOperations.MouseEvent(MouseOperations.MouseEventFlags.LeftDown);
MouseOperations.SetCursorPosition(133, 502);
// Send the Ctrl+C
SendKeys.SendWait("^c");
// Application.DoEvents();
// Print the clipboard
if (Clipboard.ContainsText())
{
Console.WriteLine("##########################################");
Console.WriteLine(Clipboard.GetText());
Console.WriteLine("##########################################");
}
// Done, lift the left mouse key
MouseOperations.MouseEvent(MouseOperations.MouseEventFlags.LeftUp);
The MouseOperations was taken from here (https://stackoverflow.com/a/7121314/1933657)
I run the program from within VisualStudio 2019, the CommandWindow shows up, the program I want comes up above the CommandWindow, the Text is selected, but nothing is ever copied to the Clipboard.
Any ideas what I am missing here?
Related
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();
}
}
I basically have code that starts the keyboard, but it opens in alphanumeric portion and the box for editing is a NumericUpDown with numbers. So, I want to open tabtip.exe aka the onscreen keyboard in windows 8.1 with the numerpad focused. Here is my current code for opening tabtip, but again it does not open with numpad by default:
using System.Runtime.InteropServices; //added for keyboard closure
using System.Windows.Interop; //Keyboard closure - must add reference for WindowsBase
//Added for keyboard closure
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(String sClassName, String sAppName);
//open keyboard
void openKeyboard()
{
ProcessStartInfo startInfo = new ProcessStartInfo(#"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);
}
//close keyboard
void closeKeyboard()
{
uint WM_SYSCOMMAND = 274;
uint SC_CLOSE = 61536;
IntPtr KeyboardWnd = FindWindow("IPTip_Main_Window", null);
PostMessage(KeyboardWnd.ToInt32(), WM_SYSCOMMAND, (int)SC_CLOSE, 0);
}
There's also seems to be some registry edit you can do, but I can't seem to get it to make the numpad portion of the taptip keyboard in windows 8.1 to show:
Windows 8 Desktop App: Open tabtip.exe to secondary keyboard (for numeric textbox)
Currently with Windows 8.1, not much functionality seems to be programmatically exposed.
The code below will cause the tabtip.exe to read the registry because the original process is killed.
It is not completely reliable, but is a way to for it to respond to some registry values.
The part about docking is optional, it forces it to dock each time via the registry change.
The process.Kill(); should be in a try/catch since it occasionally doesn't have permission and can throw an exception.
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string sClassName, string sAppName);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(int hWnd, uint msg, int wParam, int lParam);
private static void KillTabTip()
{
// Kill the previous process so the registry change will take effect.
var processlist = Process.GetProcesses();
foreach (var process in processlist.Where(process => process.ProcessName == "TabTip"))
{
process.Kill();
break;
}
}
public void ShowTouchKeyboard(bool isVisible, bool numericKeyboard)
{
if (isVisible)
{
const string keyName = "HKEY_CURRENT_USER\\Software\\Microsoft\\TabletTip\\1.7";
var regValue = (int) Registry.GetValue(keyName, "KeyboardLayoutPreference", 0);
var regShowNumericKeyboard = regValue == 1;
// Note: Remove this if do not want to control docked state.
var dockedRegValue = (int) Registry.GetValue(keyName, "EdgeTargetDockedState", 1);
var restoreDockedState = dockedRegValue == 0;
if (numericKeyboard && regShowNumericKeyboard == false)
{
// Set the registry so it will show the number pad via the thumb keyboard.
Registry.SetValue(keyName, "KeyboardLayoutPreference", 1, RegistryValueKind.DWord);
// Kill the previous process so the registry change will take effect.
KillTabTip();
}
else if (numericKeyboard == false && regShowNumericKeyboard)
{
// Set the registry so it will NOT show the number pad via the thumb keyboard.
Registry.SetValue(keyName, "KeyboardLayoutPreference", 0, RegistryValueKind.DWord);
// Kill the previous process so the registry change will take effect.
KillTabTip();
}
// Note: Remove this if do not want to control docked state.
if (restoreDockedState)
{
// Set the registry so it will show as docked at the bottom rather than floating.
Registry.SetValue(keyName, "EdgeTargetDockedState", 1, RegistryValueKind.DWord);
// Kill the previous process so the registry change will take effect.
KillTabTip();
}
Process.Start("c:\\Program Files\\Common Files\\Microsoft Shared\\ink\\TabTip.exe");
}
else
{
var win8Version = new Version(6, 2, 9200, 0);
if (Environment.OSVersion.Version >= win8Version)
{
const uint wmSyscommand = 274;
const uint scClose = 61536;
var keyboardWnd = FindWindow("IPTip_Main_Window", null);
PostMessage(keyboardWnd.ToInt32(), wmSyscommand, (int)scClose, 0);
}
}
}
You can call the above method from a custom version of a TextBox where OnTouchDown is overridden and an additional DependencyProperty is created to indicate if the field uses the NumericKeyboard:
#region NumericKeyboard
public static readonly DependencyProperty NumericKeyboardProperty = DependencyProperty.Register("NumericKeyboard", typeof(bool), typeof(CustomTextBox), new FrameworkPropertyMetadata(false));
/// <summary> Returns/set the "NumericKeyboard" state of the CustomTextBox. </summary>
public bool NumericKeyboard
{
get { return (bool)GetValue(NumericKeyboardProperty); }
set { SetValue(NumericKeyboardProperty, value); }
}
#endregion
protected override void OnTouchDown(TouchEventArgs e)
{
base.OnTouchDown(e);
Focus();
if (IsReadOnly == false)
ShowTouchKeyboard(true, NumericKeyboard);
}
Currently, I have not had any success using similar techniques to position the TabTip window around the screen when in a floating (non-docked) state.
I tried it with findwindow and process but it didn't work, how can I find a specific button ?
For example I have the button class AfxWnd90u and the instance 21. I want to check if this button is visible. I tried it with this code, but I couldn't find the button. I think I made a mistake with the instance.
Between I didn't use findwindow here because I experimented a little bit.
//////IMPORTANT/////////////
System.Diagnostics.Process[] move = System.Diagnostics.Process.GetProcessesByName("PartyGaming");
ArrayList save = new ArrayList();
RECT rct = new RECT();
listBox1.Items.Add(move.Length);
List<System.Diagnostics.Process> process = new List<System.Diagnostics.Process>();
// use only the process with the button AfxWnd90u21
for (int i = 0; i < move.Length;++i )
{
IntPtr hCheck = FindWindowEx(move[i].MainWindowHandle, IntPtr.Zero, "AfxWnd90u21", null);
//if button is visible
if (hCheck != IntPtr.Zero)
process.Add(move[i]);
//////IMPORTANT/////////////
}
I believe a combination of FindWindow and SendMessage Windows API functions will give you want you want. The tricky part will be discovering the window class names, but something like WinSpy++ could help you there.
Here's a sample of how to use the API. Open Notepad.exe a few times, type in some text and then run this sample.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<WinText> windows = new List<WinText>();
//find the "first" window
IntPtr hWnd = FindWindow("notepad", null);
while (hWnd != IntPtr.Zero)
{
//find the control window that has the text
IntPtr hEdit = FindWindowEx(hWnd, IntPtr.Zero, "edit", null);
//initialize the buffer. using a StringBuilder here
System.Text.StringBuilder sb = new System.Text.StringBuilder(255); // or length from call with GETTEXTLENGTH
//get the text from the child control
int RetVal = SendMessage(hEdit, WM_GETTEXT, sb.Capacity, sb);
windows.Add(new WinText() { hWnd = hWnd, Text = sb.ToString() });
//find the next window
hWnd = FindWindowEx(IntPtr.Zero, hWnd, "notepad", null);
}
//do something clever
windows.OrderBy(x => x.Text).ToList().ForEach(y => Console.Write("{0} = {1}\n", y.hWnd, y.Text));
Console.Write("\n\nFound {0} window(s).", windows.Count);
Console.ReadKey();
}
private struct WinText
{
public IntPtr hWnd;
public string Text;
}
const int WM_GETTEXT = 0x0D;
const int WM_GETTEXTLENGTH = 0x0E;
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, int msg, int Param, System.Text.StringBuilder text);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
}
}
Autoit provides a great way to interact with Windows.
Install the nuget package called AutoItX.Dotnet
using AutoIt;
class Program
{
static void Main(string[] args)
{
var buttonVisible = AutoItX.ControlCommand("Untitled - Notepad", "", "[CLASSNN:Edit1]", "IsVisible", "");
//in your case it would be:
//var buttonVisible = AutoItX.ControlCommand("Put the application title here", "", "[CLASSNN:AfxWnd90u21]", "IsVisible", "");
if (buttonVisible == "1")
{
Console.WriteLine("Visible");
} else
{
Console.WriteLine("Not visible");
}
}
}
I am writing a Console application using C#, in which I am firing Print jobs through code. My issue is I do not know how much time I should wait for Print Dialog after sending commands to Print. For the time being I am using Thread sleep of 1000 milliseconds.
//Sending Commands to Print(to press "Ctrl+P" button).
SendKeys.SendWait("^(p)");
Thread.Sleep(1000);
//Sending Commands to Print(to press "Enter" Button).
SendKeys.SendWait("{ENTER}");
Can anybody help me to fix this issue please. Any help will be appreciated.
Thanks in advance
Update:
Here is my whole code:
//Launch the file from the location specified in.
White.Core.Application application =White.Core.Application.Launch(#path);
Console.WriteLine("launch is done");
Thread.Sleep(_delayOfPrint);
//Sending Commands to Print(to press "Ctrl+P" button).
SendKeys.SendWait("^(p)");
Thread.Sleep(1000);
//Sending Commands to Print(to press "Enter" Button).
SendKeys.SendWait("{ENTER}");
//Get the current time as the document fired for print job.
_printedTime = DateTime.Now;
Thread.Sleep(1500);
//Closing the window.
SendKeys.SendWait("%{F4}");
I would have a maximum wait of a few seconds, but during that time I would periodically use the Win32 function FindWindowEx to see if the print dialog actually came up, and if so proceed. You can get a process' main window with code like this:
Process[] processes = Process.GetProcessesByName(appName);
foreach (Process p in processes)
{
IntPtr pFoundWindow = p.MainWindowHandle;
}
You can then pass the found main window handle to FindWindowEx to peruse the child windows to check for the print dialog. FindWindowEx has PInvoke signatures like this:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
Edit 2: Since the OP seems to be demanding I give a perfectly working function, I wrote a general one that does the trick and tested it. Here it is, working general code to wait for any child window. Call as WaitForChildWindow("myApp", "Print", 5000) for this case:
/// <summary>
/// Wait for a child window of an application to appear
/// </summary>
/// <param name="appName">Application name to check (will check all instances)</param>
/// <param name="childWindowName">Name of child window to look for (titlebar)</param>
/// <param name="timeout">Maximum time, in milliseconds, to wait</param>
/// <returns>True if the window was found; false if it wasn't.</returns>
public static bool WaitForChildWindow(string appName, string childWindowName, int timeout)
{
int sleepTime = timeout;
while (sleepTime > 0)
{
Process[] processes = Process.GetProcessesByName(appName);
foreach (Process p in processes)
{
IntPtr pMainWindow = p.MainWindowHandle;
IntPtr pFoundWindow = FindWindowEx(pMainWindow, IntPtr.Zero, null, childWindowName);
if (pFoundWindow != IntPtr.Zero)
return true;
}
Thread.Sleep(100);
sleepTime -= 100;
}
// Timed out!
return false;
}
Edit 3: Here's another way of doing it for merely owned windows that don't have a child relationship:
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hwnd, IntPtr processId);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
private extern static int GetWindowText(IntPtr hWnd, StringBuilder text, int maxCount);
public delegate bool EnumThreadDelegate(IntPtr hwnd, IntPtr lParam);
static bool EnumThreadCallback(IntPtr hWnd, IntPtr lParam)
{
StringBuilder text = new StringBuilder(500);
GetWindowText(hWnd, text, 500);
if (text.ToString() == "Print")
return false;
return true;
}
public static bool FindThreadPrintWindow(uint threadId)
{
return !EnumThreadWindows(threadId, EnumThreadCallback, IntPtr.Zero);
}
public static bool WaitForOwnedPrintWindow(string appName, int timeout)
{
int sleepTime = timeout;
while (sleepTime > 0)
{
Process[] processes = Process.GetProcessesByName(appName);
foreach (Process p in processes)
{
IntPtr pMainWindow = p.MainWindowHandle;
uint threadId = GetWindowThreadProcessId(pMainWindow, IntPtr.Zero);
if (FindThreadPrintWindow(threadId))
return true;
}
Thread.Sleep(100);
sleepTime -= 100;
}
// Timed out!
return false;
}
I'd like to know how to grab the Window title of the current active window (i.e. the one that has focus) using C#.
See example on how you can do this with full source code here:
http://www.csharphelp.com/2006/08/get-current-window-handle-and-caption-with-windows-api-in-c/
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
Edited with #Doug McClean comments for better correctness.
If you were talking about WPF then use:
Application.Current.Windows.OfType<Window>().SingleOrDefault(w => w.IsActive);
Based on GetForegroundWindow function | Microsoft Docs:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowTextLength(IntPtr hWnd);
private string GetCaptionOfActiveWindow()
{
var strTitle = string.Empty;
var handle = GetForegroundWindow();
// Obtain the length of the text
var intLength = GetWindowTextLength(handle) + 1;
var stringBuilder = new StringBuilder(intLength);
if (GetWindowText(handle, stringBuilder, intLength) > 0)
{
strTitle = stringBuilder.ToString();
}
return strTitle;
}
It supports UTF8 characters.
Loop over Application.Current.Windows[] and find the one with IsActive == true.
Use the Windows API. Call GetForegroundWindow().
GetForegroundWindow() will give you a handle (named hWnd) to the active window.
Documentation: GetForegroundWindow function | Microsoft Docs
If it happens that you need the Current Active Form from your MDI application: (MDI- Multi Document Interface).
Form activForm;
activForm = Form.ActiveForm.ActiveMdiChild;
you can use process class it's very easy.
use this namespace
using System.Diagnostics;
if you want to make a button to get active window.
private void button1_Click(object sender, EventArgs e)
{
Process currentp = Process.GetCurrentProcess();
TextBox1.Text = currentp.MainWindowTitle; //this textbox will be filled with active window.
}