I use this code to check whether my program is already open:
string RunningProcess = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(RunningProcess);
if (processes.Length > 1)
{ return true; }
It would, if the program is open, bring it to the floor and show it. How can I do? Thank you.
You have to import the following method:
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
Then you can call this method this way:
ShowWindow(process.MainWindowHandle, 0);//Hide
ShowWindow(process.MainWindowHandle, 1);//Show
NOTE: The window can just be shown if it is minimized. It won't show it if it is in the background of an other window.
If you want to show a window that is in the background of an other one you have to import this method:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
Then call it in the same way as ShowWindow:
SetForegroundWindow(process.MainWindowHandle);
NOTE: You can just set the foreground window if it is not minimized.
You can also combine both methods with IsIconic to call the right method:
[DllImport("user32.dll")]
static extern bool IsIconic(IntPtr hWnd);//Returns false if the window is minimized
The full code to show the mainwindow:
static void GotoProcess(Process process)
{
if (IsIconic(process.MainWindowHandle))
{
ShowWindow(process.MainWindowHandle, 1);
}
else
{
SetForegroundWindow(process.MainWindowHandle);
}
}
Related
Good morning,
I'm trying to figure out how to put the focus on Google Chrome. That is to say to make as a click on the software in the taskbar (already open).
Thank you for helping me to put the focus on Google Chrome.
You can use the following function to bring chrome to front and to focus it.
The code uses 2 windows API calls because what you need is not directly provided by the .Net framework.
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
public class Program
{
[DllImport("user32.dll")]
[return: MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hwnd);
private static bool FocusChromeWindow()
{
foreach (Process chrome in Process.GetProcessesByName("chrome"))
{
// In case the process did not reveal a main window handle
// try to restore it in case it is hidden
if (chrome.MainWindowHandle == IntPtr.Zero)
{
ShowWindow(chrome.Handle, 9); // 9 = Restore
}
// If main window handle is still zero,
// this chrome process is one of the background
// workers chrome starts. Skip it.
if (chrome.MainWindowHandle != IntPtr.Zero)
{
SetForegroundWindow(chrome.MainWindowHandle);
return true;
}
}
return false;
}
static void Main(string[] args)
{
FocusChromeWindow();
Console.ReadLine();
}
}
I have create a Window use WPF, I want to my Window always display on the top, So I just create a thread for it:
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
for (;;)
{
System.Threading.Thread.Sleep(3000);
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.Activate();
this.Topmost = true;
}));
}
});
}
This will make sure my window go to front in every 3 seconds.
And when I open it under Visual Studio 2015, all fine, even when I open the Start Menu, it will close start menu and bring the window on top.But when I'm not use Visual studio open the application(just double click open the application), when I open start menu, the Window just flickering, not display on the top. What I miss? and how do I let it work as like open the application under Visual Studio 2015(I'm tested on Win10)?
EDIT: I somehow missed the point covered in the title. The point I make later of "Do not do it" still holds true though. It could cause problems for users of your application.
If you really need to though, this answer may be the one you are looking for. It discusses how to keep a window in front of everything. It is still a work around (just like most answers to your question).
Old Answer
I understand your problem as: you want your window to stay on top of all other windows. Similar functionality can be found in Ubuntu and The Google Play Music desktop application for Window's (see below).
To accomplish this, all you need to do is add Topmost="True" to your Window as demonstrated below (look at the last property).
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Topmost="True">
</Window>
Unless your actual problem "is what happens when two windows have that property set?" Then I would suggest reading this article (the same article that was referenced in the comments). It states the following:
"How do I create a window that is never covered by any other windows, not even other topmost windows?"
Imagine if this were possible and imagine if two programs did this.
Program A creates a window that is "super-topmost" and so does Program
B. Now the user drags the two windows so that they overlap. What
happens? You've created yourself a logical impossibility. One of those
two windows must be above the other, contradicting the imaginary
"super-topmost" feature.
If that functionality is really what you are after, I would suggest: do not do it. All other solutions are a workaround and could cause problems for consumers of your application.
I would have used interop to do this.
public class Interop
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hwind, int cmd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
public static IntPtr GetWindowHandle(Window window)
{
return new WindowInteropHelper(window).Handle;
}
}
then use a timer:
private void Tick(object state)
{
this.Dispatcher.Invoke(() =>
{
IntPtr window = Interop.GetWindowHandle(this);
IntPtr focused = Interop.GetForegroundWindow();
if (window != focused)
{
Interop.SetForegroundWindow(window);
// Command 5 for show
Interop.ShowWindow(window, 5);
}
});
}
Code from
And for the part of your problem regarding the startmenu, just add a group policy.
Or you can make a interop to ´FindWindowEx´ to find the startbutton and disable it.
I agree with Jonas's answer but would modify it to use an event instead of a timer.
/// Get the topmost window handle
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
/// Trigger event when topmost window changed
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, TopmostWindowChangedDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
/// Set the topmost window
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
/// Show a window
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hwind, int cmd);
// Constant variables for topmost window changed event
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
/// Keep track of the last topmost window with a name
private static IntPtr topWinHandle { get; set; }
/// Implementation of topmost window changed delegate
private TopmostWindowChangedDelegate TopmostWindowChanged { get; set; }
Then set up the handlers in one of your startup methods
// Set topmost window changed event handler
TopmostWindowChanged = new TopmostWindowChangedDelegate(WinEventProc);
// Set event hook for topmost window changed
IntPtr hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, TopmostWindowChanged, 0, 0, WINEVENT_OUTOFCONTEXT);
And then move your window to topmost when the other topmost changes
/// Make sure this window stays on top
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
// Get current window name from handle
IntPtr handle = GetForegroundWindow();
if(handle != YOUR_WINDOW'S_HANDLE)
{
// Move your window back to the top
SetForegroundWindow(YOUR_WINDOW'S_HANDLE);
ShowWindow(YOUR_WINDOW'S_HANDLE, 5);
}
}
I want to create a software like a virtualkeyboard, you have a AlwaysTop Window and use this to put some data on another process/windows. In this case I will record all data on clipboard and compare if this data is compatible with a pattern (A### is the patern and A123 is compatible with the patern), if yes the application will put it in a listbox and the user can paste it on another process/windows (already open) clicking on item on list.
My question is about how to put this information on the last application/process used, I already started a prototype of code but the line indicated is wrong, on my code it's the currentprocess and need to be the last used before click on my form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")]
static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("User32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
private void button2_Click(object sender, EventArgs e)
{
Process currentProcess = Process.GetCurrentProcess(); //this line is wrong
IntPtr hWnd = currentProcess.MainWindowHandle; //this line is wrong
if (hWnd != IntPtr.Zero)
{
SetForegroundWindow(hWnd);
ShowWindow(hWnd, 9);
SendKeys.Send("A123");
}
}
}
}
I get on simple solution, instead of get the process I just send the combination ALT+TAB and work for all cases that I need. Below the solution if anyone need in the future:
string old_clipboard = Clipboard.GetText();
Clipboard.SetText("A123");
SendKeys.SendWait("%{Tab}");
SendKeys.SendWait("^V");
Thread.Sleep(100);
Clipboard.SetText(old_clipboard);
Ps.: I put one delay because the SendWait works only on caller windows, as the target of ^V is another process it´s don´t work well.
Best regards. =)
I'm trying to build a global hotkey application with C# in Visual Studio 2012 to run on Windows 7. I have everything working except the SendKeys are never showing in the application.
Here is the code I am using to send the keystrokes:
Updated to debug with GetFocusedWindow example.
StringBuilder className = new StringBuilder(256);
IntPtr hWnd = GetForegroundWindow();
GetClassName(hWnd, className, className.Capacity);
Debug.WriteLine("Foreground window: {0}={1}", hWnd.ToInt32().ToString("X"), className);
hWnd = GetFocusedWindow();
GetClassName(hWnd, className, className.Capacity);
Debug.WriteLine("Focused window: {0}={1}", hWnd.ToInt32().ToString("X"), className);
SendKeys.Send("Hello World");
When I debug the program, focus Notepad, and hit the hotkey I get the following debug message and the keystrokes are never inserted into Notepad:
Foreground Window: 4F02B6=Notepad
Focused Window: 1B6026A=WindowsForms10.Window.8.app.0.bf7d44_r11_ad1
How can I send keystrokes to the current foreground window?
Foreground windows doesn't necessary mean focused window. A child window of the top-level foreground window may have the focus, while you're sending keys to its parent.
Retrieving the focused child window from another process is a bit tricky. Try the following implementation of GetFocusedWindow, use it instead of GetForegroundWindow (untested):
static IntPtr GetFocusedWindow()
{
uint currentThread = GetCurrentThreadId();
IntPtr activeWindow = GetForegroundWindow();
uint activeProcess;
uint activeThread = GetWindowThreadProcessId(activeWindow, out activeProcess);
if (currentThread != activeThread)
AttachThreadInput(currentThread, activeThread, true);
try
{
return GetFocus();
}
finally
{
if (currentThread != activeThread)
AttachThreadInput(currentThread, activeThread, false);
}
}
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr GetFocus();
[DllImport("user32.dll", SetLastError = true)]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
Updated to address the comment:
When I use this function it sets the focus to my application window.
It's hard to tell what's wrong on your side, the following works for me when the focus is inside Notepad:
private async void Form1_Load(object sender, EventArgs e)
{
var className = new StringBuilder(200);
while (true)
{
await Task.Delay(500);
IntPtr focused = GetFocusedWindow();
GetClassName(focused, className, className.Capacity);
var classNameStr = className.ToString();
this.Text = classNameStr;
if (classNameStr == "Edit")
SendKeys.Send("Hello!");
}
}
I am using a WebBrowser control for some automated testing. The problem is that occasionally - not all the time - when I am testing uploading images, the file upload dialog box does not close and the the program just "hangs" and waits for manual input, which defeats the purpose of the whole automated process. What I want to do is to "force" a close of the dialog box, but have been unable to figure this out. Any help or direction would be much appreciated.
The thing to realize is that this code works some of the time, but NOT all of the time. I need help figuring out how to make this code work ALL of the time.
Here is the code:
async Task PopulateInputFile(System.Windows.Forms.HtmlElement file, string fname)
{
file.Focus();
// delay the execution of SendKey 500ms to let the Choose File dialog show up
var sendKeyTask = Task.Delay(5000).ContinueWith((_) =>
{
// this gets executed when the dialog is visible
//SendKeys.Send(fname + "{ENTER}");
//PressKey(Keys.Space, false);
SendKeys.SendWait(fname);
PressKey(Keys.Enter, false);
}, TaskScheduler.FromCurrentSynchronizationContext());
file.InvokeMember("Click"); // this shows up the dialog
await sendKeyTask;
// delay continuation 500ms to let the Choose File dialog hide
await Task.Delay(5000);
}
async Task Populate(string fname)
{
var elements = webBrowser.Document.GetElementsByTagName("input");
foreach (System.Windows.Forms.HtmlElement file in elements)
{
if (file.GetAttribute("name") == "file")
{
this.Activate();
this.BringToFront();
file.Focus();
await PopulateInputFile(file, fname);
file.RemoveFocus();
}
}
}
Ok, so here is the solution. You have to use the WIN API to close the window. I found the class name of the "Choose File to Upload" dialog by using SPY++, which turns out to be: #32770.
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
int iHandle = FindWindow("#32770", "Choose File to Upload");
if (iHandle > 0)
{
// close the window using API
SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
}
Not really an answer, but it may turn into an answer later. Are use sure the focus is inside the IE "Choose File to Upload" dialog, when you do SendKeys? Use the following to verify that, put the code from below Task.Delay(4000) into your ContinueWith and check the output from Debug.Print.
static class Win32
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
private async void Form1_Load(object sender, EventArgs ev)
{
await Task.Delay(4000);
var currentWindow = new System.Text.StringBuilder(1024);
Win32.GetWindowText(Win32.GetForegroundWindow(), currentWindow, currentWindow.Capacity);
Debug.Print("Currently focused window: \"{0}\"", currentWindow);
}