Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Windows Forms / WinForm General / March 2006

Tip: Looking for answers? Try searching our database.

WM_ERASEBKGND problem

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
jh - 28 Mar 2006 16:00 GMT
I've encountered a strange problem with GDI/GDI+ and windows forms/win32. To
explain it shortly: I've a user control with a NC area. When painting the NC
area I ask for a window DC using GetDCEx with parameters DCX_WINDOW |
DCX_CACHE. I also use the wParam of the WM_NCPAINT message which contains the
update region for the NC area (or 1 to update the whole NC area). After
creating the graphics object and painting the NC area (if necessary) the hDC
is released. Next, the WM_ERASEBKGND message arrives which contains an OS
supplied hDC in the wParam. Using this hDC, which is used automatically by
the WmEraseBkgnd method in the System.Windows.Forms.Control class if
UserPaint is true and AllPaintingInWmPaint is false, causes the problem: the
window background is NOT erased due to the fact that the system region of the
supplied hDC is NULL. This is even more strange while the update region of
the window is NOT null. The erase problem occurs when an external window
obscured the NC area of the form hosting my user control. To solve this
problems I've several workarounds: (1) set ControlStyles.AllPaintingInWmPaint
is true (forcing the control the handle background painting in the WmPaint
handler not using the OS supplied hDC for the WM_ERASEBKGND message, (2) not
using the hClipRgn parameter of GetDCEx (and neglecting the OS supplied
update region for the NC area) and (3) reinvalidate the window after handling
of the WM_NCPAINT event (the latter solution is not nice of course). Please
let someone me know if there is a better solution and if this is a bug in
win32 GDI. Thanks in advance.
Stoitcho Goutsev (100) - 29 Mar 2006 15:17 GMT
jh,

Without reproducing the problem and playing with some sample application I
don't think anyone will know the answer, unless struggle with the same
problem.

I'd suggest to post simple compilable sample that demonstrates your problem.

Signature

Stoitcho Goutsev (100)

> I've encountered a strange problem with GDI/GDI+ and windows forms/win32.
> To
[quoted text clipped - 28 lines]
> let someone me know if there is a better solution and if this is a bug in
> win32 GDI. Thanks in advance.
jh - 29 Mar 2006 16:37 GMT
Stoitcho Goutsev,

See below a small sample application which can be used to reproduce the
problem. Compile and show the form and move another form over the sample to
see the painting problem. Switching on the AllPaintingInWmPaint flag will do
the correct painting. Please let me know your results.

Thanks in advance.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Test
{
    public class FormTest : Form
    {
        private NCControl ncControl;
        private CheckBox checkBox1;

        public FormTest()
        {
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "FormTest";

            ncControl = new NCControl();
            ncControl.Dock = DockStyle.Fill;

            checkBox1 = new CheckBox();
            checkBox1.Text = "AllPaintingInWmPaint";
            checkBox1.Size = new Size(80, 17);
            checkBox1.AutoSize = true;
            checkBox1.Location = new Point(10, 10);
            checkBox1.Anchor = AnchorStyles.Left | AnchorStyles.Top;

            checkBox1.CheckedChanged += new EventHandler(checkBox1_CheckedChanged);
            ncControl.Controls.Add(checkBox1);

            this.Controls.Add(ncControl);
        }

        void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            this.ncControl.SetStyleAllPaintingInWmPaint(checkBox1.Checked);
        }
    }

    public class NCControl : ContainerControl
    {
        public NCControl() : base()
        {
            this.SetStyle(ControlStyles.ResizeRedraw, true);
        }

        public void SetStyleAllPaintingInWmPaint(bool value)
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, value);
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_NCCALCSIZE:
                    this.WmNcCalcSize(ref m);
                    break;
                case WM_NCPAINT:
                    this.WmNcPaint(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        private void WmNcCalcSize(ref Message m)
        {
            base.WndProc(ref m);

            if (m.WParam == IntPtr.Zero)
            {
                RECT clientRect = (RECT) Marshal.PtrToStructure(m.LParam, typeof(RECT));
                Marshal.StructureToPtr(this.GetClientRectangleAsRECT(clientRect),
m.LParam, false);
            }
            else
            {
                NCCALCSIZE_PARAMS p = (NCCALCSIZE_PARAMS)
Marshal.PtrToStructure(m.LParam, typeof(NCCALCSIZE_PARAMS));
                p.rgrc0 = this.GetClientRectangleAsRECT(p.rgrc0);
                Marshal.StructureToPtr(p, m.LParam, false);
            }

            m.Result = IntPtr.Zero;
        }

        private RECT GetClientRectangleAsRECT(RECT clientRect)
        {
            clientRect.left += Math.Min(10, clientRect.right - clientRect.left);
            clientRect.top += Math.Min(10, clientRect.bottom - clientRect.top);
            clientRect.bottom -= Math.Min(10, clientRect.bottom - clientRect.top);
            clientRect.right -= Math.Min(10, clientRect.right - clientRect.left);

            return clientRect;
        }

        private void WmNcPaint(ref Message m)
        {
            base.WndProc(ref m);

            IntPtr hRgnClip = IntPtr.Zero;

            int flags = DCX_WINDOW | DCX_CACHE | DCX_CLIPSIBLINGS |
DCX_LOCKWINDOWUPDATE;

            if ((int) m.WParam != 1)
            {
                hRgnClip = m.WParam;
                flags |= DCX_INTERSECTRGN;
            }

            IntPtr hDC = GetDCEx(this.Handle, hRgnClip, flags);

            using (Graphics g = Graphics.FromHdc(hDC))
            {
                Rectangle frameRectangle = new Rectangle(0,0,this.Width, this.Height);
                Rectangle innerRectangle = frameRectangle;

                innerRectangle.Inflate(-10, -10);
               
                Region frameRegion = new Region(frameRectangle);
                frameRegion.Exclude(innerRectangle);

                using (SolidBrush brush = new SolidBrush(Color.Red))
                    g.FillRegion(brush, frameRegion);

                frameRegion.Dispose();
            }

            ReleaseDC(this.Handle, hDC);

            m.Result = IntPtr.Zero;
        }

       public const int WM_NCCALCSIZE = 0x00000083;
        public const int WM_NCPAINT = 0x00000085;
       
        public const int DCX_WINDOW = 0x0000001;
        public const int    DCX_CACHE = 0x00000002;
        public const int    DCX_CLIPSIBLINGS = 0x00000010;
        public const int    DCX_INTERSECTRGN = 0x00000080;
        public const int    DCX_LOCKWINDOWUPDATE = 0x00000400;

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct NCCALCSIZE_PARAMS
        {
            public RECT rgrc0;
            public RECT rgrc1;
            public RECT rgrc2;
            public IntPtr lppos;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true,
SetLastError = true)]
        public static extern IntPtr GetDCEx(IntPtr hWnd, IntPtr hRgnClip, int
flags);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true,
SetLastError = true)]
        public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
    }
}

> jh,
>
[quoted text clipped - 36 lines]
> > let someone me know if there is a better solution and if this is a bug in
> > win32 GDI. Thanks in advance.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.