i'm trying to add a new MenuItem using DLL Fucntions imported of the user32.dll using DLLImort to a third party application out of my WPF app.
No I'd like to get the click event of the newly generated MenuItem. Any ideas? Here's the code so far. I know there are functions of SetWindowHookEx or something else, but I'm stuck.
It's some test code and not bulletproofed..
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;
}
}
Thanks for any ideas or suggestions in advance.
Your first step is to put down the C# and understand how the native menu API works. Start here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms647553.aspx
I strongly recommend that you create a new C++ project and write a simple program to add a menu and respond to clicks.
The key information is found in the documentation I linked to, with my emphasis:
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.
You need to intercept that message. I suspect that means to need to use a global WH_CALLWNDPROC
hook. That's going to need an unmanaged DLL to implement the hook.
User contributions licensed under CC BY-SA 3.0