locked
Using User32.dll's InvalidateRect RRS feed

  • Question

  • Unless anybody has a better suggestion, I am trying to redraw a portion of the desktop using InvalidateRect from User32.  Basically, I have an image that I am drawing to the desktop, and need to clear where it was just drawn before drawing the next frame.

    I'm currently failing miserably (i.e. nothing happens) with this code:

    Rectangle Rect = new Rectangle(GetPosition(), _i.Size);
    WindowsAPI.RECT lpRect = WindowsAPI.RECT.FromRectangle(Rect);
    IntPtr ptrRect = Marshal.AllocHGlobal(Marshal.SizeOf(lpRect));
    Marshal.StructureToPtr(lpRect, ptrRect,false);
    WindowsAPI.InvalidateRect(WindowsAPI.GetDesktopWindow(), ptrRect, true);

    internal class WindowsAPI
    {
       [System.Runtime.InteropServices.
    DllImport("user32.dll")]
       public extern static IntPtr GetDesktopWindow();
       [
    DllImport("user32.dll")]
       public static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);

       [Serializable, StructLayout(LayoutKind.Sequential)]

       public struct RECT
       {
          public int Left;
          public int Top;
          public int Right;
          public int Bottom;
          public RECT(int left_, int top_, int right_, int bottom_)
          {
             Left = left_;
             Top = top_;
             Right = right_;
             Bottom = bottom_;
          }
          public int Height { get { return Bottom - Top; } }
          public int Width { get { return Right - Left; } }
          public Size Size { get { return new Size(Width, Height); } }

          public Point Location { get { return new Point(Left, Top); } }
          // Handy method for converting to a System.Drawing.Rectangle
          public Rectangle ToRectangle()
          {
            
    return Rectangle.FromLTRB(Left, Top, Right, Bottom);
          }
          public static RECT FromRectangle(Rectangle rectangle)
          {
             return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom);
          }
          public override int GetHashCode()
          {
             return Left ^ ((Top << 13) | (Top >> 0x13))
             ^ ((Width << 0x1a) | (Width >> 6))
             ^ ((Height << 7) | (Height >> 0x19));
          }
    #region Operator overloads
          public static implicit operator Rectangle(RECT rect)
          {
             return Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom);
          }
          public static implicit operator RECT(Rectangle rect)
          {
             return new RECT(rect.Left, rect.Top, rect.Right, rect.Bottom);
          }
    #endregion
    }

    Any Suggestions?

    Wednesday, August 30, 2006 10:01 PM

Answers

  • I don't think you'll be able to make this work reliably.  The desktop window is managed and painted by the shell.  You can blast a bitmap to it but it will break once the user starts moving windows around.  You'll need to somehow get the WM_PAINT messages for the desktop window.  That might be possible with a WH_CALLWNDPROC hook installed with SetWindowsHookEx().  Very expensive btw.  You'll still have a heckofatime properly merging the desktop wallpaper with your own bitmap.  And if you do get it to work on Windows XP, Vista is bound to break it.

    Consider painting your bitmap in a borderless window instead, put at the bottom of the Z-order...
    Thursday, August 31, 2006 1:40 PM
    Moderator

All replies

  • - Invalidating an area doesn't cause an immediate redraw. It just sends WM_PAINT messages that will eventually be processed by the application(s) with windows in that area.

    - I'm not sure GetDesktopWindow is the right choice. Perhaps you should consider GetShellWindow instead.

    - Don't forget to free the memory you allocate with Marshal.AllocHGlobal. Or better yet, skip the manual allocation by changing the lpRect parameter type in the InvalidateRect declaration to ref RECT.

     

    Thursday, August 31, 2006 7:57 AM
  • I don't think you'll be able to make this work reliably.  The desktop window is managed and painted by the shell.  You can blast a bitmap to it but it will break once the user starts moving windows around.  You'll need to somehow get the WM_PAINT messages for the desktop window.  That might be possible with a WH_CALLWNDPROC hook installed with SetWindowsHookEx().  Very expensive btw.  You'll still have a heckofatime properly merging the desktop wallpaper with your own bitmap.  And if you do get it to work on Windows XP, Vista is bound to break it.

    Consider painting your bitmap in a borderless window instead, put at the bottom of the Z-order...
    Thursday, August 31, 2006 1:40 PM
    Moderator
  • In that case, what is a good way to redraw the area behind the image immediately?  Can I capture the image before redrawing and just repaint the old image on top to clear?
    Thursday, August 31, 2006 1:41 PM