How To Give Back Focus From Console Window in C#? - c#

I have a C# console application (A) that opens with the black windows console. Sometimes at startup it steals the focus from another program (B) that needs the focus.
Question: How can I give focus back from A.exe to B.exe ?
A -> Focus -> B
Details:
Program B is not mine and I can't do anything about it. It has a GUI, multiple windows and 1 of them needs the focus (it might be a modal dialog window).
Program A doesn't need any focus and it doesn't interact in any way with program B.
Program A starts via Startup shortcut and runs basically in background (it is released but still in development though, that's why console window)
I have a few moments/up to minutes to check and give the focus back.

// this should do the trick....
[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);
}
}

To do this for your current running C# Console app...
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr zeroOnly, string lpWindowName);
public const int SW_RESTORE = 9;
static void FocusMe()
{
string originalTitle = Console.Title;
string uniqueTitle = Guid.NewGuid().ToString();
Console.Title = uniqueTitle;
Thread.Sleep(50);
IntPtr handle = FindWindowByCaption(IntPtr.Zero, uniqueTitle);
Console.Title = originalTitle;
ShowWindowAsync(new HandleRef(null, handle), SW_RESTORE);
SetForegroundWindow(handle);
}

Related

Sending a string of characters as a keystroke to any application in WPF [duplicate]

I want to simulate F5 key press in my C# program. When IE is open, I want to be able refresh my website automatically.
How can I do that?
Here's an example...
static class Program
{
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
[STAThread]
static void Main()
{
while(true)
{
Process [] processes = Process.GetProcessesByName("iexplore");
foreach(Process proc in processes)
{
SetForegroundWindow(proc.MainWindowHandle);
SendKeys.SendWait("{F5}");
}
Thread.Sleep(5000);
}
}
}
a better one... less anoying...
static class Program
{
const UInt32 WM_KEYDOWN = 0x0100;
const int VK_F5 = 0x74;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
[STAThread]
static void Main()
{
while(true)
{
Process [] processes = Process.GetProcessesByName("iexplore");
foreach(Process proc in processes)
PostMessage(proc.MainWindowHandle, WM_KEYDOWN, VK_F5, 0);
Thread.Sleep(5000);
}
}
}
You can use the Win32 API FindWindow or FindWindowEx to find the window handle of the open browser and then just call SendMessage with WM_KEYDOWN. Typically it's easiest just to pass the window caption to FindWindowEx and have it find the associated window handle for you.
If you are starting the browser process yourself via a Process process object then you can use process.MainWindowHandle instead of calling FindWindowEx.
Spy++ is a very useful tool when you want to start working with other windows. It basically allows you to learn another program's hierarchy of UI elements. You can also monitor all of the messages that go into the window you're monitoring. I have more info in this thread.
The F5 keystroke has this virtual key code:
const int VK_F5 = 0x74;
The p/invoke signature for FindWindowEx in C# is:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
You can p/invoke (bring in) the Win32 API SendMessage like this:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
So to recap, you call FindWindowEx directly from your C# code after having the above code somewhere inside your class. FindWindowEx will return a window handle. Then once you have the window handle, you can send any keystroke(s) to the window, or call many other Win32 API calls on the window handle. Or even find a child window by using another call to FindWindowEx. For example you could select the edit control of the browser even and then change it's text.
If all else goes wrong and you think you're sending the right key to the window, you can use spy++ to see what messages are sent to the window when you manually set focus to the browser and manually press F5.
The easiest way to send (simulate) KeyStrokes to any window is to use the SendKeys.Send method of .NET Framework.
Checkout this very intuitive MSDN article http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
Particularly for your case, if your browser window is in focus, sending F5 would just involve the following line of code:
SendKeys.Send("{F5}");
Simple one, add before Main
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
Code inside Main/Method:
string className = "IEFrame";
string windowName = "New Tab - Windows Internet Explorer";
IntPtr IE = FindWindow(className, windowName);
if (IE == IntPtr.Zero)
{
return;
}
SetForegroundWindow(IE);
InputSimulator.SimulateKeyPress(VirtualKeyCode.F5);
Note:
Add InputSimulator as reference. To download Click here
To find Class & Window name, use WinSpy++. To download Click here
Another alternative to simulating a F5 key press would be to simply host the WebBrowser control in the Window Forms application. You use the WebBrowser.Navigate method to load your web page and then use a standard Timer and on each tick of the timer you just re-Navigate to the url which will reload the page.
Easy, short and no need window focus:
Also here a usefull list of Virtual Key Codes
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private void button1_Click(object sender, EventArgs e)
{
const int WM_SYSKEYDOWN = 0x0104;
const int VK_F5 = 0x74;
IntPtr WindowToFind = FindWindow(null, "Google - Mozilla Firefox");
PostMessage(WindowToFind, WM_SYSKEYDOWN, VK_F5, 0);
}
Use mouse_event or keybd_event. They say not to use them anymore but you don't have to find the window at all.
using System;
using System.Runtime.InteropServices;
public class SimulatePCControl
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void keybd_event(uint bVk, uint bScan, uint dwFlags, uint dwExtraInfo);
private const int VK_LEFT = 0x25;
public static void LeftArrow()
{
keybd_event(VK_LEFT, 0, 0, 0);
}
}
Virtual Key Codes are here for this one: http://www.kbdedit.com/manual/low_level_vk_list.html
Also for mouse:
using System.Runtime.InteropServices;
using UnityEngine;
public class SimulateMouseClick
{
[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);
//Mouse actions
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public static void Click()
{
//Call the imported function with the cursor's current position
uint X = (uint)0;
uint Y = (uint)0;
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
Debug.LogError("SIMULATED A MOUSE CLICK JUST NOW...");
}
//...other code needed for the application
}
Instead of forcing an F5 keypress when you're just trying to get the page to postback, you can call a postback based on a JS event (even mousemove or timer_tick if you want it to fire all the time). Use the code at http://weblogs.asp.net/mnolton/archive/2003/06/04/8260.aspx as a reference.

