8

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

这在 32 位机器上运行良好,包括 XP 和 Vista,但在 64 位 Vista 上(没有 x64 XP 可以测试)重绘就不能正常工作。

有人对从哪里开始追踪这个有任何想法吗?

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

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

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

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

4

8 回答 8

14

这听起来很像这个问题。

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

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

这困扰了我们很长时间,因为不同的 x64 安装会显示不同的症状。上面的 MSDN 博客帖子有一些可能的解决方法 - 我们最终使用辅助线程异步处理窗口大小,这相当巧妙地解决了问题。

于 2009-02-17T00:23:22.880 回答
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 stuff/updates/service 打包了它停止传播 WM_SIZE 的最大嵌套级别,在最新的 XP 32bit/sp2 下可能从 15 到 31 不等,甚至更高(实际上无法访问)。

但是在 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 );
    }
  }
}
于 2009-02-17T15:39:53.283 回答
1

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

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

  1. 将计时器添加到您的应用程序。
  2. 在事件处理程序中调用 flakyControl.Update()

我会将计时器设置为大约 5 秒。然后在 Win64 上运行应用程序,看看是否能解决问题。如果是这样,那么最可能的原因是您的控件之一没有正确发出它已失效的信号。

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

于 2009-02-15T14:54:04.143 回答
1

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

于 2009-11-06T15:48:55.890 回答
0

对我来说听起来像是显示驱动程序的问题...

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

于 2008-12-22T17:44:55.990 回答
0

我同意戈登的观点。我见过一些问题,即全新的 64 位机器在 32 位下看起来不错的程序出现显示问题,但在 64 位机器上会出现奇怪的问题。更新到最新/推荐的驱动程序几乎总能解决问题。

于 2008-12-22T17:48:32.330 回答
0

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

于 2009-02-14T12:15:45.043 回答
0

我相信这与树中嵌套的 HWND 的数量有关。我不知道具体细节,但对 64 位的嵌套 HWND 有一些限制。我看到它发生的时候,我通过从完整的 vista 基本(或航空)主题退回到 windows 经典来解决它。在这一点上,问题消失了。

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

于 2009-02-15T06:00:56.450 回答