Skip to content

Instantly share code, notes, and snippets.

@u338steven
Created August 23, 2016 02:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save u338steven/d9a129b20caeaa162c1b892d26a38188 to your computer and use it in GitHub Desktop.
Save u338steven/d9a129b20caeaa162c1b892d26a38188 to your computer and use it in GitHub Desktop.
Monitoring context menu opened (SetWinEventHook)
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