@aaronsgiles@corteximplant.com
@aaronsgiles@corteximplant.com avatar

aaronsgiles

@aaronsgiles@corteximplant.com

Rogue emulation programmer & demon hunter. Formerly of #Microsoft, #MAME, #Connectix, and #LucasArts. Still active in the Seattle choral scene #SeattleSings via Summer Fling Singers and Sine Nomine.

Author of #DREAMM emulator and the #ymfm audio library.

This profile is from a federated server and may be incomplete. Browse more on the original instance.

dosnostalgic, to random
@dosnostalgic@mastodon.social avatar

Star Wars Jedi Knight: Mysteries of the Sith Remastered 3.0
https://www.moddb.com/news/star-wars-jedi-knight-mysteries-of-the-sith-remastered-30

aaronsgiles,
@aaronsgiles@corteximplant.com avatar

@dosnostalgic Huh, wonder if they manually recreated the cutscenes or if we included the scripts (unused) with the original. We originally intended to run them ingame, but in the end decided it was safer to prerender them to guarantee audio sync across varying systems.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Hooray, he finally did a feature on my all-time favorite arcade game.

https://www.youtube.com/watch?v=FeaIpUTpo34

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Bizarre OG bug of the day:

The Win95 version of X-Wing runs fine on Windows but quits immediately on MacOS.

The code does a big heap allocation (4MB via HeapAlloc()) at startup, and then returns the result. A subsequent downstream function checks that result against 0 (NULL), and quits immediately if it is.

Except that this downstream function only checks the low 16 bits of the result. Meaning that if the allocation happens to land on a 64k boundary, it looks like a failure.

What makes this more likely to happen is that large heap allocations (above 512k) are documented to fall back to using VirtualAlloc, which allocates memory in page-size (4k) granules. So now you have a 1-in-16 chance of landing there.

The reason it happens on the Mac and not Windows is due to my emulator's memory management. For 32-bit Windows programs I allocate a full 4GB of host memory space and then map just the pages that have been allocated. This means that I need to honor the page granularity of the host system, and ARM-based Macs run with a 16k page granularity, so all VirtualAllocs will produce 16k aligned addresses. Thus, you have a 1-in-4 chance of landing on a 64k boundary there.

Thinking the best workaround would be to change VirtualAlloc so it never returns 64k-aligned results. A bit gross, but workable.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

FYI, GOG is having a "May the 4th" Star Wars game sale, so if you want to pick up some cheap Star Wars classics or the new Dark Forces remaster, now would be a good time.

Here's a list of GOG games that work in DREAMM: https://aarongiles.com/dreamm/buy/

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Arrrgh. Found a bug in the InstallShield code that is going to require an ugly workaround.

One of InstallShield's 16-bit components calls LoadLibrary(), which returns a handle to the loaded library's instance. In 16-bit land, this also happens to be the segment selector of the library's automatic data segment.

In DREAMM's implementation of Windows, all 16-bit segment selectors are allocated from the upper half of the LDT, so they'll all be 0x8000 or above and thus have their top bit set. This makes it super easy to identify whether a user space 32-bit pointer is a true 32-bit pointer (top bit clear) or whether it is a segment:offset pair (segment in the top 16 bits, thus the top bit set).

So, back to LoadLibrary(). The return value from LoadLibrary is a segment selector if there's no error, or else a value below 32 if there is an error. InstallShield compares the return value against 32, but uses a signed compare instead of an unsigned compare. Which means my segment selector with the high bit set is interpreted as an error.

Since there's no rule limiting the range of segment selectors returned by Windows, I consider this a bug in InstallShield.

Think I'm going to try a kludgy workaround rather than abandoning my LDT allocation strategy because it's quite heavily baked into my 16-bit logic.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

In case you ever wondered why InstallShield was so damn slow, I can tell you that one of the reasons has to do with improper message handling.

An InstallShield installer is actually a collection of programs that talk to each other during the installation process. They do this by way of sending broadcast messages back & forth. Broadcast messages are sent to every top-level window in the system. And because they use the SendMessage API, the sender is stuck waiting for every receiving thread to respond before it can continue.

