
TheForger's Win32 API Programming Tutorial - userbinator
http://www.winprog.org/tutorial/
======
wirrbel
My first job out of university was in a company that developed a GUI
appication based on the Win32 C API. In fact, the product has been on the
market for so long, that it's code had been a Win16 application in the past
and pre-dated Win 3.1 (It is a product for a niche market, and had been the
first Windows program on the market there, with all other software being MS-
DOS Applications).

So, I came from university, had written Software during my master thesis with
Qt, had some exposure to Gtk on my home PC a few years before, and I faced
this obscure Win32 API, which looks ugly, appaling, antiquated and plainly
awful.

But: Development was actually quite pleasant, and, while it didn't offer the
flexibility of full-blown object oriented libraries like Gtk or Qt, it was
amazingly good at getting stuff done. I wouldn't start a new project in it of
course and it seems Microsoft has pretty much abandoned the API. But, I have
to admit that I can see how it served Microsoft and its developer community
well for a few years. In fact, a lot of things in there where quite thoughtful
and I can still appreciate the non-bloaty way of doing things, if I see how
many processes and memory an electron app uses that doesn't do much more than
what a simple Win32 program does.

~~~
bni
"Microsoft has pretty much abandoned the API"

No they havent. Everything else in Windows land is just built on top of it.

I also made some Win32 development at one point. The programs made using only
Win32 have a very snappy and light weight feel to them that is very nice. It
is fairly low level and more for the machine than for humans. But I doubt you
can have both of these things.

~~~
userbinator
_No they havent. Everything else in Windows land is just built on top of it._

There were even some articles recently about that:

