Hacker News new | past | comments | ask | show | jobs | submit login
Building a new Windows 3.1 app in 2019: A Slack Client (yeokhengmeng.com)
705 points by yeokm1 32 days ago | hide | past | web | favorite | 236 comments

Notice the binary size of the app is only 64KiB.

In the demoscene this would be a disqualification as it's 676 bytes over the limit, but in this case I'll overlook it because of the sheer awesomeness of what you've done (and I'm sure trimming off 676 bytes wouldn't be too difficult ;-)

More seriously, this is an excellent proof-of-concept that a Slack client does not need to use hundreds of MB of RAM and consume most of a modern CPU core to provide its basic functionality. I'm a long-time Win32 programmer who started in the tail-end of the Win16 days and one of the things I've wanted to write if I had the time and need was a Win32 native Slack client, to show that it can be done with far less resources, but you've gone even further with Win16. Win32 has native TLS support (via SChannel library, not well-documented but examples exist) and you'd be able to even use it practically (32-bit applications will run on all current versions of Windows, both 32 and 64-bit.)

Note that C89 only prevents declarations of variables in the middle of a scope; you can simply create an inner scope with new variable declarations at its start. Like so...

    case WM_PAINT: {
      HDC hdc = BeginPaint(hwnd, &ps);
Another small tip: if you make it a dialog-based application, you won't have to bother with WM_PAINT and drawing text yourself --- you can just make the "statusText" and "settingsText" edit controls, and use SetWindowText (or SetDlgItemText) to set their content. They will paint themselves automatically just like the listboxes that you used for the chat contents and userlist. At least you'll save some of those 676 bytes that way...

It's kind of silly compare a bare bones get/post to an entire app. This reminds me of my attempts to write an IRC client in an evening.

Creating a native Windows app to mimic the Electron Slack client would not be a trivial task.

His point is that this bare bones get/post app in Electron will be much, much "larger".

And that is why it would foolish for them to post a barebones slack client in electron. But they don't publish that. They have published a full featured client that is cross platform. I am not a fan of electron and would very much prefer a desktop app. But we are finally seeing emergence of desktop applications from major players for Linux because of electron. It's not ideal but so wasn't the previous solution.

> But we are finally seeing emergence of desktop applications from major players for Linux because of electron.

In my experience, Electron applications seldomly follow the UI conventions of the host OS or offer much in terms of integration.

If the desktop app is really just the web site in a locked-down browser, then what benefits does this offer to just the normal web page?

I like the conceptual separation. I like alt-tabbing to "Slack" not "Chrome". It also doesn't have any of the header bar so the electron app has more UX control, including access to OS level window menu options. Also it can do things that you can't do inside the browser. E.g., I've seen electron apps that come with other background processes. I also think it performs better in terms of versioning/caching resources. So an electron app could be just a web-site, but they often are much more.

That's true but some of that could already be implemented in browsers itself. E.g. web page could request to be in a separate window with different icon and ask for OS-wide api permissions. Now we have to run several fully-featured browser (Elecron) instances, not sharing system libraries, under different versions. This reminds me "write once, run everywhere" Java with bundled binary JREs because of incompatibilities between vendors... But there is some progress - for example IBKR TWS client can't play sounds as it was linked with an old libavformat.so which I no longer have in the system. Browsers have most of libs statically linked.

Web pages are constrained by the functionality made available to them by the browser - which is (purposely) very limited. Electron apps run on a native JavaScript interpreter (NodeJS) and have full access to the OS.

As far as UI inconsitencies go, most libraries I have used for native apps (Qt, Swing, Tk, etc) also do not feature UI elements that are consistent with the OS. Many developers simply can't afford to support multiple UIs just because they subjectively look a bit better.

> most libraries I have used for native apps (Qt, Swing, Tk, etc) also do not feature UI elements that are consistent with the OS

Huh? Okay, maybe Swing doesn't support native-looking widgets (I have less experience with it), but I can personally attest that Qt and Tk (or more precisely Ttk) apps nowadays use a platform-native look-and-feel on Windows, macOS, and Linux alike, by default (i.e. with zero effort on the part of the app developer). It might not be absolutely pixel perfect, but it's way closer than an Electron app.

Existing frameworks like Qt or GTK could also be used for a Cross-Platform solution

And just because it's electron doesn't mean it's inherently Cross-Platform look at discord for example It took too long for a initial desktop client to be released and then it ha issues with things like screen sharing not working as expected

>Existing frameworks like Qt or GTK could also be used for a Cross-Platform solution

They could but finding engineers with that kind of experience would be harder and cost a lot more. Far easier to retrain web frontend engineers.

It isn't like Qt is some bizarre arcane wizardry. You give a web developer a few days and they can productively be contributing to a Qt app.

Yeah but then the dev has to investigate how to solve certain patterns in Qt's ways which they already know how to solve in the web frameworks, and just like with natural languages, sometimes there are no straightforward ports for concepts, and it requires a ton of extra work that you couldn't foresee until getting halfway through the whole project. Adopting new tech is not without serious costs and risks. Also, no GUI framework I've ever seen has figured out a decent composability solution nearly as well done as the DOM, for better or worse. Not to mention the gigantic web ecosystem that just works in Electron.

Sorry, but if the way forward really is that every desktop application of the future has to ship with a full copy of Chrome, come with all the bloat and baggage of the web platform and continue its questionable UI conventions - all just because companies are too cheap to offer some training - then I really don't see how that is a desirable future.

Electron is bad enough from a user perspective, but it's downright horrible to see how it's instilled a rather defeatist approach in front-end developers.

"But I already know Javascript, it's too hard to figure out something else"

> But we are finally seeing emergence of desktop applications from major players for Linux because of electron

It's not like Maya, Steam, Chrome, Firefox, Skype, Adobe Reader, Houdini, DaVinci, Nuke, TeamViewer, Blender... haven't been working on Linux for ages (or more recently Bitwig, Reaper...). And conversely it's not like every Electron app has a linux build.

Most likely, the real solution here is to make a very highly performance tuned Electron for Wayland, and make it possible for multiple Electron apps to share at least some part of the footprint of that runtime.

Fixed costs vs variable costs. That fixed cost of Electron does come with some sizable benefits, so if you don't take advantage of them ofc Electron will just be bloat.

I think you could get pretty far without Electron. While a closer Slack experience would require some HTML rendering (VS languages have had an embeddable web view for a long time), alot of the formatting could be native (probably have to do some parsing) as could things like file uploads, image display, etc.

I can't help but agree with you. Honestly I think it went to hell when we decided that it was acceptable to call an electron app native, but that may have been a symptom, not a cause.

Before Electron people had the arguments about bloated apps when it came to WPF and Qt. And Java apps, like WPF (and most Qt apps I’ve used lately) lacks true integration with native OS widgets so as a user I get an uncanny-valley feeling.

At least with Electron you’re essentially forced to style everything - and ever since Windows 8 (or Windows Vista) Microsoft has been actively uglifying native widgets.

I did consider Java as I was writing it, but at the same time Java is actually pretty fast, but there is no doubt that it doesn't use native components most of the time (there is a gnome toolkit bindings for Java, so it is possible).

Still Java feels speedy, I think because it is compiled and doesn't need wacked workarounds like not having non-floating point numbers.

I’ve never seen Java running on Windows 3.x - how long did they maintain it for? Or did it use Win32S?

Update: ah, Microsoft released their own port in 1997: https://www.cnet.com/news/ie-gets-java-for-windows-3-1/ - I wonder how long they maintained that for.

> Before Electron people had the arguments about bloated apps when it came to WPF and Qt.

which is funny when you see that Qt runs on microcontrollers now.

Some years ago I worked on a very popular Windows desktop C++ program that had to stay small and backwards compatible, which meant only Win32 APIs and homemade libraries. Designers by the dozens would be hired, then get fed up with these limitations and quit, complaining that they wanted to have the freedom to make UIs in HTML and CSS, and that users are used to interacting with Web UIs so everything should look like that.

Later, at a different job, the UI was Electron based, but designers no longer worked in HTML, they used some other tools and it had become the job of engineers to write the HTML and CSS to match.

These trends seem to be driven partly by conventional wisdom about the lowest common denominator among young people in the workforce, e.g. javascript and html are so much easier, let's build everything on those, and next thing you know those have become a given and the next crop of kids will use something new on top of that. Or maybe something like QT will win and native code will become a first class citizen again with secondary support inside browsers via WebAssembly?

Some years ago I worked on a very popular Windows desktop C++ program that had to stay small and backwards compatible, which meant only Win32 APIs and homemade libraries.

That's funny, because it's exactly the type of job I'd love doing --- and I have been working on stuff like that (native code, mostly Win32, with some hardware/drivers/embedded stuff) for a long time; if you haven't guessed already, I try to stay very far away from the web stuff, even though I know HTML/CSS/JS and can use it if needed.

I mean I am not a fan of C++ (though I don't hate it either), and I love how easy and well libraries for e.g Python works together and how easy they are to find and install, but I don't think it is necessary to go all the way to native code -- Java/Kotlin on the JVM performs pretty well (and you can always outsource the heavy parts to C).

There is no direct correlation between the size of an executable (64kb) and the size of the RAM usage (can be hundreds of MB). I could not find any information about the total memory usage of the application, is it described anywhere?

Its running on a ThinkPad 390e, 64mb as standard, and tops out at 256mb, so there is your upper bound.

Even at an absolute worst case it still beats the pants off Slack.

You are correct. My 390E has 384MB of RAM but only 256MB is accessible by Win 3.1.

An earlier blog post shows this http://yeokhengmeng.com/2016/09/windows-for-workgroups-3-11-...

And is probably quite a bit faster, too.

It's also lacking so many features as to be unusable.

Win 3.1 apps can also access memory in 64K segments which I only use 1 to hold the humongous HTTP+JSON reply from Slack.

Wikipedia says "However, no single process can use more than 16 MB.". Not sure where is the source of that though.



It’s a limitation from the 286 Protected Mode.

It feels a lot closer to write for MCUs if you write for 16-bit programs nowadays. The only difference is that MCUs are much more barebone and so less managed, but the constraints set by hardware however is the most distinctive common spot.


Microcontroller unit.

Think MCUs are of the kinds like Arduino and microBit. There are also SBCs where bigger and more power hungry devices like Raspberry Pi belongs to.

Super late, but the term MCU refers to the actual chip -- analogous to SoC for the main chip on a raspi.

You don't call the raspi an SoC, and it's debatable that you'd call a prototyping platform like Arduino an MCU. The MCU is the main Atmel AVR, Microchip PIC, or similar part that drives such a board.

Hey thanks for the tips. Let me adjust the blog post to mention this point

> More seriously, this is an excellent proof-of-concept that a Slack client does not need to use hundreds of MB of RAM and consume most of a modern CPU core to provide its basic functionality.

If you’re so sure that this is possible, then where is the Electron competitor which allows us to build cross platform applications like this, with the same levels of productivity and a consistent and decent user interface? No one needs to be convinced that a native Slack client for each platform would be much better, I wish they would build those clients. The problem is most companies can’t reasonably justify the costs of building multiple native clients when a single cross platform one is good enough.

There is Delphi and Lazarus as open-source clone of it

Lazarus can use the Windows API on Windows, gtk/qt on Linux, and carbon/cocoa on Mac.

There is also a custom drawn mode that draws the GUI directly rather than using platform apis. That also runs on Android, but it not maintained anymore, so only up to Android 5 or something

Delphi is supposed to run on Android and iOS.

And Delphi 1 ran on Windows 3.1, so you could have used the same GUI since then

There is Delphi and Lazarus as open-source clone of it

Shhh! Ixnay on the Lazarusay. If people find out, I'll lose my magical secret weapon for blasting out little windows gui apps.

Seriously though, if you ever find yourself needing a few buttons on a windows desktop that do simple things, Lazarus is amazing for whipping that up in a few minutes and still looking professional.

Agreed. I'm not a huge fan of Pascal, but it's better than JS and Lazarus makes knocking up a simple GUI trivially easy.

Nah, when people find out it is Pascal, they run away. Can't type begin and end, such words are just too long

Qt and to some extent GTK+ come close. GTK+ can be programmed in Vala which is a fine language that transpiles to C and supports idioms such as asynchronous programming.

> Qt and to some extent GTK+ come close

Both are C++: developers are more expensive to hire, and stuff takes more time to develop and debug. I'm proficient in C++ (programming for living since 2000), but I wouldn't pick the language for 2D GUIs in 2019.

> GTK+ can be programmed in Vala

Picking a non-mainstream languages is risky. Harder to find developers. Way more likely to find bugs in the toolchain and these can easily cost weeks to fix.

You can also write GTK+ in JavaScript for that matter, or Python. Vala is a very underrated language though and it should be very easy for a good JavaScript programmer to pick it up.

Enough languages have bindings for GTK or Qt to make it viable

> Both are C++: developers are more expensive to hire, and stuff takes more time to develop and debug.

Have you seen the state of Javascript 'ecosystem' and job market?? Both statements are false.

The real reason is that C++ toolkits don't have platform and device independence. HTML and CSS are really good and powerful design tools, especially compared to composing raw pixels like you'd (essentially) be forced to do with Qt and GTK.

The ignorance in this thread is rather concerning.

Let me correct: GTK+ is not C++, it's C. Qt is very cross-platform: it supports about 10 platforms, including Linux, Windows, and macOS. You are not doing anything close to compositing raw pixels in Qt or GTK+. They have layout managers that are specifically made for typical application UIs, and they have lots of ready-made widgets. Qt also has QML, which is a declarative UI descriptions language kind of like HTML/CSS but much more productive because (gasp) it's actually designed from the ground up for applications, not websites.

but I wouldn't pick the language for 2D GUIs in 2019

Which one would you recommend?

I mostly program for Windows and use C# for the GUI.

Cross-platform story is complicated, though. I have good experience creating a custom GUI framework for embedded Linux: drm/kms, gles, NanoVG, [DllImport], everything on top is custom C# code in .NET core 2.2. But that approach is not for everyone. I only needed 10-15 screens with simple GUI on them, it’s a 5” touchscreen with no other user-facing devices. Creating more advanced UX this way would consume too much time.

There’re Avalonia and Xamarin. Didn’t used them at that time because I needed full-screen GUI for a single-application Linux, without any desktop environments or user mode OS components. For desktops and especially mobile apps they might work OK.

It’s unpopular opinion here, but I think Electron is not that bad for GUI, esp. when writing TypeScript instead of JS. I think it’s similar story to Unity3D or PHP: low entry barrier attracted inexperienced programmers, then the whole ecosystem is judged based on the output of these inexperienced people.

Great reply, thanks very much!

That's cross platform for Windows, Mac and Linux, but what about Web, Android and iOS?

Ignoring that you probably _don't_ want the same interface across all of those...

Qt, as well as Windows, macOS and Linux actually can do Android [0] and iOS [1], and Web is halfway there [2].

[0] https://doc.qt.io/qt-5/android.html

[1] https://doc.qt.io/qt-5/ios.html

[2] https://wiki.qt.io/Qt_for_WebAssembly

I just want to step in quick to advocate. Please do not use Qt for the web. Their web export tools aren't just unfinished, they're actively hostile to web paradigms. The finished product doesn't render to the DOM, it's completely screenreader inaccessible, it overrides browser preferences. In a lot of ways, Qt on the web is even worse than Flash was.

You know all of the arguments against Electron that people trot out about how it's not real native, and it doesn't follow the right UX conventions or paradigms? Qt on the web is exactly like Electron on native, except way worse and without any sign that it's going to improve, because fundamentally Qt is structured around the idea that it should be able to spit out a binary blob of pixels instead of hooking into web-native primitives like the DOM.

Look into something that's showing more promise, like .NET and Razor. The Rust community is also doing some good work here, although I don't know that they have any UI frameworks that are mature enough to be reliable in an enterprise setting.

These aren't true cross-platform efforts yet, since they're still forcing you to think about HTML. But if I was going to bet on any project ending up with a real cross-platform solution that felt good on the web, some kind of export option from an Open Source Windows Forms or similar is probably what I would bet on. Either Microsoft or (possibly) the Rust community are the two parties that I think are most likely to end up producing a true native UI toolkit that can actually export to the web in a usable, acceptable way.

That's exactly what your users don't want you to do!

You do not want the same UI on desktop and mobile.

Beeware [0] does it too, natively in python. The architecture and code base are very nice as well. [1]

[0] http://www.beeware.org [1] https://dan.yeaw.me/posts/gui-widget-for-beeware/

Xamarin and Uno Platform

Windows 3.1 apps are somewhat cross-platform because they can be run with Wine on Linux.

It's even better: 64-bit Windows doesn't support 16-bit Win 3.1 apps anymore, but you can still run them via Wine on the Linux subsystem.

It should be noted that WineVDM[0] will allow you to run 16-bit Windows applications on Windows without the Linux subsystem.

[0] https://github.com/otya128/winevdm

It would have been relatively straightforward for Microsoft to support 16-bit on 64-bit, but they decided not to. I can't help but feel that that is just more evidence that whoever is running Windows development these days hates everything that used to make it a good desktop.

64-bit Windows has never supported 16-bit. This has nothing to do with "whoever is running Windows development these days"

Back when 64-bit Windows came out (with XP and Server 20003), the adoption was pretty small since most applications were not 64-bit and did not need 64-bit address spaces. Microsoft saw the opportunity to kill at least one backward compatibility burden by not even trying to support 16-bit for x64. They figured, rightly, that by the time x64 became widespread, 16-bit would be obsolete.

> 64-bit Windows has never supported 16-bit.

Don't believe I said otherwise.

> This has nothing to do with "whoever is running Windows development these days"

> Microsoft saw the opportunity to kill at least one backward compatibility burden by not even trying to support 16-bit for x64.

These two statements are at odds. Microsoft used to take compatibility extremely seriously. It would have been relatively trivial to allow 16-bit applications to run, and obviously there is desire to do so since WineVDM exists, they just arbitrarily decided not to.

I suspect this is because they've become infected with developers who use Linux a lot and think nothing of breaking compatibility every release, let alone in cases like this.

Virtual 8086 mode was gone, but they could have just emulated it. The real reason 16-bit apps don't run is Microsoft didn't think it was worth the effort.

Wasn't 64-bit windows 2k/64 itanium-based, not x86-based? If so it would have required supporting existing binaries compiled for a different architecture. My understanding is that the only 16-bit support in 64-bit windows is a few specific loaders for things like 16-bit installers (please correct me if I'm wrong)

Yes, the initial 64-bit OS was IA64 and that was the perfect excuse to dump NTVDM, instead of trying to do a W16OW64 or something of that sort. x64 XP and 2003 further solidified that decision because they were "professional" SKUs and Microsoft could dictate that they didn't care about DOS/Win16 for the "new" platform.

It didn't exactly run 16-bit installers. https://devblogs.microsoft.com/oldnewthing/20131031-00/?p=27...

Indeed. This point is usually missed. You can even run Windows apps in BSD and macOS.

It's Beeware. https://beeware.org/

> Write your apps in Python and release them on iOS, Android, Windows, MacOS, Linux, Web, and tvOS using rich, native user interfaces. Multiple apps, one codebase, with a fully native user experience on every platform.

This sounds great, but it seems there's no out-of-the-box support for a rich text textbox?

I have a python script that I want to deploy as self-contained app for windows and osx with a gui. Finding a framework that works, is decent to use, doesn't need hundreds of MBs of dependencies, and has rich text support is...not easy.

Have a look at nuitka for compiling your script to a binary.

Thanks, I'll try it! I was using pyinstaller atm.

I'm still trying to figure out if there's a GUI that supports different text with mixed colors and features out of the box, and that's not horribly broken in OS X

In the old days, you would just go on AOL's Windows programming section, find a shareware rich text control, and use that.

In the old days, I would do it in Delphi and have the controls already in my toolbox :)

