I want to be able to have my application to always be on top. so when I open a new program and that becomes on top even though I have this.TopLevel value set to true, the application will see it is not on top no more and then go back on top.
I know I can do this with a timer, but I am hoping their is a better way.
You can use a method located in user32.dll.
using System.Runtime.InteropServices;
You are going to need these variables:
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;
Import the method from the DLL...
[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);
Then in your code, use this to set the window position to the topmost window.
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
I hope this helps you!
I suggest you catch the event for new windows and see if you are on top after the new window opens:
https://stackoverflow.com/a/40698254/2557128
Related
I'm Currently Developing a Windows Server Core Shell/Windows Shell Replacement that's CPU and RAM Efficient.
But it keeps getting in the way if I click on the Desktop.
Is there any way of letting it stay on the desktop/behind all other windows?
It Shouldn't take too much CPU and Ram.
Cant comment yet, so here is something ive found:
Setting a Windows form to be bottommost
so you only have to add this to your class / Form
[System.Runtime.InteropServices;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_BOTTOM = new IntPtr(1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOACTIVATE = 0x0010;
and then on the Form.Activate and the Form.Load event you have to run the declared method like this:
SetWindowPos(Handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
Code from Richard Ev
I recently implemented the solutions from this question to hide a WPF Window's icon. I found that when that solution is used in conjunction with ResizeMode=NoResize, the app's title bar context menu fails to disable Min/Max/Resize options.
The odd thing is the context menu doesn't incorrectly enable certain options, it just leaves the state of the context menu from before the icon was hidden. I found this using a simple test app that can make the necessary calls to hide the icon, and can update the Window's ResizeMode on the fly.
Icon Shown, ResizeMode=CanResize
Title bar buttons and context menu are correct.
Icon Hidden, ResizeMode=CanResize
Still correct
Icon Hidden, ResizeMode=NoResize
Title bar buttons are correctly hidden, but the context menu retains it's previous state. If I switch to CanMinimize then to NoResize, the context menu would only have "Minimize" enabled.
This becomes a problem when a resize-able WPF Window launches another Window which is set to NoResize (and you are hiding the icon).
Question
Are there additional Windows API functions that can force the Context Menu to reevaluate its state? What about the NoResize option might be causing this weird behavior? As this only affects the NoResize option, could there be a workaround at the WPF level?
EDIT - My goal is to avoid using WindowStyle=ToolWindow or the WS_EX_TOOLWINDOW extended window style. I've found a few problems with that window style in the past, one is desribed on this question. One of my goals with this whole approach was to emulate the look of ToolWindow without actually having to use it.
Using .NET 4.0 and Windows 8.1 Enterprise (I do not know if it works with other .NET versions or a different OS), you just need to use the WS_EX_TOOLWINDOW extended style instead of the WS_EX_DLGMODALFRAME one.
So the code will be:
public partial class MainWindow : Window
{
[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);
private const int GWL_EXSTYLE = -20;
private const int WS_EX_DLGMODALFRAME = 0x0001;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_FRAMECHANGED = 0x0020;
private const int WM_SETICON = 0x0080;
private const int WS_EX_TOOLWINDOW = 0x00000080;
public MainWindow()
{
InitializeComponent();
ResizeMode = System.Windows.ResizeMode.NoResize;
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
IntPtr hwnd = new WindowInteropHelper(this).Handle;
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW);
SendMessage(hwnd, WM_SETICON, new IntPtr(1), IntPtr.Zero);
SendMessage(hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero);
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE |
SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
Let's hope it can help you.
I am using this code (on windows 2003) to remove and resize window:
Process process = Process.GetProcessById(12121);
IntPtr mwh = process.MainWindowHandle;
SetWindowLong(mwh, GWL_STYLE, WS_VISIBLE);
ShowWindowAsync(mwh, 3);
SetWindowPos(mwh, new IntPtr(0), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
And declarations:
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
static readonly int GWL_STYLE = -16;
static readonly int SWP_NOMOVE = 0x2;
static readonly int SWP_NOSIZE = 0x1;
static readonly int SWP_FRAMECHANGED = 0x20;
static readonly int WS_VISIBLE = 0x10000000;
Everything works correct, when I am resizing window associated with process started by me. But when I want to do this with other users windows, then it does nothing.
How to make it works for other users windows?
The behavior is by design in Windows Vista and later, due to the User Interface Privilege Isolation (UIPI). You could solve it if you have access to the source code of the controlled applications.
Read this answer for more: https://stackoverflow.com/a/15445510.
process.MainWindowHandle is a .NET concept, there is no such thing as a main window in native desktop apps and therefore might not always work correctly on other processes. You should check if mwh is IntPtr.Zero, if it is then you need to use EnumWindows + GetWindowThreadProcessId + IsWindowVisible to find the applications window.
Calling SetWindowLong(mwh, GWL_STYLE, WS_VISIBLE); on a window you did not create is not OK. You need to call GetWindowLong first the get the existing style, remove all the styles you don't want and add WS_POPUP. You might want to remove some of the extended styles as well.
What is needed to grab the handle of a visible window and set it to remain on top?
For example being able to set the onTop property of some other application ( let's say notepad) to be on top.
Is there a simple way to do this with Win 7 or 8 ? not really looking for low level trickery with windows API's if possible.
Thank you
You can make a window Topmost given a window handle via:
[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);
The method to get the appropriate window handle varies based on the application. You likely can get it via Process.MainWindowHandle, though sometimes it requires using EnumWindows in the Windows API if it's not a "main window".
Using the above, for Notepad, for example, you could do:
var processes = Process.GetProcessesByName("notepad");
SetWindowPos(processes.First().MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
HWND_TOPMOST will put the window on to permanently (until some other window is tagged as topmost) but if you want the window to simply pop to the front try:
static readonly IntPtr HWND_TOP = new IntPtr(0);
Is there a managed way to set the always on top flag/setting on a window that is external to my application or will I need to P/Invoke a native function?
And if P/Invoke is the only way what is the function call required and from which dll?
Since asking the question I have been researching this and came across what looks like a good example of how to achieve this via p/invoking SetWindowPos in 'user32.dll'. I will come back and accept this answer if this works.
[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 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
public static void MakeTopMost (IntPtr hWnd)
{
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}
Simple answer:
TopMost = true;