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);
}
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>
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);
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)
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";
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);
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
);
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;
}
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);
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);
}
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);
}
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 (1)
actually copying and paste this code I get the following errors:
23:58:02 **** Incremental Build of configuration Debug for project Prog1 ****
Info: Internal Builder is used for build
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o Main.o "..\Main.cpp"
..\Main.cpp: In function 'int wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)':
..\Main.cpp:12:24: error: cannot convert 'const wchar_t [22]' to 'LPCSTR {aka const char*}' in assignment
wc.lpszClassName = CLASS_NAME;
^~~~~
~..\Main.cpp:26:5: error: cannot convert 'const wchar_t*' to 'LPCSTR {aka const char*}' for argument '2' to 'HWND__* CreateWindowExA(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID)'
);
^
23:58:02 Build Failed. 2 errors, 0 warnings. (took 285ms)