I was actually thinking of giving it a go, but the idea of a Python backend and a Delphi frontend is as attractive as recoding everything in ASM.

Yes, because Slack is one man shop that can’t afford to hire one or two Windows, Mac, and Linux developers.

Actually, s/Slack/Tidal/ if you want to add insult to injury. Electron app for Windows and Mac (but well, nice features overall). However, no Linux build.

Slack does have (very-long-time-beta) Linux build[0], though I personally prefer to just use Slack through my browser instead of suffering through an Electron app.

[0] https://slack.com/downloads/linux

The web version work also well in Firefox, so you don't need to give all your RAM.

Slack calls don't work reliably in Chrome/Electron on linux anyway, so no loss here.

Here’s a free lightweight native Mac client (with dark mode oooOooo) https://www.sblack.online/

What are your criteria for something being an Electron competitor?

It was more or less a rethorical question (I guess that’s why I’m being downvoted), because there is no competitor. If there was, then Electron wouldn’t be so extremely popular in the first place, and we’d see a lot more popular apps made with all the tools mentioned in the other replies to my post.

Thanks, I'm assuming there is some core application capability that people are getting from Electron. In terms of 'write once run anywhere' Java has that covered but doesn't offer a means to spec UIs with HTML/CSS, so if that is the deal killer then it would be nice if Java added that capability for applications.

