添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a C# winforms app that runs a macro in another program. The other program will continually pop up windows and generally make things look, for lack of a better word, crazy. I want to implement a cancel button that will stop the process from running, but I cannot seem to get the window to stay on top. How do I do this in C#?

Edit: I have tried TopMost = true; , but the other program keeps popping up its own windows over top. Is there a way to send my window to the top every n milliseconds?

Edit: The way I solved this was by adding a system tray icon that will cancel the process by double-clicking on it. The system tray icon does no get covered up. Thank you to all who responded. I read the article on why there is not a 'super-on-top' window... it logically does not work.

Yes, set a timer for every few milliseconds that will set your Form.TopMost to true. Then, just to make it interesting, when the "crazy" program loads, play the audio clip from Mortal Kombat "FIGHT!" :-P BFree Mar 25, 2009 at 20:46 You might thought your comment was hilarious, you might thought you could ridicule bad practice. My problem was creating a context menu that floats over a form with a flowlayoutpanel. A flowlayoutpanel can only be scrolled if you call it's Activate() method, Focus() is NOT enough in certain circumstances. You just won't be able to scroll it. That steals focus from the contextmenu even if it has exclusive topmost = true! As any sensible person knows it's godly practive to let your winform applications run in MTAThread mode and give every form it's own thread which makes the solution simple: ASA Feb 18, 2014 at 9:57 Behold, a devil: pastebin.com/sMJX0Yav It works flawlessly without flickering and the sleep(1) is enough to keep it from draining serious performance. Who keeps looking in his taskmanager anyways while he focuses on a context menu? Once the context menu closes it hopefully runs into the empty exception handler and dies. You might build in a isDisposed break though. ASA Feb 18, 2014 at 9:59 @Traubenfuchs That will fail because of Cross-thread operation exception. This should work. mekb Jul 21, 2019 at 2:29 In case any other complete newbies see this in 2016 and beyond, try Form.ActiveForm.TopMost user736893 Sep 6, 2016 at 13:33 In my case I also had to give the Window a Start Position, otherwise it was not staying at the top topMostForm.StartPosition = FormStartPosition.CenterScreen see also: learn.microsoft.com/en-us/dotnet/api/… Thomas Feb 18, 2021 at 11:51

I was searching to make my WinForms application "Always on Top" but setting "TopMost" did not do anything for me. I knew it was possible because WinAmp does this (along with a host of other applications).

What I did was make a call to "user32.dll." I had no qualms about doing so and it works great. It's an option, anyway.

First, import the following namespace:

using System.Runtime.InteropServices;

Add a few variables to your class declaration:

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;

Add prototype for user32.dll function:

[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 (I added the call in Form_Load()), add the call:

SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);

[Reference][1] [1]: http://www.c-sharpcorner.com/uploadfile/kirtan007/make-form-stay-always-on-top-of-every-window/

This works not only for WinForms applications, but also for console windows. Nice find! – rojo Jun 19, 2016 at 23:09 Nice, can confirm this works. But how would I be able to change it back to not be the top most? is there a HWND_BOTTOMMOST flag that you can share? – Mark Apr 26, 2018 at 14:35 @Mitra M, that's not real at all. Windows works entirely with handles, and any window have one. Check out my edit in this answer: I've added a way to use it in WPF, too. – Davide Cannizzo Nov 9, 2018 at 19:15 @Mark Yes, there is a flag HWND_NOTOPMOST (= -2). See learn.microsoft.com/en-us/windows/win32/api/winuser/… – Kevin Vuilleumier Jul 17, 2019 at 7:02

If by "going crazy" you mean that each window keeps stealing focus from the other, TopMost will not solve the problem.

Instead, try:

CalledForm.Owner = CallerForm;
CalledForm.Show();

This will show the 'child' form without it stealing focus. The child form will also stay on top of its parent even if the parent is activated or focused. This code only works easily if you've created an instance of the child form from within the owner form. Otherwise, you might have to set the owner using the API.

Setting CalledForm.Owner to itself (CalledForm) will cause a System.ArgumentException: 'A circular control reference has been made. A control cannot be owned by or parented to itself.' – mekb Jul 21, 2019 at 2:16 I tried, this... do I need to be continually doing it? The 'crazy program' takes over immediately... – jle Mar 25, 2009 at 20:40 No - if you set your form.TopMost = true, it should work. The "crazy" program must have it's dialogs set to TopMost as well, in which case, you can't override it. – Reed Copsey Mar 25, 2009 at 20:48

I had a momentary 5 minute lapse and I forgot to specify the form in full like this:

  myformName.ActiveForm.TopMost = true;

But what I really wanted was THIS!

  this.TopMost = true;
                Worked perfect for me.               if (checkBox1.Checked == true)             {                 this.TopMost = true;             }             else             {                 this.TopMost = false;             }
