The fun part was making a C++ class that could build up an in-memory dialog template. You had to do it that way because it was dynamically sized based on the message you displayed and the buttons you needed. If you used the default colors, you might be able to tell they were different if you squinted but you wouldn't know which was mine and which was Microsoft's.
These days you can just use a TaskDialog, of course, and it's way more flexible than MessageBox. But it's fun to remember the old techniques.
With some of them it was dead easy and you can do it on window creation.
Others you had to hook it out by playing with the window params (SetWindowLong) and getting the underlying control and then changing it.
Some controls had their own bespoke way where you would send messages to the control then it would take care of it.
Some you would have to iterate over the control list that window controlled and change it.
In some cases it was just such a pain you were better off making your own custom control window that was just a mashup of other controls that you could control.
It was one part experimentation and one part reading the docs (if the control had it). Now if it was a built in windows control you were playing with. You had to take on the risk on windows version update the customization you did would break if you did non documented things.