Что может вызвать проблемы с перерисовкой в ​​64-битной Vista, но не в 32-битной в .NET WInForms? - PullRequest
8 голосов
/ 22 декабря 2008

Это происходит при компиляции для Any Cpu, а также при компиляции в x86. Разделы графического интерфейса не перерисовываются, пока не будут изменены их размеры, например, если основная форма развернута, некоторые элементы управления не изменяют ее размер, а другие имеют разделы, которые не перерисовываются и отображают то, что было ранее.

Это прекрасно работает на 32-битных компьютерах, как в XP, так и в Vista, но в 64-битной Vista (без x64 XP для тестирования) перерисовка просто не работает должным образом.

У кого-нибудь есть идеи о том, с чего начать отслеживать это?

Редактировать: Это происходит на 2 отдельных машинах, и по крайней мере на той, на которой я сейчас работаю, установлены последние драйверы от NVidia.

Edit2: запуск 32-разрядной виртуальной машины XP на моей 64-разрядной машине, и приложение не обнаруживает проблему перерисовки в виртуальной машине

Edit3: Это может быть проблема с драйверами, но мы не знаем, когда или когда драйверы решат проблему. Сотрудник говорит, что с картой ATI в домашних условиях меньше проблем, чем с NVidia, но я обновляю свои видеодрайверы почти ежемесячно в течение последних нескольких месяцев, и это все еще не решено, поэтому мы не можем просто выпустить наш продукт и просто скажите нашим клиентам, что когда-нибудь производители драйверов найдут способ исправить это.

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

Ответы [ 8 ]

14 голосов
/ 17 февраля 2009

Звучит ужасно, как эта проблема.

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

В x64 Windows ограничивает глубину вложения, и после определенной точки (12-15 вложенных окон) она просто больше не будет отправлять сообщения WM_SIZE. Это ограничение не существует в x86. Это ограничение влияет на код как x86, так и x64, работающий в x64-версиях Windows.

Это дурачило нас целую вечность, так как разные установки x64 показывали бы разные симптомы. У публикации блога MSDN выше есть некоторые возможные обходные пути - мы закончили тем, что использовали вторичный поток, чтобы сделать размеры окна асинхронно, это решило проблему довольно аккуратно.

3 голосов
/ 17 февраля 2009

Если вы используете Windows Forms, это может быть связано с проблемами ограничения вложенности в 64-битной Windows.

Подробности здесь: http://www.feedghost.com/Blogs/BlogEntry.aspx?EntryId=17829

В итоге ...

Из источника MS в Control.SetBoundsCore:

SafeNativeMethods.SetWindowPos(new HandleRef(window, Handle), NativeMethods.NullHandleRef, x, y, width, height, flags);

// NOTE: SetWindowPos causes a WM_WINDOWPOSCHANGED which is processed
// synchonously so we effectively end up in UpdateBounds immediately following
// SetWindowPos.
//
//UpdateBounds(x, y, width, height);

А из MSDN:

http://social.msdn.microsoft.com/forums/en-US/windowsuidevelopment/thread/25181bd5-394d-4b94-a6ef-06e3e4287527/

"Небольшое расследование показало, что Windows перестает отправлять WM_SIZE когда он достигает определенного вложения уровень. Другими словами, он не отправит WM_SIZE для ваших дочерних окон, если вы попытаться изменить их размер при обработке WM_SIZE в родительских. в зависимости на вещи пользователя / обновления / сервис максимальный уровень вложенности который он перестает распространять WM_SIZE может варьируются от 15 до 31 и даже сильно выше (фактически недоступно) под последняя версия XP 32bit / sp2.

Но это все еще слишком мало под XP x64 и все еще некоторые уродливые вещи случается с другими сообщениями под некоторыми сборки Vista.

Так что это, безусловно, ошибка Windows. "

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

public class FixedPanel : Panel
{
  protected override void SetBoundsCore( int x, int y, int width, int height, BoundsSpecified specified )
  {
    base.SetBoundsCore( x, y, width, height, specified );

    if( specified != BoundsSpecified.None )
    {
      if( ( specified & BoundsSpecified.X ) == BoundsSpecified.None )
      {
        x = Left;
      }
      if( ( specified & BoundsSpecified.Y ) == BoundsSpecified.None )
      {
        y = Top;
      }
      if( ( specified & BoundsSpecified.Width ) == BoundsSpecified.None )
      {
        width = Width;
      }
      if( ( specified & BoundsSpecified.Height ) == BoundsSpecified.None )
      {
        height = Height;
      }
    }

    if( x != Left || y != Top || width != Width || height != Height )
    {
      UpdateBounds( x, y, width, height );
    }
  }
}
1 голос
/ 06 ноября 2009

Если вы используете решение BeginInvoke (), описанное в MSDN blog , обязательно отключите стыковку дочерних элементов элемента управления, который переопределяет OnSizeChanged (). У меня был Dock = DockStyle.Fill, и мне пришлось изменить его на DockStyle.None, чтобы исправление заработало.

1 голос
/ 15 февраля 2009

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

Вы можете поэкспериментировать с этим, выполнив следующее.

  1. Добавьте таймер в ваше приложение.
  2. В обработчике событий вызовите flakyControl.Update ()

Я бы установил таймер на что-то длинное, например, на 5 секунд. Затем запустите приложение на Win64 и посмотрите, исправит ли это проблему. Если это так, то наиболее вероятной причиной является то, что один из ваших элементов управления неправильно сигнализирует о том, что он был признан недействительным.

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

0 голосов
/ 15 февраля 2009

Я полагаю, это связано с количеством вложенных HWND в дереве. Я не знаю конкретных деталей, но были некоторые ограничения, наложенные на вложенные HWND с 64 битами. Когда я видел, что это происходит, я обхожу его, возвращаясь к полной базовой (или аэро) теме Vista, к классической Windows. На этом этапе проблемы исчезают.

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

0 голосов
/ 14 февраля 2009

Тот факт, что вы можете запустить программу в виртуальной ОС без проблем, говорит о том, что это проблема с драйвером, потому что (по крайней мере, в VirtualPC) графическая карта эмулируется. Это означает, что некоторые вещи, которые графическая карта обычно обрабатывает, теперь выполняются процессором и, следовательно, не взаимодействуют с графическим драйвером. Имейте в виду, что я не специалист по виртуализации и полагаю, что уровень виртуализации может повлиять на проблему другими способами.

0 голосов
/ 22 декабря 2008

Я бы согласился с Гордоном. Я видел проблемы, когда на новых 64-битных машинах возникали проблемы с отображением программ, которые выглядели нормально под 32-битными, но на 64-битных машинах возникали странные проблемы. Обновление до последних / рекомендуемых драйверов почти всегда решало проблему.

0 голосов
/ 22 декабря 2008

Звучит как проблема с драйвером дисплея ...

Попробуйте обновить драйверы до последних версий и посмотреть, решит ли это проблему? Разница в 64/32 бита - это, вероятно, красная сельдь ...

...