Почему мое приложение MF C зависает после взаимодействия с обеими полосами прокрутки? - PullRequest
1 голос
/ 09 января 2020

Я работаю над приложением MF C (работающим под Win10), которое включает в себя окно графического редактора в стиле CAD. Окно редактора содержит значки, которые пользователь может перемещать и настраивать.

В макетах со многими элементами мы обнаруживаем, что окно редактора может зависать до 30 секунд. Эта проблема была , а не , когда большинство наших пользователей были на Windows 7; похоже, это начало происходить с Windows 10, но я не вернулся к Win7, чтобы подтвердить.

Точная последовательность действий, вызывающих зависание:

  1. Прокрутка по горизонтали (с помощью горизонтальной полосы прокрутки)
  2. Прокрутка по вертикали (с использованием вертикальной полосы прокрутки) )
  3. Приложение зависает примерно на 20-30 секунд, затем восстанавливает

Незначительные изменения описанных выше шагов также вызывают временное зависание; например, вертикальная прокрутка с помощью кнопки мыши, а затем горизонтальная прокрутка с помощью полосы прокрутки также вызывает зависание.

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

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

Мои вопросы:

  1. Есть ли какие-либо изменения в Windows 10 относительно большого количества CWnd, которые могут взаимодействовать с прокруткой, вызывая зависание?
  2. Какие инструменты Windows предоставляет для отладки этого сценария? Должен ли я смотреть на WinDbg? Должен ли я сосредоточиться на профилировании проблемы без использования специальных средств отладки?

Я собираюсь работать над этой проблемой с точки зрения внутреннего приложения (чтобы исключить возможность того, что наш код напрямую вызывая зависание), но я был бы признателен за любые рекомендации по наилучшему подходу к устранению этой проблемы, предполагая, что в нашем коде нет ничего очевидного, например, 30-секундный вызов функции.


Спасибо для комментариев. Вот некоторая новая информация:

  • Низкое использование процессора во время этого события; колеблется в пределах 1-3%, поэтому мой код не является узким местом ЦП.
  • Я добавил операторы TRACE в свои обработчики HSCROLL и VSCROLL как в точке входа, так и в точке выхода. Кажется, что зависание происходит до входа в мой обработчик VSCROLL, сразу после нажатия левой кнопкой мыши на полосу прокрутки.
  • Код имеет обработчик для LButtonDown, но он делает Похоже, что при нажатии на полосу прокрутки не ударил
  • Приложение имеет 208 объектов GDI и 66 объектов пользователя, поэтому я думаю, что мы значительно ниже предела
  • Эта проблема наблюдалась на все протестированные ПК с Win10, он не уникален для одной машины

Собираюсь сейчас попробовать Spy ++.

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

void CDrawing60View::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    TRACE("OnHScroll:Begin\r\n");

    int i = 1;
    switch ( nSBCode )
    {
    case SB_LEFT :  //   Scroll to far left.
        i = 2 ;
        break ;
    case SB_ENDSCROLL : //   End scroll.
        i = 3 ;
        break ;

    case SB_LINELEFT :  //   Scroll left.  left arrow on left side of scroll bar
        i = 4 ;
        break ;

    case SB_LINERIGHT : //   Scroll right.  right arrow on right side of scroll bar
        i = 5 ;
        break ;

    case SB_PAGELEFT :  //   Scroll one page left.
        i = 6 ;
        break ;

    case SB_PAGERIGHT : //   Scroll one page right.
        i = 7 ;
        break ;

    case SB_RIGHT : //   Scroll to far right.
        i = 8 ;
        break ;

    case SB_THUMBPOSITION : //   Scroll to absolute position. The current position is specified by the nPos parameter.
        i = 9 ;
        break ;

    case SB_THUMBTRACK :    //   Drag scroll box to specified position. 
        i = 10;
        break ;
    }

    CFormView::OnHScroll(nSBCode, nPos, pScrollBar);

    CPoint p = GetScrollPosition(); // p = how much we have scrolled in the horizontal/vertical directions

    SNAP_TO_8_PIXELS (p.x);
    SNAP_TO_8_PIXELS  ( p.y)
    ScrollToPosition ( p ) ;

    MoveDrawing . LastScrollPositionX = p . x ; // used when saving the drawing
    MoveDrawing . LastScrollPositionY = p . y ;

    TRACE("OnHScroll:End\r\n");
}

void CDrawing60View::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    TRACE("OnVScroll:Begin\r\n");

    int i = 0;
    switch ( nSBCode )
    {
    case SB_BOTTOM :    //   Scroll to bottom.
        i = 2 ;
        break ;
    case SB_ENDSCROLL : //   End scroll.
        break ;
    case SB_LINEDOWN :  //   Scroll one line down.
        i = 2 ;
        break ;
    case SB_LINEUP :    //   Scroll one line up.
        i = 2 ;
        break ;
    case SB_PAGEDOWN :  //   Scroll one page down.
        i = 2 ;
        break ;
    case SB_PAGEUP :    //   Scroll one page up.
        i = 2 ;
        break ;
    case SB_THUMBPOSITION : //   Scroll to the absolute position. The current position is provided in nPos.
        i = 2 ;
        break ;
    case SB_THUMBTRACK :    //   Drag scroll box to specified position. The current position is provided in nPos.
        i = 2 ;
        break ;
    case SB_TOP :   //   Scroll to top. 
        i = 2 ;
        break ;
    }

    CFormView::OnVScroll(nSBCode, nPos, pScrollBar);
    CPoint p = GetScrollPosition(); // p = how much we have scrolled in the horizontal/vertical directions

    SNAP_TO_8_PIXELS (p.x);
    SNAP_TO_8_PIXELS ( p.y)
    ScrollToPosition ( p ) ;

    MoveDrawing . LastScrollPositionX = p . x ; // used when saving the drawing
    MoveDrawing . LastScrollPositionY = p . y ;

    TRACE("OnVScroll:End\r\n");
}

Хорошо, Spy ++ дал некоторые интересные результаты. Когда я запускаю Spy ++, я не могу воспроизвести эту проблему! . Интересно, предполагает ли это состояние гонки в моих обработчиках, потому что единственный эффект, который я могу себе представить в Spy ++, заключается в замедлении работы.

1 Ответ

0 голосов
/ 04 февраля 2020

Это оказалось проблемой Windows ОС. Служба поддержки Майкрософт предоставила объяснение высокого уровня: новые функции Windows мешают моему приложению.

Похоже, что мое расследование указывало в правильном направлении: ntdll.dll или dwm.exe является виновником, а не мой исполняемый файл.

Тот факт, что Spy ++ сглаживает мою проблему, довольно показателен. Это указывает на то, что мы не сталкиваемся со строгим ограничением производительности, и это также показывает, что это не остановило мое приложение; что-то на уровне ОС мешает само себе.

Представитель службы поддержки Microsoft попросил меня использовать инструмент администрирования совместимости, включенный в Windows ADK в разделе Инструменты совместимости приложений. Используя этот мастер, я создал базу данных shim (.sdb), содержащую исправление для ScrollWindowsExFlags .

Затем я использовал следующую команду в командной строке с повышенными привилегиями для установки базы данных shim:

sdbinst -u <path to the sdb file>

Из службы поддержки Microsoft:

Имеет много детей windows для прокрутки является причиной. Когда они прокручиваются, DWM должен обновлять внутренние данные для каждого перемещаемого окна. Слишком много из них подавляет DWM.

...