Проблема с WH_CALLWNDPROCRET

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

hhk = SetWindowsHookEx(WH_CALLWNDPROCRET, HookProcSetTextRet, hinst, threadID);

(Переменная hhk находится в общих данных.)
Однако я не понимаю некоторых действий, в частности:

LRESULT CALLBACK HookProcSetTextRet(int code,WPARAM wParam,LPARAM lParam) {  
PCWPRETSTRUCT st = (PCWPRETSTRUCT)lParam;
switch (HIWORD(st->wParam)) {
    case WM_COMMAND: {
        /*
        For lbn_xxx:
        wParam
        The low-order word is the list box identifier. 
        The high-order word is the notification message.

        lParam
        Handle to the list box. 
        */
            switch (HIWORD(st->wParam)) {
                case LBN_DBLCLK: {
                        log << L"\tWM_COMMAND ---  LBN_DBLCLK" << endl;
                    }
                    break;

                case LBN_SELCHANGE: {
                        log <<  L"\t+++ WM_COMMAND -LBN_SELCHANGE" << endl;
                        log << L"\t\tHandle to list box : " << st->lParam << endl;

                        HWND lbHwnd = (HWND) st->lParam;

                        res = SendMessage(lbHwnd, LB_GETCOUNT, 0, 0);
                        curSel = SendMessage(lbHwnd, LB_GETCURSEL, 0, 0);
                        log << L"\t\t\tLB_GETCURSEL returned : " << curSel << endl;
                        if (LB_ERR != curSel) {
                            res = SendMessage(lbHwnd, LB_GETTEXT, curSel,  
                                     (LPARAM)(LPTSTR) szBuf);
                                log << L"\t\tLB_GETTEXT returned : " << res <<                  
                                       L"\t\tszBuf: " << szBuf << endl;
                        }
                    }
                    break;

                default:
                    break;
            }
        }  // WM_COMMAND
    /* snip */
}
return CallNextHookEx(0, code, wParam, lParam); 
}

LBN_SELCHANGE перехватывается, но значение, возвращаемое LB_GETCURSEL и LB_GETTEXT, всегда одно и то же.
LBN_DBLCLK никогда не перехватывается.

Подобное несоответствие наблюдается и с другими сообщениями WM_. Само приложение как-то ест эти сообщения?
Спасибо за любые идеи...

ОБНОВЛЕНИЕ:
Следуя предложению, сделанному ниже, я реализовал хук WH_GETMESSAGE. Похоже, он получает сообщение о двойном щелчке из списка.
К сожалению, LB_GETCOUNT возвращает правильное число, но LB_GETCURSEL всегда возвращает 0, а LB_GETTEXT по-прежнему ничего не возвращает...

    case WM_LBUTTONDBLCLK: {
        const unsigned int BUFFER_SIZE = 1024;
        wchar_t titleBuffer[BUFFER_SIZE];
        UINT curSel = LB_ERR;
        LRESULT res = LB_ERR;

        MSG * pMsg = (MSG *) lParam;
        HWND lbHwnd = pMsg->hwnd;

        log << L"\tGetMsgProc\t\tWM_LBUTTONDBLCLK" << endl;

        // Sanity check
        HWND parent = GetParent(lbHwnd);
        GetWindowText(parent, titleBuffer, BUFFER_SIZE - 1);
        log << L"\t\tParent Title : " << titleBuffer << L"\tParent HWND : " << parent << endl;

        // Sanity check
        GetClassName(lbHwnd, titleBuffer, BUFFER_SIZE - 1);
        log << L"\t\tList box class name: " << titleBuffer << L"\tList box hwnd: " << pMsg->hwnd << endl;

        res = SendMessage(lbHwnd, LB_GETCOUNT, 0, 0);
        if (LB_ERR != res) { log << L"\t\t\tLB_GETCOUNT : " << res << endl; }

        curSel = SendMessage(lbHwnd, LB_GETCURSEL, 0, 0);
        log << L"\t\t\tLB_GETCURSEL returned : " << curSel << endl;
        if (LB_ERR != curSel) {
            res = SendMessage(lbHwnd, LB_GETTEXT, curSel, (LPARAM)(LPTSTR) titleBuffer);
            if (LB_ERR == res ) { log << L"\t\t\tLB_GETTEXT Error -- invalid index" << endl; }
            else {
                log << L"\t\tLB_GETTEXT returned : " << res << L"\t\tszBuf: " << titleBuffer << endl;
            }
        }
        else { log << L"\t\tLB_GETCURSEL returned LB_ERR" << endl; }
    }

person Number8    schedule 24.07.2009    source источник
comment
Является ли поле списка множественным или одиночным выбором? В документации сообщения LB_GETCURSEL совершенно ясно указано, что оно не должно и не будет работать со списками с множественным выбором.   -  person DeusAduro    schedule 24.07.2009
comment
Почти уверен, что это одиночный выбор. Я посмотрю, что произойдет с LB_GETSELCOUNT. Не знаю, почему есть сообщение LBN_SELCHANGED, а не LBN_DBLCLK?   -  person Number8    schedule 24.07.2009
comment
LB_GETSELCOUNT возвращает LB_ERR.   -  person Number8    schedule 24.07.2009
comment
К сожалению, у меня нет spyxx.exe на целевом компьютере. Хук также не получает сообщения WM_LBUTTON*.   -  person Number8    schedule 24.07.2009


Ответы (2)


Я всегда находил, что документации по оконным хукам очень не хватает.

Судя по их именам, я думаю, что хук WH_CALLWNDPROCRET всегда будет вызываться где-то после соответствующего хука WH_CALLWNDPROC. В документации SendWindowsHookEx говорится о WH_CALLWNDPROC:

Устанавливает процедуру ловушки, которая отслеживает сообщения до того, как система отправит их оконной процедуре назначения.

Это говорит о том, что он получает только те сообщения, которые отправлены (SendMessage, что напрямую вызывает оконную процедуру), а не опубликовано (PostMessage, что помещает сообщение в очередь сообщений).

Если это действительно проблема, вы можете попробовать установить хук WH_GETMESSAGE вместе с существующим хуком. Этот хук вызывается, когда сообщения удаляются из очереди сообщений (обычно с помощью оконной процедуры). Попробуйте и посмотрите, ловит ли этот хук потерянные сообщения.

person Thomas    schedule 24.07.2009
comment
Извините, я тоже в растерянности. Может быть, попробуйте отключить хук WH_CALLWNDPROCRET, посмотрите, изменится ли это? - person Thomas; 28.07.2009

LBN_DBLCLK не будет отправлен, если для списка не установлено состояние LBS_NOTIFY. Не знаю, почему LB_GETCURSEL и LB_GETTEXT не работают...

person Goz    schedule 24.07.2009