SetFocus () завершается ошибкой с допустимым дескриптором окна - PullRequest
3 голосов
/ 10 марта 2012

У меня есть программа с несколькими пользовательскими элементами управления. Одним из таких пользовательских элементов управления является элемент управления вводом текста. Поскольку окно не получает автоматически фокус клавиатуры, когда вы щелкаете по нему, я создал хук мыши в моей программе, который вызывает SetFocus () для окна, когда пользователь щелкает в этом окне. Однако есть проблема.

Если другая программа имеет фокус, когда вы щелкаете по окну моей программы (или любому из элементов управления в этом окне), SetFocus () завершается ошибкой. Затем я должен нажать еще раз, чтобы добиться успеха. Вот код:

LRESULT CALLBACK kbfProc(int nCode, WPARAM wParam, LPARAM lParam) // Keyboard focus switching procedure
{
    switch(nCode)
    {
        case HC_ACTION:
        {
            if(wParam == WM_LBUTTONDOWN || wParam == WM_NCLBUTTONDOWN)
            {
                MOUSEHOOKSTRUCT * mhs = (MOUSEHOOKSTRUCT*) lParam;

                if(SetFocus(mhs->hwnd) == NULL)
                {
                    printf("SetFocus(Hwnd = %.8x) failed. Error code: %lu\n", mhs->hwnd, GetLastError());
                } else {

                    printf("SetFocus(Hwnd = %.8x) returned success.\n", mhs->hwnd);
                }
            }

        }
        break;
    }

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

И вывод этих вызовов printf таков:

SetFocus(Hwnd = 00410c06) failed. Error code: 87
SetFocus(Hwnd = 00410c06) returned success.
SetFocus(Hwnd = 01740fc8) failed. Error code: 87
SetFocus(Hwnd = 01740fc8) returned success.

Код ошибки 87: ERROR_INVALID_PARAMETER, но я, очевидно, передаю в функцию действительный дескриптор окна, так почему же он не работает?

Ответы [ 2 ]

3 голосов
/ 10 марта 2012

Каждый раз, когда вы вызываете SetFocus, окно должно быть присоединено к очереди сообщений вызывающего потока, иначе SetFocus вернет недействительное значение, если это не так.Чтобы обойти это, сначала используйте SetForegroundWindow, когда мышь перемещается над окном, прежде чем вызывать SetFocus.

1 голос
/ 12 марта 2012

Я нашел решение.Я закончил тем, что много гуглял и пробовал много разных вещей, и в итоге я наткнулся на эту веб-страницу.Это немного длинное чтение, оно немного многословно и трудно понять, но в нем много информации.Я закончил тем, что добавил некоторый код в обработчик WM_ACTIVATE моего главного окна, который ищет дочернее окно, которое щелкнуло, когда окно активировано.Вот весь код:

Вот процедура хука:

LRESULT CALLBACK kbfProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    switch(nCode)
    {
        case HC_ACTION:
        {
            if(wParam == WM_LBUTTONDOWN || wParam == WM_NCLBUTTONDOWN)
            {
                MOUSEHOOKSTRUCT * mhs = (MOUSEHOOKSTRUCT*) lParam;

                BringWindowToTop(MainWindow->t_hwnd);
                SetFocus(mhs->hwnd);
            }

        }
        break;
    }

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

Вот код, который я вставил в обработчик WM_ACTIVATE:

    case WM_ACTIVATE:
    {
        unsigned long state = (unsigned long) wParam & 0x0000FFFF;
        unsigned long mState = (unsigned long) wParam & 0xFFFF0000;

        if(state != 0)
        {
            ...[some code here]...

            FocusChildWindow(hwnd);
        }

        ...[some code here]...
    }
    break;

А вот FocusChildWindow ()функция:

void FocusChildWindow(HWND hwnd)
{
    POINT mpos;
    GetCursorPos(&mpos);

    RECT wr;
    GetWindowRect(hwnd, &wr);

    mpos.x -= wr.left;
    mpos.y -= wr.top;

    HWND cw = ChildWindowFromPoint(hwnd, mpos);

    if(cw == NULL || cw == hwnd)
    {
        SetFocus(hwnd);
    } else {

        GetCursorPos(&mpos);
        HWND cw2;

        while(1)
        {
            POINT sc = mpos;
            MapWindowPoints(HWND_DESKTOP, cw, &sc, 1);

            cw2 = ChildWindowFromPoint(cw, sc);

            if(cw2 == NULL || cw2 == cw)
            {
                SetFocus(cw);
                break;
            } else {

                cw = cw2;
            }


        }

    }

}

Работает как шарм.Еще раз спасибо всем за ваш вклад и идеи по этой проблеме.

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