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.