Skip to content

Framework - Add Wine detection weighing system - #40

Merged
mulderf0x merged 1 commit into
Mulderland:mainfrom
keenanweaver:detect-os-ntdll
Oct 21, 2026
Merged

mulderf0x merged 1 commit into
Mulderland:mainfrom
keenanweaver:detect-os-ntdll

Conversation

@keenanweaver

Copy link
Copy Markdown
Contributor

This changes the Linux detection to check the value of ntdll.dll instead of path-based detection. This is much less fragile. I've only tested on Linux. Detection working as expected:

Output folder: C:\GOG Games\Tom Clancys Splinter Cell\system\scripts
 // Downloading https://github.com/ThirteenAG/WidescreenFixesPack/releases/download/sc/SplinterCell.WidescreenFix.zip
 // Partially extracting WidescreenFix.zip
 // Partially extracting WidescreenFix.zip
Delete file: WidescreenFix.zip
Output folder: C:\GOG Games\Tom Clancys Splinter Cell\system
 // Downloading https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases/download/Win32-latest/msacm32-Win32.zip
 // Partially extracting msacm32.zip
Delete file: msacm32.zip
 // Downloading https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases/download/Win32-latest/msvfw32-Win32.zip
 // Partially extracting msvfw32.zip
Delete file: msvfw32.zip
 // DgVoodoo2: Linux/Deck detected, download v2.81.3 (old compatible version)
 // Downloading https://cdn.mulderload.eu/tools/dgvoodoo/dgVoodoo2_81_3.zip
Failed: https://cdn.mulderload.eu/tools/dgvoodoo/dgVoodoo2_81_3.zip
Delete file: dgVoodoo2.zip
 // Downloading https://cdn.de.mulderload.eu/tools/dgvoodoo/dgVoodoo2_81_3.zip
 // Validating dgVoodoo2.zip
 // Partially extracting dgVoodoo2.zip
 // Partially extracting dgVoodoo2.zip
 // Partially extracting dgVoodoo2.zip
Delete file: dgVoodoo2.zip
Output folder: C:\GOG Games\Tom Clancys Splinter Cell
 // Downloading https://cdn.mulderload.eu/games/splinter-cell/impr_gfx/SC1_PS3_Textures.zip
Failed: https://cdn.mulderload.eu/games/splinter-cell/impr_gfx/SC1_PS3_Textures.zip
Delete file: SC1_PS3_Textures.zip
 // Downloading https://cdn.de.mulderload.eu/games/splinter-cell/impr_gfx/SC1_PS3_Textures.zip

I'd be glad to make a validation test in CI for this change.

Like the other PR, this one was created with Claude Code.

LLM summary:

Replace the path-based Linux detection and the "Are you on Steam Deck (or Linux)?" prompt with a check against Wine's ntdll.dll:

- If ntdll exports wine_get_version, we're running under Wine (Windows' ntdll doesn't export it), otherwise "Windows".
- Under Wine, wine_get_host_version gives the host sysname: "Linux" -> "Linux", "Darwin" -> "macOS", any other host name (e.g. "FreeBSD") is returned as is.

The result is still memoized, and the DETECT_OS macro is unchanged.

Tested with Wine 10.0 and Proton Experimental (Wine 11.0).

Assisted-by: Claude Code (Claude Opus 5.5)

@mulderf0x

mulderf0x commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Hi @keenanweaver,

Thanks again for this new PR :)
Nice to have some help!

Well. I'm a little more sceptical about this approach, although I agree it's a clean solution.

Initially (a long time ago), I only checked for a Wine entry in the Registry. Then, one day, I came across a strange case where someone had installed Wine on Windows.

I'm worried your PR would incorrectly identify that system as Linux in that exact same scenario.

That's why I'd feel more confident prompting the user in the rare cases where the OS is ambiguous. Also, having 3 (or 5) independent signals is nice: if they all agree, the result is clear. Otherwise, we can use the majority vote to preselect the most likely answer in the user prompt.

So maybe we should simply replace one of the three existing signals with your ntdll check. Which one do you think would make the most sense to replace?

--

PS: I don't have a strong opinion on macOS. I hadn't really thought about it, and I didn't even know Wine was available on macOS. I honestly doubt that many of "my" games/installers would work on macOS anyway. Plus, many recipes use an "If Linux, Else" approach.
So maybe, if we detect "Darwin", we should simply abort the installation? I'm open to discussing this, though, I admit it's a bit radical.

@keenanweaver

Copy link
Copy Markdown
Contributor Author

Thanks for the review! If it helps, I implemented this check into the installers for Silent Hill 2: Enhanced Edition and Freelancer HD Edition several years ago and I haven't heard of any strange behavior as a result of it. Those installers are InnoSetup, so the implementation is different, but the same check is used in those. FL HDE also has /ForceWineOn / /ForceWineOff switches, which would be a nice way to work around any undesired behavior we could put in your installers.

I'll look into a 'heuristics' sort of weighing. If a couple of conditions are met, we can definitively say what the OS is. I'm pretty concerned about the Z:\ pathing, because that's not guaranteed to be there in a prefix. A user can easily unmount that letter in the Wine prefix and the check would fail. Very unlikely to happen, but it's possible. As a fallback if anything's too ambiguous, it asks the user what they're using. Which works, and isn't too annoying since it's one dialog box.