One of the programs that is running (at least in the 32-bit InstallShield I've been digging into) launches the main setup.exe process and then sits in a loop that looks like this:

while (!done)<br></br>{<br></br>    // 1. allow incoming messages to process<br></br>    PeekMessage(); <br></br><br></br>    // 2. Wait 200ms to see if setup.exe has exited yet<br></br>    done = WaitForSingleObject(process_handle, 200); <br></br>}<br></br>

During the call to WaitForSingleObject(), incoming messages are not processed. So anytime one of these broadcast messages is sent, it will land on this process' window, and it is likely to spend up to 200ms doing nothing until it finally responds. And since the sender is stuck waiting, it can't do any further work either.

For a program that's so ubiquitous, that's a pretty rookie mistake!

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

So InstallShield manages to extract all of its files now, but then falls over trying to read a file named inst16.ex. Which is interesting because it doesn't extract such a file. It does, however, extract a file named inst32i.ex.

One theory is that the frontend decides this is a 32-bit system and extracts a 32-bit installer, but when it comes time to launch, they use different logic and conclude that this is a 16-bit system after all.

I did notice an attempt to dynamically load W32SYS.DLL, which is part of Win32s, so I went ahead and implemented the GETWIN32SINFO function they want to call in there. But after that, they still try to access inst16.ex.

Wonder if there are any detailed breakdowns of InstallShield's files and behaviors lurking on the interwebs....

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Managed to dig up some rudimentary information on PROGMAN. That plus some DDESpy traces allowed me to figure out how to respond to a DDE initiate request, and then accept commands. Seems like it's good enough to just blindly ack all the commands without doing any work, which is great. There appears to be no real return values.

It seems some installers expect PROGMAN to always be running, while others are able to launch it if it is not. I decided to detect the broadcast WM_DDE_INITIATE message and auto-launch my stub PROGMAN handler in response, so it's effectively there without needing to explicitly launch it.

Then I spent the rest of the day in scheduling hell as these new code paths revealed some problems in my task scheduling logic and how cross-task messages were being sent, along with interactions between thread and task scheduling. Think I might finally have it working ok now, but my brain is seriously fried!

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Managed to lay my hands on some rare Chinese and Japanese LucasArts releases!

First we have Chinese (both Simplified and Traditional) releases of Escape from Monkey Island. These will work fine in the next DREAMM beta, since the game handles its own font management and rendering.

Next we have the Chinese (Traditional) version of Indy Desktop. Obviously, I need to implement multibyte decoding and get a font before that's viable, but it does launch and play.

Then we have a Japanese release of Yoda Stories. Like the Chinese Indy Desktop release, this will also require work to get decoding and a font working.

Finally we have the Japanese release of Star Wars Screen Entertainment. Only the installer is in Japanese, so you can successfully navigate it and install, revealing essentially a normal English release (though some of the screensaver modules have been tweaked in unknown ways).

Not sure when I'll tackle the Windows font issues. That might have to wait for the next release. We'll see. But at least they will all be recognized in the next version.

image/png
image/png

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

New DREAMM beta is now available: https://aarongiles.com/dreamm/beta

New in 3.0b9:

  • Added support for Star Wars Screen Entertainment installers
  • Extended internal scripting language to auto-navigate the SWSE installer
  • Enabled key configuration for Dark Forces GOG (needs reinstall) and Dark Forces Demo
  • Improved behavior of minimized windows for Windows games
  • Improved system menu behavior for Windows games
  • Removed unsupported video options in Indy Fate Talkie
  • Removed unsupported audio options in Secret of Monkey Island CD
  • Fixed subtle memory corruption that led to crashes in Behind the Magic and Episode 1 Insider's Guide
  • Fixed crash in SWSE Posters module due to memory trashing
  • Fixed bug in FXAM that led to incorrect shadow effect in SWSE Rebel Clock
  • Completed internal reorg to help reduce crashes on quit in Windows games
aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

As far as I can tell, nobody has ever created an open-source replacement for winhelp, which is a bummer. So many early Windows programs relied on it to display help, and right now I don't have a legitimate way to make it work.

Microsoft did provide a version of winhelp that ran as late as Windows 8, but I can't get it to run on modern systems, and it has modern dependencies.

Maybe I can just try to get the Win2k version running. I see it's a 16-bit program. Would be an interesting test of my implementation in a more general way. It's laid out of kind crazy, with 102(!) segments, though the import list doesn't look too nasty. Something for later experimentation I guess....

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Implemented some basic Windows scripting today so that SWSE installation is automatic. I may eventually do this for the various supported updaters as well, but for SWSE it was kind of important as there are a lot of options that need to be configured appropriately.

video/mp4

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Another fun subtlety of 16-bit Windows is that I've found code that relies heavily on its DOS roots. For example, file I/O can either be done through Windows functions or by calling traditional INT 21h functions, and they are interchangeable. The same file handles have to work for both.

In fact, I was getting random memory trashing because my 32-bit Windows file handles are 16-bit arbitrary numbers. Then yesterday I discovered code that takes the file handle and uses it as an index into a table that it uses to keep track of open file properties. It was clearly relying on Windows returning DOS file handles, which are just numbers ranging from 0..MAXFILES-1.

By handing back random 16-bit values as handles, the code was modifying random memory way outside of expected bounds. Sigh. So now 16-bit programs have an alternate DOS-like file handle table which maps to the real 32-bit file handles.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Tracked down one of my nasty 16-bit crashes to lack of segment selector hygiene. Basically, they had done a GlobalAlloc(), and loaded ES with the selector to it. When done, they called GlobalFree() but left ES pointing to the now-invalid segment.

In theory this wouldn't be a problem (assuming they aren't accessing after the free), except then they called a function that saved/restored ES, and upon restoration, the POP ES was attempting to reload the now-invalid segment.

Fix was easy enough: any time I release a segment selector, I check the live DS/ES/FS/GS, and if any of them are pointing to that segment, I reset them to a null selector. You can't access through a null selector (which would indicate use-after-free anyways), but at least pushing/popping doesn't produce a GPF.

And after that, I'm able to make it all the way through the SWSE installer. Which is good, because the loose files are not generally available, and extracting them is a bit tricky.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

New DREAMM beta is up: https://aarongiles.com/dreamm/beta

New in 3.0b8:

  • Split the Manage tab into separate Manage and Data tabs
  • Fixed several issues with new font logic; selecting a font in SWSE now works correctly
  • Fixed bug where configuration changes in SWSE were not sticky
  • Fixed resolution configuration in Outlaws demo
  • Fixed crash in Windows versions of X-Wing/TIE Fighter
  • Fixed GMIDI configuration for the Windows version of Indy Fate
  • Fixed clipping issues with listboxes and other controls
  • Exposed "Developer Mode" option in Grim Fandango
  • Partial internal reorg to help reduce crashes on quit in Windows games; this will take another release or two to complete
aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Quaid... Quaid... Start the reactor... Free Mars!

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Man, YouTube on Firefox has gotten really bad in the past few weeks. Every action on the screen takes a noticeable amount of time to complete, and it gets worse the longer I leave the browser open. Quitting and restarting makes it a little more bearable for a while, but it quickly degrades. Not sure if it's Firefox's issue or Google being dicks again, but either way it sucks.

I do use uBlock Origin, but have it turned off for YouTube (since I pay for premium). Wonder if Google is still making my life miserable simply because it's installed. (And no, I'm not going to switch browsers for this issue.)

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