Edit >> looks like JavaFX WebView is a thing now, plus the jxbrowser embeds chromium in a Java App... not sure of the performance of either of these implementations

> 'write once run anywhere'

That's the biggest lie ever, with these newfangled "cross-platform" solutions.

I want to watch the guy who has to sit down and port electron to a platform it doesn't run on yet. It's just a few lines of code, right?

Java had the same problem, everyone who ran Linux in early 2000s remembers. It's still not something I would want to port, but at least it runs on more systems ootb than electron.

You are being downvoted because the idea that electron is the only way to get cross platform GUIs is absurd and comes from inexperience and a lack of research. FLTK, Juce and Qt are just some of the options for creating cross platform UIs that end up being much smaller and MUCH faster than electron. Electron is popular because people learn javascript and don't want to learn C++. I can't completely fault this mentality for toy programs, but at some point the false sweeping statements get pretty old.

It's weird to assume that developers who use Electron do so because they are ignorant, incompetent and lazy.

The truth is, everybody knows about Qt, GTK and so on, and everybody knows Electron is heavy but you have to be realistic. As a company do you want to spend that much money hiring a ton of C++ developers over a much longer period of time, or do you go for the solution which, while not ideal, allows you to develop a cross platform app in a much shorter time?

These days many people run Electron apps without even knowing it, showing that it's an ok solution.

