0

I want to try and run the official SetWinEventHook() example given at https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwineventhook:

// Global variable.
HWINEVENTHOOK g_hook;

// Initializes COM and sets up the event hook.
//
void InitializeMSAA()
{
    CoInitialize(NULL);
    g_hook = SetWinEventHook(
        EVENT_SYSTEM_MENUSTART, EVENT_SYSTEM_MENUEND,  // Range of events (4 to 5).
        NULL,                                          // Handle to DLL.
        HandleWinEvent,                                // The callback.
        0, 0,              // Process and thread IDs of interest (0 = all)
        WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); // Flags.
}

// Unhooks the event and shuts down COM.
//
void ShutdownMSAA()
{
    UnhookWinEvent(g_hook);
    CoUninitialize();
}

// Callback function that handles events.
//
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
                             LONG idObject, LONG idChild,
                             DWORD dwEventThread, DWORD dwmsEventTime)
{
    IAccessible* pAcc = NULL;
    VARIANT varChild;
    HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &varChild);  
    if ((hr == S_OK) && (pAcc != NULL))
    {
        BSTR bstrName;
        pAcc->get_accName(varChild, &bstrName);
        if (event == EVENT_SYSTEM_MENUSTART)
        {
            printf("Begin: ");
        }
        else if (event == EVENT_SYSTEM_MENUEND)
        {
            printf("End:   ");
        }
        printf("%S\n", bstrName);
        SysFreeString(bstrName);
        pAcc->Release();
    }
}

I wanted to compile and run this using Visual Studio, so I created a Windows Console Application Project with content:

#include <windows.h>
#include <iostream>
#include <conio.h>
#include <oleacc.h>

// Global variable.
HWINEVENTHOOK g_hook;

// Initializes COM and sets up the event hook.
//
void HandleWinEvent(HWINEVENTHOOK, DWORD, HWND,
    LONG, LONG,
    DWORD, DWORD);

void InitializeMSAA()
{
    HRESULT hrCoInit = CoInitialize(NULL);
    g_hook = SetWinEventHook(
        EVENT_SYSTEM_MENUSTART, EVENT_SYSTEM_MENUEND,  // Range of events (4 to 5).
        NULL,                                          // Handle to DLL.
        HandleWinEvent,                                // The callback.
        0, 0,              // Process and thread IDs of interest (0 = all)
        WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); // Flags.
}

// Unhooks the event and shuts down COM.
//
void ShutdownMSAA()
{
    UnhookWinEvent(g_hook);
    CoUninitialize();
}

// Callback function that handles events.
//
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
    LONG idObject, LONG idChild,
    DWORD dwEventThread, DWORD dwmsEventTime)
{
    IAccessible* pAcc = NULL;
    VARIANT varChild;
    HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &varChild);
    if ((hr == S_OK) && (pAcc != NULL))
    {
        BSTR bstrName;
        pAcc->get_accName(varChild, &bstrName);
        if (event == EVENT_SYSTEM_MENUSTART)
        {
            printf("Begin: ");
        }
        else if (event == EVENT_SYSTEM_MENUEND)
        {
            printf("End:   ");
        }
        printf("%S\n", bstrName);
        SysFreeString(bstrName);
        pAcc->Release();
    }
}

int main()
{
    std::cout << "Hello World!\n";
    InitializeMSAA();
    MSG msg;
    
    while (1) {
        //if (_getch() == 'q') {
        //    break;
        //}
        GetMessage(&msg, NULL, 0, 0);
        TranslateMessage(&msg);
        DispatchMessage(&msg);
     }
    ShutdownMSAA();
    return 0;
}

This code is running fine, but is not detecting events. I am trying to generate events by opening and closing the Start Menu.

How can I make this example code work?

Alok
  • 7,734
  • 8
  • 55
  • 100
  • 3
    The Start 'Menu' is not a menu in the UIA sense. You'll need to open a genuine [menu](https://learn.microsoft.com/en-us/windows/win32/menurc/menus). – IInspectable Mar 16 '22 at 13:56
  • @IInspectable: I am trying this exmaple in console application which does not have menu. Should I try this example in GUI application? – Alok Mar 16 '22 at 14:19
  • @Alok you can run your code in a console app, and then run a separate GUI app that has a menu. Your console app should receive the menu events. However, your console app is using an out-of-context hook, which requires a message loop, which your code currently lacks – Remy Lebeau Mar 16 '22 at 15:01
  • *The client thread that calls SetWinEventHook must have a message loop in order to receive events.* more concrete you need call `GetMessage` or `PeekMessage` - otherwise you callback can not be called – RbMm Mar 16 '22 at 15:02
  • @RbMm: I have added `GetMessage` in loop in main method(updated question) still I am not seeing events captured. I am trying to open Viual Studio's Menu. – Alok Mar 16 '22 at 19:15
  • 1
    you wrong add this. the `GetMessage` must be called all time. you first wait for key press. – RbMm Mar 16 '22 at 19:21
  • @RbMm: updated loop code still not able to make it work :( – Alok Mar 16 '22 at 19:27
  • in last variant HandleWinEvent must be called when menu start/end – RbMm Mar 16 '22 at 19:35
  • Visual Studio's menu is not a menu either. – Jonathan Potter Mar 16 '22 at 22:35
  • It's been a few days, has your problem been solved? – Junjie Zhu - MSFT Apr 21 '22 at 03:15
  • @Junjie: yes problem has got solved. – Alok Apr 21 '22 at 09:50
  • @Alok, If my answer helped you resolved your issue, please [mark](https://meta.stackexchange.com/a/5235) it as accepted. Thank you. – Junjie Zhu - MSFT Apr 22 '22 at 01:35

1 Answers1

1

According to the explanations for EVENT_SYSTEM_MENUSTART and EVENT_SYSTEM_MENUEND in the official documentation.

The system sends this event for standard menus, which are identified by HMENU, created using menu-template resources or Win32 menu API elements.

As @Remy Lebeau said, 'run a separate GUI app that has a menu'.

After your console program starts, you can run a Win32 desktop application with menu.

I modified your code to run in VS2019. Added CALLBACK in front of HandleWinEvent.

#pragma comment(lib,"Oleacc.lib")
// Global variable.
HWINEVENTHOOK g_hook;

// Initializes COM and sets up the event hook.
//
void CALLBACK HandleWinEvent(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD, DWORD);

Here are my test results,

enter image description here

Junjie Zhu - MSFT
  • 2,086
  • 1
  • 2
  • 6