Drawing to a window's title bar problems

G

Guest

I'm trying to add another button to a window's title bar to use as a "keep
this window on top" button. I've managed to draw the button using the code
below (C#) but I'm having a couple of other problems...

....
private bool buttonChecked = false;
private int buttonSize = 16;
private int buttonX = 226;
private int buttonY = 6;

[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

public const int WM_NCPAINT = 0x085;
public const int WM_NCLBUTTONDOWN = 0x0A1;
public const int WM_NCLBUTTONUP = 0x0A2;
....

....
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCPAINT:
base.WndProc (ref m);
IntPtr hDC = GetWindowDC(m.HWnd);
Graphics g = Graphics.FromHdc(hDC);
PaintNC(m.HWnd);
g.Dispose();
ReleaseDC(m.HWnd, hDC);
m.Result = IntPtr.Zero;
break;
case WM_NCLBUTTONDOWN:
base.WndProc (ref m);
Point pd = new Point((int)m.LParam);
int xPos = pd.X - this.Location.X;
int yPos = pd.Y - this.Location.Y;
if (xPos > buttonX && xPos < (buttonX + buttonSize) && yPos > buttonY &&
yPos < (buttonY + buttonSize))
{
IntPtr hDCa = GetWindowDC(m.HWnd);
Graphics gra = Graphics.FromHdc(hDCa);
buttonChecked = !buttonChecked;
}
break;
default:
base.WndProc(ref m);
break;
}
}

protected void PaintNC(System.IntPtr hWnd)
{
IntPtr hDC = GetWindowDC(hWnd);
Graphics g = Graphics.FromHdc(hDC);
if (buttonChecked)
ControlPaint.DrawButton(g, buttonX, buttonY, buttonSize, buttonSize,
ButtonState.Checked);
else
ControlPaint.DrawButton(g, buttonX, buttonY, buttonSize, buttonSize,
ButtonState.Normal);
g.Dispose();
ReleaseDC(hWnd, hDC);
}
....

The first problem I'm having is that is doesn't use the Window theme
anymore for the window. It uses the classic win98 style theme with the
gradient title bar.

The second problem is that when I click the button it doesn't refresh the
window so it doesn't show that it's pushed it. I have to minimise and then
maximise the window to see the changes. I tried using the invalidate() method
but that only works in the client area of the window.

Any ideas?

Darrell
 
D

Dmitriy Lapshin [C# / .NET MVP]

Things to check:
1. The MSDN example on WM_NCPAINT uses GetDCEx to get the proper HDC, not
GetWindowDC
2. You dispose of the Graphics object created out of the DC, and then you
explicitely release the DC... I suspect you can actually end up releasing
the DC twice which is obviously not a good thing to do.
3. You always return zero as the result of processing WM_NCPAINT. Make sure
the DefWindowProc returns the same value - otherwise you can potentially
prevent the system from doing some more work, for example painting the theme
graphics. Sounds a bit far-fetched, but I'd still check the return value
just to be safe.
The second problem is that when I click the button it doesn't refresh the
window so it doesn't show that it's pushed it. I have to minimise and then
maximise the window to see the changes. I tried using the invalidate()
method
but that only works in the client area of the window.

As it should - Invalidate works for client area only. I didn't manage to
find a non-client counterpart - you can try to use SendMessage API directly
to send the WM_NCPAINT message to the window, but this is just a guess.

Also, take a look at this:

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=23250&lngWId=1
http://www.ActualTools.com/

--
Sincerely,
Dmitriy Lapshin [C# / .NET MVP]
Bring the power of unit testing to the VS .NET IDE today!
http://www.x-unity.net/teststudio.aspx

redneon said:
I'm trying to add another button to a window's title bar to use as a "keep
this window on top" button. I've managed to draw the button using the code
below (C#) but I'm having a couple of other problems...

...
private bool buttonChecked = false;
private int buttonSize = 16;
private int buttonX = 226;
private int buttonY = 6;

[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

public const int WM_NCPAINT = 0x085;
public const int WM_NCLBUTTONDOWN = 0x0A1;
public const int WM_NCLBUTTONUP = 0x0A2;
...

...
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCPAINT:
base.WndProc (ref m);
IntPtr hDC = GetWindowDC(m.HWnd);
Graphics g = Graphics.FromHdc(hDC);
PaintNC(m.HWnd);
g.Dispose();
ReleaseDC(m.HWnd, hDC);
m.Result = IntPtr.Zero;
break;
case WM_NCLBUTTONDOWN:
base.WndProc (ref m);
Point pd = new Point((int)m.LParam);
int xPos = pd.X - this.Location.X;
int yPos = pd.Y - this.Location.Y;
if (xPos > buttonX && xPos < (buttonX + buttonSize) && yPos > buttonY &&
yPos < (buttonY + buttonSize))
{
IntPtr hDCa = GetWindowDC(m.HWnd);
Graphics gra = Graphics.FromHdc(hDCa);
buttonChecked = !buttonChecked;
}
break;
default:
base.WndProc(ref m);
break;
}
}

protected void PaintNC(System.IntPtr hWnd)
{
IntPtr hDC = GetWindowDC(hWnd);
Graphics g = Graphics.FromHdc(hDC);
if (buttonChecked)
ControlPaint.DrawButton(g, buttonX, buttonY, buttonSize, buttonSize,
ButtonState.Checked);
else
ControlPaint.DrawButton(g, buttonX, buttonY, buttonSize, buttonSize,
ButtonState.Normal);
g.Dispose();
ReleaseDC(hWnd, hDC);
}
...

The first problem I'm having is that is doesn't use the Window theme
anymore for the window. It uses the classic win98 style theme with the
gradient title bar.

The second problem is that when I click the button it doesn't refresh the
window so it doesn't show that it's pushed it. I have to minimise and then
maximise the window to see the changes. I tried using the invalidate()
method
but that only works in the client area of the window.

Any ideas?

Darrell
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top