How can I get graphics through message WM_NCPAINT ?
-
For repainting the nonclient area myself, I process the message WM_NCPAINT. But the value got from wParam always is 1. Why? How can I get the nonclient area's graphics?
If you have a reference to the non-client area, you can use
Control.CreateGraphics
to return aGraphics
object for any control. Remember to callGraphics.Dispose
on it when you're done, though.-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
If you have a reference to the non-client area, you can use
Control.CreateGraphics
to return aGraphics
object for any control. Remember to callGraphics.Dispose
on it when you're done, though.-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
If you have a reference to the non-client area, you can use
Control.CreateGraphics
to return aGraphics
object for any control. Remember to callGraphics.Dispose
on it when you're done, though.-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
I know I can get the form's graphics with CreateGraphics(). Can I get the title bar's graphics? or How can I determine the title bar's retangle? The wParam gotten from WM_NCPAINT always is 1.
Right, I didn't catch that before. The
wParam
in the WM_NCPAINT message should be 1 if the entire window frame needs repainting (covered in the docs for WM_NCPAINT). Also in that same doc is an example that you could easily use after importing a couple Win32 functions (I can't think of or find any .NET equivalents). P/InvokeGetDCEx
(optionallyReleaseDC
, butGraphics.Dispose
would free the handle). and passhwnd
,(HRGN)wParam
, andDCX_WINDOW|DCX_INTERSECTRGN
. Even though hwnd is 1, this supposedly works (at least according the docs). I tried a quick example and got minimal success. Of course, I threw it together quickly. I also found on thatGraphics.FromHwnd
works when passing theMessage.HWnd
field from the overriddenDefWndProc
for my form. Hopefully this helps somewhat. Good luck!-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
Right, I didn't catch that before. The
wParam
in the WM_NCPAINT message should be 1 if the entire window frame needs repainting (covered in the docs for WM_NCPAINT). Also in that same doc is an example that you could easily use after importing a couple Win32 functions (I can't think of or find any .NET equivalents). P/InvokeGetDCEx
(optionallyReleaseDC
, butGraphics.Dispose
would free the handle). and passhwnd
,(HRGN)wParam
, andDCX_WINDOW|DCX_INTERSECTRGN
. Even though hwnd is 1, this supposedly works (at least according the docs). I tried a quick example and got minimal success. Of course, I threw it together quickly. I also found on thatGraphics.FromHwnd
works when passing theMessage.HWnd
field from the overriddenDefWndProc
for my form. Hopefully this helps somewhat. Good luck!-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
Please check following codes, it dosen'g work properly, the title bar is still empty. ( the method PanitNonClientArea(Graphics, RectangleF) can work properly. )
protected override void WndProc(ref Message m) { Graphics g; RectangleF rectf; Point pt; switch (m.Msg) { case WMConsts.WM_NCPAINT : IntPtr hrgn = m.WParam; if ( hrgn != (IntPtr)1 ) { Region rgn = Region.FromHrgn(hrgn); g = CreateGraphics(); rectf = rgn.GetBounds(g); PaintNonClientArea(g, rectf); } else { g = CreateGraphics(); rectf = new RectangleF(0,-23, Width, 23); PaintNonClientArea(g, rectf); g.Dispose(); } //base.WndProc(ref m); break; default : base.WndProc (ref m); break; } }
-
Please check following codes, it dosen'g work properly, the title bar is still empty. ( the method PanitNonClientArea(Graphics, RectangleF) can work properly. )
protected override void WndProc(ref Message m) { Graphics g; RectangleF rectf; Point pt; switch (m.Msg) { case WMConsts.WM_NCPAINT : IntPtr hrgn = m.WParam; if ( hrgn != (IntPtr)1 ) { Region rgn = Region.FromHrgn(hrgn); g = CreateGraphics(); rectf = rgn.GetBounds(g); PaintNonClientArea(g, rectf); } else { g = CreateGraphics(); rectf = new RectangleF(0,-23, Width, 23); PaintNonClientArea(g, rectf); g.Dispose(); } //base.WndProc(ref m); break; default : base.WndProc (ref m); break; } }
As a quick note, and this may be trivial, but all implementations I've seen (including in Win32) always call the "base"
WndProc
orDefWndProc
. You're only doing it if the message isn'tWM_NCPAINT
. Also, the docs forWM_NCPAINT
say that it calls theDefWindowProc
, which isDefWndProc
in the Control class. Did you try putting a breakpoint in your code to see if it's even getting there? If not, you might try moving this to an override ofDefWndProc
instead ofWndProc
. I don't know, maybe both callbacks get it. As I said in my previous post, I had some success. I forgot to mention that I was usingGraphics.FromHwnd
instead ofCreateGraphics
. This seemed to work in most cases. I was able to ruin the nonclient area, but could never paint in it. Apparently, I was able to create aGraphics
object successfully, but I would always get an exception when creating aRegion
from thewParam
, which would explain why I couldn't paint anything (I couldn't get the bounds in which to paint).-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
As a quick note, and this may be trivial, but all implementations I've seen (including in Win32) always call the "base"
WndProc
orDefWndProc
. You're only doing it if the message isn'tWM_NCPAINT
. Also, the docs forWM_NCPAINT
say that it calls theDefWindowProc
, which isDefWndProc
in the Control class. Did you try putting a breakpoint in your code to see if it's even getting there? If not, you might try moving this to an override ofDefWndProc
instead ofWndProc
. I don't know, maybe both callbacks get it. As I said in my previous post, I had some success. I forgot to mention that I was usingGraphics.FromHwnd
instead ofCreateGraphics
. This seemed to work in most cases. I was able to ruin the nonclient area, but could never paint in it. Apparently, I was able to create aGraphics
object successfully, but I would always get an exception when creating aRegion
from thewParam
, which would explain why I couldn't paint anything (I couldn't get the bounds in which to paint).-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
I found that there is not difference between
WndProc
andDefWndProc
. Sometimes theWM_NCPAINT
'swParam
is 1. In this case, it will not be successful to create aRegion
. I found the graphics retrived not the same betweenIntPtr hdc = GetWindowDC(m.HWnd) Graphics g = Graphics.FromHDC(hdc)
andGraphics g = Graphics.FromHWnd(hdc)