Отладка ошибок фокусировки WIN32

Я занимаюсь разработкой приложения для WIN32/C++, содержащего главное окно и множество дочерних окон, и я ищу инструменты, которые могли бы помочь мне отследить ошибки фокусировки.

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

ОБНОВЛЕНИЕ: Джеффри Рихтер написал статью в 1997 году, в которой, среди прочего, содержится инструмент для нахождения фокуса: http://www.microsoft.com/msj/0397/Win32/Win320397.aspx

3 ответа

Решение

Журнал сообщений Spy++ даст полную запись изменений фокуса, но попытка декодировать то, что происходило из журнала, является рутиной. Противный интерфейс Spy++ не помогает.

Удаленная отладка полезна, потому что отладчик не будет мешать активации и фокусировке вашего приложения, но я не уверен, что есть простой способ определить сфокусированное окно из отладчика. Вот пара статей о его настройке. Подсказка: если это не работает, перепроверьте настройки DCOM и брандмауэра.

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

Для его инициализации просто создайте таймер где-нибудь в коде инициализации вашей программы:

// Check the focus ten times a second
// Change hwndMain to your main application window
// Note that this won't work if you have multiple UI threads
::SetTimer(hwndMain, 1, 100, HighlightTimerProc);

и добавьте следующий код:

LRESULT CALLBACK HighlightWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_NCHITTEST:
        return HTTRANSPARENT;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

VOID CALLBACK HighlightTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
    // static locals are bad
    static bool initialised = false;
    static HWND hwndHighlight = 0;

    if (!initialised)
    {
        HINSTANCE hInstance = 0;

        WNDCLASSEX wcex;

        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = HighlightWndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = 0;
        wcex.hCursor        = 0;
        wcex.hbrBackground  = (HBRUSH)(COLOR_HIGHLIGHTTEXT);
        wcex.lpszMenuName   = 0;
        wcex.lpszClassName  = L"HighlightWindowClasss";
        wcex.hIconSm        = 0;

        ATOM atomHighlightClass = RegisterClassEx(&wcex);

        hwndHighlight = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW,
            (LPCTSTR)atomHighlightClass, L"", WS_POPUP,
            CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

        // Set opacity to 200/255
        SetLayeredWindowAttributes(hwndHighlight, 0, 200, LWA_ALPHA);

        initialised = true;
    }

    static HWND hwndCurrentHighlight = 0;

    HWND hwndFocus = GetFocus();
    if (hwndFocus != hwndCurrentHighlight)
    {
        if (hwndFocus == 0)
        {
            ShowWindow(hwndHighlight, SW_HIDE);
        }
        else
        {
            RECT rect;
            GetWindowRect(hwndFocus, &rect);
            MoveWindow(hwndHighlight, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, false);
            ShowWindow(hwndHighlight, SW_SHOW);
        }
        hwndCurrentHighlight = hwndFocus;
    }
}

Инструмент Inspect, часть загрузки Windows SDK, может быть полезен здесь. Он предназначен для тестирования двух API-интерфейсов, связанных с расширенными возможностями - MSAA и UI Automation, - и одна из вещей, которую используют эти API-интерфейсы, - это возможность доступа и инструменты тестирования для отслеживания фокуса.

Простейший способ использовать его для отслеживания фокуса - перевести его в режим MSAA, проверить параметры, чтобы отслеживать только изменения фокуса (т. Е. Отключить по указателю мыши), а затем включить желтый прямоугольник выделения. Теперь, когда фокус меняется, вы можете видеть движение прямоугольника. В качестве бонуса, если фокус переместится на что-то скрытое или вне экрана, вы не увидите прямоугольник, но имя и класс элемента управления Win32 будут отображены в окне.

Обратите внимание, что Inspect показывает расширенный набор событий фокуса: вы получаете не только изменения фокуса HWND, но и уведомления, когда фокус перемещается в определенных элементах управления, например, между элементами в списке. Это нужно автоматическому тестированию и доступности, но для ваших целей вам следует просто игнорировать их; это дополнительная информация, но она не должна слишком мешать.

Я думаю, что вы можете использовать Spy++, которые являются частью Visual Studio или Windows SDK. Он говорит вам много другой информации, вы также можете захватывать сообщения, отправленные в выбранное окно.

http://msdn.microsoft.com/en-us/library/dd460760.aspx

Другие вопросы по тегам