New DREAMM beta is up:

https://aarongiles.com/dreamm

New in 3.0b7:

  • Many improvements to GDI support, including proper support for bitmap brushes
  • Broader font support, including auto-generation of bold/italic fonts
  • Most SWSE screen savers run fine now, except that Poster Art crashes occasionally
  • Fixed bad memory leak that led to Windows crashes
  • Fixed detection of size updates, which should fix Jedi Knight/MotS user interface
  • Fixed Indy Desktop weirdness
aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Anyone know if there's a native build of gnu make for Windows that doesn't totally suck for performance? I suspect it suffers from the well-known "doing tons of stat() calls is super cheap on Linux and very costly on Windows" issue.

My project isn't that big (~50 files), but it takes make over 15 seconds to figure out what to build on Windows. Using WSL on the same machine via the folder mount (so it's not even the native Linux filesystem), it takes just 2-3 seconds. On MacOS it's instantaneous (as I suspect it would be on native Linux as well).

I've tried a couple different standard builds, so it seems endemic to the default way the tool builds for Windows. Just curious if anyone has dug into it to maybe implement a smarter mechanism for Windows.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

New DREAMM beta available:

https://aarongiles.com/dreamm/beta/

SWSE and SWChess Windows are unlocked but there are lots of problems, so don't bother reporting any bugs to me on these. SWSE also needs manual extraction from the installer.

  • Many improvements Windows support, specifically 16-bit Windows:
    • Can now load multiple 16-bit tasks together in the same address space
    • Hooked up midiOut and 16-bit multimedia timer multimedia support
    • Implemented many new GDI features, including support for non-solid brushes and binary ROPs
    • Added support for owner-draw listboxes and better messages for 16-bit controls
    • INI files are now read/written from actual INI files instead of using registry proxy
    • 16-bit nametable resources now support type renaming as well
  • New partially working "game": Star Wars Screen Entertainment (still crashes in spots but works partially)
  • New non-working game: Star Wars Chess, Windows (loads fine but won't let you play)
  • Indy Desktop/Yoda Stories now provide their own wavemix.ini configuration settings
  • Disabled video options for DIG95 version of The Dig
  • Fixed bug in GDI line drawing logic that sometimes caused a hang
  • Fixed improper fault when fetching 80-bit floating point values from read-only segments
  • Fixed crash when launching the DOS version of The Dig
aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Well, that's 4 of the SWSE screensavers (Darth Vader, Hyperspace, Imperial Clock, and Space Battles) working relatively stably with music and sound effects.

Rebel Clock is almost there, but doesn't draw 100% correctly yet. (Probably CreatePolygonRgn isn't quite right.)

