I need Form2 to be always on top of every single window - including games in fullscreen. This always works with windowed-mode applications, but it sometimes won't appear topmost when another app is in fullscreen mode. (Games, OpenGL, direct)
How can I fix this?
Form1:
Overlay overlayui = new Overlay();
overlayui.TopMost = true; // I have tried setting TopMost to false, same result.
overlayui.Show();
Form2:
Settings in WinForms designed view:
FormBorderStyle = none
ControlBox = false
ShowIcon = false
ShowInTaskBar = false
TopMost = false
I've implemented this piece of code used in similar issues:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
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;
public Overlay()
{
InitializeComponent();
this.Bounds = Screen.PrimaryScreen.Bounds;
}
I then implemented a timer (interval 10 ms):
private void timer1_Tick(object sender, EventArgs e)
{
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
internal class MessagesFilter : IMessageFilter
{
private readonly IntPtr ControlHandler;
private const int WM_KEYUP = 0x0101;
public MessagesFilter(IntPtr ControlHandler)
{
this.ControlHandler = ControlHandler;
}
#region IMessageFilter Members
public bool PreFilterMessage(ref Message m)
{
// TODO: Add MessagesFilter.PreFilterMessage implementation
if (m.Msg == WM_KEYUP)
{
if (m.HWnd == ControlHandler)
{
Keys k = ((Keys)((int)m.WParam));
if (k == Keys.Enter)
return true;
}
}
return false;
}
#endregion
}
EDIT:
I've implemented new timer :
SetWindowPos(processNOtopmost, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE )
So first time brings to top my app, and second one is removing from topmost external app.
Still same problem, sometimes it works, sometimes it doesn't.
You want to set:
TopMost = true
As far as i'm aware though this only makes it the topmost Window for you Application.
You have no control over other applications unless you prevent loss of Focus completely (not advised)
And besides most of the applications that are 'Stealing' focus from you will be DirectX and get priority on the GPU.
Related
I've already checked out:
SetWindowPos not working on Form.Show()
Launch an application and send it to second monitor?
However, none of these solutions seem to work for me. I want to open an external program on a different monitor.
This is my current code:
public const int SWP_NOSIZE = 0x0001;
public const int SWP_NOZORDER = 0x0004;
public const int SWP_SHOWWINDOW = 0x0040;
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
[DllImport("user32.dll")]
public static extern bool UpdateWindow(IntPtr hWnd);
Process application = new Process();
application.StartInfo.UseShellExecute = false;
application.StartInfo.FileName = ".......";
if (application.Start())
{
Rectangle monitor = Screen.AllScreens[1].Bounds; // for monitor no 2
SetWindowPos(
application.MainWindowHandle,
IntPtr.Zero,
monitor.Left,
monitor.Top,
monitor.Width,
monitor.Height,
SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
UpdateWindow(application.MainWindowHandle); // tried even with application.Handle
}
First of all, you don't need UpdateWindow, calling SetWindowPos is probably enough. You just need to make sure that the window handle is created (because the process is being started). Simply add the following line before calling SetWindowPos:
application.WaitForInputIdle();
If WaitForInputIdle() doesn't work for you, you might try something like:
while (application.MainWindowHandle == IntPtr.Zero)
{
await Task.Delay(100);
}
The following code works fine for me:
Process application = new Process();
application.StartInfo.UseShellExecute = false;
application.StartInfo.FileName = "notepad.exe";
if (application.Start())
{
application.WaitForInputIdle();
/* Optional
while (application.MainWindowHandle == IntPtr.Zero)
{
await Task.Delay(100);
} */
Rectangle monitor = Screen.AllScreens[1].Bounds; // for monitor no 2
SetWindowPos(
application.MainWindowHandle,
IntPtr.Zero,
monitor.Left,
monitor.Top,
monitor.Width,
monitor.Height,
SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
}
Note that this will only set the position of the window, not its size though. If you want the size to be changed as well, you'll need to remove the SWP_NOSIZE flag.
I'm trying to embed the osk in a wpf window or a user control and I've found the code below and it's working for notepad but for tabtip.exe, it's saying that it doesn't have a graphical interface??
WaitForInputIdle failed. This could be because the process does not have a graphical interface.
I tried letting it sleep for awhile instead of calling waitForInputIdle method but it throws another exception:
Process has exited, so the requested information is not available.
But in my task manager, I can still see TabTip.exe running.
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private System.Windows.Forms.Panel _panel;
private Process _process;
public MainWindow()
{
InitializeComponent();
_panel = new System.Windows.Forms.Panel();
windowsFormsHost1.Child = _panel;
}
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);
[DllImport("user32")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
private const int SWP_NOZORDER = 0x0004;
private const int SWP_NOACTIVATE = 0x0010;
private const int GWL_STYLE = -16;
private const int WS_CAPTION = 0x00C00000;
private const int WS_THICKFRAME = 0x00040000;
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
base.OnClosing(e);
if (_process != null)
{
_process.Refresh();
_process.Close();
}
}
private void ResizeEmbeddedApp()
{
if (_process == null)
return;
SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)_panel.ClientSize.Width, (int)_panel.ClientSize.Height, SWP_NOZORDER | SWP_NOACTIVATE);
}
protected override Size MeasureOverride(Size availableSize)
{
Size size = base.MeasureOverride(availableSize);
ResizeEmbeddedApp();
return size;
}
private void button1_Click_1(object sender, RoutedEventArgs e)
{
button1.Visibility = Visibility.Hidden;
ProcessStartInfo psi = new ProcessStartInfo("C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe");
_process = Process.Start(psi);
Thread.Sleep(500);
//_process.WaitForInputIdle();
SetParent(_process.MainWindowHandle, _panel.Handle);
// remove control box
int style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
style = style & ~WS_CAPTION & ~WS_THICKFRAME;
SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);
// resize embedded application & refresh
ResizeEmbeddedApp();
}
}
}
Edit: Inspired by rene's comment, I've tried to obtain the window ptr as below and used spy++ to verify that the address that FindWindow gives is pointing to the correct window, but it's still not moving:
IntPtr KeyboardWnd = FindWindow("IPTip_Main_Window", null);
int style = GetWindowLong(KeyboardWnd, GWL_STYLE);
style = style & ~WS_CAPTION & ~WS_THICKFRAME;
SetWindowLong(KeyboardWnd, GWL_STYLE, style);
SetWindowPos(KeyboardWnd, IntPtr.Zero, 0, 0, (int)_panel.ClientSize.Width, (int)_panel.ClientSize.Height, SWP_NOZORDER | SWP_NOACTIVATE);
Edit 2: My first thought was that tab tip couldn't be resized, but then I noticed a behavior when I try to move the window across two different screen, it'll resize to fit the screen size, so I'm sure there must be a way to resize, so I started spy++(x64) to check :
Edit 3: after tinkering abit with user32 api and no progress, I've tried to use a memory scanner to scan for the x and y position of tabtip and change it, however, it's not refreshing until a repaint is triggered, I'm wondering the feasibility going down that path.
Can you try to run your handle code in STA thread? I had a similar issue with native window, which I had resolved using STA thread.
var thread = new Thread(() => {
// Your code here
});
thread.TrySetApartmentState(ApartmentState.STA);
thread.Start();
I had a similar problem, and the reason I had it was that I started a program that needed to be run by an administrator with a non-administrative program, and it would pop up with WaitForInputIdle failed. This could be because the process does not have a graphical interface, so I assume you try starting your program with an administrator
There's an existing question on StackOverflow on how to show a form without stealing focus. The answer is override ShowWithoutActivation and return true:
protected override bool ShowWithoutActivation
{
get { return true; }
}
This works well enough.
Now i want to go one step further. i want a show a Form (i.e. make it visible), but have it be behind other forms in the z-order.
Possible in .net?
If not, possible with P/Invoke?
Bonus Chatter
Calling SendToBack() doesn't work:
RunnerForm frm = new RunnerForm();
// frm.Show();
frm.Visible = true;
frm.SendToBack();
A little bit of PInvoke using SetWindowPos function
public static class HWND {
public static readonly IntPtr
NOTOPMOST = new IntPtr(-2),
BROADCAST = new IntPtr(0xffff),
TOPMOST = new IntPtr(-1),
TOP = new IntPtr(0),
BOTTOM = new IntPtr(1);
}
public static class SWP {
public static readonly int
NOSIZE = 0x0001,
NOMOVE = 0x0002,
NOZORDER = 0x0004,
NOREDRAW = 0x0008,
NOACTIVATE = 0x0010,
DRAWFRAME = 0x0020,
FRAMECHANGED = 0x0020,
SHOWWINDOW = 0x0040,
HIDEWINDOW = 0x0080,
NOCOPYBITS = 0x0100,
NOOWNERZORDER = 0x0200,
NOREPOSITION = 0x0200,
NOSENDCHANGING = 0x0400,
DEFERERASE = 0x2000,
ASYNCWINDOWPOS = 0x4000;
}
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
private void button1_Click(object sender, EventArgs e) {
RunnerForm frm = new RunnerForm();
SetWindowPos(frm.Handle, HWND.BOTTOM, 0, 0, 0, 0, SWP.SHOWWINDOW | SWP.NOMOVE | SWP.NOOWNERZORDER | SWP.NOSIZE | SWP.NOACTIVATE);
}
To add on to the viable solution Lars provided, you could also prevent the user from ever changing the window's Z order altogether.
To do that, you would override the form's WndProc method and catch the WM_WINDOWPOSCHANGING message that is sent to a window when its size, position, or Z order position is about to change. The super cool thing about this message—I think it's one of my favorites—is that it actually allows you to change or modify the parameters of the change that is about to take place.
So in this case, you'll want to set the SWP_NOZORDER flag to prevent the window's Z order from being changed.
The notable thing about this approach is that it will always maintain your window in the Z order at the last position you left it. The user won't be able to bring it to the front, which may or may not be a good thing, depending on how your UI is designed. It will also work just fine with controls other than forms.
Sample code pulled from one of my libraries:
internal class NativeMethods
{
public const int WM_WINDOWPOSCHANGING = 0x46;
public const int WM_WINDOWPOSCHANGED = 0x47;
[Flags()]
public enum SetWindowPosFlags
{
SWP_NOSIZE = 0x1,
SWP_NOMOVE = 0x2,
SWP_NOZORDER = 0x4,
SWP_NOREDRAW = 0x8,
SWP_NOACTIVATE = 0x10,
SWP_FRAMECHANGED = 0x20,
SWP_DRAWFRAME = SWP_FRAMECHANGED,
SWP_SHOWWINDOW = 0x40,
SWP_HIDEWINDOW = 0x80,
SWP_NOCOPYBITS = 0x100,
SWP_NOOWNERZORDER = 0x200,
SWP_NOREPOSITION = SWP_NOOWNERZORDER,
SWP_NOSENDCHANGING = 0x400,
SWP_DEFERERASE = 0x2000,
SWP_ASYNCWINDOWPOS = 0x4000,
}
public enum WindowZOrder
{
HWND_TOP = 0,
HWND_BOTTOM = 1,
HWND_TOPMOST = -1,
HWND_NOTOPMOST = -2,
}
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hWnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public SetWindowPosFlags flags;
// Returns the WINDOWPOS structure pointed to by the lParam parameter
// of a WM_WINDOWPOSCHANGING or WM_WINDOWPOSCHANGED message.
public static WINDOWPOS FromMessage(Message msg)
{
// Marshal the lParam parameter to an WINDOWPOS structure,
// and return the new structure
return (WINDOWPOS)Marshal.PtrToStructure(msg.LParam, typeof(WINDOWPOS));
}
// Replaces the original WINDOWPOS structure pointed to by the lParam
// parameter of a WM_WINDOWPOSCHANGING or WM_WINDOWPSCHANGING message
// with this one, so that the native window will be able to see any
// changes that we have made to its values.
public void UpdateMessage(Message msg)
{
// Marshal this updated structure back to lParam so the native
// window can respond to our changes.
// The old structure that it points to should be deleted, too.
Marshal.StructureToPtr(this, msg.LParam, true);
}
}
}
And then I have a slick little subclassed form that raises .NET events corresponding to these messages and allows the event handler to modify the values or cancel the event if desired. I don't handle SWP_NOZORDER, but you can get an idea of how it might work.
public class FormEx : System.Windows.Forms.Form
{
// ...snip constructors and such
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case NativeMethods.WM_WINDOWPOSCHANGING:
this.WmWindowPosChanging(m);
return;
// ...snip
}
base.WndProc(m);
}
private void WmWindowPosChanging(ref Message m)
{
// Extract the WINDOWPOS structure corresponding to this message
NativeMethods.WINDOWPOS wndPos = NativeMethods.WINDOWPOS.FromMessage(m);
// Determine if the size is changing (absence of SWP_NOSIZE flag)
if (!((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOSIZE) == NativeMethods.SetWindowPosFlags.SWP_NOSIZE))
{
// Raise the LowLevelSizeChanging event
SizeChangingEventArgs e = new SizeChangingEventArgs(this.Size, new Size(wndPos.cx, wndPos.cy));
this.OnLowLevelSizeChanging(e);
// Determine if the user canceled the size changing event
if (e.Cancel)
{
// If so, add the SWP_NOSIZE flag
wndPos.flags = wndPos.flags | NativeMethods.SetWindowPosFlags.SWP_NOSIZE;
wndPos.UpdateMessage(m);
}
}
// Determine if the position is changing (absence of SWP_NOMOVE flag)
if (!((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOMOVE) == NativeMethods.SetWindowPosFlags.SWP_NOMOVE))
{
// Raise the LowLevelPositionChanging event
PositionChangingEventArgs e = new PositionChangingEventArgs(this.Location, new Point(wndPos.x, wndPos.y));
this.OnLowLevelPositionChanging(e);
// Determine if the user canceled the position changing event
if (e.Cancel)
{
// If so, add the SWP_NOMOVE flag
wndPos.flags = wndPos.flags | NativeMethods.SetWindowPosFlags.SWP_NOMOVE;
wndPos.UpdateMessage(m);
}
}
base.WndProc(m);
}
// ...snip event infrastructure
}
Edit: Hmm, this code was originally written in VB.NET and I ran it through an automatic translator. It looks like the refs didn't get properly inserted everywhere that they should be when making function calls. Follow the urging of the compiler to fix it...
This should do the trick:
RunnerForm frm = new RunnerForm();
myMainForm.Owner = frm;
I have a borderless form which is always on top and with WS_EX_NOACTIVATE flag set to prevent it for gaining focus.
const int WS_EX_NOACTIVATE = 0x08000000;
protected override CreateParams CreateParams {
get {
CreateParams param = base.CreateParams;
param.ExStyle |= WS_EX_NOACTIVATE;
return param;
}
}
Form contains small picture box for moving (since it's borderless):
private void pictureBox4_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
ReleaseCapture();
SendMessage(this.Handle, 0xa1, 0x2, 0);
}
}
However when I move the window it doesn't get redrawn/shown, only when I release the mouse button does it move the form to new location.
I have seen applications which work in a similar fashion but they do show the window while moving (for example some virtual keyboards I've seen). I've also seen many questions elsewhere on net about this issue but with no answer.
Can someone please tell me if it is possible to show a window/form like this while moving (like "normal" window), and if yes, how to do it?
I think I've found solution. I would very appreciate if someone could check to see if everything is done correctly (no conflict of some kind with messages). I've changed the code above for moving form using picture, into the following:
[DllImportAttribute("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInstertAfter, int x, int y, int cx, int cy, uint flags);
const int SWP_NOSIZE = 0x0001;
const int SWP_NOZORDER = 0x0004;
private void pictureBox4_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
//ReleaseCapture();
//SendMessage(this.Handle, 0xa1, 0x2, 0);
SetWindowPos(Handle, IntPtr.Zero, this.Location.X + e.X,
this.Location.Y + e.Y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
So basically I removed those two method (function) calls and repleaced them with SetWindowPos(). at first I had problems with flickering and incorrect positioning but then I remembered to check if coordinates are client or screen coordinates...
how to change the window style of a form outside your app?hard question?
i am actually trying to move a form witch is topmost and has no border.
i have the handle(hWnd) of the window.
i can write thousands of lines of code if guaranteed to work.
Assuming that this window could be from any app produced from any kind of Win32-based runtime, it looks like you'll have to resort to p/invoke of the core Win32 apis for window operations.
For example, you could use SetWindowPos, which can be imported from user32.dll. It's signature is this:
BOOL SetWindowPos(HWND hWnd,
HWND hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
UINT uFlags
);
I'm not going to assume that you've done a p/invoke import before, so let's go from the top. Let's just bash out a windows forms app:
1) Create a windows forms app and then add these declarations to the Form1 class:
/* hWndInsertAfter constants. Lifted from WinUser.h,
* lines 4189 onwards depending on Platform SDK version */
public static IntPtr HWND_TOP = (IntPtr)0;
public static IntPtr HWND_BOTTOM = (IntPtr)1;
public static IntPtr HWND_TOPMOST = (IntPtr)(-1);
public static IntPtr HWND_NOTOPMOST = (IntPtr)(-2);
/* uFlags constants. Lifted again from WinUser.h,
* lines 4168 onwards depending on Platform SDK version */
/* these can be |'d together to combine behaviours */
public const int SWP_NOSIZE = 0x0001;
public const int SWP_NOMOVE = 0x0002;
public const int SWP_NOZORDER = 0x0004;
public const int SWP_NOREDRAW = 0x0008;
public const int SWP_NOACTIVATE = 0x0010;
public const int SWP_FRAMECHANGED = 0x0020;
public const int SWP_SHOWWINDOW = 0x0040;
public const int SWP_HIDEWINDOW = 0x0080;
public const int SWP_NOCOPYBITS = 0x0100;
public const int SWP_NOOWNERZORDER = 0x0200; /* Don't do owner Z ordering */
public const int SWP_NOSENDCHANGING = 0x0400; /* Don't send WM_WINDOWPOSCHANGING */
public const int SWP_DRAWFRAME = SWP_FRAMECHANGED;
public const int SWP_NOREPOSITION = SWP_NOOWNERZORDER;
public const int SWP_DEFERERASE = 0x2000;
public const int SWP_ASYNCWINDOWPOS = 0x4000;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SetWindowsPos(IntPtr hWnd,
IntPtr hWndInsertAfter,
int x,
int y,
int cx,
int cy,
UInt32 uFlags);
The annoying thing with p/invoke of Win32 windows methods is that you then have to start importing various numeric constants etc that Win32 uses - hence all the gumph beforehand.
Refer to the MSDN link for the SetWindowPos method for an explanation of what they do.
2) Add a button to the form called cmdMakeHidden and then write the handler as follows:
private void cmdMakeHidden_Click(object sender, EventArgs e)
{
//also causes the icon in the start bar to disappear
//SWP_HIDEWINDOW is the 'kill -9' of the windows world without actually killing!
SetWindowPos(this.Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_HIDEWINDOW);
}
Replace the 'this.Handle' with the window handle of your choice to hide that window.
This method is actually used to apply multiple changes at once, hence the need to use some of the SWP_NO* options. For example, you should specify SWP_NOSIZE otherwise passing 0 for cx and cy will cause the window to shrink to zero width and height at the same time.
To demonstrate moving a window, add another button your form called cmdMove and then write the click handler as follows:
private void cmdMove_Click(object sender, EventArgs e)
{
SetWindowPos(this.Handle, HWND_TOP, 100, 100, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOREPOSITION);
}
This code moves your form to 100,100 whenever you hit the button.
Again, replace the this.Handle as you see fit. HWND_TOP here is completely optional, since reordering has been disabled with the SWP_NOZORDER and SWP_NOREPOSITION flags.
Hope this helps get you on the right track!