Instantly share code, notes, and snippets.
Created
August 23, 2016 02:45
-
Save u338steven/d9a129b20caeaa162c1b892d26a38188 to your computer and use it in GitHub Desktop.
Monitoring context menu opened (SetWinEventHook)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Runtime.InteropServices; | |
using System.Drawing; | |
using System.Windows.Forms; | |
class ContextMenuObserverWin32 : Form | |
{ | |
[STAThread] | |
public static void Main() | |
{ | |
Application.Run(new ContextMenuObserverWin32()); | |
} | |
[DllImport("user32.dll")] | |
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, | |
WinEventDelegate lpfnWinEventProc, uint idProcess, | |
uint idThread, uint dwFlags); | |
[DllImport("user32.dll")] | |
static extern bool UnhookWinEvent(IntPtr hWinEventHook); | |
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, | |
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); | |
public const uint WINEVENT_OUTOFCONTEXT = 0x0000; | |
public const uint WINEVENT_SKIPOWNTHREAD = 0x0001; | |
public const uint WINEVENT_SKIPOWNPROCESS = 0x0002; | |
public const uint WINEVENT_INCONTEXT = 0x0004; | |
public const uint EVENT_SYSTEM_MENUPOPUPSTART = 0x0006; | |
private Label _result; | |
private IntPtr _hook = IntPtr.Zero; | |
ContextMenuObserverWin32() | |
{ | |
_result = new Label(); | |
_result.AutoSize = true; | |
_result.Location = new Point(10, 10); | |
Controls.AddRange(new Control[] { _result }); | |
this.TopMost = true; | |
this.AutoSize = true; | |
this.MinimizeBox = false; | |
this.MaximizeBox = false; | |
this.Text = "ContextMenu Observer Win32"; | |
_hook = SetWinEventHook(EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART, IntPtr.Zero, | |
WindowEventCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); | |
} | |
protected override void OnClosed(EventArgs e) | |
{ | |
if (_hook != IntPtr.Zero) | |
{ | |
UnhookWinEvent(_hook); | |
_hook = IntPtr.Zero; | |
} | |
base.OnClosed(e); | |
} | |
private void WindowEventCallback(IntPtr hWinEventHook, uint eventType, | |
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) | |
{ | |
_result.Text = Win32Menu.GetMenuTexts(hwnd); | |
if (string.IsNullOrEmpty(_result.Text)) | |
{ | |
_result.Text = "コールバックされたけど、メニュー取得できなかったよ"; | |
} | |
} | |
} | |
class Win32Menu | |
{ | |
#region Win32Interop | |
const int MFS_DISABLED = 0x00000003; | |
const int MIIM_STATE = 0x00000001; | |
const int MIIM_ID = 0x00000002; | |
const int MIIM_SUBMENU = 0x00000004; | |
const int MIIM_STRING = 0x00000040; | |
const int MN_GETHMENU = 0x01E1; | |
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); | |
[DllImport("user32.dll")] | |
static extern int GetMenuItemCount(IntPtr hMenu); | |
[DllImport("user32.dll", CharSet = CharSet.Unicode)] | |
static extern bool GetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, [In, Out] MENUITEMINFO lpmii); | |
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] | |
public class MENUITEMINFO | |
{ | |
public int cbSize = Marshal.SizeOf(typeof(MENUITEMINFO)); | |
public int fMask; | |
public int fType; | |
public int fState; | |
public int wID; | |
public IntPtr hSubMenu; | |
public IntPtr hbmpChecked; | |
public IntPtr hbmpUnchecked; | |
public IntPtr dwItemData; | |
public IntPtr dwTypeData; | |
public int cch; | |
} | |
#endregion | |
public static string GetMenuTexts(IntPtr hwnd) | |
{ | |
var results = ""; | |
var hMenu = SendMessage(hwnd, MN_GETHMENU, IntPtr.Zero, IntPtr.Zero); | |
if (hMenu == IntPtr.Zero) | |
{ | |
return results; | |
} | |
var count = GetMenuItemCount(hMenu); | |
var itemInfo = new MENUITEMINFO(); | |
itemInfo.fMask = MIIM_STRING | MIIM_STATE | MIIM_SUBMENU | MIIM_ID; | |
for (var i = 0; i < count; ++i) | |
{ | |
var itemName = GetMenuItemName(hMenu, i, ref itemInfo); | |
if (string.IsNullOrEmpty(itemName)) | |
{ | |
continue; | |
} | |
results += itemName + "\n\n"; | |
} | |
return results; | |
} | |
private static string GetMenuItemName(IntPtr hMenu, int index, ref MENUITEMINFO itemInfo) | |
{ | |
itemInfo.dwTypeData = IntPtr.Zero; | |
GetMenuItemInfo(hMenu, index, true, itemInfo); | |
++itemInfo.cch; | |
itemInfo.dwTypeData = Marshal.AllocHGlobal(itemInfo.cch * sizeof(char)); | |
GetMenuItemInfo(hMenu, index, true, itemInfo); | |
var itemName = Marshal.PtrToStringUni(itemInfo.dwTypeData); | |
Marshal.FreeHGlobal(itemInfo.dwTypeData); | |
return itemName; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment