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.
Related
When I click ctrl+c in a console window, event is raised and application can execute some piece of code which should be executed before exiting.
However, when I click [X] close button, event is raised too, but in a short time, my app I forcibly closed - when 'end execution' event is still in progress.
Is it possible to set longer timeout before windows will forcibly close app?
EDIT:
Im setting:
[DllImport("Kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ControlEventHandler e, bool add);
public delegate void ControlEventHandler(ConsoleEvent consoleEvent);
When I click ctrl+c on console window, Im receiving: CTRL_C, and I can process code in mu event handler.
When I click [x] close button, I'm receiveing CTRL_CLOSE flag, I can process handler too, but only for 1-2secs. Then console windwo disappers...
Is it possible to set longer timeout before windows will forcibly close app?
Unfortunately, no. Starting with Windows Vista, you are allowed only 10 seconds or so grace period after receiving the CTRL_CLOSE_EVENT before the console window automatically closes. If you haven't exited the handler by the time 10 seconds has elapsed, then your process is unceremoniously terminated. (Obviously, if you return from the handler sooner, you will not get the full 10 seconds.)
As far as I can tell, this is part of a larger design strategy to ensure that applications cannot override the will of the user. Older versions of the SDK documentation spoke of a dialog box that would appear if the process didn't respond within a certain time-out period, but all mention of that is gone from the current version of the SDK documentation. The dialog box went MIA in Vista, it doesn't exist anymore. This is probably connected to the fact that applications can no longer block system shutdown either.
This doesn't affect your pressing Ctrl+C because that raises a different signal—CTRL_C_EVENT. Same thing with Ctrl+Break, which raises CTRL_BREAK_EVENT. But as far as I can tell from the documentation, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT are simply notifications, giving you a chance to clean up before you are terminated. There is no way to block termination or extend the grace period.
There is only one workaround that I can think of, and that is to disable the close button on the console window itself. I see that you're using C#, so a bit of P/Invoke will be required:
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);
private const uint MF_BYCOMMAND = 0x0;
private const uint SC_CLOSE = 0xF060;
void DisableConsoleCloseButton()
{
IntPtr hWnd = GetConsoleWindow();
if (hWnd != IntPtr.Zero)
{
IntPtr hMenu = GetSystemMenu(hWnd, false);
if (hMenu != IntPtr.Zero)
{
DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
}
}
If you go this route, you will obviously need to provide the user with some way of closing the console window from within your application. In Win32-land, that functionality would call the FreeConsole function to close it, but I'll bet that's wrapped up in one of the .NET classes. Been too long for me to remember what it's called.
My customer has two Windows 8.1 PCs sitting side-by-side in their business. My .NET 4.5 winforms app runs on both systems. If the app goes to the background when the user opens some other program, or clicks some other open program, that is fine. But when a barcode scan occurs, my winforms app is supposed to come to the front and be in the foreground in front of all other open programs.
It works perfectly on Windows 7, but doesn't jump to the front on Windows 8.1. Here is the relevant code:
private void BringToTheFront() {
System.Threading.Thread.Sleep(400);
if (this.WindowState == FormWindowState.Minimized) {
this.WindowState = FormWindowState.Normal;
}
//this.TopMost = true;
this.Activate();
System.Threading.Thread.Sleep(100);
BringToFront();
}
private static class User32 {
[DllImport("User32.dll")]
internal static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
internal static readonly IntPtr InvalidHandleValue = IntPtr.Zero;
}
public void Activate() {
Process currentProcess = Process.GetCurrentProcess();
IntPtr hWnd = currentProcess.MainWindowHandle;
if (hWnd != User32.InvalidHandleValue) {
User32.SetForegroundWindow(hWnd);
User32.ShowWindow(hWnd, 1);
}
}
A few notes on this code: BringToFront() is a built-in .net function available with winforms, so I call that inside my custom BringToTheFront() function.
The last function shown, Activate(), overrides/hides the built-in .net Activate() function in winforms. You can see the DllImport stuff.
Originally, on my Win7 box, I didn't need to resort to p/invoking win32 calls to get this to work. I simply called this.Activate and it worked fine.
On Win8.1, if my app is merely minimized, when the barcode scan occurs, it pops up and receives focus. But if it's BEHIND anything else (not minimized), its icon flashes at the bottom when a scan occurs, but it doesn't come to the front.
Notice the commented-out this.TopMost = true. When I uncomment that code, the app stays in the front always and will not allow anything to go in front of it. This approach is disruptive and the customers don't like it.
Notice my thread sleeps. Those are just experiments in hopes that a slight delay would help. It doesn't seem to.
Is there anything I can do to make this work?
Moderator: This is not a duplicate of Bring .NET winform to front (focus) on Windows 8 -- I already tried everything posted there and it doesn't work on Win8. So this clarifies the issue and illustrates what I have tried.
Have you tried setting the TopMost on and off again? According to the Reference Source, that property is doing a little more than simply setting an underlying value.
In order to get the application name of the foreground Window (or the name of application file) I want to use GetActiveWindow with GetWindowModuleFileName.
I found a similar question relating to GetWindowText here
That implementation of GetWindowText works fine, but GetWindowModuleFileName only returns a value for visual studio (when I click inside the devenv) for all other applications it stays blank.
Any hint how I can find out what goes wrong? Might this have to do with permission/security of my application querying the applicationfilename of another process?
EDIT: http://support.microsoft.com/?id=228469 looks like this doesn't work under Win >=XP
Any alternatives how to get the application file name?
In order to get the application name of the foreground Window (or the name of application file) I want to use GetActiveWindow with GetWindowModuleFileName.
... querying the applicationfilename of another process ...
In my opinion your problem with use of GetActiveWindow() function. It is used for gathering information from the calling thread/process only. If calling thread is inactive GetActiveWindow return 0;
From MSDN:
GetActiveWindow Retrieves the window handle to the active window attached to the calling thread's message queue.
Try to use GetForegroundWindow() function instead of GetActiveWindow()
By chance do you have UAC turned off?
Starting with Vista, if your code touches an HWND in another process, your process needs to be run at the same privilege level.
In other words, if the window is hosted in a process running as administrator, your app must also run as administrator.
I found a workaround using this:
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
IntPtr handle = IntPtr.Zero;
handle = GetForegroundWindow();
uint processId;
if (GetWindowThreadProcessId(handle, out processId) > 0)
{
Console.WriteLine(Process.GetProcessById((int)processId).MainModule.FileName);
}
c#.How to ensure process window launched by Process.Start(ProcessStartInfo) has focus of all Forms?
Thanks,
Usage of SetForegroundWindow and other methods of setting of focus has a lot of restrictions. If you really want to be sure, that the started process will receive focus I recommend you to use following native (unmanaged) functions
SystemParametersInfo (SPI_GETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)&dwLockedTimeout, 0);
SystemParametersInfo (SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)0,
SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
before process start and restore
SystemParametersInfo (SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)&dwLockedTimeout,
SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
at the end. A call like
WaitForInputIdle (pi.hProcess, 5000);
after the program start and before restoring of SPI_SETFOREGROUNDLOCKTIMEOUT can be also helpful if you will have problems with immediate
Process.Start returns a Process object. To give the process focus, firstly set up the following PInvoke:
[DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr hWnd);
Then, use:
MyProcess = Process.Start(ProcessStartInfo);
SetForegroundWindow(MyProcess.MainWindowHandle);
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?