> It's weird to assume that developers who use Electron do so because they are ignorant, incompetent and lazy.

I don't think I said all that

> As a company do you want to spend that much money hiring a ton of C++ developers over a much longer period of time,

This I think is a big assumption. Making a GUI isn't really that difficult. Most of the time in a program doesn't go into making the actual UI. I never hear someone who is experienced in making UIs say that electron saves them so much time, it is always people assuming it takes an army of C++ people to do what one person can do with electron, which is bizarre, especially over the course of something that is more than a prototype.

> I don't think I said all that

Kind of: "inexperience", "lack of research", "don't want to learn C++"

> Making a GUI isn't really that difficult.

Also a big assumption, especially for cross-platform GUIs.

If you don't know the difference between "inexperience and a lack of research" and "ignorant, incompetent and lazy" then I don't know what to tell you. It seems like you are hallucinating some sort of persecution.

It is not a big assumption, I've done it many times. What is it that you think electron gives you that cross platform GUIs don't have? Making the actual UI is usually pretty trivial, it isn't even logic, just data through function calls.

rvanmil 32 days ago [flagged]

> toy programs

> false sweeping statements


I think misunderstood what I said - I can understand not learning C++ for toy programs, but at some point making thousands of users use an electron program is pretty silly.

You do realize that one thing can be more popular but still have competition, right?

Sure, I’m just saying there is a huge gap and other tools, even though they technically work, haven’t proven to be good enough to become as widely adopted as Electron.


I built a Win 3.1 app during a company hackathon just for fun. Here, I detail learnings and process for how a new old app can be created with the aid of modern tools and hindsight of old technologies. And perhaps what lessons can it offer us today.

Without the benefit of modern libraries and languages, I had to read up and take care of many low level details, socket programming, HTTP, JSON parsing, UI design in code all under tight memory constraints. Nevertheless, it was a terrific lesson in understanding how things work under the hood.