– yosh
                Feb 7, 2020 at 12:05
                @Yosh, you could just do: this.TopMost = checkBox1.Checked; And I should have replied 2 years ago :D
– Dave
                Mar 2 at 9:53
                Yes! This is what I wanted. Setting TopMost = true forced my form on top of everything, including chrome, when it reality it's just a settings box and I needed it on top of the main form. Kudos to you internet person.
– MDMoore313
                Oct 18, 2016 at 0:29

The following code makes the window always stay on top as well as make it frameless.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace StayOnTop
    public partial class Form1 : Form
        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);
        public Form1()
            InitializeComponent();
            FormBorderStyle = FormBorderStyle.None;
            TopMost = true;
        private void Form1_Load(object sender, EventArgs e)
            SetWindowPos(this.Handle, HWND_TOPMOST, 100, 100, 300, 300, TOPMOST_FLAGS);
        protected override void WndProc(ref Message m)
            const int RESIZE_HANDLE_SIZE = 10;
            switch (m.Msg)
                case 0x0084/*NCHITTEST*/ :
                    base.WndProc(ref m);
                    if ((int)m.Result == 0x01/*HTCLIENT*/)
                        Point screenPoint = new Point(m.LParam.ToInt32());
                        Point clientPoint = this.PointToClient(screenPoint);
                        if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)12/*HTTOP*/ ;
                                m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
                        else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)10/*HTLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)2/*HTCAPTION*/ ;
                                m.Result = (IntPtr)11/*HTRIGHT*/ ;
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)15/*HTBOTTOM*/ ;
                                m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
                    return;
            base.WndProc(ref m);
        protected override CreateParams CreateParams
                CreateParams cp = base.CreateParams;
                cp.Style |= 0x20000; // <--- use 0x20000
                return cp;
                Agree with Alexan - what makes your program topmost?  It seems like it's actually just the "topmost = true" statement, which isn't working in a lot of cases.  All the rest of the code doesn't really answer the problem.
– Fhaab
                Jul 13, 2017 at 22:33

What is the other application you are trying to suppress the visibility of? Have you investigated other ways of achieving your desired effect? Please do so before subjecting your users to such rogue behaviour as you are describing: what you are trying to do sound rather like what certain naughty sites do with browser windows...

At least try to adhere to the rule of Least Surprise. Users expect to be able to determine the z-order of most applications themselves. You don't know what is most important to them, so if you change anything, you should focus on pushing the other application behind everything rather than promoting your own.

This is of course trickier, since Windows doesn't have a particularly sophisticated window manager. Two approaches suggest themselves:

  • enumerating top-level windows and checking which process they belong to, dropping their z-order if so. (I'm not sure if there are framework methods for these WinAPI functions.)
  • Fiddling with child process permissions to prevent it from accessing the desktop... but I wouldn't try this until the othe approach failed, as the child process might end up in a zombie state while requiring user interaction.
  • What if I don't want my window to be active, I just want it topmost (informative, not interactive)? I ask only because actually issuing a "topmost=True" is not working in my case (it works on systems, not on others). – Fhaab Jul 13, 2017 at 22:36 Found this to work for us: this.Show(); this.Activate(); this.BringToFront(); But this answer got us to that solution. Thanks! – jibbs Oct 31, 2017 at 14:22

    In the code behind for Window_Deactivated:

    private void Window_Deactivated(object sender, EventArgs e)
            Window window = (Window)sender;
            window.Activate();
    

    This will keep your window on top.

    Based on clamum's answer, and Kevin Vuilleumier's comment about the other flag responsible for the behavior, I made this toggle that switches between on-top and not on-top with a button press.

    private void button1_Click(object sender, EventArgs e)
            if (on)
                button1.Text = "yes on top";
                IntPtr HwndTopmost = new IntPtr(-1);
                SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
                on = false;
                button1.Text = "not on top";
                IntPtr HwndTopmost = new IntPtr(-2);
                SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
                on = true;
    

    If you just want to Have Window Forms on top of a Game:(CSGOYour game needs to be in Fulscreen WINDOWED mode) or while you open different programs. Just use TopMost = true; In the:

    private void Forms1_Load(object sender, EventArgs e)
                TopMost = true;
    

    In the Latest Version of .Net 6 Visual studio 2022 Just wanted to point this one if you are trying to do this for games :D

    I did something i little bit differnt kinda found it much easier

    so first on Form Load

    private void Form1_Load(object sender, EventArgs e)
       this.Shown += new EventHandler(Form1_Shown);//let your form show up here
    private void Form1_Shown(Object sender, EventArgs e)
      Form1.ActiveForm.TopMost = true //and then do your TopMost logic 
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.