在.NET WInForms中,64位vista而不是32位vista上,什么会导致重绘问题?

在.NET WInForms中,64位vista而不是32位vista上,什么会导致重绘问题?,winforms,windows-vista,64-bit,redraw,Winforms,Windows Vista,64 Bit,Redraw,在为任何Cpu编译以及编译到x86时都会发生这种情况。GUI的部分不会重新绘制,除非调整大小,例如,如果主窗体最大化,则某些控件不会随之调整大小,而其他控件的部分不会重新绘制并显示以前的内容 这在32位机器上运行良好,包括XP和Vista,但在64位Vista(没有x64 XP可供测试)上,重画无法正常工作 有人知道从哪里开始追踪吗 编辑:这发生在两台不同的机器上,至少我当前使用的一台机器具有来自NVidia的最新驱动程序 Edit2:在我的64位计算机上运行32位XP虚拟机,并且应用程序在VM

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

这在32位机器上运行良好,包括XP和Vista,但在64位Vista(没有x64 XP可供测试)上,重画无法正常工作

有人知道从哪里开始追踪吗

编辑:这发生在两台不同的机器上,至少我当前使用的一台机器具有来自NVidia的最新驱动程序

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

Edit3:这可能是一个驱动程序问题,但我们不知道驱动程序是否或何时会修复该问题。一位同事说,与NVidia相比,ATI卡在家中出现的问题更少,但在过去几个月里,我几乎每月都在更新视频驱动程序,但问题仍然没有得到解决,因此我们不能只是发布产品,然后告诉客户,有一天驱动程序制造商可能会着手解决这个问题


有人知道应该避免哪些事情吗?我们编译为x86,所有组件都是x86。我似乎无法在测试项目中的任何组件上重现这个问题,而且我还并没有听到其他任何人在大多数组件论坛上报告这些问题,所以很可能是我们正在做的事情。

听起来像是显示驱动程序的问题


尝试更新到最新的驱动程序,看看这是否解决了问题?64/32位的差异可能是一种误导…

我同意戈登的观点。我曾经看到过这样的问题,即全新的64位机器在32位以下的程序中出现显示问题,但在64位机器上会出现奇怪的问题。更新到最新/推荐的驱动程序几乎总能解决这个问题。

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

我认为这与树中嵌套的HWND的数量有关。我不知道具体细节,但对64位的嵌套HWND有一些限制。在我看到它出现的时候,我通过从完整的vista basic(或aero)主题返回到windows classic来解决它。在这一点上,问题消失了


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

我认为此问题最可能的原因是应用程序中的重画问题。在64位上可能存在细微的windows消息顺序差异,从而在代码中暴露了此问题

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

  • 在应用程序中添加计时器
  • 在事件处理程序中调用flakyControl.Update()
  • 我会将计时器设置为5秒左右。然后在Win64上运行应用程序,看看这是否解决了问题。如果是这样,那么最有可能的原因是您的一个控件没有正确地发出无效的信号

    我将从应用程序中的任何自定义控件开始。系统地向代码中的每个重写方法和事件处理程序添加更新调用。最终,您将找到一个修复该问题的程序,然后您将知道错误的实际位置

    这听起来很像问题

    在窗口上调整窗口大小时,通常会得到一个链,其中每个窗口接收一条
    WM\u SIZE
    消息,然后在其子窗口上调用
    MoveWindow()
    (或类似),然后子窗口又接收一条
    WM\u SIZE
    ,依此类推。我确信.NET在幕后也做同样的事情

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


    这让我们迷惑了很久,因为不同的x64安装会显示不同的症状。上面的MSDN博客文章有一些可能的解决方法-我们最终使用了一个辅助线程来异步处理窗口大小,这相当巧妙地解决了问题。

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

    详情如下:

    总之

    从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:

    “一项小调查显示Windows停止发送WM_大小的文件 当它到达某个特定的巢穴时 级别。换句话说,它不会发送 WM_大小到您的子窗口,如果您 处理时尝试调整它们的大小 父项中的WM_大小。取决于 关于用户资料/更新/服务 在以下位置打包最大嵌套级别: 它停止传播的WM_大小可能会 从15到31不等,甚至更多 在以下条件下更高(实际上无法达到) 最新XP 32位/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 );
        }
      }
    }
    
    如果使用MSDN中描述的BeginInvoke()解决方案,请确保禁用ch的对接