SetForegroundWindow only working while visual studio is open

I'm trying to set with c# a process window to the foreground / focus (from an application that has no focus in that moment when doing it), therefore I'm using the user32.dll static extern bool SetForegroundWindow(IntPtr hWnd) method:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
public void setFocus()
{
SetForegroundWindow(process.MainWindowHandle);
}
Every thing is working fine, but only if I have the visual studio 2008 open, I don't even need to to start the application from the VS08, it's enough to have the project open with it. The moment I'm closing the project my application can't set the other window to the foreground. The only result is that in the taskbar the other window is blue highlighted. The moment I'm going to open my project with the VS08 again it's working fine.
I have not the slightest idea why...I thought the problem could be that he can't import the dll but then it wouldn't be highlighted, and other win32 functions like static extern bool ShowWindow(IntPtr hWnd, IntPtr status); are working even when the project is closed.
Any solutions or hints for this problem?
Edit:
I read the remarks for the function and I had the idea that my application has not the focus, so I tried this one:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
static extern bool AllowSetForegroundWindow(int procID);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
public void setAUTFocus()
{
IntPtr hWnd = GetForegroundWindow();
uint processID = 0;
uint threadID = GetWindowThreadProcessId(hWnd, out processID);
int intID = (int)processID;
AllowSetForegroundWindow(intID);
SetForegroundWindow(process.MainWindowHandle);
}
Now I'm searching for the window process that has focus at the moment and set the AllowSetForegroundWindow for this window and trying to set the focus on my window now. But the same problem, the moment I have the project in VS open it's working, if not I'm getting only the blue highlight in the taskbar.
During having my application running I can open / close the vs project, the moment it's open everything is working, the moment it's closed it's not working, I have no interaction with the VS project while running my application. Seriously I don't get it.
After searching a few days on the internet I have found one posible simple solution to make SetForegroundWindow to work on windows 7: press Alt key before calling SetForegroundWindow.
public static void ActivateWindow(IntPtr mainWindowHandle)
{
//check if already has focus
if (mainWindowHandle == GetForegroundWindow()) return;
//check if window is minimized
if (IsIconic(mainWindowHandle))
{
ShowWindow(mainWindowHandle, Restore);
}
// Simulate a key press
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
//SetForegroundWindow(mainWindowHandle);
// Simulate a key release
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
SetForegroundWindow(mainWindowHandle);
}
And the win32api imports
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x1;
private const int KEYUP = 0x2;
private const uint Restore = 9;
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hWnd, uint Msg);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
I had an issue with sending the Alt-key as it forced the window menu to open when I selected enter (instead of the OK button which is what I wanted).
This worked for me:
public static void ActivateWindow(IntPtr mainWindowHandle)
{
//check if already has focus
if (mainWindowHandle == GetForegroundWindow()) return;
//check if window is minimized
if (IsIconic(mainWindowHandle))
{
ShowWindow(mainWindowHandle, Restore);
}
// Simulate a key press
keybd_event(0, 0, 0, 0);
SetForegroundWindow(mainWindowHandle);
}

