It must have been difficult and frustrating to work as part of the Windows team back in those days.
You see all the wacky software that doesn't follow the rules properly, does whatever it wants, breaks things. And you have to figure out how Windows can accommodate all that software, keep it from breaking, and also prevent it from messing up a computer or undo the damage.
They did not have the option of saying "this app developer wrote shitty software, sucks to be them, not my problem."
I wonder how much of this problem was caused by lack of adequate documentation describing how an installer should behave, and how much was developers not reading that documentation and being content when it works on their machine.
> I wonder how much of this problem was caused by lack of adequate documentation describing how an installer should behave, and how much was developers not reading that documentation and being content when it works on their machine.
There is a third option: the developers knew the rules and chose to ignore them for some reason. A modern example of this is the Zig language’s decision to reverse engineer and use undocumented APIs in Windows in preference of using documented APIs.
> In addition to what @The-King-of-Toasters said, the worst case scenario is really mild: A new version of windows comes out, breaking ntdll compatibility. Zig project adds a fix to the std lib. Application developer recompiles their zig project from source, and ships an update to their users.
Uh so what if the application developer isn't around any more?
The fact that they consider the worst case to be one where the application is still actively supported and the developer is willing to put up with this nonsense is pretty surprising. Not sure how anyone could believe that.
My excitement for Zig dropped the longer they stayed at 0.x (and they really have meant 0.x with the breaking changes they were making). This decision from them completely killed it for me.
I understood not using the C Runtime and instead creating direct wrappers over the Win32 API, but going a level lower to APIs that are not guaranteed to be stable is nutty.
There were no rules in DOS, or r_x permissions like Unix.
The DOS kernel itself didn't really impose any structure on the filesystem. All that mattered was:
- The two files that comprised DOS itself (MSDOS.SYS, IO.SYS) had to be "inode" 0 and 1 on the disk in early versions,
- the kernel parsed \CONFIG.SYS on boot, and I think looked for \COMMAND.COM if you didn't specify a different shell with COMSPEC= in CONFIG.SYS. There were defaults if \CONFIG.SYS didn't exist, but of course all your DEVICE= stuff won't load and you'll probably not have a working mouse, CD-ROM, etc.
\AUTOEXEC.BAT was optional. That's it. Any other files could be anywhere else. I think the MS-DOS installer disk put files in C:\DOS by convention but that was just a convention. As long as COMMAND.COM was findable DOS would boot and be useable-and if you mucked something up you just grab your DOS boot floppy with A:\COMMAND.COM on it and fix it.
From what I recall most installers-if provided-made a directory in \ and put all their files there, mixing executables with read-write data. There was no central registry of programs or anything unless you were using a third party front-end.
Windows 3.x and 95 inherited the DOS legacy there.
> I think the MS-DOS installer disk put files in C:\DOS by convention but that was just a convention.
That assume that you where going to install the OS, which assumes that you had an hard drive :-). The original IBM PC didn't, and anyway MS-DOS didn't support folders until version 2.0.
On those old PCs you would boot your computer on a floppy drive with all the files on the root of a floppy, and execute your command there. There was not much to work with anyway, check the content of the boot floppy of MSDOS 1.0 [1].
And also, especially if you had a single floppy, you wouldn't even use it: to run your software you would boot a disk with a IO.SYS, MSDOS.SYS, COMMAND.COM and an AUTOEXEC.BAT that would start your favorite word processor (WordStar of course :-D ).
Yep I don't think the Microsoft installer was there until version 4 or 5. Around the time MS was making DOS more "user-friendly" with things like /LONGDESCRIPTIVESWITCHES, DOSKEY, MIRROR, UNDELETE and UNFORMAT. It looked like the blue text-mode Windows XP installer.
> I wonder how much of this problem was caused by lack of adequate documentation describing how an installer should behave, and how much was developers not reading that documentation and being content when it works on their machine.
It was mostly the latter. And when Windows broke, people would blame it on Microsoft, not on the software they installed. The same if the software broke. And you didn’t have online updates at the time that could retroactively add fixes. So Microsoft had to do everything they could to ensure broken software would still work, while also keeping Windows working, the best they could.
> So Microsoft had to do everything they could to ensure broken software would still work
I think they chose to do everything they could to keep it limping along. An alternative would've been a name-and-shame approach, like "This program crashed because the author made this mistake: [short description or code or whatever]", and leave them out to try until the devs stopped doing those dumb things. After a few years of pain, people would've gotten with the program, so to speak. Instead, they chose the path that put zero pressure on devs to write correctly-behaving software.
The thing is, Microsoft got its position of dominance exactly because they did that - and that was because by doing this, the users' programs kept working. Remember that users outnumber developers by far and the last thing Microsoft wanted was for people to not upgrade Windows because they broke their previously working programs.
This was even more important at a time when Microsoft had actual competition in the OS space and people weren't able to just go online and download updates.
Nobody said it was by accident. They had deals with PC manufacturers for decades where they sold licenses based on the number of PCs sold by the manufacturer regardless of if the PC used MSDOS or another OS (like DRDOS), making all other options more expensive unless the client asked for them.
But the important thing is that the clients pretty much never asked for other OSes because all of their software worked on MSDOS - and later Windows. People bought computers to run their software, so if the software they wanted to run needed MSDOS or Windows, they'd buy the machines that ran that OS.
And by extension, if the software they wanted to run wouldn't run on the next version of MSDOS or Windows, they wouldn't have a reason to upgrade MSDOS or Windows. But from a user's perspective MSDOS/Windows was the best choice because everything supported it.
Microsoft didn't rely on just backwards compatibility (especially since the idea of "backwards compatibility" relies on something to be compatible with in the first place) but it was an incredibly important aspect of their strategy.
> And what does the customer do if the vendor has discontinued it? Or charges for an upgrade? Or has gone out of business?
Those can all be filed under Not My Problem (as in, Microsoft's problem,) and safely ignored. On the other hand, when Highly Influential So-And-So upgrades from 3.1 to 95 or whatever, and Very Population Application v4.9.6 starts falling over, Microsoft gets the black eye whether they deserve it or not. The whole equation changes.
> After a few years of pain, people would've gotten with the program, so to speak.
Not necessarily. This was still very much the time in which choosing to stick with an old version which worked (e.g. Windows 3.1) wasn't uncommon.
Just look at how many people jumped from XP to 7 due to the network effect of "Vista sucks" and then multiply that by the fact that, at the time of 3.1->95, people had far fewer computer security concerns, if any.
Why would I buy a new version of Windows, if none of my existing software will work on it, so I have to buy new versions of everything? Sounds expensive.
Raymond Chen already discussed this. Microsoft wants to sell Windows. Windows exists to run software. If Windows doesn't run software, Microsoft doesn't make that sale.
If your business runs on some obscure piece of software for which updates are neither cheap or easy, you're not going to buy Windows if it doesn't run that software.
Name and shame doesn't work because the developer isn't part of the transaction.
One workaround Microsoft has done for use-after-free is detecting when an application is prone to this and using an allocator that doesn't actually free RAM immediately. It believe that lovely bit of fun is a function of "Heap Quarantine".
Yes, the real, can't say no world of system software is not what one might wish.
The biggest cause for this problem isn't lack of docs, but poor OS design. Like, why would you let apps change anything without restrictions to begin with? Of course, then you have to have some dumb hidden folder wasting space to restore the changes, and this "waste space for no good reason because we can't architect properly" is still a common issue
You're not wrong, but largely as a result of dubious architectural decisions made in the name of backwards compatibility and minimal hardware requirements, Microsoft sold 40 million copies of Windows 95 in its first year, compared to 300,000 copies of Windows NT 3.1.
Consider:
Windows 95 ran the vast majority of MS-DOS and Windows 3.1 applications with minimal performance loss, supported MS-DOS and Windows 3.x drivers for hardware that lacked 32-bit driver support, and ran acceptably on a 386 with as little as 4 MB RAM.
The properly architected Windows NT 3.1, released two years before Windows 95, had limited MS-DOS and Windows 3.1 application support, required NT-specific drivers for all hardware, and required 12 MB RAM to boot, 16 MB to do anything useful, and you really wanted a 486 for decent performance.
Now try a 3rd comment that actually connects to the design deficiency described in the article instead of a generic grievance about rearchitectrue that included a gazillion of changes
I agree. Why should the person who bought a computer be allowed to own it? Phone ecosystems got this the right way - the company that made the device owns it, and the person who bought it does not!
Don't speak in empty slogans, connect it to the article/comment!
Some app does some thing, then the OS reverts it! Where is "you" and "own" in this process? Do you own the "C:\Windows\SYSBCKUP" folder? Do you own the undo process?
Would your "ownership" rights increase if instead the OS didn't waste any space, but simply blocked downgrades of system components without user warning/intervention? Or had an even better process?
In the era of Windows 95, having a network connection was still a rarity.
Expecting modern systems to have package management and sandboxing mechanisms would have been 20 years ahead of their time.
One of the craziest Raymond Chen stories is one where a Windows API call would return a pointer to a data structure the OS had allocated for the operation. The programmers at Microsoft made the data structure bigger than they needed, for future expansion. But some third party devs noticed the extra space, and started to use it to store data for their program. Then when Windows tried to start using the extra space, those applications would crash.
Reasonable people can disagree on a lot of things in programming. But I still do not understand how one can consider writing to memory the OS owns to be ok. It's sheer professional malpractice to do that kind of thing. With stuff like that, I don't think that any amount of documentation would have helped. The issue was that those programmers simply did not care about anything except getting their own program working, and did whatever the most expedient method was to get there.
> But I still do not understand how one can consider writing to memory the OS owns to be ok.
Go to Vogons and look at all of the memory tricks people will use to get various games running on MS-DOS. This kind of juggling exactly which drivers to load, etc. is why Microsoft added the boot menu in MS-DOS 6.0 to CONFIG.SYS.
I'm not necessarily saying that this was the case here, but it smells like that to me.
Back then, many programmers originally learned their ropes in an 8-bit home computer era (or earlier), where it used to be completely normal and even necessary that you used whatever memory region you got away with.
For example, on the C64, you would get away with using the memory locations $02, $2A, $52, $FB to $FE, $02A7 to $02FF, and $0313 as scratch space for your own programs. Memory was incredibly scarce. I can’t blame programmers for sticking with their habits and for taking several years to unlearn and adjust their misconceptions about who owns what if they came from a home computer era where that pattern used to be the only way to get stuff done.
>I still do not understand how one can consider writing to memory the OS owns to be ok.
Things were different back then. People did a lot of hacky stuff to fit their programs into memory, because you were genuinely constrained by hardware limitations.
Not to mention, the idea of the OS owning the machine was not as well developed as it is today. Windows 3.11 was just another program, it didn't have special permissions like modern OSes, and you would routinely bypass it to talk to the hardware directly.
"Not to mention, the idea of the OS owning the machine "
I agree--back then when computers had <=4MB or RAM I would've called hogging unused memory for some selfish speculative future use "professional malpractice".
When an OS uses any memory that's otherwise unused as a file cache, which is instantly available if an application wants more memory, but isn't shown as "unused": "This OS is terrible, I have 16GB of RAM but all of it is being used!"
When an OS doesn't do this: "This OS is terrible, I bought all this RAM and the OS doesn't use it!"
> Things were different back then. People did a lot of hacky stuff to fit their programs into memory, because you were genuinely constrained by hardware limitations.
Are you going to tell them what "32-bit Clean" meant for Mac developers, or will we let them find out that particular horror movie for themselves?
TBH i think a more likely explanation is that they needed to somehow identify separate instances of that data structure and they thought to store some ID or something in it so that when they encountered it next they'd be able to do that without keeping copies of all the data in it and then comparing their data with the system's.
Or you desperately need to tag some system object and the system provides no legitimate means to do so. That can be invaluable when troubleshooting things, or even just understanding how things work when the system fails to document behavior or unreasonably conceals things.
I've been there and done it, and I offer no apologies. The platform preferred and the requirements demanded by The Powers That Be were not my fault.
Ask the Zig people, who just started relying on undocumented unstable Windows behaviour intentionally due to some kind of religious belief: https://codeberg.org/ziglang/zig/issues/31131
When I was a kid, I released a small GUI program online that I made with either VB6 or VB.NET. The program used the standard open-file dialog. When I created the installer for my program through VB's release wizard, there was a page where it pointed out that my program depended on a certain system library (because of the open-file dialog) and it asked me if I wanted to include that library in the installer. I think the default answer was yes, or maybe it wasn't but it sounded like an obvious thing to enable so I did it. Apparently this screwed over and broke open-file dialogs globally across Windows for everyone who wasn't on the same version of Windows as me. Whoops! It's too bad that VB had such a foot-gun in it, and that the article's workaround didn't save those users.
>Windows 95 worked around this by keeping a backup copy of commonly-overwritten files in a hidden C:\Windows\SYSBCKUP directory. Whenever an installer finished, Windows went and checked whether any of these commonly-overwritten files had indeed been overwritten.
This is truly unhinged. I wonder if running an installer under wine in win95 mode will do this.
Granted, but at the same time it's also resolutely pragmatic.
Apparently there was already lots of software out there which expected to be able to write new versions of system components. As well as buggy software that incidentally expected to be able to write old versions, because its developers ignored Microsoft's published best practices (not to mention common sense) and and didn't bother to do a version comparison first.
The choice was to break the old software, or let it think it succeeded then clean up after the mess it made. I'd bet they considered other alternatives (e.g. sandbox each piece of software with its own set of system libraries, or intercept and override DLL calls thus ignoring written files altogether) but those introduce more complexity and redirection with arguably little benefit. (I do wonder if the cleanup still happens if something like an unexpected reboot or power loss happens at exactly the wrong time).
Could the OS have been architected in a more robust fashion from the get-go? Of course.
Could they have simply forbidden software from downgrading system components? Sure, but it'd break installers and degrade the user experience.
Since the OS historically tolerated the broken behavior, they were kind of stuck continuing to tolerate it. One thing I learned leading groups of people is if you make a rule but don't enforce it, then it isn't much of a rule (at least not one you can rely on).
I would argue the deeper mistake was not providing more suitable tooling for developers to ensure the presence of compatible versions of shared libraries. This requires a bit of game theory up front; you want to always make the incorrect path frictiony and the correct one seamless.
There was (and still is) VerInstallFile, however this was introduced in Windows 3.1 and it is possible installers wanted to also support Windows 3.0 (since there wasn't much of a time gap between the two many programs tried to support both) so they didn't use it.
It is important to remember that Microsoft created some of this chaos to begin with. Other aspects can be attributed to "the industry didn't understand the value of $x or the right way to do $y at the time". And some of this is "nonsense you deal with when the internet and automatic updates is not yet a thing".
Why did programs overwrite system components? Because Microsoft regularly pushed updates with VC++ or Visual Studio and if you built your program with Microsoft's tools you often had to distribute the updated components for your program to work - especially the Visual C runtime and the Common Controls. This even started in the Win3.11 days when you had to update common controls to get the fancy new "3d" look. And sometimes a newer update broke older programs so installers would try to force the "correct" version to be installed... but there's no better option here. Don't do that and the program the user just installed is busted. Do it and you break something else. There was no auto-update or internet access so you had to make a guess at what the best option was and hope. Mix in general lack of knowledge, no forums or Stack Overflow to ask for help, and general incompetence and you end up with a lot of badly made installers doing absolute nonsense.
Why force everyone to share everything? Early on primarily for disk space and memory reasons. Early PCs could barely run a GUI so few hundred kilobytes to let programs have their own copy of common controls was a non-starter. There was no such thing as "just wait for everyone to upgrade" or "wait for WindowsUpdate to roll this feature out to everyone". By the early 2000s the biggest reason was because we hadn't realized that sharing is great in theory but often terrible in practice and a system to manage who gets what version of each library is critical. And we also later had the disk space and RAM to allow it.
But the biggest issue was probably Microsoft's refusal to provide a system installer. Later I assume antitrust concerns prevented them from doing more in this area. Installers did whatever because there were a bunch of little companies making installers and every developer just picked one and built all their packages with it. Often not updating their installer for years (possibly because it cost a lot of money).
Note: When I say "we" here that's doing a lot of heavy lifting. I think the Unix world understood the need for package managers and control of library versions earlier but even then the list of problems and the solutions to them in these areas varied a lot. Dependency management was far from a solved problem.
This is bog-standard boring stuff (when presented with a similar problem, Linux invented containers lol) - read some of his other posts to realize the extent Microsoft went to maintain backwards compatibility - some are insane, some no doubt led to security issues, but you have to respect the drive.
It’s not bog-standard. Containers are not equivalent to doing what is described in the article.
Containers are in fact redirecting writes so an installer script could not replace system libraries.
The equivalent would be a Linux distro having the assumption that installer scripts will overwrite /usr/lib/libopenssl.so.1 with its own version and just keeping a backup somewhere and copying it back after the script executes.
No OS that I know of does that because it’s unhinged and well on Linux it would probably break the system due to ABI compatibility.
If they had taken essentially the same approach as wine and functionally created a WINEPREFIX per application then it would not be unhinged.
edit: also to be clear, I respect their commitment to backwards compatibility which is what leads to these unhinged decisions. I thoroughly enjoy Raymond Chen’s dev blog because of how unhinged early windows was.
It's easy to forget in these discussions that Microsoft didn't have infinity resources available when writing Windows, and often the dodgy things apps were doing only became clear quite late in the project as app compatibility testing ramped up. Additionally, they had to work with the apps and history they had, they couldn't make apps work differently.
You say, oh, obviously you just should redirect writes to a shadow layer or something (and later Windows can do that), but at the time they faced the rather large problem that there is no formal concept of an installer or package in Windows. An installer is just an ordinary program and the OS has no app identity available. So, how do you know when to activate this redirection, and what is the key identifying the layer to which redirects happen, and how do you handle the case where some writes are upgrades and others are downgrades, etc, and how do you do all that in a short amount of time when shipping (meant literally in those days) will start in just a few months?
I mean it looks like they did try to redirect writes somehow. They probably tried more sane options until they arrived here.
>there is no formal concept of an installer or package in Windows.
this one is on them, I think package managers already existed - doesn’t seem like there was ever a blocker for windows to have a package manager but Microsoft never bothered until very recently
With hindsight sure, but I don't think any desktop operating systems had package managers in that era. macOS certainly didn't. NeXTStep had their .app bundle concept, but no legacy. And UNIX package managers were of no use - few of them properly supported third party packages distributed independently of the OS vendor, especially not ones that could upgrade the OS itself.
Windows 95 was not Windows NT and it still used the FAT32 file system, where it was not really possible to enforce access rights.
As TFA says:
You even had installers that took even more extreme measures and said, “Okay, fine, I can’t overwrite the file, so I’m going to reboot the system and then overwrite the file from a batch file, see if you can stop me.”
Well and the earliest versions of Windows 95 used FAT16 (specifically VFAT for support for LFNs or long file names). So enjoy those ridiculous cluster sizes if your hard disk even approached a gig or so.
If an installer expects to be able to overwrite a file and fails to do so, it might crash, leaving the user with a borked installation.
Of course you can blame the installer, but resolution of the problem might take a long time, or might never happen, depending on the willingness of the vendor to fix it.
> If . . . the replacement has a higher version number than the one in the SYSBCKUP directory, then the replacement was copied into the SYSBCKUP directory for safekeeping.
This as well. I know there are a million ways for a malicious installer to brick Win95, but a particularly funny one is hijacking the OS to perpetually rewrite its own system components back to compromised version number ∞ whenever another installer tries to clean things up.
Whats unhinged about a periodic integrity check? Doesn't seem much different than a startup/boot check. If you're talking about security, you've come to the wrong OS.
I find articles like this a good counter to the idea that typical software used to be better in the past (usually with an appeal to an idea that people were “real programmers” in those days and anything other than C as used in the 90s is a modern extravagance)
In my 25 years of using Windows I've grown so much disdain towards annoying, broken, slow installers that I started to instead extract them like zip archives, using various tools: 7-Zip, UniExtract, Observer plugin for Far Manager, sometimes even manual carving.
Most things just worked after being extracted like that. Some things needed a few registry entries, or regsvr32 some dll files.
The sad lesson is to be both proactive and reactive if you want a clean environment. Trust, verify, and stick around to clean up someone else's mess after the fact.
It doesn't say for certain, but assuming the version of this they settled on (restoring components after the installation finished) is what they shipped in the original version of Windows 95, then no, I don't think this could have caused hangs in the installer itself (unless Win95 misjudged whether the installer had completed or not and started the restore process early?).
No, most likely bad algorithms for dealing with registry stuff. The kind of thing that worked well on tester machines with small registry sizes and exploded in the real world.
> Some components addressed this problem by providing their own installer for the component, and telling installers, “You are not allowed to install these component file directly. Instead, you must run our custom installer.
This existed until Windows XP but with different name and behavior. Only from Vista, they added permissions to restrict user and third party programs to modify system files easily.
Windows, especially old versions, were beautifully pragmatic. Think about the things that would need to exist on an open-source OS to match this functionality. You'd need to:
1. Convince people to distribute programs via installers.
2. Provide some way that installers can tell the OS that they're an installer (and not invent 5 different ways to do this!)
3. Convince the creators of installers to actually use that function.
4. Convince library creators to maintain backward compatibility (big ask).
5. Convince people to not fork said libraries, creating ambiguous upgrade paths.
6. If there are multiple distros, convince them all to use the same backup/restore format for libraries (and not treat their own favorite libraries as "special")
They absolutely created 10 different ways to install software; they didn't really advertised they were an installer; the only backward compatible thing there are the MS libraries; there was no common backup/restore format.
Instead, the Unix people made a mechanism for random programs to use their own libraries and not touch the system one. In fact, Windows had one too, but most applications still decided they need to break the system.
One of the biggest pitfalls in understanding the world is interpreting everything as an absolute. If someone says "dogs have four legs", you might think "well, I saw a dog with three legs, so there's no value in the idea that dogs have four legs, and I'll conclude that if I see tracks from an animal that seems to have four legs, it's impossible to know if it's a dog or a giant centipede". It's a pernicious little quirk of our minds that we fall for this kind of thinking.
To wit. The idea that installers on Windows behaved the way I described is an interesting fact. The idea that a few installers did things in unusual ways is a much less interesting fact. Putting them on the same level robs you of the insight, and if this is a pattern then there are a lot of things you simply can't learn, because an exception could be found.
It must have been difficult and frustrating to work as part of the Windows team back in those days.
You see all the wacky software that doesn't follow the rules properly, does whatever it wants, breaks things. And you have to figure out how Windows can accommodate all that software, keep it from breaking, and also prevent it from messing up a computer or undo the damage.
They did not have the option of saying "this app developer wrote shitty software, sucks to be them, not my problem."
I wonder how much of this problem was caused by lack of adequate documentation describing how an installer should behave, and how much was developers not reading that documentation and being content when it works on their machine.
> I wonder how much of this problem was caused by lack of adequate documentation describing how an installer should behave, and how much was developers not reading that documentation and being content when it works on their machine.
There is a third option: the developers knew the rules and chose to ignore them for some reason. A modern example of this is the Zig language’s decision to reverse engineer and use undocumented APIs in Windows in preference of using documented APIs.
https://codeberg.org/ziglang/zig/issues/31131
This comment is pretty wild:
> In addition to what @The-King-of-Toasters said, the worst case scenario is really mild: A new version of windows comes out, breaking ntdll compatibility. Zig project adds a fix to the std lib. Application developer recompiles their zig project from source, and ships an update to their users.
Uh so what if the application developer isn't around any more?
The fact that they consider the worst case to be one where the application is still actively supported and the developer is willing to put up with this nonsense is pretty surprising. Not sure how anyone could believe that.
>ignore them for some reason
The reasons are clearly stated in the issue you have linked.
"As Zig has evolved, it has become a target to avoid calling Win32 APIs from kernel32.dll etc., instead using lower-level ones in ntdll.dll."
If we needed an example of why we should avoid using passive voice, this is it.
This sentence doesn't include examples of the passive voice.
Ha, you're absolutely right. The "has become a target" got me there. So glad, Zig wasn't targeted there.
The sentence that you quoted is more generic. The Zig issue is only one example of "some reason".
Wow! What a mind-bogglingly stupid idea. I will cancel my plans to learn Zig.
My excitement for Zig dropped the longer they stayed at 0.x (and they really have meant 0.x with the breaking changes they were making). This decision from them completely killed it for me.
I understood not using the C Runtime and instead creating direct wrappers over the Win32 API, but going a level lower to APIs that are not guaranteed to be stable is nutty.
ntdll.dll APIs are guaranteed to be stable though
Kinda wild
Before Windows 95/3.x, there was DOS.
There were no rules in DOS, or r_x permissions like Unix.
The DOS kernel itself didn't really impose any structure on the filesystem. All that mattered was:
- The two files that comprised DOS itself (MSDOS.SYS, IO.SYS) had to be "inode" 0 and 1 on the disk in early versions,
- the kernel parsed \CONFIG.SYS on boot, and I think looked for \COMMAND.COM if you didn't specify a different shell with COMSPEC= in CONFIG.SYS. There were defaults if \CONFIG.SYS didn't exist, but of course all your DEVICE= stuff won't load and you'll probably not have a working mouse, CD-ROM, etc.
\AUTOEXEC.BAT was optional. That's it. Any other files could be anywhere else. I think the MS-DOS installer disk put files in C:\DOS by convention but that was just a convention. As long as COMMAND.COM was findable DOS would boot and be useable-and if you mucked something up you just grab your DOS boot floppy with A:\COMMAND.COM on it and fix it.
From what I recall most installers-if provided-made a directory in \ and put all their files there, mixing executables with read-write data. There was no central registry of programs or anything unless you were using a third party front-end.
Windows 3.x and 95 inherited the DOS legacy there.
> I think the MS-DOS installer disk put files in C:\DOS by convention but that was just a convention.
That assume that you where going to install the OS, which assumes that you had an hard drive :-). The original IBM PC didn't, and anyway MS-DOS didn't support folders until version 2.0.
On those old PCs you would boot your computer on a floppy drive with all the files on the root of a floppy, and execute your command there. There was not much to work with anyway, check the content of the boot floppy of MSDOS 1.0 [1].
And also, especially if you had a single floppy, you wouldn't even use it: to run your software you would boot a disk with a IO.SYS, MSDOS.SYS, COMMAND.COM and an AUTOEXEC.BAT that would start your favorite word processor (WordStar of course :-D ).
[1] https://www.youtube.com/watch?v=0-X7Thsn0pI
Yep I don't think the Microsoft installer was there until version 4 or 5. Around the time MS was making DOS more "user-friendly" with things like /LONGDESCRIPTIVESWITCHES, DOSKEY, MIRROR, UNDELETE and UNFORMAT. It looked like the blue text-mode Windows XP installer.
> I think the MS-DOS installer disk put files in C:\DOS by convention but that was just a convention.
Yes. For whatever reason my father used C:\SYS and I inherited it, along with C:\WIN for Windows.
> I wonder how much of this problem was caused by lack of adequate documentation describing how an installer should behave, and how much was developers not reading that documentation and being content when it works on their machine.
It was mostly the latter. And when Windows broke, people would blame it on Microsoft, not on the software they installed. The same if the software broke. And you didn’t have online updates at the time that could retroactively add fixes. So Microsoft had to do everything they could to ensure broken software would still work, while also keeping Windows working, the best they could.
> So Microsoft had to do everything they could to ensure broken software would still work
I think they chose to do everything they could to keep it limping along. An alternative would've been a name-and-shame approach, like "This program crashed because the author made this mistake: [short description or code or whatever]", and leave them out to try until the devs stopped doing those dumb things. After a few years of pain, people would've gotten with the program, so to speak. Instead, they chose the path that put zero pressure on devs to write correctly-behaving software.
The thing is, Microsoft got its position of dominance exactly because they did that - and that was because by doing this, the users' programs kept working. Remember that users outnumber developers by far and the last thing Microsoft wanted was for people to not upgrade Windows because they broke their previously working programs.
This was even more important at a time when Microsoft had actual competition in the OS space and people weren't able to just go online and download updates.
> The thing is, Microsoft got its position of dominance exactly because they did that
Yeah, right. No bribes, no preinstalled software...
They dominated by ... accident.
Nobody said it was by accident. They had deals with PC manufacturers for decades where they sold licenses based on the number of PCs sold by the manufacturer regardless of if the PC used MSDOS or another OS (like DRDOS), making all other options more expensive unless the client asked for them.
But the important thing is that the clients pretty much never asked for other OSes because all of their software worked on MSDOS - and later Windows. People bought computers to run their software, so if the software they wanted to run needed MSDOS or Windows, they'd buy the machines that ran that OS.
And by extension, if the software they wanted to run wouldn't run on the next version of MSDOS or Windows, they wouldn't have a reason to upgrade MSDOS or Windows. But from a user's perspective MSDOS/Windows was the best choice because everything supported it.
Microsoft didn't rely on just backwards compatibility (especially since the idea of "backwards compatibility" relies on something to be compatible with in the first place) but it was an incredibly important aspect of their strategy.
Yes, but that doesn't solve the customer's problem
And what does the customer do if the vendor has discontinued it? Or charges for an upgrade? Or has gone out of business?
https://devblogs.microsoft.com/oldnewthing/20031224-00/?p=41...
I'm pretty sure another one was "what if you're wrong/have a false positive detection, and slander another company, one with lawyers?"
> And what does the customer do if the vendor has discontinued it? Or charges for an upgrade? Or has gone out of business?
Those can all be filed under Not My Problem (as in, Microsoft's problem,) and safely ignored. On the other hand, when Highly Influential So-And-So upgrades from 3.1 to 95 or whatever, and Very Population Application v4.9.6 starts falling over, Microsoft gets the black eye whether they deserve it or not. The whole equation changes.
> Those can all be filed under Not My Problem (as in, Microsoft's problem,) and safely ignored.
It was absolutely Microsoft’s problem. Had it ignored compatibility issues, what incentives would users have had to buy Windows 95?
> After a few years of pain, people would've gotten with the program, so to speak.
Not necessarily. This was still very much the time in which choosing to stick with an old version which worked (e.g. Windows 3.1) wasn't uncommon.
Just look at how many people jumped from XP to 7 due to the network effect of "Vista sucks" and then multiply that by the fact that, at the time of 3.1->95, people had far fewer computer security concerns, if any.
Why would I buy a new version of Windows, if none of my existing software will work on it, so I have to buy new versions of everything? Sounds expensive.
But your computer will be secure and then pedophiles and terrorirst wouldn't stand a chance.
Raymond Chen already discussed this. Microsoft wants to sell Windows. Windows exists to run software. If Windows doesn't run software, Microsoft doesn't make that sale.
If your business runs on some obscure piece of software for which updates are neither cheap or easy, you're not going to buy Windows if it doesn't run that software.
Name and shame doesn't work because the developer isn't part of the transaction.
One workaround Microsoft has done for use-after-free is detecting when an application is prone to this and using an allocator that doesn't actually free RAM immediately. It believe that lovely bit of fun is a function of "Heap Quarantine".
Yes, the real, can't say no world of system software is not what one might wish.
IIRC Sim City 2000 is one such piece of software.
It was SimCity Classic.
Not too different to using MS's mimalloc to run zenlisp under OpenBSD because the core malloc will just tell good try, but GTFO to the interpreter.
The biggest cause for this problem isn't lack of docs, but poor OS design. Like, why would you let apps change anything without restrictions to begin with? Of course, then you have to have some dumb hidden folder wasting space to restore the changes, and this "waste space for no good reason because we can't architect properly" is still a common issue
You're not wrong, but largely as a result of dubious architectural decisions made in the name of backwards compatibility and minimal hardware requirements, Microsoft sold 40 million copies of Windows 95 in its first year, compared to 300,000 copies of Windows NT 3.1.
Consider:
Windows 95 ran the vast majority of MS-DOS and Windows 3.1 applications with minimal performance loss, supported MS-DOS and Windows 3.x drivers for hardware that lacked 32-bit driver support, and ran acceptably on a 386 with as little as 4 MB RAM.
The properly architected Windows NT 3.1, released two years before Windows 95, had limited MS-DOS and Windows 3.1 application support, required NT-specific drivers for all hardware, and required 12 MB RAM to boot, 16 MB to do anything useful, and you really wanted a 486 for decent performance.
Now try a 3rd comment that actually connects to the design deficiency described in the article instead of a generic grievance about rearchitectrue that included a gazillion of changes
I agree. Why should the person who bought a computer be allowed to own it? Phone ecosystems got this the right way - the company that made the device owns it, and the person who bought it does not!
Don't speak in empty slogans, connect it to the article/comment!
Some app does some thing, then the OS reverts it! Where is "you" and "own" in this process? Do you own the "C:\Windows\SYSBCKUP" folder? Do you own the undo process?
Would your "ownership" rights increase if instead the OS didn't waste any space, but simply blocked downgrades of system components without user warning/intervention? Or had an even better process?
They could have had file permissions. They could have had a package manager instead of third-party installers.
Also note that Microsoft Office has a long history of not following Windows rules. Microsoft didn't even set a good example.
In the era of Windows 95, having a network connection was still a rarity. Expecting modern systems to have package management and sandboxing mechanisms would have been 20 years ahead of their time.
They had. Sort of. MS-DOS was a single user system. See attrib for details.
One of the craziest Raymond Chen stories is one where a Windows API call would return a pointer to a data structure the OS had allocated for the operation. The programmers at Microsoft made the data structure bigger than they needed, for future expansion. But some third party devs noticed the extra space, and started to use it to store data for their program. Then when Windows tried to start using the extra space, those applications would crash.
Reasonable people can disagree on a lot of things in programming. But I still do not understand how one can consider writing to memory the OS owns to be ok. It's sheer professional malpractice to do that kind of thing. With stuff like that, I don't think that any amount of documentation would have helped. The issue was that those programmers simply did not care about anything except getting their own program working, and did whatever the most expedient method was to get there.
> But I still do not understand how one can consider writing to memory the OS owns to be ok.
Go to Vogons and look at all of the memory tricks people will use to get various games running on MS-DOS. This kind of juggling exactly which drivers to load, etc. is why Microsoft added the boot menu in MS-DOS 6.0 to CONFIG.SYS.
I'm not necessarily saying that this was the case here, but it smells like that to me.
Back then, many programmers originally learned their ropes in an 8-bit home computer era (or earlier), where it used to be completely normal and even necessary that you used whatever memory region you got away with.
For example, on the C64, you would get away with using the memory locations $02, $2A, $52, $FB to $FE, $02A7 to $02FF, and $0313 as scratch space for your own programs. Memory was incredibly scarce. I can’t blame programmers for sticking with their habits and for taking several years to unlearn and adjust their misconceptions about who owns what if they came from a home computer era where that pattern used to be the only way to get stuff done.
>I still do not understand how one can consider writing to memory the OS owns to be ok.
Things were different back then. People did a lot of hacky stuff to fit their programs into memory, because you were genuinely constrained by hardware limitations.
Not to mention, the idea of the OS owning the machine was not as well developed as it is today. Windows 3.11 was just another program, it didn't have special permissions like modern OSes, and you would routinely bypass it to talk to the hardware directly.
"Not to mention, the idea of the OS owning the machine "
I agree--back then when computers had <=4MB or RAM I would've called hogging unused memory for some selfish speculative future use "professional malpractice".
Some of that attitude survives to this day:
When an OS uses any memory that's otherwise unused as a file cache, which is instantly available if an application wants more memory, but isn't shown as "unused": "This OS is terrible, I have 16GB of RAM but all of it is being used!"
When an OS doesn't do this: "This OS is terrible, I bought all this RAM and the OS doesn't use it!"
> Things were different back then. People did a lot of hacky stuff to fit their programs into memory, because you were genuinely constrained by hardware limitations.
Are you going to tell them what "32-bit Clean" meant for Mac developers, or will we let them find out that particular horror movie for themselves?
> But I still do not understand how one can consider writing to memory the OS owns to be ok.
Your manager tells you to reduce memory usage of the program "or else".
TBH i think a more likely explanation is that they needed to somehow identify separate instances of that data structure and they thought to store some ID or something in it so that when they encountered it next they'd be able to do that without keeping copies of all the data in it and then comparing their data with the system's.
^^ The voice of experience, here.
Or you desperately need to tag some system object and the system provides no legitimate means to do so. That can be invaluable when troubleshooting things, or even just understanding how things work when the system fails to document behavior or unreasonably conceals things.
I've been there and done it, and I offer no apologies. The platform preferred and the requirements demanded by The Powers That Be were not my fault.
Ask the Zig people, who just started relying on undocumented unstable Windows behaviour intentionally due to some kind of religious belief: https://codeberg.org/ziglang/zig/issues/31131
>back in those days.
> You see all the wacky software that doesn't follow the rules properly, does whatever it wants, breaks things.
Just like today. Software is hard, software engineering even harder.
When I was a kid, I released a small GUI program online that I made with either VB6 or VB.NET. The program used the standard open-file dialog. When I created the installer for my program through VB's release wizard, there was a page where it pointed out that my program depended on a certain system library (because of the open-file dialog) and it asked me if I wanted to include that library in the installer. I think the default answer was yes, or maybe it wasn't but it sounded like an obvious thing to enable so I did it. Apparently this screwed over and broke open-file dialogs globally across Windows for everyone who wasn't on the same version of Windows as me. Whoops! It's too bad that VB had such a foot-gun in it, and that the article's workaround didn't save those users.
>Windows 95 worked around this by keeping a backup copy of commonly-overwritten files in a hidden C:\Windows\SYSBCKUP directory. Whenever an installer finished, Windows went and checked whether any of these commonly-overwritten files had indeed been overwritten.
This is truly unhinged. I wonder if running an installer under wine in win95 mode will do this.
This is truly unhinged
Granted, but at the same time it's also resolutely pragmatic.
Apparently there was already lots of software out there which expected to be able to write new versions of system components. As well as buggy software that incidentally expected to be able to write old versions, because its developers ignored Microsoft's published best practices (not to mention common sense) and and didn't bother to do a version comparison first.
The choice was to break the old software, or let it think it succeeded then clean up after the mess it made. I'd bet they considered other alternatives (e.g. sandbox each piece of software with its own set of system libraries, or intercept and override DLL calls thus ignoring written files altogether) but those introduce more complexity and redirection with arguably little benefit. (I do wonder if the cleanup still happens if something like an unexpected reboot or power loss happens at exactly the wrong time).
Could the OS have been architected in a more robust fashion from the get-go? Of course.
Could they have simply forbidden software from downgrading system components? Sure, but it'd break installers and degrade the user experience.
Since the OS historically tolerated the broken behavior, they were kind of stuck continuing to tolerate it. One thing I learned leading groups of people is if you make a rule but don't enforce it, then it isn't much of a rule (at least not one you can rely on).
I would argue the deeper mistake was not providing more suitable tooling for developers to ensure the presence of compatible versions of shared libraries. This requires a bit of game theory up front; you want to always make the incorrect path frictiony and the correct one seamless.
There was (and still is) VerInstallFile, however this was introduced in Windows 3.1 and it is possible installers wanted to also support Windows 3.0 (since there wasn't much of a time gap between the two many programs tried to support both) so they didn't use it.
It is important to remember that Microsoft created some of this chaos to begin with. Other aspects can be attributed to "the industry didn't understand the value of $x or the right way to do $y at the time". And some of this is "nonsense you deal with when the internet and automatic updates is not yet a thing".
Why did programs overwrite system components? Because Microsoft regularly pushed updates with VC++ or Visual Studio and if you built your program with Microsoft's tools you often had to distribute the updated components for your program to work - especially the Visual C runtime and the Common Controls. This even started in the Win3.11 days when you had to update common controls to get the fancy new "3d" look. And sometimes a newer update broke older programs so installers would try to force the "correct" version to be installed... but there's no better option here. Don't do that and the program the user just installed is busted. Do it and you break something else. There was no auto-update or internet access so you had to make a guess at what the best option was and hope. Mix in general lack of knowledge, no forums or Stack Overflow to ask for help, and general incompetence and you end up with a lot of badly made installers doing absolute nonsense.
Why force everyone to share everything? Early on primarily for disk space and memory reasons. Early PCs could barely run a GUI so few hundred kilobytes to let programs have their own copy of common controls was a non-starter. There was no such thing as "just wait for everyone to upgrade" or "wait for WindowsUpdate to roll this feature out to everyone". By the early 2000s the biggest reason was because we hadn't realized that sharing is great in theory but often terrible in practice and a system to manage who gets what version of each library is critical. And we also later had the disk space and RAM to allow it.
But the biggest issue was probably Microsoft's refusal to provide a system installer. Later I assume antitrust concerns prevented them from doing more in this area. Installers did whatever because there were a bunch of little companies making installers and every developer just picked one and built all their packages with it. Often not updating their installer for years (possibly because it cost a lot of money).
Note: When I say "we" here that's doing a lot of heavy lifting. I think the Unix world understood the need for package managers and control of library versions earlier but even then the list of problems and the solutions to them in these areas varied a lot. Dependency management was far from a solved problem.
> This is truly unhinged.
This is bog-standard boring stuff (when presented with a similar problem, Linux invented containers lol) - read some of his other posts to realize the extent Microsoft went to maintain backwards compatibility - some are insane, some no doubt led to security issues, but you have to respect the drive.
It’s not bog-standard. Containers are not equivalent to doing what is described in the article.
Containers are in fact redirecting writes so an installer script could not replace system libraries.
The equivalent would be a Linux distro having the assumption that installer scripts will overwrite /usr/lib/libopenssl.so.1 with its own version and just keeping a backup somewhere and copying it back after the script executes.
No OS that I know of does that because it’s unhinged and well on Linux it would probably break the system due to ABI compatibility.
If they had taken essentially the same approach as wine and functionally created a WINEPREFIX per application then it would not be unhinged.
edit: also to be clear, I respect their commitment to backwards compatibility which is what leads to these unhinged decisions. I thoroughly enjoy Raymond Chen’s dev blog because of how unhinged early windows was.
Man, after looking at the veritable pile of stinking matter that is claude code, compare it with the NT 4 source leak.
Windows may have suffered its share of bad architectural decisions, but unhinged is a word that I wouldn't apply to their work on Windows.
I think you guys read “unhinged” as way more negative than I meant.
Just because I am saying it’s unhinged doesn’t mean I don’t think it’s cool
I’ve never read any windows source so I can still contribute to wine but I’ve read the NT kernel is really high quality
It's easy to forget in these discussions that Microsoft didn't have infinity resources available when writing Windows, and often the dodgy things apps were doing only became clear quite late in the project as app compatibility testing ramped up. Additionally, they had to work with the apps and history they had, they couldn't make apps work differently.
You say, oh, obviously you just should redirect writes to a shadow layer or something (and later Windows can do that), but at the time they faced the rather large problem that there is no formal concept of an installer or package in Windows. An installer is just an ordinary program and the OS has no app identity available. So, how do you know when to activate this redirection, and what is the key identifying the layer to which redirects happen, and how do you handle the case where some writes are upgrades and others are downgrades, etc, and how do you do all that in a short amount of time when shipping (meant literally in those days) will start in just a few months?
I mean it looks like they did try to redirect writes somehow. They probably tried more sane options until they arrived here.
>there is no formal concept of an installer or package in Windows.
this one is on them, I think package managers already existed - doesn’t seem like there was ever a blocker for windows to have a package manager but Microsoft never bothered until very recently
With hindsight sure, but I don't think any desktop operating systems had package managers in that era. macOS certainly didn't. NeXTStep had their .app bundle concept, but no legacy. And UNIX package managers were of no use - few of them properly supported third party packages distributed independently of the OS vendor, especially not ones that could upgrade the OS itself.
Windows 95 was not Windows NT and it still used the FAT32 file system, where it was not really possible to enforce access rights.
As TFA says:
You even had installers that took even more extreme measures and said, “Okay, fine, I can’t overwrite the file, so I’m going to reboot the system and then overwrite the file from a batch file, see if you can stop me.”
Well and the earliest versions of Windows 95 used FAT16 (specifically VFAT for support for LFNs or long file names). So enjoy those ridiculous cluster sizes if your hard disk even approached a gig or so.
You are right that it’s not equivalent, but the article explains why redirecting the writes wasn’t a viable option.
> If they had taken essentially the same approach as wine and functionally created a WINEPREFIX per application then it would not be unhinged.
Man, wouldn't it have been nice if everyone had enough hard drive space in those days in order to do something like that...
Two words: proprietary installers.
If an installer expects to be able to overwrite a file and fails to do so, it might crash, leaving the user with a borked installation.
Of course you can blame the installer, but resolution of the problem might take a long time, or might never happen, depending on the willingness of the vendor to fix it.
> If . . . the replacement has a higher version number than the one in the SYSBCKUP directory, then the replacement was copied into the SYSBCKUP directory for safekeeping.
This as well. I know there are a million ways for a malicious installer to brick Win95, but a particularly funny one is hijacking the OS to perpetually rewrite its own system components back to compromised version number ∞ whenever another installer tries to clean things up.
Whats unhinged about a periodic integrity check? Doesn't seem much different than a startup/boot check. If you're talking about security, you've come to the wrong OS.
I agree, it's unhinged for applications to overwrite newer versions of system files with older ones.
You'd have to track down some 16bit Win3.x software to install. Probably on floppy disks since CD-ROMs weren't common.
Then blindly overwriting the shared libraries despite the guidance what the vendor of the OS provides is actually hinged, yes?
> Whenever an installer finished, Windows went and checked whether any of these commonly-overwritten files had indeed been overwritten.
> Basically, Windows 95 waited for each installer to finish
How could it tell that a particular process was an installer? Just anything that writes to the PROGRA~1 or WINDOWS folders?
The latter, according to https://devblogs.microsoft.com/oldnewthing/20260324-00/?p=11...
Egg on my face for not scrolling down to see the comments after reading the article. Thanks!
And 6-7 years later the `WinSxS` directory was born and these days it is tens of gigabytes.
`Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase`
In an administrator command prompt. You can thank me when it's finished ;-)
I find articles like this a good counter to the idea that typical software used to be better in the past (usually with an appeal to an idea that people were “real programmers” in those days and anything other than C as used in the 90s is a modern extravagance)
In my 25 years of using Windows I've grown so much disdain towards annoying, broken, slow installers that I started to instead extract them like zip archives, using various tools: 7-Zip, UniExtract, Observer plugin for Far Manager, sometimes even manual carving.
Most things just worked after being extracted like that. Some things needed a few registry entries, or regsvr32 some dll files.
I love the naiveté of this approach.
Unlike <arbitrary heuristic>, it's so easy to reason about. I wish this kind of approach was still viable.
The sad lesson is to be both proactive and reactive if you want a clean environment. Trust, verify, and stick around to clean up someone else's mess after the fact.
OMG, is this the reason why every other installer would get stuck at 99% forever? :D
It doesn't say for certain, but assuming the version of this they settled on (restoring components after the installation finished) is what they shipped in the original version of Windows 95, then no, I don't think this could have caused hangs in the installer itself (unless Win95 misjudged whether the installer had completed or not and started the restore process early?).
No, most likely bad algorithms for dealing with registry stuff. The kind of thing that worked well on tester machines with small registry sizes and exploded in the real world.
Someone thought the "commit all previous operations to persistent storage" step would take just 1% of the time.
> Some components addressed this problem by providing their own installer for the component, and telling installers, “You are not allowed to install these component file directly. Instead, you must run our custom installer.
Aha, that’s why they do that.
This existed until Windows XP but with different name and behavior. Only from Vista, they added permissions to restrict user and third party programs to modify system files easily.
wow. this is insane. never new such mechanic was ever remotely considered or possible. pretty neat
Windows, especially old versions, were beautifully pragmatic. Think about the things that would need to exist on an open-source OS to match this functionality. You'd need to:
1. Convince people to distribute programs via installers.
2. Provide some way that installers can tell the OS that they're an installer (and not invent 5 different ways to do this!)
3. Convince the creators of installers to actually use that function.
4. Convince library creators to maintain backward compatibility (big ask).
5. Convince people to not fork said libraries, creating ambiguous upgrade paths.
6. If there are multiple distros, convince them all to use the same backup/restore format for libraries (and not treat their own favorite libraries as "special")
That's not exactly what Windows installers did.
They absolutely created 10 different ways to install software; they didn't really advertised they were an installer; the only backward compatible thing there are the MS libraries; there was no common backup/restore format.
Instead, the Unix people made a mechanism for random programs to use their own libraries and not touch the system one. In fact, Windows had one too, but most applications still decided they need to break the system.
One of the biggest pitfalls in understanding the world is interpreting everything as an absolute. If someone says "dogs have four legs", you might think "well, I saw a dog with three legs, so there's no value in the idea that dogs have four legs, and I'll conclude that if I see tracks from an animal that seems to have four legs, it's impossible to know if it's a dog or a giant centipede". It's a pernicious little quirk of our minds that we fall for this kind of thinking.
To wit. The idea that installers on Windows behaved the way I described is an interesting fact. The idea that a few installers did things in unusual ways is a much less interesting fact. Putting them on the same level robs you of the insight, and if this is a pattern then there are a lot of things you simply can't learn, because an exception could be found.
1-3 are covered by package managers in pretty much every Linux distro and BSD.
I think you misunderstand. 1-3 are not goals, they're steps to the goal. Linux and BSD have different goals from Windows.
> 2. Provide some way that installers can tell the OS that they're an installer (and not invent 5 different ways to do this!)
It is still blows my mind what to tell the distro flavour and version I still need to rely on the shell globbing.