什么可能导致64位Vista上的重绘问题,而不是.NET WInForms中的32位重绘问题?

时间:2008-12-22 17:35:39

标签: winforms windows-vista 64-bit redraw

在编译Any Cpu以及编译为x86时会发生这种情况。 GUI的各个部分不会重新绘制,除非它被调整大小,例如,如果主窗体最大化,某些控件不会随之调整大小,而其他部分的部分不会重绘并显示之前的内容。

这适用于32位机器,包括XP和Vista,但在64位Vista上(没有x64 XP可以测试)重绘只是不能正常工作。

任何人都有关于从何处开始跟踪此事的想法?

编辑:这发生在2台不同的机器上,至少我目前使用的是NVidia的最新驱动程序。

Edit2:在我的64位计算机上运行32位XP虚拟机,并且该应用程序没有在VM中显示重绘问题

Edit3:这可能是驱动程序问题,但我们不知道驱动程序是否或何时会解决问题。一位同事说家里的ATI卡比NVidia的问题要少,但过去几个月我一直在每月更新我的视频驱动程序而且还没有解决,所以我们不能只发布我们的产品并告诉我们的客户,有一天司机制造商可能会解决这个问题。

有没有人对要避免的事情有任何见解?我们正在编译为x86,所有组件都是x86。我似乎无法使用测试项目中的任何组件重现此问题,我还没有听到其他人在大多数组件论坛上报告这些问题,因此很可能这是我们正在做的事情。

8 个答案:

答案 0 :(得分:14)

听起来非常像this问题。

在Windows上调整窗口大小时,您通常会得到一个链,其中每个窗口都会收到WM_SIZE条消息,然后在其子级上调用MoveWindow()(或类似),然后会收到WM_SIZE和等等。我确信.NET在幕后做同样的事情。

在x64上,Windows限制了此嵌套的深度,在某个点(12-15个嵌套窗口)之后,它将不再发送WM_SIZE个消息。 x86上似乎不存在此限制。此限制会影响在x64版本的Windows上运行的x86和x64代码。

这让我们玩了很多年,因为不同的x64安装会显示不同的症状。上面发布的MSDN博客有一些可能的解决方法 - 我们最终使用辅助线程异步地执行窗口大小,这很好地解决了问题。

答案 1 :(得分:3)

如果您使用的是Windows窗体,则可能与Windows 64位上的嵌套限制问题有关。

详细信息: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。根据   关于USER的东西/更新/服务   打包最大嵌套级别   它停止传播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 );
    }
  }
}

答案 2 :(得分:1)

我认为此问题的最可能原因是您的应用程序中的重绘问题。在64位上有一个微妙的Windows消息排序差异可能会在您的代码中暴露此问题。

您可以通过执行以下操作来试验此操作。

  1. 为您的应用添加计时器。
  2. 在事件处理程序中调用flakyControl.Update()
  3. 我会将计时器设置为长达5秒的时间。然后在Win64上运行该应用程序,看看是否能解决问题。如果是这样,那么最可能的原因是你的一个控件没有正确地表明它已被无效。

    我会从应用程序中的任何自定义控件开始。系统地向代码中的每个重写方法和事件处理程序添加Update调用。最终你会找到解决问题的那个,然后你就会知道bug究竟在哪里。

答案 3 :(得分:1)

如果您使用MSDN上blog中描述的BeginInvoke()解决方案,请确保禁用覆盖OnSizeChanged()的控件的子对接。我有Dock = DockStyle.Fill并且必须更改为DockStyle.None才能使修复工作。

答案 4 :(得分:0)

听起来像显示器驱动程序问题...

尝试更新到最新的驱动程序,看看是否能解决问题? 64/32位差异可能是红鲱鱼......

答案 5 :(得分:0)

我同意戈登的观点。我已经看到全新的64位机器出现问题的问题,程序在32位下看起来很好,但在64位机器上会出现奇怪的问题。更新到最新/推荐的驱动程序几乎总是解决问题。

答案 6 :(得分:0)

您可以在没有问题的情况下在虚拟操作系统上运行该程序,这表明它是一个驱动程序问题,因为(至少在VirtualPC中)图形卡是模拟的。这意味着图形卡通常会处理的一些事情现在由CPU完成,因此不与图形驱动程序交互。请注意,我不是虚拟化方面的专家,我认为虚拟化层可能会以其他方式影响该问题。

答案 7 :(得分:0)

我认为这与树中嵌套的HWND的数量有关。我不知道具体的细节,但是对64bit的嵌套HWND有一些限制。我看到它发生的时间,我通过从完整的vista基本(或航空)主题回退到Windows经典来解决它。此时问题就消失了。

尝试切换到classic,如果解决了,请查看是否可以减少嵌套的HWND数量。