1

I have developed a WinForms application in C# that can make any window "top most" by selecting it from drop down list and toggle a checkbox.

But having an app open for that seems a bit silly, so I was wondering if it is possible to add an entry to the top left icon in Windows that runs a program of my choice?

I don't have any experimental code because I don't know what that icon/spot is called, therefor I can't research it.

rekire
  • 47,260
  • 30
  • 167
  • 264
f2lollpll
  • 997
  • 6
  • 15

2 Answers2

3

I found this code that appears to do what you want:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WinFormsSystemMenuTest
{
    public partial class Form1 : Form
    {
        #region Win32 API Stuff

        // Define the Win32 API methods we are going to use
        [DllImport("user32.dll")]
        private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("user32.dll")]
        private static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, Int32 wFlags, Int32 wIDNewItem, string lpNewItem);

        /// Define our Constants we will use
        public const Int32 WM_SYSCOMMAND = 0x112;
        public const Int32 MF_SEPARATOR = 0x800;
        public const Int32 MF_BYPOSITION = 0x400;
        public const Int32 MF_STRING = 0x0;

        #endregion

        // The constants we'll use to identify our custom system menu items
        public const Int32 _SettingsSysMenuID = 1000;
        public const Int32 _AboutSysMenuID = 1001;

        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            /// Get the Handle for the Forms System Menu
            IntPtr systemMenuHandle = GetSystemMenu(this.Handle, false);

            /// Create our new System Menu items just before the Close menu item
            InsertMenu(systemMenuHandle, 5, MF_BYPOSITION | MF_SEPARATOR, 0, string.Empty); // <-- Add a menu seperator
            InsertMenu(systemMenuHandle, 6, MF_BYPOSITION, _SettingsSysMenuID, "Settings...");
            InsertMenu(systemMenuHandle, 7, MF_BYPOSITION, _AboutSysMenuID, "About...");

            base.OnHandleCreated(e);
        }

        protected override void WndProc(ref Message m)
        {
            // Check if a System Command has been executed
            if (m.Msg == WM_SYSCOMMAND)
            {
                // Execute the appropriate code for the System Menu item that was clicked
                switch (m.WParam.ToInt32())
                {
                    case _SettingsSysMenuID:
                        MessageBox.Show("\"Settings\" was clicked");
                        break;
                    case _AboutSysMenuID:
                        MessageBox.Show("\"About\" was clicked");
                        break;
                }
            }

            base.WndProc(ref m);
        }
    }
}

I found it here. This seems to be what you want, yes?

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
Camron B
  • 1,650
  • 2
  • 14
  • 30
  • 1
    The code in the Load event handler belongs in an override for OnHandleCreated(). – Hans Passant Jan 04 '12 at 17:51
  • Wow, that looks easier than expected! going to try it out in half an hour or so. From the link it appears to be exactly what I want :) – f2lollpll Jan 04 '12 at 17:53
  • 5
    Add this line to the Load event handler to see why: `ShowInTaskbar = false;` There are many properties that cause the native window to be re-created. Your system menu customization will be lost when that happens. – Hans Passant Jan 04 '12 at 17:56
  • @HansPassant Thanks! I have modified the code. – Camron B Jan 04 '12 at 18:10
1

This area of a winform is called the "Non client area".

But I think the simplest solution, if your goal is to add your switch to all external winforms, is to create process that will place a little form with your on/off switch at the top left of the active window form. You can try to put it directly on the external form, but you will have problems with position priorities.

Since you included "WinApi" in your question, I guess you are able to get the window handle, coordinates and topmost property of the current running processes.

Léon Pelletier
  • 2,701
  • 2
  • 40
  • 67