I've been searching all over the net for answers to get a program to the foreground. I've been doing it the ghetto way by sending alt-tab keystrokes with SendKeys. I've tried this and it doesn't work,
private void execute()
{
setApp("League of Legends.exe");
Thread.Sleep(1500);
}
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
private static void setApp(String filename)
{
Process[] SameProcesses = Process.GetProcessesByName(filename);
Process SameProcess = SameProcesses[0];
if (SameProcess.Equals(null))
{
System.Windows.Forms.MessageBox.Show("No process");
}
else
{
SetForegroundWindow(SameProcess.MainWindowHandle);
}
}
Related
I have a singletone instance of window in my WPF application (which is not main window). Due to it's structure, this window only closes when the main window is closed; If the user closes this window, it becomes hidden. When I click on some image in main window, I want the following behaviour of second window:
If window is hidden and image was clicked, I want to show it on top of all windows (but NOT by setting Topmost = true, I want just SHOW it on top, rather than fix it on top forever).
If window is shown on top, there is nothing to do.
If window is open, but covered by other window or minimized, I also want to show it on top only ONCE.
What I have at the moment:
// In some application class
private void Image_MouseDown(object sender, MouseButtonEventArgs e)
{
if (App.Current.MyWindow == null)
{
App.Current.MyWindow = WeightImageWindowView.Instance;
}
App.Current.MyWindow.ShowTop();
}
...
// in MyWindow class
public void ShowTop()
{
this.Topmost = true;
this.Show();
if (this.WindowState == WindowState.Minimized)
{
this.WindowState = WindowState.Normal;
}
var a = this.Activate();
var b = this.Focus();
this.Topmost = false;
}
I tried to use all these commands one by one, in pairs and all together, but didn't get the behaviour described above.
WndHelper.BringToFront(this);
Use the helper below and just call bringtofront
public class WndHelper
{
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hWnd);
public static void HideWindow(Window window)
{
var wih = new WindowInteropHelper(window);
WndHelper.ShowWindow(wih.Handle, 0);
}
public static void BringToFront(Window window)
{
var wih = new WindowInteropHelper(window);
BringToFront(wih.Handle);
}
//If the window is minimized, then Restore must be run first
//Windows that are in the background are enough to set as Foreground
public static void BringToFront(IntPtr hWnd)
{
if (hWnd == IntPtr.Zero)
return;
try
{
if (WndHelper.IsIconic(hWnd)) //the window is minimized
{
WndHelper.ShowWindow(hWnd, 9); // SW_RESTORE = 9
WndHelper.SetForegroundWindow(hWnd); // set window to foreground
}
else
WndHelper.SetForegroundWindow(hWnd);
}
catch { }
}
}
Thanks #Villiam! I found the following solution:
Set MyWindow.ShowActivated = true;
Rewrite ShowTop method as:
public void ShowTop()
{
if (this.WindowState == WindowState.Minimized)
{
this.WindowState = WindowState.Normal;
}
this.Topmost = true;
this.Show();
this.Topmost = false;
}
i have a windows desktop application with c# and framework 4.6
the app run in system tray and there is a shortcut icon on desktop
when user click the icon to run it if the app already run dont run new instance, only show (bring to front) existing app
public sealed class SingleInstance
{
private const int SW_HIDE = 0;
private const int SW_SHOW = 5;
public static bool AlreadyRunning()
{
bool running = false;
try
{
// Getting collection of process
Process currentProcess = Process.GetCurrentProcess();
// Check with other process already running
foreach (var p in Process.GetProcesses())
{
if (p.Id != currentProcess.Id) // Check running process
{
if (p.ProcessName.Equals(currentProcess.ProcessName) == true)
{
running = true;
IntPtr hFound = p.MainWindowHandle;
if (User32API.IsIconic(hFound)) // If application is in ICONIC mode then
User32API.ShowWindow(hFound, User32API.SW_RESTORE);
User32API.SetForegroundWindow(hFound); // Activate the window, if process is already running
break;
}
}
}
}
catch { }
return running;
}
}
public class User32API
{
[DllImport("User32.dll")]
public static extern bool IsIconic(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public const int SW_SHOW = 5;
public const int SW_RESTORE = 9;
}
if app run back of the any windows it can show (bring to front) but it in system tray cant show
EDIT:
minimize to tray
private void Form1_Resize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
Hide();
}
}
to open
private void notifyIcon1_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
this.Show();
this.WindowState = FormWindowState.Normal;
}
You can implement a Mutex to make sure there is only one instance of your application running. You can also use it to communicate between instances so the second instance can notify the first one that the user attempted to start your app a second time.
There is already a really good answer to this over here: https://stackoverflow.com/a/522874/14877741
It explains the Mutex concept a lot better than I could and it even has an example that brings the application window back to the foreground.
I am working on a console application that is supposed to catch the event when the clipboard content changes. There is an API in WinRT for this, Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged. I have already tested this on a WinForms and WPF application, and it works perfectly. However I am experiencing problems when doing this in a console application. The code is pretty basic. When doing it on a WinForms application, I simply write this line of code:
public MyApp()
{
InitializeComponent();
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += OnClipboardChanged;
}
public async void OnClipboardChanged(Object sender, Object e)
{
MyCodeHere
}
However when trying to do the same in my console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += OnClipboardChanged;
}
public static void OnClipboardChanged(Object sender, Object e)
{
Console.WriteLine("Hello");
}
}
Yet the console just exits after starting it. If I put "Console.ReadKey" then it still errors but does not exit. Neither way invokes the event I have written in Main. I want the console to be running and not end, even if there is a clipboard change. So it should constantly run in the background, and everytime the clipboard changes then it should just WriteLine a "Hello" to the console. I have gone through all the other answers but none of them works for me, because they want to manipulate the clipboard whereas I am invoking an event on the content change of the clipboard. Thanks for all the help!
Another question, will there be any perfomance difference if I use C++/winRT instead?
In a console context, you must ensure windows messages are processed as clipboard depends on it, so for example, you can use Winforms' DoEvents method (if you don't have a real window and nothing pumps messages):
class Program
{
static void Main()
{
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += (s, e) => Console.WriteLine("ContentChanged");
Console.WriteLine("Press any key to quit");
do
{
System.Windows.Forms.Application.DoEvents();
if (Console.KeyAvailable)
break;
Thread.Sleep(100); // for example
}
while (true);
}
}
To enable Winforms support in a .NET 5 Console project, here is the simplest way of doing it (you don't even need to add the Windows.SDK nuget package), just modify the .csproj to something like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
</PropertyGroup>
</Project>
If you don't have .NET 5, or don't want to reference Winforms, then you can declare your own message pump using P/Invoke, like this:
class Program
{
[STAThread]
static void Main()
{
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += (s, e) => Console.WriteLine("ContentChanged");
Console.WriteLine("Press any key to quit");
do
{
while (GetMessage(out var msg, IntPtr.Zero, 0, 0) != 0)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
if (Console.KeyAvailable)
break;
Thread.Sleep(100);
Console.Write(".");
}
while (true);
}
[StructLayout(LayoutKind.Sequential)]
private struct MSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public POINT pt;
public int lPrivate;
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[DllImport("user32")]
private static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, int wMsgFilterMin, int wMsgFilterMax);
[DllImport("user32")]
private static extern bool TranslateMessage(ref MSG lpMsg);
[DllImport("user32")]
private static extern IntPtr DispatchMessage(ref MSG lpmsg);
}
I have a simple WinForm app with a button, and on-click I am trying to populate search keyword on Google Chrome already running (on chrome window). When I execute this program and click the button, Chrome window get presented (restored from minimized) but the focus still remains on my WinForm app and SendKeys does not work.
Is there a better way to do this?
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
[DllImport("User32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
[DllImport("User32.DLL")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IntPtr chromeHandle = FindWindow("Chrome_WidgetWin_1", null);
if(chromeHandle == IntPtr.Zero)
{
MessageBox.Show("Chrome is not running");
return;
}
SetForegroundWindow(chromeHandle);
SendKeys.SendWait("search term");
}
}
}
I have a simple WPF application. Under normal use, App.xaml will launch MainWindow.xaml. But I would like to set it up so that if it is invoked with a special command line argument, that it will function as a console application instead.
So here's roughly what my App.xaml.cs file looks like:
using System;
namespace MyProject
{
public partial class App : Application
{
public void App_OnStartup(object sender, StartupEventArgs e)
{
if (e.Args.Length == 1 && e.Args[0].Equals("/console"))
{
Console.WriteLine("this is a test");
Environment.Exit(0);
}
else
{
var mainWindow = new MainWindow();
mainWindow.Show();
}
}
}
}
I would expect that when I run MyProject.exe /console from the command line, it would print the string "this is a test". But right now it doesn't print anything. How can I get it to work?
We have special class for this purpose:
internal static class ConsoleAllocator
{
[DllImport(#"kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[DllImport(#"kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport(#"user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SwHide = 0;
const int SwShow = 5;
public static void ShowConsoleWindow()
{
var handle = GetConsoleWindow();
if (handle == IntPtr.Zero)
{
AllocConsole();
}
else
{
ShowWindow(handle, SwShow);
}
}
public static void HideConsoleWindow()
{
var handle = GetConsoleWindow();
ShowWindow(handle, SwHide);
}
}
Just call ConsoleAllocator.ShowConsoleWindow() and then write to Console
If you don't want the Application object to be created then you should create a separate class containing a Main entry point:
class Startup
{
[STAThreadAttribute]
public static int Main(string[] args)
{
if (args.Length == 0)
{
// run windowed
App app = new App();
app.InitializeComponent();
app.Run();
}
else
{
// run console
ConsoleManager.Show();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
return 0;
}
}
You'll also need to go into your application settings and change "Startup object" to "YourProjectNamespace.Startup", see this article for more details.
The console functions I'm calling come from the accepted answer to this question which shows how to tap into the standard Console streams.