Search code examples
winapihwndsetwindowshookex

Get HMENU from HWND within a Hook


I'm installing a hook within my application to get the standard EDIT context menu (with undo/copy/edit/paste/etc.). I need to insert a new menu item for my application.

I've set a windows hook, but I can't seem to get the HMENU for the context menu. This is where I set the hook:

g_hHook = SetWindowsHookEx(WH_CALLWNDPROC, HookCallWndProc, NULL, GetCurrentThreadId());

Here is my callback function:

LRESULT CALLBACK HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        LPCWPSTRUCT cwps = (LPCWPSTRUCT)lParam;
        switch(cwps->message)
        {
            case WM_CREATE:
            {
                WCHAR szClass[128];
                GetClassName(cwps->hwnd, szClass, 127);

                if (wcscmp(szClass, L"#32768") == 0)
                {
                    LPCREATESTRUCT lpcs = (LPCREATESTRUCT)cwps->lParam;
                    HMENU hMenu = GetMenu(cwps->hwnd);
                    // hMenu is 0x0

                    //MENUINFO info;

                    //ZeroMemory(&info, sizeof(MENUINFO));
                    //info.cbSize = sizeof(info);
                    //GetMenuInfo(hMenu, &info);

                    MessageBox(NULL, L"Test", L"Test", NULL);
                }
                break;
            }
        }
    }

    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

I also tried setting the hook with WH_CALLWNDPROCRET, but this one doesn't even capture the WM_CREATE message for the menu.

Does anyone know how to obtain the HMENU for this particular situation?

Thanks, Kevin


Solution

  • You can send the MN_GETHMENU message to get the HMENU:

    case WM_CREATE:
    {
         WCHAR szClass[128];
        GetClassName(cwps->hwnd, szClass, 127);
        if (wcscmp(szClass, L"#32768") == 0)
        {
            // Must delay MN_GETHMENU...
            PostMessage(g_hDlg,WM_APP,(WPARAM)cwps->hwnd,(LPARAM)HookCallWndProc);
        }
        break;
    }
    
    ...
    
    LRESULT CALLBACK MyWindow(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
    {
        switch(msg)
        {
        case WM_APP:
            if (lp == (LPARAM)HookCallWndProc) // Just making sure it is our special message 
            {
                HMENU hMenu = (HMENU) SendMessage((HWND)wp,MN_GETHMENU,0,0);
                if (hMenu)
                {
                    AppendMenu(hMenu,MF_STRING,666,L"Hello SO");
                }
            }
            break;
    

    This is a bit hacky but hacks are pretty much unavoidable when customizing controls like this...