I had to do things the old-fashioned way reading books and header files due to the dearth of online documentation. I can empathise with the plight of the programmers of yesteryears who had to code without the benefit of online search engines.

With this blog post, I hope you'll find it interesting to learn about developing a modern-ancient app for Win 3.1.

https://github.com/yeokm1/w31slack https://github.com/yeokm1/http-to-https-proxy

I expected to be compiled in some kind of VM, not on an actual computer with Windows 3.11 :-).

I feel "old-style" documentation is much better than we have now. My most productive _python_ only work times were when I had only the python .hlp file and a _physical_ paper book.

What are your impressions?

I've been programming since 1983. The internet opened up publishing to the masses, which means that non-professional people could also publish, resulting in much more documentation than ever before.

But now the amateur documentation writers are competing with the professional ones; the quality of the professional documentation is still as high as ever, but it can be drowned out by the amateur quality documentation.

All in all, finding the information you need is MUCH quicker via a search engine, but the signal-to-noise ratio is lower.

The quality of Microsoft's own documentation has also fallen considerably; the latest nail in the coffin is that docs.microsoft.com thing that started to replace MSDN several years ago, that created tons of ridiculous fuckups in the "migration process". While doing that they also "open sourced" their documentation on GitHub, which to me sounds more like they're just trying to rely on free labour from the "community" to fix the mess.

One of the more memorable WTFs I've seen is this, which is still wrong as of this post:


Compare to the old version of the page on MSDN:


See what's missing? The newer version is not the correct one... in "migrating" the document to the new site, for a reason that completely defines all rational explanation, the return type of the function declaration became void. There are plenty of pages on the new site with this serious error, and they've remained unfixed for well over a year. People report such problems on their GitHub, and they get fixed --- individually --- as they're reported, but it still boggles the mind how such a blatant and widespread error could go through (and the old, correct, content deleted flippantly) without someone in power shouting "STOP!":


MSDN was a gold standard in the 90's. Now you have tragedies like social.technet.com

The low quality of the technet "answers" are mind-boggling. Why doesn't Microsoft pull the plug on this?

Also, what's the purpose of the people who will answer nearly any question with a very low-quality (but wordy) answer? What are they getting from this effort?

There must be some reputation game there.

You see it on SO too, people answering basic questions 2 seconds after they're postedd with long pastes from documentation that are sorta related to the original question.

So much this.

It depends on which docs you are looking at, but some are very broken, with broken links, broken tables, broken text formatting...

Do you know of any way to get a handle to the old docs or perhaps a full MSDN dump of 3 years ago or so? (other than the web archive)? Perhaps the latest MSDN offline release or something?

I don't even mind paying.

I still miss the old MSDN offline help system. Once you got the hang of it, most of the time, you could find what you needed right away by typing the right thing in the Index.

Also, putting your cursor on a keyword, hitting F1, and getting the right result immediately. If I let myself I get so frustrated and angry by the massive regressions we've made over the last 20 years.

I work like this every day in my game that I am building. I’m almost the only one using the engine, and 90% of my work is in lua. I use the source code and the lua 5.1 reference for everything.

I hardly google something in a week of work, since there is nothing online about anything. It is like heaven compared to other ”google driven” programming things I have done. I feel very productive pretty much all the time, even when debugging mysterious real time issues.

In fact, sometimes I work with wifi off just because it creates a special peace of mind — and then I have to turn it on to do git push :)

Prior to online search engines there were similar offline resources such as the MSDN CDs.

Agreed. But such CDs are tough to locate today.

Borland's compilers had the best documentation. They included a much of the MSDN API reference in their built-in help files.

Hmm. Borland and Watcom compilers came up in my research. Will look into them for help next time!

Yeah Borland was great with docs

The Eye might have these, they have a bunch of old Microsoft/msdn related stuff.

We use Visual Basic 6 for a lot more than we should at work...going back to that from using Python, Ruby, and even PHP was a shok.

I thought porting a Python script to VB wouldn't be a big deal, but like you said, things youtake for granted like JSON and certain dictionaries are just lacking.

I haven't touched VB6 in ages - I tend to wonder what it would be like "going back to it".

