关于c#:在第三方应用程序的AppendMenu之后发生点击事件

Hook up click event after AppendMenu of 3rd party Application

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

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

这是一些测试代码,没有防弹..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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/zh-cn/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来实现该钩子。