I have a problem with a program that loses focus. It's not my program. How can I write a second program to set focus to that window every 1-2 seconds? Is is possible to do that?
You can use following Win32 API call if you want to focus some other program/process.
[DllImport("user32.dll")]
static extern bool SetForegroundWindow (IntPtr hWnd);
private void BringToFront(Process pTemp)
{
SetForegroundWindow(pTemp.MainWindowHandle);
}
use spy++ or other ui tools to find the class name of the window you want to focus, say its: focusWindowClassName. Then add the below functions:
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[System.Runtime.InteropServices.DllImport("User32.dll")]
public static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//Then:
// [Edit] Changed IntPrt to IntPtr
IntPtr hWnd = FindWindow("focusWindowClassName", null); // this gives you the handle of the window you need.
// then use this handle to bring the window to focus or forground(I guessed you wanted this).
// sometimes the window may be minimized and the setforground function cannot bring it to focus so:
/*use this ShowWindow(IntPtr handle, int nCmdShow);
*there are various values of nCmdShow 3, 5 ,9. What 9 does is:
*Activates and displays the window. If the window is minimized or maximized, *the system restores it to its original size and position. An application *should specify this flag when restoring a minimized window */
ShowWindow(hWnd, 9);
//The bring the application to focus
SetForegroundWindow(hWnd);
// you wanted to bring the application to focus every 2 or few second
// call other window as done above and recall this window again.
Related
I am trying to intercept the "Save Print Output As" dialog in Revit so I can programmatically insert a path and file name. This dialog pops up every time for every view or sheet that is printed when printed separately or only once if a combined document is printed once.
So far, I have assembled the viewset however when it comes time to print, I do not have access to the window because it opens and closes too soon. I am hoping there is a more "hacky" way to intercept it.
In Revit, the event handler:
a.ControlledApplication.DocumentPrinting += new EventHandler<Autodesk.Revit.DB.Events.DocumentPrintingEventArgs>(AppDocumentPrinting);
only activates after the name/destination has been selected but before the document has printed so it doesnt quite help.
I have found this post which explains how to cycle through the windows which I am able to do but I don't know how to listen for the window to be opened and I can't find anything on it. The SO post also mentions something about p/invoke but I haven't found much documentation on it.
I have looked at subscribing to events but I haven't found anything on being able to subscribe to listen to a window opening.
My printer setup is currently Microsoft print to pdf which doesn't seem to allow the PrintToFile option. Regardless though, I would still like to be able to handle the dialog if it pops up if it is possible.
Any and all help/direction is appreciated.
My code:
EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero); // cant find window because it doesnt exist
printManager.SubmitPrint(); // Window opens for user input here and then closes
// doc.Print(pdfviewSet); // option B: Window opens for user input here and then closes
EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero); // cant find window because it doesnt exist
code adapted from other SO post
// P/Invoke declarations <--- suspect the answer might lie here?
protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
// Callback for examining the window
protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
int size = GetWindowTextLength(hWnd);
if (size++ > 0 && IsWindowVisible(hWnd))
{
StringBuilder sb = new StringBuilder(size);
GetWindowText(hWnd, sb, size);
if (sb.ToString().Equals("Save Print Output As", StringComparison.Ordinal))
{
uint procId = 0;
GetWindowThreadProcessId(hWnd, out procId);
Debug.WriteLine($"Found it! ProcID: {procId}");
FlaUI.Core.Application application = FlaUI.Core.Application.Attach(Process.GetCurrentProcess());
string appName = application.Name;
Window mainWindow = application.GetMainWindow(new UIA3Automation());
ConditionFactory cf = new ConditionFactory(new UIA3PropertyLibrary());
mainWindow.FindFirstDescendant(cf.ByProcessId(int.Parse(procId.ToString()))).AsTextBox().Enter("test"); // try to enter info here but returns null because window has closed.
}
}
return true;
}
Dialog I am trying to intercept:
Other info I have looked at:
p/invoke - not too sure how to implement this.
tried this but printed a blank page
How to subscribe to events
Tim Corry's Youtube video on subscribing to events
I have to track the running time of a program.
That program exposes the following window
At the same time I launch my program which in a timer does:
private void TimerCheckGroups_Tick(object sender, EventArgs e)
{
IntPtr windowPtr = FindWindowByCaption(IntPtr.Zero, "Execution");
if (windowPtr != IntPtr.Zero)
Console.Beep();<--------
}
But the beep line never gets hit.
Have I misunderstood the meaning of a window caption?
--ADD--
I'll try to make the execution phases clearer.
Startup----> launch my logger.
User-------> launches program A that launches program B (not visible) that launches window C. C has caption Execution.
When I launch the solution proposed by dontbyteme the only the B program appears so only 1 window.
In short
logger: not visible since it's a tray program
program A: visible since it's the main program
program B: not visible since it's set to Notvisible
program C: not visible why?!?!?!?
--SOLUTION THANX TO JARRETT--
logger stays idle with a timer monitoring processes
program A starts but nobody cares about it. Then program A launches program B
when program B is awake i find the window and start logging
The following question addresses how to find out when programs launch. Detecting the launch of a application Also, you can enumerate windows on your machine with a dll import and using EnumWindows. Sample pInvokes that will help you are listed.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(IntPtr hWnd);
You can try getting the window by running through each window and compare to the title:
foreach(Window window in Application.Current.Windows)
{
if(window.Title == "Execution")
{
Console.Beep();
// ...
}
}
The Title property is what you called Caption.
There are a few PInvoke functions out there for grabbing window handles, but how do you grab the exact window handle that is in use: for example the richTextBox1 window within an app? or a Notepad.exe's textbox handle? Also text on webpages in chrome/firefox.
An example that grabs all three would be bad ass... most appreciated would be within Google Chrome or Firefox: whether it be textboxes or right on the PAGE.
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr GetFocus();
that works for windows within the application itself, but it failed in notepad & in chrome
As you said, GetFocus only works for window handles managed by the current thread's message queue. What you need to do is temporarily attach your message queue to another process:
Get the foreground window's handle with GetForegroundWindow.
Get the thread ID for your thread and the thread that owns the foreground window with GetWindowThreadProcessId.
Attach your message queue to the foreground window's thread with AttachThreadInput.
Call GetFocus which will return window handles from the foreground window's thread.
Disconnect from the foreground window's thread with AttachThreadInput again.
Something like this:
using System.Runtime.InteropServices;
public static class WindowUtils {
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr GetWindowThreadProcessId(
IntPtr hWnd,
IntPtr ProcessId);
[DllImport("user32.dll")]
static extern IntPtr AttachThreadInput(
IntPtr idAttach,
IntPtr idAttachTo,
bool fAttach);
[DllImport("user32.dll")]
static extern IntPtr GetFocus();
public static IntPtr GetFocusedControl() {
IntPtr activeWindowHandle = GetForegroundWindow();
IntPtr activeWindowThread =
GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero);
IntPtr thisWindowThread =
GetWindowThreadProcessId(this.Handle, IntPtr.Zero);
AttachThreadInput(activeWindowThread, thisWindowThread, true);
IntPtr focusedControlHandle = GetFocus();
AttachThreadInput(activeWindowThread, thisWindowThread, false);
return focusedControlHandle;
}
}
(Source: Control Focus in Other Processes)
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);
}
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)