Как настроить системное меню формы Windows?

Я хочу добавить в приложение пункт age About About. Я хочу добавить его в «системное меню» приложения (тот, который появляется, когда мы нажимаем значок приложения в верхнем левом углу). Итак, как я могу это сделать в .NET?

Windows упрощает получение дескриптора копии системного меню формы для целей настройки с GetSystemMenu функции GetSystemMenu . Жесткая часть заключается в том, что вы сами можете выполнить соответствующие изменения в возвращаемом меню, используя такие функции, как AppendMenu , InsertMenu и DeleteMenu как и если бы вы программировали непосредственно против Win32 API.

Однако, если все, что вы хотите сделать, это добавить простой пункт меню, это действительно не так уж сложно. Например, вам нужно будет использовать функцию AppendMenu потому что все, что вы хотите сделать, это добавить элемент или два в конец меню. Выполнение чего-либо более продвинутого (например, вставка элемента в середине меню, отображение растрового изображения в элементе меню, отображение элементов меню, установка элемента меню по умолчанию и т. Д.) Требует немного больше работы. Но как только вы знаете, как это делается, вы можете пойти на дикую природу. Документация по функциям, связанным с меню, рассказывает все.

Вот полный код формы, который добавляет строку разделителя и элемент «О» в нижней части ее системного меню (также называемое меню windows):

 using System; using System.Windows.Forms; using System.Runtime.InteropServices; public class CustomForm : Form { // P/Invoke constants private const int WM_SYSCOMMAND = 0x112; private const int MF_STRING = 0x0; private const int MF_SEPARATOR = 0x800; // P/Invoke declarations [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool InsertMenu(IntPtr hMenu, int uPosition, int uFlags, int uIDNewItem, string lpNewItem); // ID for the About item on the system menu private int SYSMENU_ABOUT_ID = 0x1; public CustomForm() { } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); // Get a handle to a copy of this form's system (window) menu IntPtr hSysMenu = GetSystemMenu(this.Handle, false); // Add a separator AppendMenu(hSysMenu, MF_SEPARATOR, 0, string.Empty); // Add the About menu item AppendMenu(hSysMenu, MF_STRING, SYSMENU_ABOUT_ID, "&About…"); } protected override void WndProc(ref Message m) { base.WndProc(ref m); // Test if the About item was selected from the system menu if ((m.Msg == WM_SYSCOMMAND) && ((int)m.WParam == SYSMENU_ABOUT_ID)) { MessageBox.Show("Custom About Dialog"); } } } 

И вот как выглядит готовый продукт:

Форма с пользовательским системным меню

Я сделал решение Коди Грея еще на один шаг и сделал из него многоразовый class. Это часть моего приложения для регистрации журнала приложений, которое должно скрывать информацию о нем в системном меню.

https://github.com/ygoe/FieldLog/blob/master/LogSubmit/Unclassified/UI/SystemMenu.cs

Его можно легко использовать следующим образом:

 class MainForm : Form { private SystemMenu systemMenu; public MainForm() { InitializeComponent(); // Create instance and connect it with the Form systemMenu = new SystemMenu(this); // Define commands and handler methods // (Deferred until HandleCreated if it's too early) // IDs are counted internally, separator is optional systemMenu.AddCommand("&About…", OnSysMenuAbout, true); } protected override void WndProc(ref Message msg) { base.WndProc(ref msg); // Let it know all messages so it can handle WM_SYSCOMMAND // (This method is inlined) systemMenu.HandleMessage(ref msg); } // Handle menu command click private void OnSysMenuAbout() { MessageBox.Show("My about message"); } } 

Значение-добавление довольно мало для количества выводов, которые вам понадобятся. Но это возможно. Используйте GetSystemMenu () для извлечения дескриптора системного меню. Затем InsertMenuItem добавит запись. Вы должны сделать это в переопределении OnHandleCreated (), чтобы воссоздать меню, когда окно будет воссоздано.

Переопределите WndProc (), чтобы распознать сообщение WM_SYSCOMMAND, которое создается, когда пользователь нажимает на него. Посетите pinvoke.net для объявлений pinvoke, которые вам понадобятся.

Я знаю, что этот ответ старый, но мне очень понравился ответ LonelyPixel. Однако для работы с WPF потребовалась некоторая работа. Ниже приведена версия WPF, поэтому вам не нужно :).

 ///  /// Extends the system menu of a window with additional commands. /// Adapted from: /// https://github.com/dg9ngf/FieldLog/blob/master/LogSubmit/Unclassified/UI/SystemMenu.cs ///  public class SystemMenuExtension { #region Native methods private const int WM_SYSCOMMAND = 0x112; private const int MF_STRING = 0x0; private const int MF_SEPARATOR = 0x800; [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem); #endregion Native methods #region Private data private Window window; private IntPtr hSysMenu; private int lastId = 0; private List actions = new List(); private List pendingCommands; #endregion Private data #region Constructors ///  /// Initialises a new instance of the  class for the specified /// . ///  /// The window for which the system menu is expanded. public SystemMenuExtension(Window window) { this.window = window; if(this.window.IsLoaded) { WindowLoaded(null, null); } else { this.window.Loaded += WindowLoaded; } } #endregion Constructors #region Public methods ///  /// Adds a command to the system menu. ///  /// The displayed command text. /// The action that is executed when the user clicks on the command. /// Indicates whether a separator is inserted before the command. public void AddCommand(string text, Action action, bool separatorBeforeCommand) { int id = ++this.lastId; if (!this.window.IsLoaded) { // The window is not yet created, queue the command for later addition if (this.pendingCommands == null) { this.pendingCommands = new List(); } this.pendingCommands.Add(new CommandInfo { Id = id, Text = text, Action = action, Separator = separatorBeforeCommand }); } else { // The form is created, add the command now if (separatorBeforeCommand) { AppendMenu(this.hSysMenu, MF_SEPARATOR, 0, ""); } AppendMenu(this.hSysMenu, MF_STRING, id, text); } this.actions.Add(action); } #endregion Public methods #region Private methods private void WindowLoaded(object sender, RoutedEventArgs e) { var interop = new WindowInteropHelper(this.window); HwndSource source = PresentationSource.FromVisual(this.window) as HwndSource; source.AddHook(WndProc); this.hSysMenu = GetSystemMenu(interop.EnsureHandle(), false); // Add all queued commands now if (this.pendingCommands != null) { foreach (CommandInfo command in this.pendingCommands) { if (command.Separator) { AppendMenu(this.hSysMenu, MF_SEPARATOR, 0, ""); } AppendMenu(this.hSysMenu, MF_STRING, command.Id, command.Text); } this.pendingCommands = null; } } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WM_SYSCOMMAND) { if ((long)wParam > 0 && (long)wParam <= lastId) { this.actions[(int)wParam - 1](); } } return IntPtr.Zero; } #endregion Private methods #region Classes private class CommandInfo { public int Id { get; set; } public string Text { get; set; } public Action Action { get; set; } public bool Separator { get; set; } } #endregion Classes 

Версия принятого ответа VB.NET:

 Imports System.Windows.Forms Imports System.Runtime.InteropServices Public Class CustomForm Inherits Form ' P/Invoke constants Private Const WM_SYSCOMMAND As Integer = &H112 Private Const MF_STRING As Integer = &H0 Private Const MF_SEPARATOR As Integer = &H800 ' P/Invoke declarations  _ Private Shared Function GetSystemMenu(hWnd As IntPtr, bRevert As Boolean) As IntPtr End Function  _ Private Shared Function AppendMenu(hMenu As IntPtr, uFlags As Integer, uIDNewItem As Integer, lpNewItem As String) As Boolean End Function  _ Private Shared Function InsertMenu(hMenu As IntPtr, uPosition As Integer, uFlags As Integer, uIDNewItem As Integer, lpNewItem As String) As Boolean End Function ' ID for the About item on the system menu Private SYSMENU_ABOUT_ID As Integer = &H1 Public Sub New() End Sub Protected Overrides Sub OnHandleCreated(e As EventArgs) MyBase.OnHandleCreated(e) ' Get a handle to a copy of this form's system (window) menu Dim hSysMenu As IntPtr = GetSystemMenu(Me.Handle, False) ' Add a separator AppendMenu(hSysMenu, MF_SEPARATOR, 0, String.Empty) ' Add the About menu item AppendMenu(hSysMenu, MF_STRING, SYSMENU_ABOUT_ID, "&About…") End Sub Protected Overrides Sub WndProc(ByRef m As Message) MyBase.WndProc(m) ' Test if the About item was selected from the system menu If (m.Msg = WM_SYSCOMMAND) AndAlso (CInt(m.WParam) = SYSMENU_ABOUT_ID) Then MessageBox.Show("Custom About Dialog") End If End Sub End Class 
  • Передача данных между формами
  • Как заставить мою программу C # Winforms запускаться как администратор на любом компьютере?
  • Ribbon UI Control для WinForms
  • Изменение размера windows без полей в нижнем правом углу
  • Выполнить одновременно два windows winform
  • Как разместить текст на ProgressBar?
  • Скрыть одиночную форму при запуске
  • Остановите «Дин» при нажатии Enter
  • Как предотвратить мерцание в ListView при обновлении одного текста ListViewItem?
  • Приложение C # Windows Forms - обновление GUI из другого streamа и classа?
  • Показывать элементы управления, добавленные программно в приложении WinForms в представлении «Дизайн»?
  • Interesting Posts

    Как просыпаться от заставки непосредственно к экрану входа в Ubuntu

    RewriteRule, который сохраняет параметры GET

    Могу ли я предотвратить пробуждение ноутбука Windows при открытии крышки?

    Удаленный рабочий стол с поддержкой нескольких мониторов в XP?

    RequiredIf Атрибут условной проверки

    Объявления переменных в файлах заголовков – статические или нет?

    Когда называется UIViewController viewDidUnload?

    Приоритет сети Ubuntu

    Поиск наложения файловой системы с использованием LD_PRELOAD

    AngularJS: ng-show / ng-hide не работает с `{{}}` интерполяцией

    Что такое комбинация клавиш для сохранения текста только в Outlook?

    Как установить обновления и завершить работу из командной строки?

    WPF: установка ширины (и высоты) в процентах

    Как объединить (объединить) кадры данных (внутренний, внешний, левый, правый)?

    Xcode 6 / Beta 4: использование заголовков мостов с объектами инфраструктуры не поддерживается

    Давайте будем гением компьютера.