Jawas and Lightsaber Duel basically work but they capture the screen to modify it, and there's some palette mismatch happening. My desktop is 32bpp and they capture it to an 8bpp version and then animate stuff on top.

A couple of others (Cantina, Character Biographies) just draw a black screen, but seem to be working. Thinking a clipping or palette issue.

Death Star Trench needs me to implement flipping in StretchDIBits.

Blueprints and Storyboards both crash in the same way. They do a bitmap blit with brush, relying on ternary raster ops, which is a pretty fresh feature, so I suspect something there might be going awry.

Scrolling Text crashes in a different way. No idea on that one.

The UI mostly works as well. Had to change the way I manage device contexts because SWSE grabs one and draws into it over a long period without calling GetDC each time. I was relying on that to update the visible clip region, so when you moved windows around the clip would be incorrect.

Had to implement quite a lot of new stuff to get here!

image/png
image/png
image/png

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Discovered there was a Windows version of Star Wars Chess, so decided to look into it. As usual, it revealed some limitations in my emulation and ultimately caused me to pull quite a few threads to even get it up and limping.

In this case, I had to support loading multiple 16-bit EXEs into the same process, much like the Win32 VDM does. Previously I had just treated launching a 16-bit process like launching a 32-bit process: create an entirely fresh environment and run it in its own address space.

But SWC for some reason is written as multiple applications (tasks) that communicate aggressively via DDE using windows messaging and shared global memory. There were two ways of making that work: either maintain the 1:1 process-task mapping and figure out how to share global memory blocks between them, or switch over to launching all 16-bit tasks in the same process.

Turns out the latter is the right approach (I mean, there's a reason this is the way it's done in Windows). This is because the tight communication between programs relies on the cooperative multitasking rules of Win16, so I need to carefully control which task (and only one task at a time!) is active, and switch between them. It also meant abstracting a bunch of state (e.g., current directory) that each task maintains separately.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

My hot take on the yuzu situation: many obvious dumb mistakes were made.

When we developed Connectix VGS back in the day, we went in knowing the risks of emulating a still-active console. We went out of our way to try and make it as legit as possible, adding logic to try and detect copied disks, attempting to get a proper license from Sony, etc.

But when we did release, the thing that become most apparent was that despite all our efforts, the #1 reason people wanted it was for piracy. In fact, VGS itself was pirated waaaay more than it was sold. The people who really wanted it were by and large pirates, and they were happy to pirate both us and the games.

At that point it become crystal clear to me that there was really no way to write an emulator for a current-generation console without inviting mass piracy. In fact ever since then it's been my firm belief that emulating current-gen anything is a fool's errand and should be avoided unless you're looking for trouble.

The fact that yuzu was pulling in $30k+/month from donations and creating an Android version was just fuel for the fire. Add to that Nintendo's well-known litigious nature regarding emulation and the whole TOTK foolishness, and I honestly can't believe it took this long for them to be shut down.

I'm just glad they didn't go to court and lose badly.

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Total fail.

Last October I picked up tickets to see Ministry, Gary Numan, and Front Line Assembly at the Showbox in Seattle. Since the concert was scheduled for March, I dutifully put it in my calendar so that I wouldn't forget. Or at least that's what I've always done in the past.

Fast forward to today, and I'm browsing upcoming events to see when the concert is, and I'm not seeing it. Suddenly, a sinking feeling starts in my gut. I frantically search my email receipts to find the purchase, and locate the date.

March 2. Aaaaarrrrgh. Can't believe I bought tickets to an event and forgot to show up. I must have spaced on actually putting in my calendar. 🤦🤦🤦🤦

aaronsgiles, to random
@aaronsgiles@corteximplant.com avatar

Let's do this. 👍

  • All
  • Subscribed
  • Moderated
  • Favorites
  • provamag3
  • thenastyranch
  • magazineikmin
  • ngwrru68w68
  • mdbf
  • rosin
  • Youngstown
  • vwfavf
  • slotface
  • modclub
  • khanakhh
  • cubers
  • kavyap
  • DreamBathrooms
  • cisconetworking
  • PowerRangers
  • everett
  • Durango
  • InstantRegret
  • osvaldo12
  • tester
  • normalnudes
  • tacticalgear
  • ethstaker
  • GTA5RPClips
  • anitta
  • Leos
  • megavids
  • All magazines