Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What could cause redraw issues on 64-bit vista but not in 32-bit in .NET WInForms?

This happens when compiling for Any Cpu as well as compiling to x86. Sections of the GUI doesn't redraw unless it's resized, for instance if the main form is maximized some of the controls don't resize with it, and others have sections that don't redraw and displays the what was previously there.

This works fine on 32-bit machines, both XP and Vista, but on 64-bit Vista (don't have x64 XP to test with) the redrawing just isn't working properly.

Anyone have any ideas on where to start tracking this down?

Edit: This occurs on 2 separate machines, and at least the one I'm currently on has the latest drivers from NVidia.

Edit2: Running a 32-bit XP virtual machine on my 64-bit machine and the application doesn't exhibit the redrawing issue in the VM

Edit3: It may be a driver issue, but we don't know if or when drivers will fix the issue. A co-worker says there's fewer issues with an ATI card at home than with NVidia, but I've been updating my video drivers pretty much monthly for the past few months and it's still not resolved, so we can't just release our product and just tell our customers that some day the driver manufacturers may get around to fixing this.

Does anyone have any insight on what things to try to avoid? We're compiling as x86 and all our components are x86. I can't seem to reproduce this issue with any of the components in test projects, and I haven't heard anyone else report these issues on most of the the component forums, so it is fairly likely that it's something we're doing.

like image 271
Davy8 Avatar asked Dec 22 '08 17:12

Davy8


2 Answers

That sounds horribly like this problem.

When resizing windows on Windows you typically get a chain where each window receives a WM_SIZE message and then calls MoveWindow() (or similar) on its children which in turn receive a WM_SIZE and so on. I'm sure that .NET does the same thing under the covers.

On x64, Windows limits the depth of this nesting, and after a certain point (12-15 nested windows) it will just not send the WM_SIZE messages anymore. This limitation does not appear to exist on x86. This limitation affects both x86 and x64 code running on x64 versions of Windows.

This foxed us for ages, as different x64 installs would show different symptoms. The MSDN blog posting above has some possible workarounds - we ended up using a secondary thread to do the window sizes asynchronously, this solved the problem fairly neatly.

like image 86
Bids Avatar answered Sep 21 '22 16:09

Bids


If you're using Windows Forms, it could be to do with nesting limitation issues on Windows 64-bit.

Details here: http://www.feedghost.com/Blogs/BlogEntry.aspx?EntryId=17829

In summary...

From the MS source, in 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);

And from MSDN:

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

"A little investigation showed that Windows stops sending WM_SIZE when it reaches some certain nesting level. In other words, it won't send WM_SIZE to your child windows if you try to resize them when you process WM_SIZE in the parent ones. Depending on the USER stuff/updates/serivice packs the maximum nesting level at which it stops propagating WM_SIZE may vary from 15 to 31 and even much higher (effectively unreachable) under latest XP 32bit/sp2.

But it still too little under XP x64 and still some similar ugly things happen to other messages under some builds of Vista.

So it is certainly a Windows bug."

You have two choices: either reduce the depth of your control hierarchy (the more ideal solution), or else derive "fixed" controls from each of the system ones that you use, as follows:

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 );
    }
  }
}
like image 45
stusmith Avatar answered Sep 23 '22 16:09

stusmith