I think with this change, it could lead to refactoring the installers to have two paths: Windows and Linux, which I think might actually be easier to maintain in the longterm. I'll iterate on it and update the PR.

Keep the vote, but replace the HKCU\Software\Wine registry check
(which can exist on a real Windows install, or WineD3D for Windows)
with a check against Wine's ntdll.dll, and use 5 detections:

1. ntdll exports wine_get_version (Windows' ntdll doesn't): 4 points
2. $SYSDIR\winecfg.exe exists (Wine prefix): 1 point
3. /usr exists: 1 point
4. /etc/os-release or /usr/lib/os-release exists: 1 point
5. /proc/version exists (Linux procfs): 1 point

ntdll weighs as much as the 4 other detections combined (score out
of 8):

- 0: "Windows"
- 1-2: ask the user, No pre-selected
- 3-4: ask the user, Yes pre-selected
- 5-8: "Linux" (ntdll + at least 1 other detection)

The pre-selected answer is also used as the default in silent mode.

Unix paths are checked through Wine's \\?\unix\ prefix instead of Z:\,
so they still work when the Z: drive is unmapped or remapped.

The result is still memoized, and the DETECT_OS macro is unchanged.

Tested with Wine 11.0 (with and without a Z: drive), and through
umu-launcher (Steam Linux Runtime 3) with UMU-Proton 10.0-4 and
GE-Proton 11-9, including prefixes without winecfg.exe and with Z:
pointed to an empty folder: all detected as Linux without a prompt.

Assisted-by: Claude Code (Claude Opus 5.5)
@keenanweaver

Copy link
Copy Markdown
Contributor Author

Added a weighing system based on feedback. This should work.

Meat proxying the LLM below:

How OS detection works

DetectOS returns "Windows" or "Linux". It works the answer out on the first call and reuses it after that. The DETECT_OS macro and every caller are unchanged.

Detections

# Check What it shows Points
1 ntdll.dll exports wine_get_version The installer is running under Wine 4
2 $SYSDIR\winecfg.exe exists A Wine prefix 1
3 \\?\unix\usr\ exists A Unix filesystem 1
4 \\?\unix\etc\os-release or \\?\unix\usr\lib\os-release exists A Linux distro / Flatpak / Steam runtime 1
5 \\?\unix\proc\version exists A Linux kernel 1

ntdll check: Windows always loads its own ntdll.dll into every process, and that one never exports Wine functions. A leftover file or registry key can't fake it,
so it's worth as much as the other four checks combined. The Freelancer: HD Edition installer, the Silent Hill 2: Enhanced Edition installer, SDL and uv all use this
check.

\\?\unix\ paths: this is Wine's own prefix for paths on the Linux filesystem. It works whatever drive letters are mapped, so the checks still work if Z: is
removed or remapped. On Windows there's nothing behind \\?\unix\, so these checks never succeed there.

Scoring (out of 8)

Score Meaning Result
5–8 ntdll plus at least one other check Linux, no prompt
3–4 ntdll alone, or 3–4 other checks without ntdll Prompt, Yes preselected
1–2 1–2 other checks, no ntdll Prompt, No preselected
0 Nothing Windows, no prompt
  • Linux is only chosen automatically when ntdll is confirmed by at least one other check.
  • If Wine ever stops exposing wine_get_version, the other checks still produce a prompt with Yes preselected instead of a silent Windows.
  • In silent mode, the preselected answer is used without showing the prompt.

Why the registry check was dropped

HKCU\Software\Wine can exist on real Windows installs:

  • The SH2EE installer writes HKCU\Software\Wine\DllOverrides whenever its "Wine/Linux Support" component is ticked, even on Windows.
  • WineD3D for Windows is configured through HKCU\Software\Wine\Direct3D.

Expected results

Environment Score Result
Windows 0 Windows
Windows with a leftover Software\Wine key 0 Windows
Wine / Proton / Steam Deck 8 Linux
Wine prefix without winecfg.exe 7 Linux
Wine with Z: removed or remapped 7–8 Linux
Flatpak (Bottles, Steam, Lutris, Heroic) 8 Linux
.exe started from a WSL2 shell (runs natively on Windows) 0 Windows
Wine inside WSL2 8 Linux

Testing

  • Wine 11.0: 8/8 → Linux. With winecfg.exe removed, 7/8 → Linux, with no prompt (run non-silently). With Z: removed, the \\?\unix\ checks still found
    everything.
  • umu-launcher (Steam Linux Runtime 3): UMU-Proton 10.0-4 and GE-Proton 11-9. Fresh prefixes passed every check. A prefix without winecfg.exe and with Z: pointed
    at an empty folder still passed the ntdll and \\?\unix\ checks. Both score 7–8 → Linux.
  • Not tested: real Windows, Valve's Proton through Steam, Bottles/Flatpak, WSL2, and clicking through the prompt by hand.

@keenanweaver keenanweaver changed the title Framework - Detect Wine through ntdll Framework - Add Wine detection weighing system Oct 17, 2026
@mulderf0x

mulderf0x commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Hi @keenanweaver ! I did some more testing, and I haven't found any problems here. Everything works perfectly.

Although the previous code was already working quite well, this actually makes the detection more robust, especially by using ntdll.dll and not relying on Z:\* paths 👍

I'm gonna merge that PR today :)

Thanks again for your work!

@mulderf0x
mulderf0x merged commit 790c1ff into Mulderland:main Oct 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants