(This article is also available via the short link tomrei.ch/drmario)
In a recent article I mentioned that I've been working with some classic hardware to get some old DOS and Windows software running. I've probably been having the most fun playing around in a Windows 98 environment as it seems to be the best bridge between the classic DOS environment and the newer Windows environment we all know and love, and while I once (2.5 decades ago) felt very at home in this environment, the lack of modern OS components like Task Manager has reminded me how far we've come.
In my senior year of college, I took a class on UI development. This class was enjoyable for many reasons, one of which being a very open final project assignment. While it comprised of some large percentage of our grade (something like 50%) we were basically free to do whatever we wanted as long as we developed something with a graphical UI. I wanted to make a game, and I was enjoying playing Dr. Mario at the time, so I thought I would take a stab at creating a Dr. Mario clone in C#, which I had just recently begun tinkering with. After a few long nights of furious coding, I had a somewhat working prototype, and in my spare time over the next few weeks, I polished it up and added features like network play and background music. The result was a fun to play recreation, and it netted me an A grade both on the final project and in the UI development class. I also zipped up the game and stuck it on my website as a sample of my coding prowess, available to download for several years before I eventually took it down after hearing stories of how litigious Nintendo has become. No sense in tempting fate as I had shamelessly copied several assets from the NES game.
After setting up my modern Windows 98 machine and installing and playing a few games that I enjoyed a quarter century ago, I remembered that Windows 98 had a .NET 2.0 redistributable package, and I was curious to see if I could get my Dr. Mario clone to play. A quick web search confirmed my memory, but there were some caveats. The .NET 2.0 framework had received several service packs that never made it to Windows 98, and P/Invoke calls to the Win32 API were iffy given that Windows 98 didn't have the same level of support for certain things as did newer versions of Windows. Still, I figured it was worth a shot. I grabbed the installer and threw it on the system.
After a successful install of the .NET Framework, the moment of truth finally came. I copied over my Dr. Mario game, double clicked on the exe, and... up popped the familiar .NET unhandled exception dialog. Crap. Digging into the message revealed the issue involved MCISEQ.dll, which sounded like it involved MIDI sound playback. A web search confirmed this. "Oh well," I thought.
A few days went by and the situation replayed a few times in my mind. I figured I probably had the source code somewhere, but could I get a working version to recompile? Would I need to install Visual Studio 2005? At the minimum, I would probably need to install support for the .NET 2.0 framework in my modern version of Visual Studio, but I still wasn't sure if any executables it produced would be capable of running on such an old version of the framework.
Then I started thinking about alternatives. What if I was to disassemble the game and NO-OP all the calls to play the MIDI background music? It was risky as there could be other unsupported system calls in the game. I also wasn't sure if I had all the tools necessary. I opened up a DOS Prompt on the Windows 98 machine and ran "dir /s ildasm.exe" but it returned no results. Crap. What about ilasm.exe? Interestingly, this was included with the Framework package, along with csc.exe and some other tools. So could I use the disassembler on my modern machine, NO-OP the MIDI calls, then send the resulting IL over to the Windows 98 machine and recompile it there? Worth a shot, I figured.
It took me about 20 minutes on my modern machine to run drmario.exe through the disassembler, search for all references to MIDI playback, NO-OP them, then re-run the resulting IL through the assembler. I was able to confirm it was working on my modern machine, to my surprise. The game compiled and ran, and there was silence. Golden silence. But what about on the Windows 98 machine? I copied the IL over to the Windows 98 machine to give it a shot.
The first step was running the assembler. Expecting it to barf immediately, I was surprised as ilasm.exe spit out a lot of text, followed by a success message. I checked the directory and, sure enough, there was a resulting executable file. Cool. I double clicked on it, once again expecting to see a .NET Unhandled Exception dialog, but to my surprise, up popped the title screen! Great, but I figured I wasn't out of the woods yet. I needed to see if I could actually start a game. The game configuration dialog appeared, I set some settings and clicked Play, and sure enough, the game started playing!
After poking around with it a bit more, I discovered everything seemed to be working great, including network play. It was fun to start a network game between a Windows 11 client and a Windows 98 client and see everything communicate just as I would expect it to. Score one for the .NET assembler/disassembler for still maintaining compatibility after two decades!
Anyway, I'm off to play Dr. Mario.