Not too long ago I remarked here on HN that I expected VB6 programmers might become in demand in the future (when, I don't know), similar to how COBOL programmers were/are.

Basically, for the need to convert apps, written internally for a business, from VB6 to something else (likely to VB.NET or C# - maybe on Mono - but there are other options too).

I expect this to happen when Microsoft finally kills off the VB6 runtime DLL - but so far they haven't; from what I understand, it's still available in Win10...

I'm one of the "programmers of yesteryear", part-time in the early '80s on CP/M them on to Windows 3.1 after graduation in 1984.

Doing things the old-fashioned way was harder but less was expected of you, time-wise. Getting a "database" (a set of BTrieve files, usually) set up would take days, editing on floppies, etc. It was just expected that making software was a long process.

If you happen to end up in those environments again, I would appreciate it if you take a look at my prototype web-based message board.

It's designed for compatibility, and I've tested a lot of Netscapes and IE4, but nothing on Win311 yet.

If you want to leave a comment, you can do so right on the message board. It should work, more likely with JS off.

> It should work, more likely with JS off.

Many of the 3.1-era browsers didn't have a concept of JS yet. If you're relying on noscript at all it won't work.

I did try and check if this was the case, but both links in your profile that it could have been lead to "not found" dreamhost sites.

I feel obligated to comment, so that others are not led astray by parent comment, which is INCORRECT:

<noscript> works just fine in pre-JS browsers, at least all of the ones I've tried.

It works exactly as designed: Text between <noscript> and </noscript> is displayed in browsers without JS enabled (or supported).

I am not aware of any browsers where this is not the case, and I've tested in many, including Mosaic 1.x-3.x, NN 1.x-4.x, Opera up to 3.62, and others.

(You probably happened to visit my site during an upgrade. Sorry about that.)

Why would notscript not work on a browser that has no concept of JS?

Because the <noscript> element isn't valid for the stricter form of HTML that they use. Invalid elements didn't used to show up.

From what I recall of that era, it's the exact opposite: invalid elements (like <noscript>) are simply ignored, and their contents shown. That's how <noscript> works: newer browsers which understand JavaScript know the <noscript> element and ignore its contents; older browsers which do not understand JavaScript don't know the <noscript> element so its contents are shown. The same trick is used for <noframes>: browsers like Netscape which understand frames don't show the contents of that element, while other browsers which don't understand <frame> and <frameset> will show the content of the <noframes> element, so it can be used as a fallback.

Strict validation of HTML came later with XHTML, but AFAIK all browsers which understand XHTML also understand JavaScript.

XHTML came after HTML 4.0, so it had its advent around the rise of JavaScript's popularity.

However, HTML 2.0, which you can find specified here [0], and it specifies the "ignore" behaviour. Short of spinning up an old VM, I think I'll trust that my memory hasn't failed me.

From RFC 1866:

> markup in the form of a start-tag or end-tag, whose generic identifier is not declared is mapped to nothing during tokenization. Undeclared attributes are treated similarly...

> For example: > <div class=chapter><h1>foo</h1><p>...</div> > => <H1>,"foo",</H1>,<P>,"..."

[0] https://www.w3.org/MarkUp/html-spec/

If that was true, why did <script> tags have that horrible hack where the contents started with <!-- to hide from old browsers?

Note that in the example code I gave the enclosing tag vanished, but the internal tags did not. That's why.

Some of your UI might have been easier to build with VB than VC. VB4 was the last version to support 16-bit Windows applications. You might have better luck finding VB6 libraries/code-samples that run in VB4 than you had finding C89 libraries.

I forgot to make the repo public. It's up now!

Did you get to work with a co-operative task scheduling? This version of Windows still used one I think. What's your experience if so?

Windows (not only the 16-bit 3.x, but going as far as the newest 64-bit ones) uses an event loop for the GUI: your program runs a loop calling the GetMessage function, which blocks until the next window message is available. As long as you don't take too much time processing each window message, you don't have to even think about cooperative task scheduling, since Windows will do it for you while waiting on GetMessage.

(In fact, AFAIK even in modern Windows you should avoid taking too much time to process each window message, since blocking the event loop thread makes the UI for your program unresponsive.)

I remember the user experience, I was wondering about design decisions during development.

You are guaranteed no context switches unless you explicitly request one - did it simplify some parts, or alternatively made it more complex? It's an asynchronous application.

Windows NT and Windies 95 were the first versions to have preemptive scheduling. Windows 3.11 and older would only switch tasks when he program requested new messages from the queue. Thus was totally annoying because most applications were written badly and had moments where they would go off and do things and not return to their message loop for several seconds or worse, hanging the entire system during that time. Windows felt very sluggish because of that.

And in Win95, your 16-bit apps could still do whatever they want as they were only cooperatively multi-tasked

You'd only notice if it an app crashed, at which point your only option would be to hard-reset the whole system losing all unsaved state.

bet you had fancy pants autocomplete also! That was a game changer when it came along....otherwise you had to refer to docs/books.... not to mention the limited screen size.... two monitors? no one was that rich :)

> not to mention the limited screen size.... two monitors? no one was that rich :)

I had dual screens at home in late 1995 for sure, can’t remember if I used a dual screen setup any earlier than that.

They mention having to look up function declarations in the header files, so perhaps not.

Reading this article and others by the same author on his travails of getting Windows 3.11 to install and then bridging it to modern(-ish) tech was like being transported back to the 90s when I was first learning about computers. Seeing those screenshots of the unmistakable Win 3.1-style dialogs was a real nostalgia hit. What a treat.

10 points (well, an upvote, I guess) for anyone who knows why the Windows DOS-mode installer says "Press F3 to exit"

> Seeing those screenshots of the unmistakable Win 3.1-style dialogs was a real nostalgia hit. What a treat.

When I first saw that UI in 1990 or so, I was so confused how one program could accidentally cause another one not to respond. And how all the filenames had to be in 8.3 format.

Amiga had spoiled me.

Are you asking why it’s F3 as opposed to some other key? Because that would be from the IBM CUA standard: https://en.wikipedia.org/wiki/IBM_Common_User_Access.

Yep, that's what I was thinking of. F5 for refresh is another artifact from that time.

Is it this?

Press F3 to exit setup without rebooting; A bug in the MS-Client installer prevents a file necessary for Windows 3.1x support from being installed. This isn't necessary if running solely under DOS, but it doesn't hurt in anyway, so let's install it just to be safe.

Warning: [Omitted] source link is blocked as malware by Firefox, quote gleaned from [DDG] search results.

I seem to recall that F1 and F2 had some sort of hard wired functions (that were printed on my keyboard) but I don't remember which they were...

There was never any that much hardwired functions for F1 and F2 on PC (apart for the convention that F1 is almost always help).

On the other hand there is a related issue: on DEC (and some other) terminals with LK201-style keyboards (which in turn inspired the "modern" PC/AT keyboard layout with F1-F12) the keys in positions of F1-F5 had fixed functions. This is the reason why there are about four different escape sequences across vt220-compatible terminal emulators for F5. There simply was not any DEC terminal that had F5 on its keyboard (F1-F4 are almost always mapped to PF1-PF4).

F1 was already Help by then I'm pretty sure

Yes, the nostalgia hit me hard with this.

Related: winevdm makes running 16-bit apps on 64-bit Windows possible: https://github.com/otya128/winevdm

Oh I did not know about this! I just based my understanding from the official Microsoft documentation. Thanks!

Unfortunately, even this isn't perfect. For example, when running Tetris from WEP, the colors are off/weird (I'm guessing a color depth issue). It is, however, good enough to run just about any old crap I've given it.

this is great, didn't know about this - now which 16 bit windows apps I want to run that haven't been ported or updated yet? i can't really remember

> The stack size of a 16-bit program is typically 4-6 KiB with a similar size for the heap. This is smaller than the size of the HTTP reply + JSON returned by Slack!

Maybe this would be a good opportunity to stop for a moment and reflect about whether or not the industry is really moving in the right direction.

I'm not sure slack actually uses these apis in their own app? They use websockets for a lot of the communication right? In which case the server just pushes small messages.

