Bring multiple processes to foreground windows - c#

I currently have a multi monitor app on the electron engine which opens a different window with separate content on each monitor. It uses 2 separate processes with the same name to display these windows, "home".
The app can then be used to launch different windows. One of these is called "game". This game opens a control style window on the main monitor, and then the actual game on the second monitor. Both of these are different processes both called "game".
We currently have a small C# console app that can be called and passed a string to try and bring these apps to the front which looks as below:
class Program
{
[DllImport("user32.dll")]
private static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
static void Main(string[] args)
{
BringToFront(args[0]);
}
private static void BringToFront(string title)
{
// Get a handle to the Calculator application.
Process[] processes = Process.GetProcessesByName(title);
if (processes.Length > 1)
{
foreach(Process process in processes)
{
IntPtr mainWindowHandle = process.MainWindowHandle;
if (mainWindowHandle == GetForegroundWindow()) return;
SetForegroundWindow(mainWindowHandle);
}
}
}
}
The problem is that this only ever brings 1 window to the front, not both.
I have researched this and found that it is due to the rules surrounding SetForegroundWindow, and unless I'm mistaken, when we set the first foreground window we are then not allowed to set any others as the console app/process that called the console app is no longer the foreground process.
Is there any way to accomplish bringing 2 separate windows to the front using a C# console app?

Related

How Can My Win32 App Steal Focus From My UWP App?

