What Does It Take To Port 16-Bit Windows 1.0 Applications Into Native Windows 11 Programs?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Have you ever wondered what it takes to convert an 16-bit application from the very first version of Windows, released in 1985, to run as a native 64-bit application in 2021? Well, let me tell you, it’s not as straightforward as simply opening Visual C++ 2022, and clicking “Compile”. Infact, there are a surprisingly large number of hurdles in accomplishing such a feat. Just to give an example, if you load a Windows 1.0 application under Windows 3.1, it will first pop a compatibility warning, and then, assuming it runs, it will likely have notable sizing and font issues. This does not even account for the fact that there were significant changes to the Windows API with the advent of 32-bit computing. I decided, just for my own curiosity, to see what this process involved in what ultimately became an eight and a half hour livestream. Since this ended up fairly interesting project, we’re once against rolling out another “NCommander in Realtime” video, where we cut down that livestream to a shorter video with new footage and a replacement voiceover. So, sit back, relax, and enjoy as we figure out to tack on an extra 48-bits of technological process to programs written decades ago. Even before starting the stream, I had a rough plan on how to proceed. The Windows 1.0 SDK included several example applications, and this seemed to be a fitting starting point. I planned on beginning with porting these applications to build with Visual C++ 1.5 first, since I would need to code changes to fix the window size, and properly handle support for TrueType fonts. This would then lead to Windows NT 4 and Visual C++ 6 where we would navigate the 16 to 32-bit transition. After sorting that out, we’d jump again to Server 2003, and Visual C++ 2005, where I intended to sort out 64-bit compatibility issues, and, if possible, compile for Itanium, just because I think it would be funny. Finally, we will then jump ahead to the present day, where we’d load up everything in Visual C++ 2022 Community Edition, and go for broke. In practice, not only did we do this, we even transcended the limits of the Intel x86 architecture, and embraced NT on RISC as well. But, before we get ahead of ourselves, let’s take a look at what we’re starting with. Taking it right from the top, we’ve got HELLO, which is the obligatory Hello World program that I covered as my first retrocomputing video. This is followed by is “FONTTEST”, which, as the name implies, demonstrates Windows’s native font handling capabilities. Next is SHAPES, which simply draws a few simple vector images with GDI which work regardless of the display resolution It’s appropriate then that the next program we’ll be looking at is TRACK, which draws a shape based on how the mouse is moved. This program was probably written to help demonstrate how to dynamically resize graphics. The next is TEMPLATE, which despite the name, isn’t actually a “new project” template. Instead, it’s more a demonstration of various UI widgets built into Windows. It’s also probably one of the more complex applications included here. Finally, rounding out the set is CARDFILE, TYPE, and the newcommer, WINEMINE. Let’s start with the easy one first. TYPE is a virtual typewriter application. I’m not exactly sure what the point of this is, but it lets you type one full line of text, which disappears when you press enter. CARDFILE should be familiar to many, since it was included in the box until Windows 95. For those who haven’t encountered it, it’s essentially a set of digital index cards. It was also the only application I expected to have real problems with since it has some handwritten assembly inside. I actually intended it more as an example of why these sorts of ports could be very difficult but I still expected to be able to build it for Windows 3.1 if nothing else. Finally, I also added one third party application. This is WINEMINE for Windows 1.0. As you can tell, it's basically Minesweeper. In actuality, it's a port of WINE’s Minesweeper to Windows 1.0, which was done by Nathan Lineback of ToastyTech fame. This proved to be an unexpected headache for reasons we’ll get into. Now that we’ve met the actors, let’s get down and dirty with it. Stepping into Windows 3.1, we have Visual C++ 1.52, which was the last version of the Microsoft development tools to support 16-bit programming. Our goal here is two fold. First, we need to make project files for all the Windows 1.0 applications which we’ll use in each step of the migration process. Next, we had to get them to build. It’s here where we hit our first stumbling block. Windows 3.0 changed the internal format of resource files, and more specifically, icons and bitmap graphics are in an entirely different format. This causes the resource compiler to error out, and App Studio to complain that it can’t load the RC file. This was an expected problem that proved to be an unexpected headache. I had, naively, assumed that Microsoft included a conversion tool of some sort, but nothing I tried could successfully open the Windows 1.0 resources to convert them to the 3.0 format. I had read that Borland’s Resource Workshop could do so, and I just so happened to have a copy of Borland C++ onhand. We took a brief interlude to dump the disks and install it, but its resource toolkit also errored out. After the stream, I actually found that Borland C++ 4.5 *can* convert these resources, but I’m still curious if there was some sort of Microsoft tool to do this that I haven’t found as of yet, since this seems to be a fairly large oversight. Still, for this project, this isn’t that big of a deal. For the most part, the only graphical resource used by any of these applications is the icon, so we can just remove it and use the system default. It’s not an elegant solution, but it sorta works … Well, unless we’re talking about WINEMINE which uses graphics extensively. Without a way to convert the existing assists, I have to draw my own, and well, that was enough to make me put WINEMINE aside. That being said, icons weren’t the only problem I was facing, since we still had to resolve the API differences. For one, we need to change how the actual windows dialogs were created, to account for the differences between a tiled application, and one that supported overlapping windows. In practice, this is a relatively simple code change to the CreateWindow() API call, and a few minor changes in the RC file. I also took the time to resolve compiler warnings, as it would save effort down the line. Next, we also had to resolve the issues relating to fonts. In Windows 1.0 and 2.0, the UI used unchangeable fixed-width fonts. Windows 3.0 used variable-spaced TrueType fonts, and as such, many UI elements were either misaligned, covered up, or just flat out broken. To fix this, we had to change the position of how interface elements were laid out. UI elements on Windows are traditionally defined in what is known as a resource file. While later versions of Visual Studio included an integrated resource editor, this version used an external application known as “App Studio”. Within Studio, we can redefine and redraw the dialog boxes as needed, and I also took the time to try and fix the key shortcuts, which are known as accelerators. After a lot of tinkering, I successfully fixed the UI elements so they would render correctly. I also did a bit of touchup work to some of the other applications to make them conform to Windows’s 3.1’s look and feel a bit better. After quite a bit of fiddling, I had successfully fixed all the example applications beside the previously mentioned WINEMINE, and CARDFILE. Now, I expected to have problems with CARDFILE, but I had thought I would at least get it working on Windows 3.1. The problem I ran into is that this version Microsoft Visual C++ does not support building code written in assembly. Infact, the Microsoft Macro Assembler, or MASM, was still a commercial retail product at this time and there didn’t seem to be an easy way to work around this issue. I did actually briefly look at replacing the hand written assembly with C code, and here I made a bit of a surprising discovery. Most of the assembly code within Cardfile was to do disk access via the MS-DOS int 21 interface. Microsoft provided C functions to read and write files, so I can't help but wonder why they would have coded Cardfile like this. The best guess I can come up with is that CARDFILE might have been developed very early in Windows history, back when it was still known as Interface Manager, and simply carried forward to Windows 1.0 with relatively little change. It’s also possible it was based on a pre-existing DOS application of some sort. In practice, it would be relatively straightforward to replace the handwritten assembly with C code, but it would probably mean a few hours of effort. In the interest of time, I put it aside. Still, we now have six applications fixed up and ready to go. Now it was time to double our address space and jump into the world of 32-bit computing. While there are multiple ways to do this, I decided to use Windows NT 4, and Visual C++ 6. Once I had the files copied over, it was just a matter of importing the Visual C++ 1.52 project files, which would create a new 32-bit solution to begin the migration process. Here we begin to see the differences between 16 and 32-bit computing. For one, when Microsoft ported the WIndows API forward, they removed or nulled out certain functions that were completely irrelevant such as the hPrevInstance argument, and GetInstanceData(). In those cases, I just had to remove the code in question. In other places, I had to fix the data types and function declarations. For instance, certain procedures under 16-bit Windows had been declared as using a Pascal compatible API, and as a FAR function. Under 32-bit Windows, there’s no such thing as a near or far pointer, and API functions and callbacks instead use purpose specific declarations. In practice, this is a lot trickier than it seems, since the compiler doesn’t always give great warnings, and getting it wrong can cause interesting bugs, such as the background not being properly painted. Finally, and this was the time consuming task, there were parts of Windows API that simply no longer existed. For instance, quite a few functions had been outright replaced and to name an example, the GDI function “MoveTo()”, only exists on the 16-bit versions of Windows. On 32-bit versions, you have to MoveToEx(), which takes an additional argument for a return value. There were quite a few of these types of changes, and I had to consult MSDN on multiple occasions to work out the differences. I will note that it’s very frustrating that Microsoft had a nasty habit of deleting old documentation and example code off their website, making this much harder than it should be. I just dislike that there’s this ongoing tendency to destroy perfectly good information because it's obsolete. With that rant aside, after a not insignificant amount of fiddling, I got all the major issues resolved, and I now had 32-bit versions of six applications. We’ve also jumped nearly 15 years in computing history. Now it was to look towards the future. We needed to jump ahead again to the XP-era, this time with Server 2003, and Visual Studio 2005. This represents the early the .NET era of Microsoft’s development tools, and when Microsoft began to become more strict on what code the compiler would accept. I actually expected that we would start getting compiler warnings at this point due to the legacy K&R function declarations that had been used up until this point. That surprisingly didn’t happen, and in practice, aside from one or two minor issues, we had no major problems on Server 2003. That being said, this version of Visual Studio was notable for two things. For one, it had integrated support for the then-new x64 architecture. That meant I could compile 64-bit binaries for the first time, which, somewhat surprisingly, mostly worked on the first try. Unfortunately, I had a 32-bit version of Server 2003 installed, so we didn’t immediately test them. Secondly, it should have supported Itanium. If you saw my video about Space Cadet Pinball, I have something of a soft spot for this trainwreck of a platform. Unfortunately, I couldn’t seem to add an Itanium target in VS2005, even though I had the compilers installed via the Platform SDK. I had vague memories of doing this in Visual Studio in the past, so I ended up resorting to Google to figure out what I was doing wrong. What I found is that Microsoft had actually locked out Itanium support unless one paid through the nose for the very expensive Visual Studio Team Edition. To make a long story short, I suspect that the only way I was going to get IA64 binaries was if I made a makefile to compile with the Platform SDK directly. Given the amount of headache, I ended up skipping on making an Itanium build, especially since we found out that my IA64 server was for the moment out of service, but it is still incredibly irritating to know how difficult Microsoft made this. Still, that diversion aside, it was time for the home stretch. Or well, so I thought. Moving ahead to WIndows 11, you can in fact directly convert projects from Visual Studio 2005 to 2022. Once again, I loaded all six projects, and compiled them for 64-bit Windows. True to form, they all worked just fine after being migrated over 36 years of computing history. Now, in practice, I could have ended the stream here, but I didn’t. Just for the sake of posterity, I ended up posing all my VMs for a screenshot of the TEMPLATE application running on Windows 1.0, NT4, Server 2003, and Windows 11. Chat wanted me to take this further, since there were still unexplored venues. It began with adding TEMPLATE running on Linux via WINE. It then started to go downhill from there. Since it obviously worked on WINE, it would probably work on ReactOS, right? Since I had no real reason not to try it, I quickly grabbed an installation ISO off reactos.org, and installed that in a VM. After a small bit of fiddling, we now have TEMPLATE running on six platforms. Chat, at this point, wanted to see htop measure how badly my PC was suffering, but, unfortunately, I had recently upgraded my editing rig, and it has 64 GiB of memory. Or in other words, we could go deeper, and spoiler alert, we did. Next up was to get the TEMPLATE running on OS/2, since that was a planned 32-bit successor to early Windows. I wasn’t going to go through and make a native port, although maybe that’s a future livestream idea, but I did have the OS/2 Warp CDs on hand. So, in an effort to give the crowd what they wanted, I fired up a new VM, and got installing. After the usual game of progress bar simulator, I loaded up TEMPLATE in WinOS2, and added that to the family tree. You’d think we were done now, right? No, not at all. You see, I made the mistake in mentioning that it was technically possible to install MIPS port of Windows NT 4 in QEMU, and thus transcend the limitations of the Intel architecture. I really should have walked away, but I was talked into trying it … With a set of instructions in one hand, and the bog standard NT4 CD in the other, I did actually get Windows NT for MIPS to install with relatively little fanfare. It’s not that different from the x86 version, although it has its own unique quirks. For one, it can run 16-bit Windows applications, as well as DOS based ones via NTVDM. That’s because Microsoft licensed SoftPC from Insignia and incorporated it directly into the system. That means I could load up the 16-bit version of TEMPLATE without changes. However, without add-on software, the RISC based versions of NT can not run 32-bit x86 applications, and in practice, such software only existed for DEC Alpha in the form of FX!32. The thing is, we don’t do things by half measures on this channel, so I found myself compiling TEMPLATE as a native NT MIPS binary. Let me just be upfront about this: this is far more annoying to do than it had any right to be because you have to use a special version of Visual C++ running on the machine itself. There are no cross-compilers, or cross-development tools to help you. This no doubt played a large part of why there is almost no software available for the RISC variants of Windows N. Even after transferring the source files over, I had to recreate the project files for this version of Visual Studio. Afterwards, I had to deal with the fact that compilation failed, even though the same source built just fine on x86. As it turned out I had used a few compiler macros from windowsx.h that either didn’t exist on this version of Visual C++, or were simply removed on the RISC ports. This required me to do additional patching to handle point parameters, but after 30 or so minutes of fiddling, we now have a Windows 1.0 application building as a native NT MIPS application, and thus can add this final element to the collection. At this point, things started winding down. I spent a bit of time trying to get my Itanium box going again to no avail, and then after a last minute Q&A session, finally wrapped it up after 8 hours of non-stop streaming. In closing, I might do a follow-up to this, exploring porting the remaining Windows 1.0 applications, as well as perhaps looking into building Hello World, or one of the other test applications for every released version of Windows. If you want to see that, let me know below. With all that said, if you’ve enjoyed this content, consider giving it a like, or subscribing. If you really enjoyed this content, consider supporting me on Patreon. As usual, this is NCommander, signing out, and wishing you all a pleasant day.
Info
Channel: NCommander
Views: 250,909
Rating: undefined out of 5
Keywords: ncommander, retrocomputing, windows 1.0, hello world, visual studio, visual c++, 16-bit, 32-bit, 64-bit, windows 3.1, windows nt 4, server 2003, windows 11, porting, retrodevelopment, risc, windows nt on risc, k&r c, example code porting, windows api, c development, win32, win64, itanium, visual c++ 6, visual c++ 2005, visual c++ 2022, porting software, backward compatibility, win16, masm, cardfile, interface manager, windows development
Id: kh0CdLPkJVE
Channel Id: undefined
Length: 21min 14sec (1274 seconds)
Published: Fri Nov 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.