Code:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Version 0.9 2026-9-23
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
╭── ★ New Features ★ ────────────────────────────────────────────────────────────────╮
● Support for Inno Setup v7
▪︎ All WinAPI handles now use the pointer-sized TSysHandle type, allowing the module
to work correctly under Inno Setup 7 native handle model while remaining compatible
with earlier Inno Setup versions, both ANSI and Unicode.
▪︎ ULONGLONG now safely selects TLargeInteger or a native 64-bit integer type
depending on the compiler version in use.
▪︎ DxDiag execution now uses ExecWithNativeSysDir on Inno Setup 7, while older
versions continue to use Exec with explicit filesystem redirection control.
● XML-based DirectX Diagnostics
▪︎ The DxDiag interaction has been completely overhauled.
▪︎ Instead of parsing a traditional plain-text report, the module now generates and
reads an XML report through MSXML.
▪︎ The parsed XML document is now cached for the entire installer session, so repeated
GPU/DirectX queries no longer re-launch DxDiag or re-parse the report from disk.
▪︎ XML loading is performed by GetDxDiagXMLReport, which caches a
MSXML2.DOMDocument Variant and reuses it for the whole installer session.
▪︎ DxDiag is invoked with /whql:off /x <file>, and the output path is expanded
from an Inno Setup constant before execution.
▪︎ MSXML initialization falls back from MSXML2.DOMDocument.6.0 to
MSXML2.DOMDocument.3.0 and then to the default MSXML2.DOMDocument progID.
▪︎ Node extraction uses GetXmlNodeText, a safe XPath wrapper that returns an
empty string instead of propagating COM exceptions.
▪︎ DirectX version helpers now expose explicit failure codes: -1 when the
version node is missing and -2 when DxDiag / XML loading fails.
▪︎ New GetShaderModelFromFeatureLevel maps reported Direct3D feature levels to
the highest supported HLSL shader model. The detected shader model is exposed
per adapter through the new TGPUInfo.ShaderModel field.
● Power & Battery Status
▪︎ Added IsSysPluggedIn returns True when the system is connected to AC power
or currently charging.
▪︎ Added IsBatteryPresent detects whether a physical battery is present.
▪︎ Added GetBatteryPercentage returns the current battery charge percentage
from 0100%, or -1 when unknown or no battery is present.
● Extended Windows Edition Detection
▪︎ GetOSEditionName (renamed from GetOSEditionID) now recognizes a much wider
set of Windows product types, including consumer N editions, Home Single Language,
Pro for Workstations, Pro Education, Enterprise LTSC / Evaluation, IoT Enterprise,
Hyper-V Server, Windows Team, Server Core / Semi-Annual Channel variants, and
Enterprise for Virtual Desktops.
● Precise OS Version Identification
▪︎ GetOSName can now optionally accept custom Major / Minor / Build / IsWinServer
parameters. This makes it suitable for validation based on specific requirements or
for describing a version of Windows other than the one on which the installer is
currently running.
▪︎ Additional detection now includes:
◦ Windows 2000
◦ Windows Server 2008 R2 with Service Pack 1
◦ Windows 7 with Service Pack 1
◦ Windows 8.1 with Update 1
◦ Windows Server 2025
● Graceful DxDiag Fallback Warning
▪︎ If the installed DirectX runtime is too old to produce XML output, the module now
displays a one-time localized [CustomMessages] entry named DxDiagWarning
and continues with limited functionality instead of failing silently.
● CPU Topology Reporting
▪︎ Added GetCPUPhysicalCore counts real processor cores by parsing
GetLogicalProcessorInformation relationship records.
Structure offsets are calculated dynamically for 32-bit and 64-bit installers.
Returns -1 when the API call fails or the returned buffer layout is invalid.
▪︎ GetCPUMaxClockSpeed no longer relies solely on the registry's boot-time
measurement. It now queries WMI Win32_Processor.MaxClockSpeed through
SWbemServices.Get to obtain the firmware/SMBIOS-declared maximum clock speed.
If WMI is unavailable, the previous registry-based reading is used automatically.
╰─────────────────────────────────────────────────────────────────────────────────────╯
╭── ★ Improvements ★ ────────────────────────────────────────────────────────────────╮
● Refactored Registry Access
▪︎ Added a central RegistryOpenKey helper that unifies registry-key opening and
automatically handles 32/64-bit (WOW64) redirection.
▪︎ RegistryOpenKey also accepts KEY_FORCE_WOW32 / KEY_FORCE_WOW64
sentinel bits in the root key parameter, allowing callers to request a specific
registry view when automatic OS-type access is disabled.
▪︎ All RegQuery
Ex functions now accept an OSTypeAccess flag, removing a
large amount of duplicated registry-access logic.
▪︎ Registry key handles are now closed inside try/finally blocks, preventing a
handle leak if a read fails partway through.
● Direct DWORD Reading
▪︎ RegQueryDWordValueEx now reads directly into a DWORD variable instead of manually
reassembling bytes from a buffer. This removes a potential endianness issue and
simplifies the implementation.
● 32-bit & 64-bit Installer Compatibility
▪︎ All WinAPI handles now use the conditional pointer-sized TSysHandle type,
ensuring correct operation on both x86 and x64 installers.
▪︎ The pointer-sized TSystemInfo fields lpMinimumApplicationAddress,
lpMaximumApplicationAddress, and dwActiveProcessorMask now correctly
use DWORD_PTR. This fixes address truncation on 64-bit installers.
● Sound Device Name Robustness
▪︎ Replaced the old CharsToString function with CharBufferToString.
CharBufferToString uses the API call lstrcpyn for guaranteed null-termination
handling on fixed-size Win32 character buffers. This applies to device names,
GPU strings, and other fixed-size buffers.
● Cleaner GPU String & Cache Handling
▪︎ All device-interface strings name, adapter, hardware ID, and registry key
are now processed through CharBufferToString.
▪︎ The GPU-cache initialization check, previously duplicated in all four
GetPrimaryGPU* functions, is now handled by one shared helper:
EnsureGPUsListInitialized
▪︎ GetGPUsInformation now resets its output array at the start of every call,
preventing stale entries from a previous call from leaking into a reused array.
▪︎ VRAM detection from DxDiag is now wired directly into the main adapter enumeration
loop.
▪︎ GetSpecificGPUInfoFromDxdiag now receives the VRAM parameter as in/out,
so every adapter automatically benefits from the DxDiag fallback.
● Minor Polish
▪︎ Removed the unused CUF_InTeraBytes unit and its conversion multiplier.
▪︎ GetCPUArchitecture now returns "x64" for PROCESSOR_ARCHITECTURE_AMD64
instead of the verbose "x64 (AMD or Intel)".
▪︎ KeepNumbers, previously embedded inside the old plain-text DxDiag parser,
is now a standalone reusable and documented function.
▪︎ Nearly every constant, type, and function now carries a documentation comment
describing its purpose, parameters, return values, and known caveats.
▪︎ StrToFloatEx now returns -1 immediately for empty input.
▪︎ FloatToStrEx now guards against an empty FloatToStr result.
╰─────────────────────────────────────────────────────────────────────────────────────╯
╭── ★ Bug Fixes ★ ───────────────────────────────────────────────────────────────────╮
● ANSI Large-Integer Sign Bug
(Root cause of the negative VRAM bug)
▪︎ LargeIntToExtended now takes its LowPart as a signed Integer and adds 2^32 back
when the value is returned as negative. The previous implementation assumed
the underlying Pascal Script engine always marshalled the 32-bit value as
an unsigned Cardinal. This was the actual source of the ANSI-build-only
negative VRAM and negative large-memory-value bug.
● Registry Key Access Rights
▪︎ Replaced KEY_QUERY_VALUE with the more comprehensive KEY_READ
access mask, preventing rare "access denied" errors on certain registry paths.
● ANSI/Unicode String Length
▪︎ Registry string functions now correctly allocate their receive buffer using
StringOfChar(#0, dwSize) instead of a manual "divide by 2 for Unicode"
calculation. This eliminates potential string truncation in Unicode builds.
● GetSystemTotalInstalledMemory Cross-Version Fix
▪︎ The function now correctly handles the ULONGLONG type across Inno Setup versions
instead of relying on a Currency-based conversion trick that only worked
correctly on some compiler versions.
╰─────────────────────────────────────────────────────────────────────────────────────╯
╭── ★ Renamed Functions Breaking Changes ★ ────────────────────────────────────────╮
● There are NO backward-compatible aliases in v0.9.
▪︎ Update any calling code that references the old names before upgrading.
────────────────────────────────────────────────────────────────────────────
Old name → New name
────────────────────────────────────────────────────────────────────────────
GetDisplayHorizontalResolution → GetPrimaryMonitorHorizontalResolution
GetDisplayVerticalResolution → GetPrimaryMonitorVerticalResolution
GetDisplayResolutionBit → GetPrimaryMonitorColorDepth
GetDisplayMaxRefreshRate → GetPrimaryMonitorRefreshRate
GetDisplayHorizontalDPI → GetPrimaryMonitorHorizontalDPI
GetDisplayVerticalDPI → GetPrimaryMonitorVerticalDPI
GetOSEditionID → GetOSEditionName
GetSystemTotalFreeMemory → GetSystemAvailableMemory
GetSoundDeviceName → GetSoundDeviceNames
────────────────────────────────────────────────────────────────────────────
╰─────────────────────────────────────────────────────────────────────────────────────╯