Not entirely. The font size can still be changed independently of the DPI, and not everything should be scaled as a result. Things like dividing lines and padding probably shouldn't be scaled when the font size is increased.
You still need a distinct DIP value independent of scaled font size. So the value of 'dp' vs. 'sp' in Android terms, which it looks like Windows' now also has that distinction.
And yeah this is ignoring that things like the visual winforms tool in Visual Studio really just wanted to operate in fixed positions, and just getting things to work when the window was resized wasn't always intuitive or obvious. So even if the APIs were there, the ecosystem definitely didn't care about it and Microsoft's own tools definitely didn't help.
Fixed layouts is orthogonal to all that - so long as those fixed layouts are defined in DPI-independent units, they will scale just fine. FWIW in WinForms (and also Delphi VCL, where this originated) you'd normally use anchors to design layouts that scale when the window is resized. Granted, it's nowhere near as flexible as proper layout containers - which WinForms (2.0+) also has, and which the visual form designer also supports, although it can be a pain to work with them.
(This doesn't handle multi-monitor setups well, since font size would be the same for them all. But multiple monitors were not exactly common back then.)
WM_DPICHANGED is a late addition, yes, but it's only necessary for the apps to dynamically reflow if the user changes that setting. Before it showed up, you'd have to restart the app for it to register the new value - but that does not preclude DPI independence as such.
The real problem was that almost everything in Win32 outside of CreateDialog uses device pixels to position. You were supposed to use GetDialogBaseUnits and/or MapDialogRect manually to get the correct values, and very few apps did.
For another early example, Visual Basic (VB6, pre-.NET, so we're talking 1998) measured everything in twips.