I've tried the following code:
[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr SetFocus(IntPtr hwnd);
void TakeFocus()
{
var process = Process.GetProcessesByName("myProcess").FirstOrDefault();
if (process != null)
{
// Tried each of the following:
ShowWindow(process.MainWindowHandle, 1);
ShowWindow(process.MainWindowHandle, 3);
ShowWindow(process.MainWindowHandle, 9);
ShowWindow(process.MainWindowHandle, 5);
SetFocus(process.MainWindowHandle);
SetForegroundWindow(process.MainWindowHandle);
}
}
I have a WPF companion app which runs in the background while a UWP app is running in the foreground. They communicate via WebSocket. I'm trying to create a method in the WPF app so it (or any other window) can steal focus from an activated UWP app, sending it into suspended state. Nothing I try seems to work, and there's no way to programatically make a UWP app suspend itself AFAIK without using the Launcher class (not an option for me, unless there's a way to call it without actually launching something-I haven't been able to do this). Normally I would assume it can't be done but I've seen programs that do it. Steam Big Picture Mode, for example, will steal focus from a UWP app when it is launched from a background process.
The supported way of suspending a UWP programmatically is available in the Spring 2018 update for Windows 10. It's already available in Insider builds/SDKs. This is the API to call:
https://learn.microsoft.com/en-us/uwp/api/windows.system.appresourcegroupinfo.startsuspendasync#Windows_System_AppResourceGroupInfo_StartSuspendAsync
IList<AppDiagnosticInfo> infos = await AppDiagnosticInfo.RequestInfoForAppAsync();
IList<AppResourceGroupInfo> resourceInfos = infos[0].GetResourceGroups();
await resourceInfos[0].StartSuspendAsync();
Here is a trivial sample app:
https://1drv.ms/u/s!AovTwKUMywTNoYQ3PrmBfZIGXmbULA

How to be dynamically either console application or Windows Application

I have a small application who should be executed in two modes: non UI or WPF Window. It should depend on command line arguments.
In each mode, I need to show some feedback log:
In WPF Window mode, WPF is going to take care of visualizing logs,
In no UI mode, I need a console to show logs. If my app have been started from a console (mainly cmd.exe), I'd like to use it without opening a new one. If my app have been started outside of a console (double click on explorer, a CreateProcess, ...), I need to create a new console to output my results and wait for a Readkey to close it.
I have found:
how I can create a new console:
How to open/close console window dynamically from a wpf application?,
how to get current console windows handle to show/hide it:
Show/Hide the console window of a C# console application
And I know I can statically choose between "Windows Application" or "Console Application" in project property.
Choosing "Windows Application", GetConsoleWindow() is always 0 and I don't see how to reuse a previous console.
Choosing "Console Application", I can reuse a previous console but when started from explorer in WPF Window mode, a console is created under my WPF main window.
The question is: how can an application be really dynamic? Either in WPF Window mode, with only a WPF windows (and no console at all) or in non UI, with only one console (starting one or a new created one).
It was a lot easier in Winforms, but its not too hard.
Start off with a WPF Application Project (not a console application project with WPF windows).
Create a new Program.cs class in the root directory, add the following code:
class Program
{
[DllImport("Kernel32")]
public static extern void AllocConsole();
[DllImport("Kernel32")]
public static extern void FreeConsole();
[DllImport("kernel32.dll")]
static extern bool AttachConsole(uint dwProcessId);
[STAThread]
public static void Main(string[] args)
{
bool madeConsole = false;
if (args.Length > 0 && args[0] == "console")
{
if (!AttachToConsole())
{
AllocConsole();
Console.WriteLine("Had to create a console");
madeConsole = true;
}
Console.WriteLine("Now I'm a console app!");
Console.WriteLine("Press any key to exit");
Console.ReadKey(true);
if (madeConsole)
FreeConsole();
}
else
{
WpfApplication1.App.Main();
}
}
public static bool AttachToConsole()
{
const uint ParentProcess = 0xFFFFFFFF;
if (!AttachConsole(ParentProcess))
return false;
Console.Clear();
Console.WriteLine("Attached to console!");
return true;
}
}
Now you have a console app or a WPF app. In the Properties, set the start up object as the Program.Main method. In the example above, WpfApplication1.App.Main is the old start up object (defined in the App.xaml.cs file).
Edit this misses one of your requirements about using the existing console and I will edit it as soon as I figure out how to stay in the same console window.
New Edit Now works to use the existing console!

.NET winforms app won't come to front on Windows 8.1

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.

Ensure single instance of a WPF application : Difficulty restoring the already running application to the foreground

Intention : Run a single instance of a WPF application. When a new instance, is started the already running instance should be set to the foreground.
While I have achieved most of it, I am facing a problem when the already running application is sitting in the notification tray. The code runs without an error, but fails to restore the window & set it to foreground. Code Snippet (c#):
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
var currentProcess = Process.GetCurrentProcess();
string processName = currentProcess.ProcessName;
Process[] instances = Process.GetProcessesByName(processName);
if (instances.Length > 1)
{
foreach(var instance in instances)
{
if (!currentProcess.Id.Equals(instance.Id))
{
IntPtr hWnd = instance.MainWindowHandle;
if (IsIconic(hWnd))
ShowWindow(hWnd, SW_RESTORE);
SetForegroundWindow(hWnd);
}
}
currentProcess.Kill();
}
Can any one point out what am I doing wrong. To reiterate again, it works in the case when the already running window is in maximized state but in the hindsight. It fails when the already running window is minimized to the notification tray.
Thanks
Have you verified, that your code executes the ShowWindow when the already running process is in the systray? I am asking, because I don't think that IsIconic is the correct function to use: The documentation states that it "determines whether the specified window is minimized". If the process is in the systray it isn't minimized, it is hidden.
I think you should use IsWindowVisible instead.

Allocate a console for a WinForm application

I use the following code to allocate a Console for a WinForm application. The Console window shows up successfully and the output is there. But when I close the Console window, my WinForm applicaion is closed at the same time. Why? I want to keep the WinForm window.
private void btn_to_console_Click(object sender, EventArgs e)
{
if (NativeMethods.AllocConsole())
{
lbl_console_alloc_result.Text = "Console allocation successfully!";
IntPtr stdHandle = NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE);
Console.WriteLine("from WinForm to Console!");
lbl_console_alloc_result.Text = Console.ReadLine();
}
else
lbl_console_alloc_result.Text = "Console allocation failed!";
}
[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetStdHandle")]
public static extern System.IntPtr GetStdHandle(Int32 nStdHandle);
/// Return Type: BOOL->int
[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "AllocConsole")]
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool AllocConsole();
Thanks in advance...
Closing a Console Window will shutdown any application -whether a console application, Windows Forms, native Windows app, or WPF application. This is a "feature" of Console windows.
If you don't want this behavior, you should, instead, just make a custom window to display your output instead of using a Console Window. Otherwise, you need to call FreeConsole instead of closing the Window to detach your application from the Console window.

Categories