GetFocus - Win32api help

i am trying to grab the selected text from the open form on a users machine. Currently i have tried using GetFocus which is defined as
'[DllImport("user32.dll")]
static extern int GetFocus();'
In the api it says - Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue. Which explains why my app can grab the selected text from a window thats part of my app, but not one thats external, like a pdf for example.
What alternative win32 method is available for me to use that would fit this purpose?
Thanks.
edit: this is the attempt at the moment
[DllImport("user32.dll")]
static extern int GetFocus();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, int ProcessId);
[DllImport("user32.dll")]
static extern int GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
// second overload of SendMessage
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, out int wParam, out int lParam);
const int WM_SETTEXT = 12;
const int WM_GETTEXT = 13;
private static string PerformCopy()
{
try
{
//Wait 5 seconds to give us a chance to give focus to some edit window,
//notepad for example
System.Threading.Thread.Sleep(1000);
StringBuilder builder = new StringBuilder(500);
int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
//AttachTrheadInput is needed so we can get the handle of a focused window in another app
AttachThreadInput(remoteThreadId, currentThreadId, true);
//Get the handle of a focused window
int focused = GetFocus();
//Now detach since we got the focused handle
AttachThreadInput(remoteThreadId, currentThreadId, false);
//Get the text from the active window into the stringbuilder
SendMessage(focused, WM_GETTEXT, builder.Capacity, builder);
return builder.ToString();
}
catch (System.Exception oException)
{
throw oException;
}
}
Check GetForegroundWindow.
I don't think you have much chance of succeeding with your current approach. I'm pretty sure there's no single general purpose API for getting hold of the current selection. I believe this because each application can implement text selection in its own way.
As an alternative solution you should consider using a clipboard listener. Listen for changes to the clipboard contents and whenever text is added you can suck it out of the clipboard and put it in your app's window.
I think this is a job for UI Automation (the API screen readers use). Here's a post that get's the selected text in C#.

.Net Console Application in System tray

