As we discussed in our previous article, we can use pre-defined window class names (eg: BUTTON, STATIC, etc.) or our own window class names, when calling the “CreateWindow” function. But in this article, we will learn to create our own window class and use the same while creating our own window.
Step 1. In order to create or register our own window class, first, we need to fill up the WNDCLASSEX structure entries and call the “RegisterClassEx” Win32 API function to register our class.
Window class WNDCLASSEX structure is used to fill the class information. The structure looks like below: You can find this in “winuser.h” file:
typedef struct tagWNDCLASSEX { UINT cbSize; /* Win 3.x */ UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; /* Win 4.0 */ HICON hIconSm; } WNDCLASSEX;
Where cbSize
is the size of the WNDCLASSEX
structure. style
is window class style, and it changes the behavior of the window. Multiple styles are ORed (“|”). Important member lpfnWndProc
is pointed to the address of the window procedure, which will process window messages. cbClsExtra
and cbWndExtra
members are used to indicating the number of extra bytes to allocate following the window class and following the window instance respectively. hInstance
is a handle to an application instance where the window procedure of a class is defined. hIcon
is a handle to an icon resource. hCursor
is a handle-to-class cursor resource. hbrBackground
is a handle-to-class background brush used for painting the window background. lpszMenuName is the resource name of the class menu. hIconSm is a handle to the small icon. I am not going to provide an in-detail explanation about each of these members, here; maybe I can write a separate article on this.
Now we know each member of the WNDCLASSEX structure. Let’s define the structure for our application. The code looks like below:
WNDCLASSEX wc; char szClassName[256] = "SampleWindowClass"; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = (HINSTANCE) GetModuleHandle(NULL); wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszMenuName = NULL; wc.lpszClassName = szClassName; wc.hIconSm = NULL;
Here most of the entries are assigned to NULL or 0. That means some of these entries are optional; if we assign NULL means, Win32 automatically assigns default values to them.
- We set the member cbSize with sizeof(WNDCLASSEX) structure. This is an important step and it is required.
- style is the class style and it sets as CS_HREDRAW | CS_VREDRAW. That means, whenever the window is resized, it instructs to redraw the window.
- And another important member is lpfnWndProc. We need to set the address of the callback function which will process the window messages. For the time being, we will use the default window procedure DefWindowProc. Later we will discuss creating our own window procedure to process window messages.
- cbClsExtra and cbWndExtra are set to 0; because we are not going to allocate any extra bytes.
- hInstance is required to set with instance handle of the application where window procedure is defined. We are using DefWindowProc as our window procedure and this is defined in “User32.dll”. “User32.dll” will load into our application, hence we use GetModuleHandle(NULL) to get the application instance handle. Remember that we are using the main() function as an application entry point; if we use WinMain() as an application entry point, we can use WinMain’s “hInstance” argument here. GetModuleHandle is a Win32 API function that returns the module handle of the specified module. The name of the module must be specified through its argument; if we pass NULL means, it will return the current application handle. The syntax of this function looks like below:
HMODULE WINAPI GetModuleHandle(LPCTSTR lpModuleName);
Where lpModuleName is the name of the loaded module.
- hIcon is a handle to the application icon.
- hCursor is a handle to the mouse cursor.
- hbrBackground is a handle to the brush which will be used to fill the window background. We used pre-defined window color to paint background of our window.
- lpszMenuName is the menu name.
- lpszClassName is the class name.
- hIconSm is a handle to the small icon.
Step 2. We are ready with our window class information. Now we need to register this class information in order to create our window of type this window class. We use RegisterWindowEx Win32 API to register our window class. RegisterWindowEx API function takes the address of the WNDCLASSEX
structure and registers the window class; upon success, it returns a non-zero value, otherwise, it returns 0. Our function call looks like below:
ATOM atom = RegisterWindowEx(&wc);
Step 3. Now we will create our own window with the registered window class. The statement looks like below:
HWND hWnd = CreateWindow("SampleWindowClass", "My first GUI window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, NULL, NULL, NULL, NULL);
Step 4. We need to recompile our program “sample.cpp”. Let’s recompile it:
cl sample.cpp /link user32.lib
Step 5. Now it’s time to test our application. Run our application from the command prompt.
Once runs it, observe that nothing was shown on the screen. Again our application window is not displayed. What went wrong? But on the console window, it is showing the hexadecimal number “0×00”, which is the error value we are displaying after the creation of our window; “0x00” means “No error”; which means our window got created successfully. But why it is not visible to us?
Step 6. It seems, when we run our program, our new window is displaying and immediately closing. If we stop our program to quit immediately, we can able to see our window. But is it possible to stop our program to quit immediately? Yes. We can use the Win32 API function, Sleep, to hold program execution for some time. The syntax of the Sleep Win32 API function looks like below:
VOID WINAPI Sleep(DWORD dwMilliseconds);
It takes dwMilliseconds as an argument and suspends the program execution (actually it suspends the execution of the current Thread.) until the time-out interval (mentioned through dwMilliseconds) elapses.
Let’s modify our code to place the Sleep function to suspend the program for a few seconds (10 seconds). After making these changes, our code looks like below:
// sample.cpp #include <windows.h> #include <stdio.h> int main() { WNDCLASSEX wc; char szClassName[256] = "SampleWindowClass"; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = (HINSTANCE) GetModuleHandle(NULL); wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszMenuName = NULL; wc.lpszClassName = szClassName; wc.hIconSm = NULL; ATOM atom = RegisterClassEx(&wc); if ( atom == 0 ) return 0; HWND hWnd = CreateWindow(szClassName, "My first GUI window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 400, 400, NULL, NULL, NULL, NULL); if ( hWnd != NULL ) { Sleep(10000); } return 0; }
Step 7. Again re-compile our program and run it. Observe that, now we will be able to see our window. As we mentioned in above step, this window will disappear after 10 seconds; the program terminates.
Why our window wasn’t displayed earlier? Because there was no user interaction code added into our program; hence the window was immediately closed. Then, how to add user interaction code to our application? Let’s discuss this in our next article.
**
One thought on “Win32 Programming – Register the window class”