Windows 7 - пункт меню пользовательского окна: хук GetMsgProc не вызывается - PullRequest
1 голос
/ 23 сентября 2011

Вернусь прямо к сути: пользовательский элемент меню, который я добавил в системное меню каждого окна через глобальные перехватчики Windows, не приводит к вызову GetMsgProc, когда пользователь щелкает по нему.

Вот как я добавляю пункты меню:

void HookCore::AppendTasksMenu(HWND windowHandle)
{
    // make the popup menu and set up the appearance flags for the sub-items
    m_mnuMoveToTasks = CreatePopupMenu();
    UINT tasksAppearanceFlags = MF_STRING | MF_ENABLED;

    //TODO: need to make proper iterator for MenuItemList
    list<MenuItemInfo*>::iterator iter;
    for (iter = m_menuItems->Begin(); iter != m_menuItems->End(); iter++)
    {
        // check if we are adding a separator
        if ((*iter)->GetSpecial() == MenuItemInfo::SEPARATOR)
        {
            AppendMenu(m_mnuMoveToTasks, MF_SEPARATOR, (*iter)->GetItemId(), NULL);
        }
        else
        {
            AppendMenu(m_mnuMoveToTasks,
                ((*iter)->IsChecked() ? tasksAppearanceFlags | MF_CHECKED : tasksAppearanceFlags),
                (*iter)->GetItemId(), (*iter)->GetItemName().c_str());
        }
    }

    // get the system menu and set up the appearance flag for our new system sub-menu
    HMENU mnuSystem = GetSystemMenu(windowHandle, FALSE);
    UINT itemAppearanceFlags =  MF_STRING | MF_ENABLED | MF_POPUP;

    AppendMenu(mnuSystem, MF_SEPARATOR, ID_MOVE_TO_TASK_SEP, NULL);
    // append the sub-menu we just created
    AppendMenu(mnuSystem, itemAppearanceFlags, (UINT_PTR)m_mnuMoveToTasks, MOVE_TO_TASK);
}

Это создает новое подменю в системном меню, и подменю содержит мои дополнительные пункты.Идентификаторы элементов начинаются с 1001 и увеличиваются на 1 для каждого нового элемента.Элементы могут быть отмечены или не отмечены.

Когда пользователь щелкает один из моих элементов, я ожидаю получить сообщение WM_SYSCOMMAND через GetMsgProc, но оно никогда не вызывается.Однако GetMsgProc вызывается несколько раз во время инициализации с другими сообщениями.Я вижу сообщение WM_SYSCOMMAND в CallWndProcRetProc, но оно не содержит правильный идентификатор элемента.Я ожидал получить идентификатор элемента из младшего слова wParam (как указано здесь: [http://www.codeproject.com/KB/dialog/AOTop.aspx]),, но вместо этого он просто содержит SC_MOUSEMENU.

Вот как я назначаю хук GetMsgProc:

myhookdata[GET_MSG_HOOK].nType = WH_GETMESSAGE;
myhookdata[GET_MSG_HOOK].hkprc = GetMsgProc;
myhookdata[GET_MSG_HOOK].hhook = SetWindowsHookEx(
    myhookdata[GET_MSG_HOOK].nType,
    myhookdata[GET_MSG_HOOK].hkprc,
    AppHandle, 0);

Есть идеи? Неправильные ли идентификаторы моего предмета? Как правильно идентифицировать выбранный предмет?

Спасибо!

Обновление:

Исходя из предложенных ниже советов, я попытался перехватить сообщения WM_SYSCOMMAND и WM_COMMAND в CallWndProc, CallWndProcRetProc, GetMsgProc и SysMsgProc. Сообщение выбора элемента не доставлено.

Я также попытался создать подкласс для окна, к которому принадлежит меню, и мой WndProc так и не получил сообщение о выборе элемента, хотя были доставлены другие сообщения, такие как «WM_MENUSELECT» и «WM_UNINITMENUPOPUP».

Любые указатели, где ещепроверить?

Обновление 2:

Так что, когда я делаю подкласс / отменяю класс окна, я делаю это в своем хуке CallWndProc. Я делаю подкласс, когда получаю WM_INITMENUPOPUP сообщение, и я отменяю класскогда я получаю сообщение WM_MENUSELECT для закрытия меню (когда lParam равно NULL и HIWORD(wParam) равно 0xFFFF).

Я нажимаю на системное меню (в этот момент WM_INITPOPUPMENUподнимается), переместите курсор мыши в мое подменю, которое содержит пользовательские элементы, а затем нажмите на один из элементов.Я регистрирую каждое сообщение, которое я получаю в моем новом WndProc во время этого процесса.Вот список сообщений, которые я получаю в своем WndProc во время этого теста:

WM_INITMENUPOPUP
147 (0x0093) - what is this message?
148 (0x0094) [9 times] - what is this message?
WM_NCMOUSELEAVE
WM_ENTERIDLE [2 times]
WM_NOTIFY [2 times]
WM_ENTERIDLE [2 times]
WM_NOTIFY
WM_ENTERIDLE [11 times]
WM_MENUSELECT
WM_ENTERIDLE [5 times]
WM_MENUSELECT
WM_ENTERIDLE [6 times]
WM_MENUSELECT
WM_ENTERIDLE [7 times]
WM_MENUSELECT
WM_ENTERIDLE [8 times]
WM_NOTIFY
WM_ENTERIDLE [5 times]
WM_NOTIFY
WM_ENTERIDLE
WM_NOTIFY
WM_ENTERIDLE
WM_UNINITMENUPOPUP
WM_CAPTURECHANGED

Сообщение, которое я ожидаю увидеть, когда пользователь щелкает элемент, - WM_COMMAND или WM_SYSCOMMAND.У меня нет большого опыта работы с сообщениями Windows или работы с Windows API.Правильно ли искать одно из этих двух сообщений?Там нет ни одного сообщения, но оно должно быть, верно?Я что-то упускаю?

1 Ответ

0 голосов
/ 29 сентября 2011

Хорошо, я понял это.Я не уверен почему, но я не вижу правильное сообщение ни в одном из хуков.Однако, я вижу это в WndProc, если делаю окно на подклассы.Во втором обновлении выше я сказал, что не вижу правильного сообщения при создании подклассов - я слишком рано отменил классификацию.

Итак, вот как я делаю подкласс:

if (oldWndProc == -1)
{
    oldWndProc = SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
    currentSubclassedHandle = hwnd;
}

И вотВот как я отменяю подкласс:

if (oldWndProc != -1)
{
    SetWindowLongPtr(currentSubclassedHandle, GWL_WNDPROC, (LONG)oldWndProc);
    oldWndProc = -1;
    currentSubclassedHandle = NULL;
}

Я получаю сообщение WM_SYSCOMMAND, где wParam - это идентификатор элемента пользовательского меню.Это сообщение доставляется в NewWndProc через некоторое время после последнего сообщения, которое я отправил во 2-м обновлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...