Как сделать так, чтобы окно всегда оставалось на вершине в .Net? - PullRequest
79 голосов
/ 25 марта 2009

У меня есть приложение C # winforms, которое запускает макрос в другой программе. Другая программа будет постоянно всплывать в окнах и вообще заставлять вещи выглядеть, из-за отсутствия лучшего слова, сумасшедшими. Я хочу реализовать кнопку отмены, которая остановит процесс, но я не могу заставить окно оставаться на вершине. Как мне это сделать в C #?

Редактировать: я пробовал TopMost = true; , но другая программа продолжает показывать свои собственные окна поверх. Есть ли способ отправлять мое окно наверх каждые n миллисекунд?

Редактировать: Я решил эту проблему, добавив значок в системном трее, который отменит процесс, дважды щелкнув по нему. Значок на панели задач не скрывается. Спасибо всем, кто откликнулся. Я прочитал статью о том, почему нет окна «super-on-top» ... оно логически не работает.

Ответы [ 12 ]

148 голосов
/ 25 марта 2009

Form.TopMost будет работать, если другая программа не создаст самые верхние окна.

Нет способа создать окно, которое не покрыто новыми верхними окнами другого процесса. Раймонд Чен объяснил почему.

31 голосов
/ 10 января 2016

Я искал, чтобы сделать мое приложение WinForms «Всегда сверху», но настройка «TopMost» ничего не сделала для меня. Я знал, что это возможно, потому что WinAmp делает это (вместе с множеством других приложений).

Что я сделал, так это позвонил «user32.dll». Я не стеснялся делать это, и это прекрасно работает. Во всяком случае, это вариант.

Сначала импортируйте следующее пространство имен:

using System.Runtime.InteropServices;

Добавьте несколько переменных к вашему объявлению класса:

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;

Добавить прототип для функции user32.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);

Затем в вашем коде (я добавил вызов в Form_Load ()), добавьте вызов:

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

Надеюсь, это поможет. Ссылки

21 голосов
/ 22 августа 2012

Если под "сходить с ума" вы имеете в виду, что каждое окно продолжает захватывать фокус у другого, TopMost не решит проблему.

Вместо этого попробуйте:

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

Это покажет «дочернюю» форму без кражи фокуса. Дочерняя форма также останется поверх своего родителя, даже если родитель активирован или сфокусирован. Этот код работает легко, только если вы создали экземпляр дочерней формы из формы владельца. В противном случае вам, возможно, придется установить владельца с помощью API.

15 голосов
/ 25 марта 2009
6 голосов
/ 15 июля 2015

У меня был краткий 5-минутный промежуток, и я забыл указать форму полностью, как это:

  myformName.ActiveForm.TopMost = true;

Но я действительно хотел ЭТОГО!

  this.TopMost = true;
6 голосов
/ 25 марта 2009

Установите для свойства .TopMost формы значение true.

Вы, вероятно, не хотите оставлять это все время так: установите его, когда ваш внешний процесс запускается, и верните его, когда он завершится.

5 голосов
/ 18 апреля 2017

Следующий код делает окно всегда наверху, а также делает его безрамным.

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*/ ;
                            else
                                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*/ ;
                            else
                                m.Result = (IntPtr)11/*HTRIGHT*/ ;
                        }
                        else
                        {
                            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*/ ;
                            else
                                m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
                        }
                    }
                    return;
            }
            base.WndProc(ref m);
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.Style |= 0x20000; // <--- use 0x20000
                return cp;
            }
        }
    }
}
5 голосов
/ 26 марта 2009

Я решил это путем создания иконки в системном трее с возможностью отмены.

4 голосов
/ 18 мая 2015

Почему бы не сделать вашу форму диалоговым окном:

myForm.ShowDialog();
4 голосов
/ 26 марта 2009

Какое другое приложение вы пытаетесь подавить видимость? Вы исследовали другие способы достижения желаемого эффекта? Пожалуйста, сделайте это, прежде чем подвергать своих пользователей такому мошенническому поведению, как вы описываете: то, что вы пытаетесь сделать, похоже на то, что некоторые непослушные сайты делают с окнами браузера ...

Хотя бы попытайтесь придерживаться правила Наименее сюрприз . Пользователи ожидают, что смогут определить z-порядок большинства приложений. Вы не знаете, что для них наиболее важно, поэтому, если вы что-то измените, вам следует сосредоточиться на том, чтобы продвигать другое приложение за всем, а не продвигать свое собственное.

Это, конечно, хитрее, поскольку в Windows нет особенно сложного оконного менеджера. Два подхода предлагают себя:

  1. перечисление окон верхнего уровня и проверка какой процесс они принадлежат , бросая их z-порядок, если так . (Я не уверен, если Есть каркасные методы для эти функции WinAPI.)
  2. Работа с разрешениями дочерних процессов для предотвращения доступа к рабочему столу ... но я не буду пытаться делать это до тех пор, пока другой подход не сработает, так как дочерний процесс может оказаться в состоянии зомби, требуя взаимодействия с пользователем.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...