After the first few paragraphs, I was most eager to see how he managed to handle modern TLS on Win3.1. Last time I wrangled with vintage stuff near that timeframe, that was the toughest part.

Alas, he "cheated" for it with a proxy app. Can't say I blame him, since it's probably about as much work over again to get modern TLS 1.2 working on such an old Windows.

IMHO the fact that it's hard to get TLS 1.2 (or indeed any form of "pure" cryptography) working at all on an obscure platform says a lot about the state of commonly available crypto libraries --- as those who are against regulating it like to say, it's "just math"; and math that any computer should theoretically be able to do. OpenSSL is one of the more portable ones, yet I'm not sure how it would be able to handle the 64K segmented model. It would need at least 32KB (maximum TLS record size, multiplied by both directions) and a little bit more per TLS connection. That said, a 2048-bit RSA key is "only" 256 bytes, and ECDH ones are smaller, so I think a TLS 1.2 (or even 1.3) implementation on the platform is definitely in the area of "feasible, but not trivial". A lot of IoT stuff has similar constraints (minus the segmented addressing).

If someone has got a working TLS 1.2 on such an old OS, I'll like to know too. Because I certainly haven't saw any example.

I think the work to get TLS 1.2 working will certainly dwarf the work on this Slack app.

Yes I was curious about that too. Cheater. :)

Seems to me you'd pretty much have to write a simple TLS 1.2 or 1.3 client by hand, or port an existing simple implementation.

But yeah, makes sense as it would be way too much work.

Considering that Windows 3.1 takes less space than Electron binary, one can actually run this program in VM and get better performance and less RAM usage than official app.

For Slack without Electron there's Ripcord

It runs in Windows, Mac and Linux


I updated my blog post to include a memory and disk usage comparison :)

I have DOSBOX, but Windows 3.1 runs very slowly on DOSBOX.

I was running win 3.1 under DOSBox fastly since forever (athlon days). You may have some CPU settings wrong.