Is there a way I can put a console application in the system tray when minimizing ?
Yes, you can do this.
Create a Windows Forms application and add a NotifyIcon component.
Then use the following methods (found on MSDN) to allocate and display a Console
[DllImport("kernel32.dll")]
public static extern Boolean AllocConsole();
[DllImport("kernel32.dll")]
public static extern Boolean FreeConsole();
[DllImport("kernel32.dll")]
public static extern Boolean AttachConsole(Int32 ProcessId);
When your console is onscreen, capture the minimize button click and use it to hide the console window and update the Notify icon. You can find your window using the following methods (found on MSDN):
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
// Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
// Also consider whether you're being lazy or not.
[DllImport("user32.dll", EntryPoint="FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
Be sure to call FreeConsole whenever you're ready to close the app.
using System.Windows.Forms;
using System.Drawing;
static NotifyIcon notifyIcon = new NotifyIcon();
static bool Visible = true;
static void Main(string[] args)
{
notifyIcon.DoubleClick += (s, e) =>
{
Visible = !Visible;
SetConsoleWindowVisibility(Visible);
};
notifyIcon.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
notifyIcon.Visible = true;
notifyIcon.Text = Application.ProductName;
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("Exit", null, (s, e) => { Application.Exit(); });
notifyIcon.ContextMenuStrip = contextMenu;
Console.WriteLine("Running!");
// Standard message loop to catch click-events on notify icon
// Code after this method will be running only after Application.Exit()
Application.Run();
notifyIcon.Visible = false;
}
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public static void SetConsoleWindowVisibility(bool visible)
{
IntPtr hWnd = FindWindow(null, Console.Title);
if (hWnd != IntPtr.Zero)
{
if (visible) ShowWindow(hWnd, 1); //1 = SW_SHOWNORMAL
else ShowWindow(hWnd, 0); //0 = SW_HIDE
}
}
A console has no window to minimize by itself. It runs in a command prompt window. You might hook the window messages and hide the window on minimize. In your application it's possible to add a tray icon just the same as you would do it in a windows application. Well, somehow this smells...
But: I'm not sure why you want to do this. A console application is by design different to a windows application. Hence, maybe it's an option to change the app to be a windows form application?
[DllImport("user32.dll")]
internal static extern bool SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, Int32 lParam);
static Int32 WM_SYSCOMMAND = 0x0112;
static Int32 SC_MINIMIZE = 0x0F020;
static void Main(string[] args)
{
SendMessage(Process.GetCurrentProcess().MainWindowHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
I use TrayRunner for exactly this purpose. Essentially, it wraps a console application capturing all output. But when minimized, it minimizes to the system tray instead of the task bar. You can even customize what icon to show when minimized. I use it for things like Tomcat or Apache to free up space on my taskbar without running them as Windows Services.
You can't hide a console application because it does not actually have a window to hide, seeing as how it is running in the console (the console itself is just a window of the console, not the app running in it)

Get active window text (and send more text to it)

I'm creating a small utility in C#, that will add some text to an active textbox when a global hotkey is pressed, it's a type of auto complete function. I have my global hotkey working, but now I don't know how to get the current text in the active textbox (if the active window is a textbox that is.) What I've tried so far is to use
a. GetForegroundWindow and then using that handle calling GetWindowText. This gave me the window title of the active window, not the textbox contents.
b. GetActiveWindow and using that handle to call GetWindowText. That gives me no text at all.
Here's an example of what I've done
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[ DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[ DllImport("user32.dll") ]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
static extern int GetActiveWindow();
public static void TestA() {
int h = GetForegroundWindow();
StringBuilder b = new StringBuilder();
GetWindowText(h, b, 256);
MessageBox.Show(b.ToString());
}
public static void TestB() {
int h = GetActiveWindow();
StringBuilder b = new StringBuilder();
GetWindowText(h, b, 256);
MessageBox.Show(b.ToString());
}
So, any ideas on how to achieve this?
Edit 28.01.2009:
So, I found out how to do this. This is what I used:
using System;
using System.Text;
using System.Runtime.InteropServices;
public class Example
{
[DllImport("user32.dll")]
static extern int GetFocus();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, int ProcessId);
[DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
const int WM_SETTEXT = 12;
const int WM_GETTEXT = 13;
public static void Main()
{
//Wait 5 seconds to give us a chance to give focus to some edit window,
//notepad for example
System.Threading.Thread.Sleep(5000);
StringBuilder builder = new StringBuilder(500);
int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
//AttachTrheadInput is needed so we can get the handle of a focused window in another app
AttachThreadInput(remoteThreadId, currentThreadId, true);
//Get the handle of a focused window
int focused = GetFocus();
//Now detach since we got the focused handle
AttachThreadInput(remoteThreadId, currentThreadId, false);
//Get the text from the active window into the stringbuilder
SendMessage(focused, WM_GETTEXT, builder.Capacity, builder);
Console.WriteLine("Text in active window was " + builder);
builder.Append(" Extra text");
//Change the text in the active window
SendMessage(focused, WM_SETTEXT, 0, builder);
Console.ReadKey();
}
}
Some notes about this. The example waits for 5 seconds before doing anything, giving you the chance to give focus to some edit window. In my real app I'm using a hotkey to trigger this, but that would just confuse this example. Also, in production code you should check the return values of the win32 calls to see if they succeeded or not.
It's reasonable to send keystrokes if you aware of active window and focused input field. See http://www.pinvoke.net/default.aspx/user32/keybd_event.html for API.
Please check, even em_replacesel message may not work across different process, You might need to use WM_COPYDATA or by calling window procedure as given in the url,
http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.smartphone.developer&tid=4e3a9289-9355-4af7-a5b9-84f1aa601441&cat=&lang=&cr=&sloc=en-us&p=1

Categories

Resources