how to capture system-menu event in console application in windows?

1.7k views Asked by At

It's easy to get system menu on console application (GetSystemMenu) and add some own entries (AppendMenu). But then these menu items are useless for the app. Is there any way to get into message stream that would identify what menu item was clicked ?

I've tried to hook to console window but without any result, I mean the WH_SYSMSGFILTER, all is compiling ok but there are no messages shown the hook function is not run by the system.

Next thing was ReadConsoleInput and this works partially, that is it shows mouse events on the system menu, but there is no information in MENU_EVENT_RECORD structure about what menu item was clicked.

These are my attempts all in one snippet, here the console should be flooded with messages, but only those from ReadConsoleInput appear, but these doesn't contain any useful information. No matter if user clicks on first or second added menu item there are only two codes shown 278 (0x116) WM_INITMENU and 287 (0x11F) WM_MENUSELECT, but there is no way I know to get to the wParam of WM_MENUSELECT message.

#include <windows.h>
#include <stdio.h>

HHOOK sysMsgFilterHook;
LRESULT CALLBACK SysMsgFilterCallback(int nCode, WPARAM wParam, LPARAM lParam) {
  printf("%i\n", nCode);
  return CallNextHookEx(NULL, nCode, wParam, lParam);
}

static LRESULT CALLBACK consoleWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  printf("%u\n", uMsg);
  WNDPROC origProc = (WNDPROC) GetProp(hWnd, "origProc");
  return CallWindowProc(origProc, hWnd, uMsg, wParam, lParam );
}


int main() {
  SetLastError(0);
  HWND console_hwnd = GetConsoleWindow();
  HMENU console_hMenu = GetSystemMenu(console_hwnd, FALSE);
  HINSTANCE console_hinstance = (HINSTANCE)GetWindowLong(console_hwnd, GWL_HINSTANCE);
  DWORD console_processid = GetWindowThreadProcessId(console_hwnd, NULL);
  HANDLE console_input_handle = GetStdHandle(STD_INPUT_HANDLE);

  AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "test menu item");
  AppendMenu(console_hMenu, MF_STRING | MF_CHECKED, NULL, "yet another menu item");

  WNDPROC origProc = (WNDPROC)SetWindowLongPtr(console_hwnd, GWL_WNDPROC, (LONG_PTR)&consoleWndProc);
  SetProp(console_hwnd, "origProc", (HANDLE)origProc);

  sysMsgFilterHook = SetWindowsHookEx(
    WH_SYSMSGFILTER,
    (HOOKPROC)SysMsgFilterCallback,
    console_hinstance,
    console_processid
  );

  DWORD numEvents = 0;
  INPUT_RECORD input;

  while(ReadConsoleInput(console_input_handle, &input, 1, &numEvents)) {
    //printf("input.EventType: %i\n", input.EventType);
    if (input.EventType == MENU_EVENT) {
      printf("input.Event.MenuEvent.dwCommandId %i\n", input.Event.MenuEvent.dwCommandId);
    }
  }
  //printf("GetLastError: %lu\n", GetLastError());
  UnhookWindowsHookEx(sysMsgFilterHook);
  system("pause");
  return 0;
}

I've succeeded with creating hook for mouse events, that is WH_MOUSE_LL. But all other hooks do not work.

What I intend to accomplish is to get some sort of WM_MENUCOMMAND message and then get rest with GetMenuItemInfo.

I've heard that the hooking procedure should be in another dll, but how to do that ? are there any working snippets ?

0

There are 0 answers