As you may recall, creating a simple hello, world application in the C programming language for a textual command line environment like MS-DOS (or the Windows Command Prompt) is quick, easy, and readable, even for non-programmers. It looks like so.
#include <stdio.h>
main()
{
printf("hello, world\n");
}
But as you may also recall, creating even a basic Windows application using the C programming language was both expensive—you needed Microsoft C (or compatible) and the Windows Software Development Kit, both of which cost several hundreds dollars—and difficult. Windows applications didn’t work like MS-DOS applications, as they needed to coexist with other applications and windows in a multitasking GUI-based environment. The benefits of creating applications for this environment were many. But so, too, were the complexities.
Previously, I described the basic structure of a Windows application in simple terms: The developer needed to define and then create at least one window and then create a message loop that picked out the messages—mouse clicks, button presses, application termination, and so on—to which it would reply. At a high level, that really is all there is too it. But the “details,” as Windows programming guru Charles Petzold described the remainder of the task, were quite formidable, even for experienced developers.
Before getting to that, let me introduce a quick cheat: As Petzold explains in Programming Windows 5th edition—aimed at Windows 98, NT 4.0, and Windows 2000, and the last edition of the book to cover “classical” Windows application development using the Windows API—you can approximate the simplicity of the C-based hello, world command line application in Windows by bypassing the messiness of registering a window class, creating the window, and then running a message loop. Instead, you simply open a Message Box that displays the text Hello, Windows.
Petzold’s version from 1999 looks like so.
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
MessageBox (NULL, TEXT("Hello, Windows 98!"), TEXT("HelloMsg"), 0);
}
Bringing this code into the 21st century was straightforward. I created a new project in Visual Studio 2019 Community using the Windows Desktop Application project type and the C++ language.

This project type creates what today is considered a barebones desktop application with a simple menu, a custom icon, and an About box.

But it also requires a lot of code. So, I deleted all of the code and replaced it with the modern version of Petzold’s little cheat, which was unique to the 5th edition of Programming Windows. It looks like so:
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
{
MessageBoxExW (NULL, TEXT("Hello, Windows"), TEXT("Hello, Windows"), 0, NULL);
}
Like the original hello, world, this should be mostly readable even by non-programmers. And as you should expect, it looks like so when run:

There’s not much to describe here, beyond the fact that MessageBoxExW is a more modern version of the MessageBox function that Petzold used a decade ago (and it has one extra parameter, which I’ve essentially ignored).
OK, that’s fun. But in the previous four editions of Programming Windows, Mr. Petzold laid out a truer representation of a very basic Windows application. As promised, this version always registered a windows class, created and displayed a primary application window based on that class, and then ran a message loop so that the window could respond to messages.
Rather than show you one of the old versions of this code, which didn’t vary all that much from edition to edition over the 17 years from the original publication to the 1995 4th edition (which targeted Windows 95), I will instead show you what I believe is the most minimal version possible using Visual Studio 2019, C++, and the latest version of the Windows API at the time of this writing in mid-2019. This is based on a Microsoft walkthrough on the web that I believe was created for Windows Vista and then kept updated over time.
And yeah, it’s pretty hairy.
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("DesktopApp");
static TCHAR szTitle[] = _T("Hello, Windows");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// Define and register the window class
WNDCLASSEX windowClass;
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = szWindowClass;
windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&windowClass))
{
MessageBox(NULL, _T("Call to RegisterClassEx failed!"),
_T("Hello, Windows"), NULL);
return 1;
}
hInst = hInstance;
// Create the application window
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 300, NULL,
NULL, hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL, _T("Call to CreateWindow failed!"),
_T("Hello, Windows"), NULL);
return 1;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Run the message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// The window procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, Windows");
// loop that only handles the messages you wish to respond to
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
And what do you get after all that work? This sad little window displaying non-styled text.

Unlike the earlier code examples, this one is basically unreadable to non-programmers and is probably mostly gibberish even to those who are programmers used to more modern languages and frameworks.
More to the point, that’s a lot of scaffolding for so little in output. But the issue becomes more acute when you consider the difficulty of laying out even a simple application’s user interface using only software code. Or a normal productivity application with multiple windows, toolbars, menus, and more. Over time, as applications became ever-more complex and Windows started supporting more advanced technologies like TrueType fonts, higher-resolution and then high-DPI displays, new form factors, and more, continuing with direct Windows API development just made less and less sense.
Microsoft addressed these needs over time in a variety of ways. The Microsoft Foundation Classes (MFC) provided a supposedly-thin object-oriented wrapper over the Windows APIs and supported the more modern and object-oriented C++ language. And Visual Basic provided beginners and advanced developers alike with their first taste of a true Rapid Application Development (RAD) environment with simple, drag-and-drop visual designers and point-and-click event handling.
I’ll look at both of these advances soon, as well as subsequent attempts to bring Windows and the developer environments that supported it into the 21st century. But before getting to that, I’ll wrap up the Windows API discussion with a quick look at how it evolved over the years.
More soon.
With technology shaping our everyday lives, how could we not dig deeper?
Thurrott Premium delivers an honest and thorough perspective about the technologies we use and rely on everyday. Discover deeper content as a Premium member.