在 3rd 方应用程序的 AppendMenu 之后挂接点击事件

Hook up click event after AppendMenu of 3rd party Application

我正在尝试使用从 user32.dll 使用 DLLImort 导入的 DLL 函数添加一个新的 MenuItem 到我的 WPF 应用程序之外的第三方应用程序。

不,我想获取新生成的 MenuItem 的点击事件。有任何想法吗? 到目前为止,这是代码。我知道有 SetWindowHookEx 或其他功能,但我被卡住了。

这是一些测试代码,不是防弹的..

public partial class MainWindow : Window
{

    [DllImport("user32.dll")]
    private static extern IntPtr GetMenu(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern IntPtr GetSubMenu(IntPtr hMenu, int nPos);

    [DllImport("user32.dll")]
    private static extern int GetMenuItemCount(IntPtr hMenu);

    [DllImport("user32.dll")]
    private static extern bool InsertMenuItem(IntPtr hMenu, uint uItem, bool
    fByPosition, [In] ref MENUITEMINFO lpmii);

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

    internal const UInt32 MIIM_FTYPE = 0x00000100;
    internal const UInt32 MF_STRING = 0x00000000;
    internal const UInt32 MF_OWNERDRAW = 0x00000100;

    const uint MF_POPUP = 0x00000010;

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern bool AppendMenu(IntPtr hMenu, MenuFlags uFlags, uint uIDNewItem, string lpNewItem);


    [DllImport("user32.dll")]
    static extern IntPtr CreatePopupMenu();

    [Flags]
    public enum MenuFlags : uint
    {
        MF_STRING = 0,
        MF_BYPOSITION = 0x400,
        MF_SEPARATOR = 0x800,
        MF_REMOVE = 0x1000,
        MF_POPUP = 0x00000010,
    }



    [StructLayout(LayoutKind.Sequential)]
    struct MENUITEMINFO
    {
        public uint cbSize;
        public uint fMask;
        public uint fType;
        public uint fState;
        public uint wID;
        public IntPtr hSubMenu;
        public IntPtr hbmpChecked;
        public IntPtr hbmpUnchecked;
        public IntPtr dwItemData;
        public string dwTypeData;
        public uint cch;
        public IntPtr hbmpItem;

        // return the size of the structure
        public static uint sizeOf
        {
            get { return (uint)Marshal.SizeOf(typeof(MENUITEMINFO)); }
        }
    }



    public MainWindow()
    {
        InitializeComponent();


        Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        createMenuEntry();
    }

    private void createMenuEntry()
    {
        Process[] proceses = Process.GetProcessesByName("spotify");
        Process process = proceses.Where(e => e.MainWindowTitle == "Spotify").First();
        IntPtr handle = process.MainWindowHandle;
        IntPtr mainMenu = GetMenu(handle);

        int mainMenuItemCount = GetMenuItemCount(mainMenu);

        AppendMenu(mainMenu, MenuFlags.MF_STRING, 555, "TestEntry");
    }



    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        //HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
        //source.AddHook(WndProc);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        // Handle messages...

        Debug.WriteLine((int)wParam);

        if (((int)wParam == 555))
        {
            MessageBox.Show("Click");
        }

        return IntPtr.Zero;
    }

}

感谢您提前提出任何想法或建议。

您的第一步是放下 C# 并了解本机菜单 API 的工作原理。从这里开始:https://msdn.microsoft.com/en-us/library/windows/desktop/ms647553.aspx

我强烈建议您创建一个新的 C++ 项目并编写一个简单的程序来添加菜单和响应点击。

关键信息可以在我链接的文档中找到,我强调:

When the user chooses a command item, the system sends a command message to the window that owns the menu. If the command item is on the window menu, the system sends the WM_SYSCOMMAND message. Otherwise, it sends the WM_COMMAND message.

您需要拦截该消息。我怀疑这意味着需要使用全局 WH_CALLWNDPROC 挂钩。这将需要一个非托管 DLL 来实现挂钩。