Introduction
How can you make an application's own skin window without MFC extension UI libraries like BGCControlBar, Xtreme Toolkit and so on? This article uses pure Win32 API to find the answer.
Contents
For the beginner, I want to explain the window messages that should be processed. Anybody who wants to draw a window should process the window messages as below:
Message | Description |
WM_NCPAINT | The message is sent to a window when its frame must be painted. We should paint the window here. |
WM_NCCALCSIZE | The message is sent when the size and position of a window's client area must be calculated. By processing this message, an application can control the content of the window's client area when the size or position of the window changes. |
WM_NCACTIVATE | The message is sent to a window when its non-client area needs to be changed to indicate an active or inactive state. |
WM_NCHITTEST | The message is sent to a window when the cursor moves or when a mouse button is pressed or released. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is sent to the window that has captured the mouse. |
WM_NCLBUTTONUP<br />WM_NCLBUTTONDOWN<br />WM_NCLBUTTONDBLCLK<br />WM_NCRBUTTONUP<br />WM_NCRBUTTONDOWN<br />WM_NCMOUSEMOVE | The message is posted when the user releases the left mouse button while the cursor is within the non-client area of the window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted. |
WM_GETMINMAXINFO | The message is sent to a window when the size or position of the window is about to change. An application can use this message to override the window's default maximized size and position, or its default minimum or maximum tracking size. |
WM_ACTIVATE | The message is sent to both the window being activated and the window being deactivated. If the windows use the same input queue, the message is sent synchronously. First it is sent to the window procedure of the top-level window being deactivated and then it is sent to the window procedure of the top-level window being activated. If the windows use different input queues, the message is sent asynchronously, so the window is activated immediately. |
We should create a class named SkinWindow
that takes responsibility for painting the window. The class SkinWindow
defines some functions to process the special window's message.
Function | Description |
OnNcPaint | Process message WM_NCPAINT |
OnNcActive | Process message WM_NCACTIVATE |
OnNcCalcSize | Process message WM_NCCALCSIZE |
OnNcHitTest | Process message WM_NCHITTEST |
OnNcLButtonUp | Process message WM_NCLBUTTONUP |
OnNcLButtonDown | Process message WM_NCLBUTTONDOWN |
OnNcLButtonDblClk | Process message WM_NCLBUTTONDBLCLK |
OnNcMouseMove | Process message WM_NCMOUSEMOVE |
OnNcRButtonUp | Process message WM_NCRBUTTONUP |
OnNcRButtonDown | Process message WM_NCRBUTTONDOWN |
OnSize | Process message WM_SIZE |
OnSizing | Process message WM_SIZING |
OnActive | Process message WM_ACTIVE |
OnWindowPosChanging | Process message WM_WINDOWPOSCHANGING |
OnGetMinMaxInfo | Process message WM_GETMINMAXINFO |
OnSetText | Process message WM_SETTEXT |
OnSysCommand | Process message WM_SYSCOMMAND |
Firstly, we create a new Win32 application that includes SkinWindow
in its project.
#include "skinwindow.h"
Secondly, we should define a global variant in the main CPP file.
CSkinWindow SkinWin;
Thirdly, we load the skin from resource at the function InitInstance
.
SkinWin.Load(hInstance, hWnd);
Last, we should add some code in the function WndProc
to process the special window's messages.
if( SkinWin.IsHandledMessage( message ) )
return SkinWin.WndProc( hWnd, message, wParam, lParam );
When you size or drag and move a window as fast as you can, the monitor will flash and the window will take up more CPU percent. I've tried many approaches, but the problem persists. Is there anyone who can resolve it? The problem's picture is like below.
Additional Notes
This is by no means a finished product! This is my first attempt at writing a terribly complicated Win32 application library. I want to tell a beginner how to skin a window using pure Win32 API without MFC and give the beginner some hints to comprehensive window messages. I wanted something similar to SkinWindow
in functionality, but without the overhead of MFC. There will be bugs and errors! I hope that you find this code useful. If you have any improvements/suggestions, comments/flames or questions please post them here.
History
- 14 September, 2007 -- Original version posted