反码默认窗口/系统菜单

问题描述 投票:0回答:2

我想在所有Windows的系统菜单(右键单击标题Bar或单击图标时打开的菜单)中添加“始终在顶部”菜单。

有一些这样做的应用程序,但是我找不到有用的源代码或免费应用程序,而不仅仅是它们自己的所有窗口。

还有其他实现此功能的方法(Autohotkeys或属于系统托盘中的小程序,让您选择应该保持在顶部的窗口),但是我正在寻找一种更加流利和直观的方式。

思想上,我会在标题栏中添加一个小别针按钮,但我认为这更多的是涉及,所以我现在坚持菜单变体。

使用

AddMenuItems()
windows winforms winapi
2个回答
1
投票
ApplicationExit

活动中,可能的工作可能会召唤

GetMenu(hMainWindowHandle, true)
,其中true表示还原菜单。
public static class AlwaysOnTop {

    static AlwaysOnTop() {
        Application.ApplicationExit += delegate {
            try {
                foreach (DictionaryEntry de in htThreads) {
                    Hook h = (Hook) de.Value;
                    RemoveMenu(h.hMenu, h.uniqueId, 0);
                    //DeleteMenu(h.hMenu, h.uniqueId, 0);
                    UnhookWinEvent(h.hWinEventHook);
                }
            } catch {
            }
        };
    }

    private const int EVENT_OBJECT_INVOKED = 0x8013;
    private const int OBJID_SYSMENU = -1;
    private const int WINEVENT_OUTOFCONTEXT = 0;
    private const int MF_STRING = 0x00000000;
    private const int HWND_TOPMOST = -1;
    private const int HWND_NOTOPMOST = -2;
    private const int SWP_NOMOVE = 0x0002;
    private const int SWP_NOSIZE = 0x0001;
    private const uint MF_UNCHECKED = 0x00000000;
    private const uint MF_CHECKED = 0x00000008;

    [DllImport("user32.dll")]
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    private static extern bool AppendMenu(IntPtr hMenu, uint uFlags, uint uIDNewItem, String lpNewItem);

    [DllImport("user32.dll", SetLastError = true)]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("user32.dll",SetLastError=true)]
    private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventProc lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern int UnhookWinEvent(IntPtr hWinEventHook);

    [DllImport("user32.dll", SetLastError=true)]
    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

    [DllImport("user32.dll")]
    private static extern bool CheckMenuItem(IntPtr hMenu, uint uIDCheckItem, uint uCheck);

    [DllImport("user32.dll")]
    private static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);

    //[DllImport("user32.dll")]
    //private static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);

    private static Hashtable htThreads = new Hashtable();
    private static WinEventProc CallWinEventProc = new WinEventProc(EventCallback);
    private delegate void WinEventProc(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime);
    private static void EventCallback(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) {
        //callback function, called when message is intercepted
        if (iEvent == EVENT_OBJECT_INVOKED) {
            if (idObject == OBJID_SYSMENU) {
                Hook h = (Hook) htThreads[(uint) dwEventThread];
                if (h != null && h.uniqueId == idChild) {
                    bool b = !h.Checked;
                    if (b)
                        SetWindowPos(h.hMainWindowHandle, (IntPtr) HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                    else
                        SetWindowPos(h.hMainWindowHandle, (IntPtr) HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

                    CheckMenuItem(h.hMenu, h.uniqueId, (b ? MF_CHECKED : MF_UNCHECKED));
                    h.Checked = b;
                }
            }
        }
    }

    private class Hook {
        public uint uniqueId = 1001;
        public IntPtr hWinEventHook;
        public IntPtr hMenu;
        public IntPtr hMainWindowHandle;
        public bool Checked;
    }

    public static void AddMenuItems() {
        Process[] arr = Process.GetProcesses();
        foreach (Process p in arr) {
            if (p.MainWindowHandle == IntPtr.Zero)
                continue;

            if (p.ProcessName != "mspaint") // <-- remove or change this line
                continue;

            IntPtr hMenu = GetSystemMenu(p.MainWindowHandle, false);
            if (hMenu == IntPtr.Zero)
                continue;

            bool b = AppendMenu(hMenu, MF_STRING, 1001, "Always On Top");
            uint pid = 0;
            uint tid = GetWindowThreadProcessId(p.MainWindowHandle, out pid);

            Hook h = (Hook) htThreads[tid];
            if (h == null) {
                h = new Hook();
                h.hMenu = hMenu;
                h.hWinEventHook = SetWinEventHook(EVENT_OBJECT_INVOKED, EVENT_OBJECT_INVOKED, IntPtr.Zero, CallWinEventProc, pid, tid, WINEVENT_OUTOFCONTEXT);
                h.hMainWindowHandle = p.MainWindowHandle;
                htThreads[tid] = h;
            }
        }
    }
}

这里是使用

ToolStripDropDown
而不是默认窗口菜单的示例。可以通过设置背景颜色,字体并在需要时添加一些图标来使其看起来更像默认的窗口菜单。

隐藏默认窗口菜单的难以置信的是,它更加困难。也许有更好的方法。隐藏菜单的失败尝试留在下面的代码中。右键单击字幕栏时仍显示默认菜单。

public class FormCustomMenu : Form { WindowMenu WindowMenu = new WindowMenu(); public FormCustomMenu() { //this.ShowIcon = false; } private const int WM_INITMENU = 0x116; private const int WM_INITMENUPOPUP = 0x117; private const int WM_SYSCOMMAND = 0x112; protected override void WndProc(ref Message m) { if (m.Msg == WM_SYSCOMMAND) { //WM_INITMENU || m.Msg == WM_INITMENUPOPUP) {} Point pt = Cursor.Position; int h = SystemInformation.CaptionHeight; Rectangle r = new Rectangle(this.Location, new Size(h, h)); if (!r.Contains(pt) || Cursor.Current != Cursors.Default) base.WndProc(ref m); else { Rectangle r2 = RectangleToScreen(this.ClientRectangle); WindowMenu.Show(r2.Location); } } else { base.WndProc(ref m); } } /* Failed attempts at hiding the default window menu. protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); //IntPtr hMenu = GetSystemMenu(Handle, false); //SendMessage(hMenu, WM_SETREDRAW, (IntPtr) 0, (IntPtr) 0); //int count = GetMenuItemCount(hMenu); //for (int i = count - 1; i >= 3; i--) // RemoveMenu(hMenu, (uint) i, MF_BYPOSITION); } [DllImport("user32.dll")] public static extern int GetMenuItemCount(IntPtr hMenu); [DllImport("user32.dll")] private static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); //[DllImport("user32.dll")] //public static extern IntPtr DestroyMenu(IntPtr hMenu); [DllImport("user32.dll")] public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32.dll")] private static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags); private const int MF_BYPOSITION = 0x00000400; private const int WM_SETREDRAW = 11; [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, IntPtr wParam, IntPtr lParam); // this also removes the min/max/close buttons: //private const int WS_SYSMENU = 0x80000; //protected override CreateParams CreateParams { // get { // var p = base.CreateParams; // p.Style = p.Style & ~WS_SYSMENU; // return p; // } //} */ } public class WindowMenu : ToolStripDropDown { public WindowMenu() { Items.Add(new ToolStripMenuItem("Custom1")); } }

0
投票

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.