If the target was just "Windows 3.1", he should have built a 32-bit app using the Win32s API [https://en.wikipedia.org/wiki/Win32s]

It's also probably possible to use a current compiler, maybe clang or gcc, to compile such code (officially only up to VC++ 4.2 is supported), although it might require some hacks.

Win32s applications can be executed on a limited subset of hardware supported by Windows 3.x.

Which is moot point given that the Microsoft-supplied TCP/IP stack is essentially also Win32s application and thus only runs on the same subset.

Petzold is Gold. I have a copy of the Fifth Edition that I bought new and I expect it to remain useful for some time yet.

Fwiw programming windows by Petzold through the 5th edition covers native Windows development through Windows XP.

The sixth edition on words begins to use the. Net CLR and other non-native toolchains as Microsoft changed them. So, those are less valuable to me.

If you want to do native Windows development, that is probably the single best book you could buy.

This presents c89 as the most antiquated thing in the world, but VS didn't support mixed declarations and code in a .c file until 2015. There is still a lot of code out there that avoids this to be able to work with MS's compilers.

It's now 2019, and as far as I know, MSVC still doesn't have full support for the 20-year-old C99 standard.

... in C mode, which is basically C89 (+ whatever is needed for recent C++ versions). Compiling C code in C++ mode is a common way of working around this. But MSVC is not a C compiler, it's a C++ compiler, so their unwillingness to invest in C is probably understandable.

Shortly after my comment I remembered that even in c99 or c++, there are patterns where mixed declaration and code are messy. WndProc switch statements is one example. You can't jump past a declaration of the same scope, so a case label can't declare anything unless you add curly braces.

Could have done it with C++, would have worked for calling WinAPI too.

If there are gripes about c89 I don't want to think about how different c++ support would be relative to the late 90s or early to mid 2000s, let alone now.

> Purists may not like this solution but this is the best I can do with my abilities in a reasonable amount of time.

I am going to be using this line a lot in the future.

You can probably run this app using WINE on any modern Linux 64-bit system. Or maybe even Mac OS X Catalina.

(The Linux x86 maintainers are semi-seriously considering deprecating the horrible machinations needed for 16-bit on 32-bit to work, but 16-bit on 64-bit Will be supported for the foreseeable future.)

Windows 3.1 and 16 bit would be a little too painful for me. Windows 95 was quite nice with 32 bit and preemptive multitasking though. I kind of miss this or Windows 2000.

There's also Win32s for writing 32-bit applications in Windows 3.1! It could be done because Windows 3.1 in 386 mode uses a 32-bit kernel that saw relatively few changes between 3.1 and 95. The main difference between 3.1 and 95 is that 3.1 uses a single 32-bit task for all of the GUI, but there is really a lot of 16-bit code in Windows 95 (unlike NT for example).

/me feels an urge to read Unauthorized Windows 95 back to back.

If I had a month to do whatever I wanted, I've always wanted to 'go back in time' and try to write a Doom level editor for W 3.1

NT4 was very nice, although no USB.

Didn't crash and was smooth as butter.

Last time I "used" NT4 it was to set up a machine for a specific piece of software so I could test a SICK 2D LIDAR unit (one of the blue "coffee pot" units) I had purchased off Ebay; sometime around 2014/15 IIRC.

Initially turned out that it had been set to RS485 mode, and I didn't have an adapter, and I didn't even know if it worked if I was able to get it into that mode. So with the help of a sympathetic engineer at SICK, he had me send to unit to them and he reset it (to RS232) and tested it. When I got it back, I tested it with the machine again and it worked perfectly. He didn't charge me anything for the service.

You don't see that kind of support anymore - almost no company will say "yeah, sure, send us a unit you bought second-hand off Ebay to us and we'll take a look at it, fix it, etc - and no charge to you, either - even though you're just a hobbyist and have no support contract" - it shocked me.

I find this history so super interesting.

Have you kept a nt4? Do you still use it? What do you think is the closest equivalent: win200, reactos??

No, I haven't used it since early 2000. Windows 2000 was the successor, also a good release. I guess both are pretty close to what NT4 was.

As a side note, since TFA mentions you can't run 16b apps on 64b Windows, I'd like to mention that otvdm/winevdm actually allows you to do it by running Win16 apps on Win32 using Wine!

Thanks for raising this to me!

Nice, Would have been a lot using with Visual Basic 4, but I guess easy wasn't the point.

Same with Delphi. We did decades of applications going from Turbo Pascal in the 80s to Delphi in the 90s and 00s and 10s without hardly any changes (this was possible because I wrote a tooling to convert the DOS Pascal graphics code to Delphi Windows automatically so we ran 1 version of code that compiled on both) right up until the company was sold a couple of years ago.

You could avoid the copy out of the JSON string by using a field width specifier in your printf formatting string. Those should be available in ANSI C / C89/90.

   currentToken = tokens[index];
   tokenSize = currentToken.end - currentToken.start;
   if(tokenSize <= 0){ continue; }
   printf("Current token %.*s\n", tokenSize, startOfJson + currentToken.start);

One of those things usually only people who've written printf format parser know.

The printf is just for example code.

In actual fact, I'll have to copy the data to a char array to be sent to display in the listbox.

Fair enough. I read this quite literally and thought "not exactly":

> hence I need to use those values to copy out from memory to a separate char array for printing purposes. Certainly not so trivial.

I had to do things the old-fashioned way reading books and header files [...]

O tempora o mores!

I'm getting old...

Another option would have been Turbo Pascal for Windows 3.1


Cool tutorial, I read an article about ideas for mobile applications (https://mwdn.com/mobile-app-ideas-2020-how-to-create-somethi...) and now I want to create my own, there is one idea about how to create another application from one application, I read your article and was inspired. thanks :)

> Therefore, if one wants to write an app using Windows OS standard APIs, WFW 3.11 is the oldest one can go back without putting in even more exponential effort.

Hey, what's wrong with Trumpet Winsock? :-)

My thought too - but then I recalled - vaguely - the "setup" procedure for it - so "even more exponential effort" sounded a bit right...

Trumpet Winsock is not by Microsoft :P

This is so amazing, I love all you people who take the time to do these super mega awesome tinker/fun projects and then share them with to the world!

Disappointed not to see the now deprecated WSAAsyncSelect function in use. It was their extension to make sockets play nicely with the UI event loop.

They needed some way that you could be waiting for either window messages or socket data. Otherwise your window would stop responding to input or repaint itself if some socket operation blocked.

Reading how he cheated with proxy. That was what I wanted to see. :( Had a client of a enterprise style company integrate into one of our products. Dude was the definition of cowboy coder so we often looked at logs. All I can say is wow - them logs for negotiating a https connection in BASIC..

please tell us more!

When I found a win95 box with tp7 on it, my first thought was to write 'modern' things on it. HTTPS, Haskell... I starter writing a lisp. Didn't finish sadly. Because i love the idea of bridging 'old' with the good parts of 'new'

Though Lisp is much older than Windows 95 of course :)

lisp is forever more modern, you know that

Everyone really should be made to code up a few Win32 apps, at least, before they are allowed to make an Electron app, just so they can get a real sense of what the trade-offs actually are, instead of relying on hearsay and FUD.

> Also, we can’t write our code directly on the Windows 2000 VM as it has limited software support for modern IDEs like Visual Studio Code not to mention security issues.

I'm guessing that Visual C++ 1.52 has no code editing capabilities like Visual Studio?

VC++ 1.52 has an internal text editor but nowhere near the capabilities of Visual Studio Code or any modern text editors.

I also use Git and sourcetree and they won't run on Win 2K.

This is amazing, very well done. I think every programmer should from time to time build something for a very old platform and appreciate the progress achieved so far.

By which you mean that they'll recognize everything that's been stolen from the users, right? Win 3.1 & DOS was probably about the last time I really felt in control of my PC.

> Windows 10 [...] cannot directly talk to the ancient SMB protocol used by WFW 3.11.

Not true, you can downgrade the SMB version requirement in the Windows 10 registry.

But then you'll have to spend the rest of your life dodging Ned Pyle of Microsoft.

It’s unfortunate slack is this difficult to integrate with. Jabber or IRC clients could be spun up with zero pain.

Show us :-)

I'm sure writing mIrc was not "zero pain" back in the day. And Jabber needs a XML parser which is more complex than a JSON parser.

There are tiny XML parsers out there.

Also, an IRC client is a joke, it can be compiled and built even on BSD 4.3, released in late 80's.

The suckless guys created some IRC clients in few lines, and the sj client is not that difficult.

Heck, you could write an IRC client with Bash and even with Netcat/ed.

Just use Bitlbee and MIRC. Done, Jabber client for Windows 3.1. And Telegram, and whatever Bitlbee and/or Libpurple supports.

A streaming; normalizing XML parser doesn't sound like a lot of fun to implement in C89 to me :)

I wonder how much easier this would have been in Borland C++ or Borland Pascal with OWL.

Or even Delphi! Delphi 1 targeted Win16.

Aaw cheating with https. I wonder if an embeddable library like BearSSL would be hard to get working.

Something I can try next time! I didn't know about BearSSL before

Or FreePascal/Lazarus with OpenSSL. If you build a Win16 statically linked binary it may work.


So a properly native Slack client exists for Windows 3.1 before modern platforms? Whaat the hell?

I'm a bit disappointed that the code doesn't appear to use Whitesmith style...

Do the public slack APIs offer enough to built a third party client?

I felt it was enough for me. :)


Thanks! given the amount of complaining about slack on HN I thought someone would have produced a native open source client by now. I might look into it.

Yes, it does!

And weechat-slack is great.

snprintf() may not be C89, but fgets() sure is.

Noted. Will update my blog post!

I'm pretty surprised to see slack client exists for Windows 3.1 before modern platforms


This is a lot of work to avoid using that WYSIWYG editor.

There's an option to disable the WYSIWYG editor now :)

Unfortunately, it still doesn't work as good as before: text like `Object`s (no space between the ending ` and next text) doesn't work anymore, and according to Slack's support this is 'working as intended'.

Unsure why it goes to twitter. Here is the blog post. http://yeokhengmeng.com/2019/12/building-a-new-win-3-1-app-i...

Changed now from https://twitter.com/gravislizard/status/927593460642615296.

Edit: oh, I see what happened now. We made a mistake, intending to set the URL for https://news.ycombinator.com/item?id=21831931. Sorry!

OMG, this is amazing tutorials bro

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact