How can I ensure my C# console application is always in front?
e.i. if a person clicks away from the console, how can I detect that the console has lost the focus an bring it back to front?
I have this C# console application that is waiting for users to scan bar codes, if for some reason someone clicks away from the console window then the barcode data will be "lost".
I took a look at this code posted on another thread;however, I can not seem to get this to work for me:
bring a console window to front in c#
This code thanks to #ILan keeps the console ontop of all windows, but it does not set the "focus" to keep capturing the incoming data.
class Program
{
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
const uint SWP_NOSIZE = 0x0001, SWP_NOMOVE = 0x0002, SWP_SHOWWINDOW = 0x0040;
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
static void Main()
{
IntPtr handle = GetConsoleWindow();
SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
Console.WriteLine($"Hello handle: {handle}");
Console.ReadLine();
}
}
The following will do the job if the application is the one that attached to the console.
For a complete answer how to get the handle in case that your application is not the one that attached to the console, see https://stackoverflow.com/a/28616832/2370138.
class Program
{
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
const uint SWP_NOSIZE = 0x0001, SWP_NOMOVE = 0x0002, SWP_SHOWWINDOW = 0x0040;
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
static void Main()
{
IntPtr handle = GetConsoleWindow();
SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
Console.WriteLine($"Hello handle: {handle}");
Console.ReadLine();
}
}
SetForegroundWindow has been limited since then (see Remarks in https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setforegroundwindow). It will not allow you to arbitrarily put windows in the foreground anymore, exactly to prevent you from doing what you're trying to do.
If you need other applications running on the system, you're out of luck. You'll just need to tell your users they need to have the window focused when scanning a barcode.
Related
I have the following code that opens a remote desktop window. Everything seems to be running as expected, except the last call to SetWindowPos. It seems to be setting the TopMost property correctly, but for some reason, when I launch to code, I am able to resize and move the window. I indicated SWP_NOSIZE and SWP_NOMOVE, but I can resize and move the window. I don't want it to be movable nor resized.
m_proc = new Process {
StartInfo = {
FileName = "mstsc.exe",
Arguments = #"C:\projects\...\RemoteDesktop\IPS\Workstation1.rdp"
}
};
m_proc.Start();
//Wait until process is started and main rdp window is created.
while (m_proc.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(2000);
}
// Restore the window in the working screen so we can
// manipulate its size programmatically.
PostMessage(m_proc.MainWindowHandle, WM_SYSCOMMAND, SC_RESTORE, IntPtr.Zero);
// Move the restored window by X and Y, to the top left of the virtual screen.
// Note the width and height parameters don't work in this call, so
// width and height must be provided in the .rdp file in the winposstr parameter.
MoveWindow(m_proc.MainWindowHandle,
SystemInformation.VirtualScreen.Left,
SystemInformation.VirtualScreen.Top,
SystemInformation.VirtualScreen.Width,
SystemInformation.VirtualScreen.Height, true);
// This sets the RDP window as TopMost.
UnsafeNativeMethods.SetWindowPos(m_proc.MainWindowHandle,
UnsafeNativeMethods.HWND_TOPMOST, 0, 0, 0, 0,
UnsafeNativeMethods.SWP_NOMOVE | UnsafeNativeMethods.SWP_NOSIZE);
I have the following definitions in my UnsafeNativeMethods static class:
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd,
IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
public const UInt32 SWP_NOSIZE = 0x0001;
public const UInt32 SWP_NOMOVE = 0x0002;
public const UInt32 SWP_SHOWWINDOW = 0x0040;
What am I doing wrong?
I have a security program for my schools. What i need,
I keep my Windows form up until I'm allowed to.
I can partially do with the following codes..
<code>
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);</code>
But
the above code.
Does not work in task view(windows 10)
preview
I'm trying to figure out how this code works but I just can not figure out what makes it click through.
Yes, this code is not mine since i'm trying to learn/understand it.
Assume I want the tranparancy but not the click through what needs to be changed and why?
I have been over the Windows styles pages over and over and still can not get my head around the click through part.
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class TransparentWindow : MonoBehaviour
{
[SerializeField]
private Material m_Material;
private struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
static extern int SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, int dwFlags);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, int uFlags);
[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_VISIBLE = 0x10000000;
const int HWND_TOPMOST = -1;
void Start()
{
#if !UNITY_EDITOR // You really don't want to enable this in the editor..
int fWidth = Screen.width;
int fHeight = Screen.height;
var margins = new MARGINS() { cxLeftWidth = -1 };
var hwnd = GetActiveWindow();
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
// Transparent windows with click through
SetWindowLong(hwnd, -20, 524288 | 32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetLayeredWindowAttributes(hwnd, 0, 255, 2);// Transparency=51=20%, LWA_ALPHA=2
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
DwmExtendFrameIntoClientArea(hwnd, ref margins);
#endif
}
void OnRenderImage(RenderTexture from, RenderTexture to)
{
Graphics.Blit(from, to, m_Material);
}
}
This function:
SetWindowLong(hwnd, -20, 524288 | 32);
does the trick. Windows implements the rule that Mircosoft made which is that a window that is transparent to the user must be transparent to the mouse.
With the transparency bit set WS_EX_TRANSPARENT the window becomes transparent to mouse too and click passes to the painted layer behind the transparent window.
You need not understand but make use of this 'OS feature' which was probably implemented to cover for something else.
Read this article about the subject and this answer that explains the parameters
I have a window in an application, and the Resize mode is set to NoResize, but if you click the top-left of the window, the menu items of "Maximize", "Minimize", and "Size" are still enabled. This only happens to my windows that has no icon but still has the close button. Meaning this problem isn't happening to my windows that do have an icon.
This is the code that is removing the icon but still keeps the red close button:
protected override void OnSourceInitialized(EventArgs e) {
IconHelper.RemoveIcon(this);
}
public static class IconHelper {
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
const int GWL_EXSTYLE = -20;
const int WS_EX_DLGMODALFRAME = 0x0001;
const int SWP_NOSIZE = 0x0001;
const int SWP_NOMOVE = 0x0002;
const int SWP_NOZORDER = 0x0004;
const int SWP_FRAMECHANGED = 0x0020;
const uint WM_SETICON = 0x0080;
public static void RemoveIcon(Window window) {
IntPtr hwnd = new WindowInteropHelper(window).Handle;
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
I would like to know why this is happening and would appreciate it if some one can fix this problem. I am using WPF and C#.
After launching an application using the Process class I'd like to make that window topmost. Currently, my app is the topmost window so when i launch the other app it doesn't display. One thing that came to mind is that I could set topmost = false for my application before launching the process, the problem with this is I want to give the process ample time to load up before displaying it to the user, so I'd like more control over when I switch the other application to the topmost.
You need to use P/Invoke with SetWindowPos to accopmlish this:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_SHOWWINDOW = 0x0040;
// Call this way:
SetWindowPos(theWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);