DEV Community

Cover image for Introduction to Windows GUI Programming with C++: Building Your First Window
Utkarsh Yadav
Utkarsh Yadav

Posted on

Introduction to Windows GUI Programming with C++: Building Your First Window

Windows GUI programming allows developers to create interactive and user-friendly applications for the Windows operating system. In this article, we will explore the basics of Windows GUI programming using C++ and the Win32 API. We will walk through the process of building a simple "Hello, World!" application with a graphical user interface (GUI) to help you get started with Windows GUI programming.

Prerequisites:

Before diving into Windows GUI programming, make sure you have a basic understanding of C++ programming concepts. Familiarity with functions, variables, control flow, and the C++ syntax will be beneficial. Additionally, a Windows development environment, such as Visual Studio or Code::Blocks with MinGW, will be required to compile and run the code examples.

Setting Up the Project:

To begin, create a new C++ project in your preferred development environment. Ensure that you have the necessary tools and libraries configured to build Windows applications. For example, if you're using Code::Blocks with MinGW, ensure that the appropriate compiler and linker settings are in place.

Creating a Basic Window:

Let's start by creating a basic window for our "Hello, World!" application. Open a new C++ source file and enter the following code:

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    const wchar_t CLASS_NAME[] = L"HelloWorldWindowClass";

    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,
        CLASS_NAME,
        L"Hello, World!",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (hwnd == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
            EndPaint(hwnd, &ps);
        }
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Enter fullscreen mode Exit fullscreen mode

Understanding the Code:

Now, let's break down the code and understand how it creates a basic window for our "Hello, World!" application.

#include <windows.h>
Enter fullscreen mode Exit fullscreen mode

This line includes the necessary header file <windows.h>, which provides access to the Windows API functions, constants, and data types required for creating and managing Windows applications.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Enter fullscreen mode Exit fullscreen mode

A forward declaration of the WindowProc function is provided. This function serves as the window procedure that processes messages sent to the application's window.

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmd

Line, int nCmdShow)
Enter fullscreen mode Exit fullscreen mode

The wWinMain function is the entry point for the Windows application, replacing the standard main function. It takes several parameters:

  • hInstance: Represents the handle to the application instance.
  • HINSTANCE (unused in this code): Represents the previous instance handle.
  • PWSTR pCmdLine: Pointer to a null-terminated Unicode string that contains the command-line arguments.
  • nCmdShow: Specifies how the window should be shown, such as maximizing, minimizing, or normal.
const wchar_t CLASS_NAME[] = L"HelloWorldWindowClass";
Enter fullscreen mode Exit fullscreen mode

A window class name is defined as a null-terminated Unicode string. This name will be used to register the window class.

WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);
Enter fullscreen mode Exit fullscreen mode

A WNDCLASS structure is created and initialized. It specifies the window class attributes, including the window procedure (WindowProc), the application instance handle (hInstance), and the class name (CLASS_NAME). The window class is then registered using RegisterClass to make it available for creating windows.

HWND hwnd = CreateWindowEx(
    0,
    CLASS_NAME,
    L"Hello, World!",
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    NULL,
    NULL,
    hInstance,
    NULL
);
Enter fullscreen mode Exit fullscreen mode

The CreateWindowEx function creates the main application window. It takes parameters such as window styles, class name, window text, window size, and other attributes. In this code, we use the CLASS_NAME as the class name, "Hello, World!" as the window text, and WS_OVERLAPPEDWINDOW as the window style. The CW_USEDEFAULT parameters are used to set the default size and position of the window.

if (hwnd == NULL)
{
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

After creating the window, we check if the creation was successful. If the hwnd variable is NULL, it indicates an error, and the program returns 0.

ShowWindow(hwnd, nCmdShow);
Enter fullscreen mode Exit fullscreen mode

The ShowWindow function displays the window using the specified nCmdShow parameter, which determines how the window is initially shown (e.g., maximized, minimized, or normal).

MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
Enter fullscreen mode Exit fullscreen mode

The message loop processes messages sent to the window, such as user input, window resizing, or system events. The GetMessage function retrieves messages from the application's message queue. The retrieved message is then translated using TranslateMessage, which converts keyboard input into character messages, and dispatches the message to the WindowProc function using DispatchMessage.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
            EndPaint(hwnd, &ps);
        }
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Enter fullscreen mode Exit fullscreen mode

The WindowProc function is the window procedure that handles various window messages sent to the application's window. In this code, two message cases are handled: WM_DESTROY and WM_PAINT. When the window receives the WM_DESTROY message, it posts a quit message to the message queue using PostQuitMessage, signaling the termination of the application. The WM_PAINT message is responsible for painting the window's client area. In this example, it fills the window with the COLOR_WINDOW system color.

In this article, we introduced the basics of Windows GUI programming using C++ and the Win32 API. We walked through the process of creating a basic "Hello, World!" application with a graphical user interface. Understanding the concepts of registering a window class, creating a window, handling window messages, and implementing a window procedure are essential for building more complex and interactive Windows applications. With the knowledge gained from this article, you can start exploring and building your own Windows GUI applications using C++.Peace!

Top comments (0)