Win32 Programming: How to create a simple GUI (Graphical User Interface) based application? (Part – 2)

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 “CreateWindow” function. But in this article we will learn creating 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 change the behavior of the window. Multiple styles are ORed (“|”). Important member lpfnWndProc is points to the address of the window procedure, which will process window messages. cbClsExtra and cbWndExtra members are used to indicate 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 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 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. Lets 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 default window procedure DefWindowProc. Later we will discuss about 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 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 which returns the module handle of the specified module. 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 is 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 address of WNDCLASSEX structure and registers the window class; upon success it returns 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 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 console window it is showing hexadecimal number “0×00”, which is the error value we are displaying after creation of our window; “0x00” means “No error”; that 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 Win32 API function, Sleep, to hold program execution for some time. The syntax of 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 Sleep function to suspend the program for 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.

Win32 - Sample window

Win32 – Sample window

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 about this in our next article.

**

Leave a Reply