[https://news.ycombinator.com/item?id=19883351](https://news.ycombinator.com/item?id=19883351)

[https://news.ycombinator.com/item?id=19873198](https://news.ycombinator.com/item?id=19873198)

I started with a bit of Win16 and then moved to Win32, and don't really see
why it gets a lot of hate; it's not perfect, but it looks like it does exactly
what it was meant to do, and does it well. Perhaps it's because all of the
tiny and fast applications I've used in the past were pure Win32. You can do a
lot with it in only a few KB or tens of KB. In contrast, I don't find all the
other multi-megabyte UI frameworks appealing.

~~~
pcwalton
> I started with a bit of Win16 and then moved to Win32, and don't really see
> why it gets a lot of hate; it's not perfect, but it looks like it does
> exactly what it was meant to do, and does it well.

From a birds' eye view: Because it's just not productive to write apps without
some type of modularity, and the WndProc abstraction encourages enormous
monster functions that do everything. There's a reason why all UI frameworks
have some kind of modular paradigm, whether it's object-oriented or functional
reactive or what have you.

More specifically: A lot of the core APIs are just bad. RegisterWindowEx has a
struct with a dozen random fields, and CreateWindowEx has a ton of confusing
random parameters. For example, why do you have to specify a menu when you're
creating a button? Why is dwExStyle the first parameter and dwStyle is the
fourth? Why do you have to specify a cursor explicitly instead of just having
a function that sets it if you want a non-default one? It's possible to make a
low-level C API that's actually reasonably pleasant to use, as in GTK+. Win32
is just a mess.

~~~
badsectoracula
I have worked with both and i find Gtk+'s C API to be very bad actually, much
worse than Win32. Sure, it looks more consistent but that doesn't help when
what you want to do is done in a hair-pulling way. It is also much more
verbose, though it hides that because it is overall a higher level API than
Win32.

The issues you mentioned do exist but they are just minor nitpicks - at the
end of the day it doesn't matter at all if the dwExStyle parameter is at the
first, fourth or at the last (my guess was that is first to allow for a quick
textual search and replace in code to "upgrade" from "CreateWindow(..." to
"CreateWindowEx(0, ..."). This is the sort of stuff that will never cause any
sort of issue in practice.

Also there are no confusing random parameters in CreateWindow if you actually
read the documentation. The menu parameter for a button isn't used for a menu
but for an identifier that allows you to distinguish that button from other
controls in the window.

Finally your winproc's switch can actually call dedicated functions. You can
even write a couple of macros that do that for you so you do something like

    
    
        static LRESULT HandlePaint(HWND hWnd, WPARAM wParam, LPARAM lParam);
        static LRESULT HandleSize(HWND hWnd, WPARAM wParam, LPARAM lParam);
    
        BEGIN_WINPROC(MyWinProc)
        ON_WINPROC_MESSAGE(WM_PAINT, HandlePaint)
        ON_WINPROC_MESSAGE(WM_SIZE, HandleSize)
        END_WINPROC()
    

which is pretty much the same as what you'd do in other toolkits with setting
up event handles such as

    
    
        gtk_signal_connect(GTK_OBJECT(widget), "expose_event", (GtkSignalFunc)handle_expose, NULL);
        gtk_signal_connect(GTK_OBJECT(widget), "configure_event", (GtkSignalFunc)handle_configure, NULL);
    

(or your favorite toolkit's equivalent)

~~~
stelonix
Exactly this. As a Windows API/GDI developer, I used to loathe the WndProc
way, but after looking at how Qt and Gtk do things, I really really miss it;
specially considering the aforementioned libraries requires megabytes of space
while a simple winapi program might take a couple dozen kilobytes.

What I dislike about Qt is that it's a C++ only library with no proper way to
use it in C. And Gtk imposes a convoluted object oriented C library you should
learn and the usual tried & tested RAD point & click to get forms done is way
more complicated than it should be, vis a vis the MSVC form builder, the way
.NET does it or hell, even VB6. In hindsight, Windows API/GDI was great.

~~~
Crinus
FWIW Windows - or at least the HWND parts - is also an object oriented API, it
is just closer to something like Smalltalk (which i guess was more popular at
the time) than C++. You still define a class with a message handler on it,
create instances of this class and can create subclasses. Windows are really
supposed to communicate with the outside world via messages and some Win32
calls are really just wrappers for SendMessage.

GUIs tend to fit perfectly with object oriented systems, so it makes sense for
a GUI library for a non-OOP language to need to "invent" one. I think one
failing of the Windows API was that they made this only for visual windows
instead of creating a more generic "HOBJ" object system with message passing
that the GUI bits would be implemented on and other system and user APIs would
also be able to use.

Though on the other hand Windows event-driven message passing was already a
culture shock to most programmers at the time and this could make things even
harder :-P

~~~
stelonix
What I like about Windows API when compared to GTK is exactly that: the
OO/class system is kept at a minimum and is limited to the handling of the
widget tree.

------
ovi256
This is strictly about the win32 GUI API.

There are other win32 APIs that are quite interesting:

* the networking API (native proactor servers, something that Linux doesn't have yet AFAIK)

* the security and process API, which I had the pleasure to explore recently, in order to contribute to an open source server that launches a single user server for a connected user, under the user's profile. The CreateProcessAsUser function and its interactions with user authorization tokens is quite something.

~~~
Rerarom
Also, there aren't many books about those (compared to e.g. books about the
*nix API). I only know of Hart's Windows System Programming.

~~~
voidpointer
You don't need many books on it. There's Petzold.

~~~
smush
Programming Windows 5th Edition by Charles Petzold, still commands a price on
eBay for its Win32-centric program development strategy. IIRC 6th edition used
C# .NET and 7th and 8th went all in on UWP.

~~~
SyneRyder
Just noticed that the 5th Edition is still available on Kindle (at least on
Amazon Australia) and is a lot cheaper than I expected it to be. The hardcover
edition is still very expensive there though.

------
russtrotter
I cut my teeth on making the jump from turbo pascal programs to GUI via the
Win32 API. Its "rawness" felt fun, i.e. slinging around "long" pointers to
stuff and big event handling switch statement state machines. As long as you
didn't misbehave in the message loop, you could just kinda tinker endlessly.
As both the UI evolved to many more complicated controls and the toolset was
getting more abstract, I'd always find myself asking "dangit! i wish i could
just get the UUID for the control that does the fizzywizzybizbang control that
i see in Excel here!" Maybe that mindset is akin to a modern UI developer
buried in quirksmode.org and their browser console debugger.

------
tasty_freeze
I wrote an emulator for an old 8080 microcomputer in 1999 or so using the
Win32 API. First I bought the Petzold book, but as my program grew there were
still a lot of API issues that Petzold simply couldn't fit into a book of that
already impressive size. Then I got a "Win32 API Bible" type of book, then
another from a different author, then I collected the multi-volume official
win32 api books from microsoft, ..., and ended up with more than two linear
feet of books.

And yet development was still painful. Sometimes I would want to add a feature
and I'd be amazed that in 30 minutes it was done, but far more often there
would be something that didn't work and I'd literally spend two weeks of free
time changing the order of state setting calls, or setting state that the
books didn't say needed to be set but I had seen other source code do it,
reading other program source, searching online, asking in forums...

The last release was in 2005. I'd like to work on it more, but there is no way
I'm ever going back to that codebase.

------
efdee
Ah, WinProg. The chatroom that built the world. [0] Good times, huhu.

[0] [https://www.wired.com/2005/11/chat-room-that-built-the-
world...](https://www.wired.com/2005/11/chat-room-that-built-the-world/)

~~~
markus_zhang
Is it still active? Actually I followed the link to winprog so I guess it's
still active.

~~~
GarMan
The irc channel is dead. But most of us mentioned in that article are still in
another irc channel together and talk very frequently.

~~~
markus_zhang
Oh I see, thanks, no wonder I couldn't find anything on Winprog. Is it
private? Can I join?

~~~
efdee
Just #winprog on EFnet. Not sure how active it still is nowadays.

~~~
markus_zhang
Oh thanks will give it a try.

------
maxpert
Aaaaah the memory of making the an efficient self extracting archive. What is
brilliant about the idea is that even to this very day many "new ideas" live
around same event loop idea.

~~~
rantwasp
hahahah. React? :)

~~~
mschaef
Funny you mention that, but one of the better pieces of MFC related advice I
read was to have a single central location for computing UI element states. It
did feel a lot like React does these days (albeit with less sophistication in
the underlying 'DOM model' back then, and nothing like React's differencing
stuff.)

[http://www.flounder.com/controls.htm](http://www.flounder.com/controls.htm)

To me at least, if you change the terms in that article, it looks a lot like
the arguments in favor of moving away from ad hoc jQuery spaghetti and to
React's single global rendering pass.

------
DarmokJalad1701
Nice! I learned programming using "Iczelion's Win32ASM tutorials" (archived
here:
[http://www.interq.or.jp/chubu/r6/masm32/masm006.html](http://www.interq.or.jp/chubu/r6/masm32/masm006.html)
). Same API, but in assembler. The terminology and variable names look _very_
familiar

------
pjc50
Ah, the classic approach from WinProc() upwards. While I think it might be
useful to work through this once, since then you understand what a message
loop is and how it dispatches to controls, but for almost all practical
purposes if you want to build a classic app it's easier to do it in C++ with
MFC/ATL. Or even C#/Winforms.

I note this version uses LPSTR rather than LPTSTR; perhaps it predates the
UNICODE fiasco and the brief window where UCS-2 seemed like a good idea.

~~~
Crinus
Note that if you decide to use MFC you still _need_ to know Win32. A common
misconception and source of frustration about MFC is that it is a layer over
Win32 or that it somehow replaces it, which is not the case and if you (royal
you here) expect that you'll be disappointed. MFC is a helper framework build
with Win32 and C++ to ease some bits of making a Windows application, but even
for the most basic stuff you are still dealing with Win32. It isn't a "Win32"
or "MFC" situation, it is a "just Win32" or "Win32 and MFC" situation. If you
don't like Win32 or feel it is too hard, chances are MFC wont change your
opinion either (though you can like Win32 and dislike MFC - after all it has
been left to rot).

------
mckinney
Ah the Win32 API. Oddly, I learned quite a lot of object oriented fundamentals
doing C++ Win32 programming indirectly using Paul DiLascia's excellent book
"Windows++"[1]. One of the few 90s era programming books I still have.

[1][https://web.archive.org/web/20090606220454/http://www.dilasc...](https://web.archive.org/web/20090606220454/http://www.dilascia.com/wpp.htm)

------
voldacar
I'm not much of a windows user so sorry if it's a dumb question, but don't
newer UI libraries like UWP and WinUI just act as wrappers around Win32
functions?

Like if I wrote a UWP/WinUI/etc program and disassembled it, wouldn't it just
call Win32 functions in some system dll to do things like create windows,
receive messages etc?

~~~
zerr
Not sure about others, but e.g. WinForms is a wrapper for Win32 controls. WPF
has its own rendering.

------
bluedino
Win32 was complicated. Lots of cleanup work. No forced structure. Combine that
with having to use C, and the amount of low-skilled porogrammers out there,
you could really see why there was so much terrible Windows software out
there.

Learning Windows programming gave me so much insight to programs crashing and
all the graphical bugs, beause I had caused them all in my own porograms
before.

------
dotandimet
My favorite Win32 tutorial is by Bartosz Milewski, I found it as a series of
posts on his CodeCoop website
([https://web.archive.org/web/20110129015721/http://www.codeco...](https://web.archive.org/web/20110129015721/http://www.codecoop.com/)
), that were later incorporated into his book "C++ in Action" (also findable
online).

He uses C++ to wrap every resource acquisition in a constructor and every
release of a resource in the corresponding destructor, so that by allocating
new objects on the stack you avoid a whole swath of memory management errors.
This was my first encounter with RAII (not sure if he calls it that), and it
seems a particularly elegant way to write C++ and to make the raw Win32 C API
a lot less scary.

~~~
contextfree
Windows development team now has an internal C++ library used inside Windows
source code to do similar things, which was recently made public and open
source on GitHub:
[https://github.com/Microsoft/wil/wiki](https://github.com/Microsoft/wil/wiki)

------
axilmar
Win32, especially when it comes to GUI programming, is one of the worst APIs
out there.

MFC is also quite bad because of huge abstraction leakages; it fills like
Win32 with bolted on classes.

It seems like Win32 happened a bit by accident, a bit by overengineering and a
bit by Microsoft's attempt to lock everyone to their 'special' development
environments, which did not include C as a conscious choice by Microsoft.

~~~
jussij
The design of Win32 is incredibly close to the design of Win16 and since Win16
dates back to early 90's you need to comparing it to GUI programming layers of
that same era.

So the question is, back then was there any better GUI programming layers?

And the answer is yes, there was actually an API that was better and it was
called OS/2.

At that time Microsoft was in a partnership with IBM to develop OS/2.

However, when the partnership fell apart, Microsoft just took big chunks of
that OS/2 API and created a sub par version and called it the Windows API.

~~~
Crinus
I'm pretty sure it is the other way around, the OS/2 GUI (Presentation
Manager) API is a cleaned up version of the Windows 2.x API.

~~~
mschaef
Sort of. IBM really wanted to ensure that OS/2 had an imaging model that was
compatible with what it used in some of its larger computers. This resulted in
a bunch of differences between OS/2's imaging model and GDI. (Different window
origin coordinates, etc.)

In a more Microsoft-centric world, I'm pretty sure the OS/2 API would've been
exactly as you describe it and almost strictly in parallel with Windows. In
fact, Microsoft did exactly this with Win32s (and Windows 95) In their
relationship with Windows NT (which was once known as OS/2 NT or OS/2 3.0).

The same compiled binary could run on both the 'entry level' OS and the
'server level' OS, with a bit of care taken in the way the API was used.

~~~
scottlu2
Once Microsoft agreed to the graphics api change, it was open season to
redesign the window manager api because backward compat was moot at that
point. The OS/2 window manager api was designed by the same team who designed
the win16 window manager apis. There were improvements and a bunch of api
change but at the 10K foot level the model was the same - input loop, window
messages, and window procs.

~~~
mschaef
> at the 10K foot level the model was the same - input loop, window messages,
> and window procs.

That's a fairly broad description, isn't it? At least I have a hard time
coming up with windowing API models that don't fundamentally work that way at
the lower levels. (About the only exception think of is a text-based library
that shipped with Microsoft BASIC 7.0, and that was mainly because the
language didn't support any of the abstractions needed for callbacks.)

~~~
scottlu2
That's a fair point, I'll restate: the level of abstraction that developers
were exposed to was 95% the same. Exposed message loops, window classes,
window messages, unpacking window params, post and send message semantics,
painting, single cooperative input queue (window app hanging would hang all
apps), and other equivalences.

------
GnarfGnarf
Why on earth would anyone want to learn Win32 in 2019? It's horribly
unproductive.

I've been doing Win32 (also called "Petzold-style") since 1995, and am pleased
to say I'm converting to Qt for multi-platform capability.

When I look at the dreck necessary to create a dialog box in Win32, and
compare to more modern frameworks, it's like milking a cow vs. buying milk at
the store. Sure, you're "into the fundamentals", but is that really how you
want to spend your time?

~~~
zmodem
> Why on earth would anyone want to learn Win32 in 2019?

Because it's the native API on the most common desktop OS?

~~~
dstaley
The Win32 API is on life-support. Microsoft will maintain backwards
compatibility for legacy apps of course, but learning Win32 for new
development doesn't seem like a good investment (unless, of course, you want
to get a job maintaining a legacy Win32 app).

~~~
badsectoracula
Anything that runs on the Windows desktop uses Win32 at some point in its
stack. If you work on anything that is close to Win32 then you may also need
to work with Win32 itself.

For example if you work on a game engine or toolset then you must know Win32 -
especially if you work on the tools, even if you are using a wrapper like
wxWidgets or Qt.

The only time where you can avoid Win32 is if you're using something that
completely abstracts away the entire system, like Java Swing or a web browser.

~~~
dstaley
It's a little bit more complicated. Sure, if you're doing low-level
programming I imagine you might run into the Win32 API, but if you're just
building typical desktop applications (particularly for newer devices like the
Surface Pro X or Surface Neo), you'll most likely want to use UWP. Usage of
Win32 for app development is only going to decrease overtime for typical
consumer applications. I'm sure businesses will continue building LOB apps in
WPF and WinForms until the heat-death of the universe, but there's also
businesses building apps in VB6 and you don't see many people recommending to
learn that.

