I have built a C# Windows Form application. When the form loads, it's full screen. The form has icons on it that launch other applications (not forms). I'm trying to accomplish determining whether the application is already running or not and if it's not, start it, otherwise bring it to the front. I have accomplished determining whether the application is running or not and if it's not, to start it, I just can't figure out how to bring it to the front if it is. I have read other results on Google and Stack Overflow, but haven't been able to get them to work.
Any help is greatly appreciated!
My code, so far, is:
private void button4_Click(object sender, EventArgs e)
{
Process[] processName = Process.GetProcessesByName("ProgramName");
if (processName.Length == 0)
{
//Start application here
Process.Start("C:\\bin\\ProgramName.exe");
}
else
{
//Set foreground window
?
}
}
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
private IntPtr handle;
private void button4_Click(object sender, EventArgs e)
{
Process[] processName = Process.GetProcessesByName("ProgramName");
if (processName.Length == 0)
{
//Start application here
Process.Start("C:\\bin\\ProgramName.exe");
}
else
{
//Set foreground window
handle = processName[0].MainWindowHandle;
SetForegroundWindow(handle);
}
}
If you also wish to show the window even if it is minimized, use:
if (IsIconic(handle))
ShowWindow(handle, SW_RESTORE);
Although several answers here are marked as working, they did not work in my case. I found correct code, which worked for me on blog of Joseph Gozlan. I'm repeating here this awesome code for convenience. Notice slight but very important difference with async call, compared to other answers. All credits to original code author.
[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);
}
}
Related
I use a sample code to hunt process to my windows form application from specific List
void processStartEvent_EventArrived(object sender, EventArrivedEventArgs e)
{
string processName = e.NewEvent.Properties["ProcessName"].Value.ToString();
int processID = Convert.ToInt32(e.NewEvent.Properties["ProcessID"].Value);
if (_processNames.Contains(processName))
{
Process proc = Process.GetProcessById(processID);
if (GlobalVar.SourceWinForm.InvokeRequired)
{
GlobalVar.SourceWinForm.Invoke(new MethodInvoker(delegate { ProcessHandler.SetParent(proc.MainWindowHandle, GlobalVar.SourceWinForm.Handle); }));
}
else
{
ProcessHandler.SetParent(proc.MainWindowHandle, GlobalVar.SourceWinForm.Handle);
}
}
}
as you can see i use the function :
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hwc, IntPtr hwp);
everything work good except one thing.
for example i hunted notepad application into my app.
so it really give me the notepad into my app window but the problem start when
i press for example in the notepad "Format -> Font" it open a new sub window of notepad , this sub window , my apllication is not father of this sub window.
how i can hunt the full process ? include his child (subs) windows ?
you can use:
[DllImport("user32.dll")]
private static extern
bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern
bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern
bool IsIconic(IntPtr hWnd);
and then
// bring it to the foreground
if (IsIconic(proc.MainWindowHandle))
ShowWindowAsync(proc.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(proc.MainWindowHandle);
Solution:
first of all i want to say the comments are correct and can help to someone else so please read the comments to my main question first.
but if you have specific scenario and you don't have any other option and you must use SetParent or other function like that. ( make sure you read first about SetParent and you understand what it dose )
the solution is to take the entire forms to foreground:
bool SetForegroundWindow(IntPtr hWnd);
this make all the other forms that inherit from the main form you loaded to see it on your main application ( this in case you application block and streach entire screen )
I have a Windows Form Application that will go to system tray when it is minimized. When I received a message to pop-up my application it will call ShowWindowFromTray() function. I do not want to steal focus on the application that has the focus because it might interrupts on what the user is doing.
private void ShowWindowFromTray()
{
this.Show();
this.WindowState = FormWindowState.Normal;
}
BTW this application has option that the users can check if the application will always on top or TopMost on all other windows.
Instead of Show(), use the ShowWindow() API with SW_SHOWNA:
private const int SW_SHOWNA = 4;
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private void ShowWindowFromTray()
{
ShowWindow(this.Handle, SW_SHOWNA);
}
I have two forms in my application MainForm and HexCompare. If I click off of my app to another window then I click back on one of the two forms only one of them comes to the front. How can I make it so if I click either one of the two forms it will bring both to the top of all open forms in the application? Right now I need to select each form individually to get them to the top of my stack of windows (and this can be very annoying due to the fact that HexCompare has ShowInTaskbar set to false
A good example of this working the way I want to is how most Find dialogs work. If the find dialog is clicked it brings the main form to the front if it is hidden by another application, and if the main form is clicked the find dialog will come to the front if it is hidden by another application.
How MainForm is invoked.
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
How HexCompare is invoked
private void lstCaputres_SelectedIndexChanged(object sender, EventArgs e)
{
var selectedItem = (Tuple<DateTime, byte[]>)lstCaputres.SelectedItem;
if (hexCompare == null || hexCompare.IsDisposed)
{
hexCompare = new HexCompare(selectedItem.Item2);
hexCompare.Show();
}
else
hexCompare.ChangeValue(selectedItem.Item2);
}
EDIT:
It seems that HexCompare's value of Parent is Null. If I could somehow set it to MainForm would that solve my issue, and if so how to I set it?
EDIT2:
I have semi-solved it using Tigran's solution but it causes flickering as each form is brought to the front, if there is a better solution I am still interested.
//In MainForm.cs
private void MainForm_Activated(object sender, EventArgs e)
{
hexCompare.BringToFront();
this.BringToFront();
}
//in HexCompare.cs
private void HexCompare_Activated(object sender, EventArgs e)
{
parent.BringToFront();
this.BringToFront();
}
You can use the following API wrapper to bring a form to the front of the z-order without having it steal focus. This function can be called in the Activated event of your main form, just pass it your HexCompare form as the parameter. This is not much different from the other answer but I've never witnessed any flicker as you mention in the comments.
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = 0;
private const uint SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // window handle
int hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
uint uFlags); // window positioning flags
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public void ShowInactiveTopmost(Form frm)
{
ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
frm.Left, frm.Top, frm.Width, frm.Height,
SWP_NOACTIVATE);
}
To me seems that should be enough to set TopMost=true and call BringToFront() on both forms.
hexCompare = new HexCompare(selectedItem.Item2);
hexCompare.TopMost = true;
hexCompare.Show();
hexCompare.BringToFront();
Something like this.
I open up a notepad from my program using Process.Start() but the new opened notepad covers the screen. But I do want my application to maintain its focus.
I similarly (using the same Process.Start) open up MS Excel and Word but to get focus back to my form all I need to write is:
this.Focus();
But quirk with Notepad: I open notepad (and all other processes like this)
Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.EnableRaisingEvents = true;
process.StartInfo.FileName = #"abc.log";
process.Start();
Now notepad takes the focus.
I tried these:
this.Activate(), this.Focus(), needless to mention
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr SetFocus(HandleRef hWnd);
{
IntPtr hWnd = myProcess.Handle;
SetFocus(new HandleRef(null, hWnd));
}
[DllImport("User32")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[DllImportAttribute("User32.DLL")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_RESTORE = 9;
{
ShowWindow(Process.GetCurrentProcess().MainWindowHandle, SW_RESTORE);
SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle);
}
Another lengthier solution got from here.
All which still keeps the focus on notepad. Why is it so difficult to merely get focus to a window, that too application's own window?
EDIT: At best I can open the notepad minimized, but it still wouldn't give the focus to the form after trying all the above codes. Notepad opens minimized, but focus will be still on notepad (something that sometimes we see in windows xp) and form will be out of focused.
I tried almost everything on internet (so sure about it :)). At best I could get my form on top of all other forms, but without focus (going by #Hans Passant's method). Going by heavy blocks of codes all over, I somehow felt this aint gonna be easy. So I always used SetForegroundWindow() with chunks of other code. Never thought merely SetForegroundWindow() would do the trick.
This worked.
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
Process process = new Process();
process.StartInfo.FileName = #...\abc.log";
process.Start();
process.WaitForInputIdle(); //this is the key!!
SetForegroundWindow(this.Handle);
}
At times this method yields in a focus on the parent form (in cases where my desired form is a modal child form of its parent form); in such cases, just add this.Focus() to the last line..
Even this worked:
Microsoft.VisualBasic.Interaction.Shell(#"notepad.exe D:\abc.log",
Microsoft.VisualBasic.AppWinStyle.NormalNoFocus);
Solution provided by here
I had the same problem, i eventually wound up with programmatically calling alt-tab:
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private void alttab()
{
uint WM_SYSCOMMAND = 0x0112;
int SC_PREVWINDOW = 0xF050;
PostMessage(Process.GetCurrentProcess().MainWindowHandle, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
}
//EDIT: You should use process.MainWindowHandle instead ofcourse
If you want to start a process and focus back to the form, then start that process with minimized state, like this:
Dim psi As New ProcessStartInfo("notepad")
psi.WindowStyle = ProcessWindowStyle.Minimized
Process.Start(psi)
Windows prevents apps from shoving their window into the user's face, you are seeing this at work. The exact rules when an app may steal the focus are documented in the MSDN docs for AllowSetForegroundWindow().
A back-door around this restriction is the AttachThreadInput() function. This code worked well, I did take a shortcut on finding the thread ID for the thread that owns the foreground window. Good enough for Notepad, possibly not for other apps. Do beware that Raymond Chen does not approve of this kind of hack.
private void button1_Click(object sender, EventArgs e) {
var prc = Process.Start("notepad.exe");
prc.WaitForInputIdle();
int tid = GetCurrentThreadId();
int tidTo = prc.Threads[0].Id;
if (!AttachThreadInput(tid, tidTo, true)) throw new Win32Exception();
this.BringToFront();
AttachThreadInput(tid, tidTo, false);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool AttachThreadInput(int tid, int tidTo, bool attach);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
Try this:
public partial class MainForm : Form
{
private ShowForm showForm;
public MainForm()
{
InitializeComponent();
}
private void showButton_Click(object sender, EventArgs e)
{
this.showForm = new ShowForm();
this.showForm.FormClosed += showForm_FormClosed;
this.showForm.Show(this);
}
private void showForm_FormClosed(object sender, FormClosedEventArgs e)
{
this.Focus();
}
}
I am working on an application which needs to get the last active window handle. Suppose my application is running then I want to get last active window handle that was just previously open just before my application.
#EDIT1: This is not the duplicate question. I need to get the handle of last active window not the current window.
This is similar to
alternate SO question, I would assume you would just track the active window and upon change you would then know the previously active
Edit, this is basically code copied from the question I linked that was looking for current active window but with logic to persist the lastHandle and identify when you have a new lastHandle. It's not a proven, compilable implementation:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
static IntPtr lastHandle = IntPtr.Zero;
//This will be called by your logic on when to check, I'm assuming you are using a Timer or similar technique.
IntPtr GetLastActive()
{
IntPtr curHandle = GetForeGroundWindow();
IntPtr retHandle = IntPtr.Zero;
if(curHandle != lastHandle)
{
//Keep previous for our check
retHandle = lastHandle;
//Always set last
lastHandle = curHandle;
if(retHandle != IntPtr.Zero)
return retHandle;
}
}
I needed the same thing of the last handle from the previous window I had open. The answer from Jamie Altizer was close, but I modified it to keep from overwriting the previous window when my application gets focus again. Here is the full class I made with the timer and everything.
static class ProcessWatcher
{
public static void StartWatch()
{
_timer = new Timer(100);
_timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
_timer.Start();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
setLastActive();
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
public static IntPtr LastHandle
{
get
{
return _previousToLastHandle;
}
}
private static void setLastActive()
{
IntPtr currentHandle = GetForegroundWindow();
if (currentHandle != _previousHandle)
{
_previousToLastHandle = _previousHandle;
_previousHandle = currentHandle;
}
}
private static Timer _timer;
private static IntPtr _previousHandle = IntPtr.Zero;
private static IntPtr _previousToLastHandle = IntPtr.Zero;
}