How Can My Win32 App Steal Focus From My UWP App? - c#

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

Related

A way to stop Console from exiting by user or program [duplicate]

This question already has answers here:
Is there any way to prevent console application to close?
(2 answers)
Prevent the application from exiting when the Console is closed
(3 answers)
How to prevent app from closing before finishing a task?
(1 answer)
Closed 2 years ago.
I have searched far and wide and still found nothing.
What I'm trying to accomplish is preventing/stopping the console from exiting/terminating, for example clicking X on the console or having a different program closing it (I know for a fact that it is not possible to bypass Task Managers "Kill Task").
What I have been using is the following:
private delegate bool ConsoleCtrlHandlerDelegate(int sig);
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerDelegate handler, bool add);
static ConsoleCtrlHandlerDelegate _consoleCtrlHandler;
//...
_consoleCtrlHandler += s => {/* I have a while true loop right here with some extra code doing stuffs*/};
SetConsoleCtrlHandler(_consoleCtrlHandler, true);
//...
That does work...for about 5 seconds, then closes on it's own.
Please help.
Also, DO NOT SAY CTRL+F5, as it will not accomplish my goal. My goal is beyond debugging tools.
If you want an application to be working non-stop, you should run this as a Windows service rather than a console application.
With a little research, you can convert your application to a Windows Service and set appropriate user rights for starting and stopping the service.
You can't stop someone from killing a task, if they have the admin rights to kill your task. The best you can do is to create a user with admin privileges on the machine, then run the application under that user. That will prevent any task, other than a task with admin privileges from killing your app.
Now, as far as disabling the close button on your console app, you can use the Win32 DeleteMenu API to disable the X button. Here is an example:
public const int ScClose = 0xF060;
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);
[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
static void Main(string[] args)
{
// Get a pointer to the console window
IntPtr consoleWindow = GetConsoleWindow();
// Get a pointer to the system menu inside the console window
IntPtr systemMenu = GetSystemMenu(consoleWindow, false);
// Delete the close menu item
DeleteMenu(systemMenu, ScClose, 0);
}

Bring multiple processes to foreground windows

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?

.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.

.Net Console Application that Doesn't Bring up a Console

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?

Categories