Jump to content

Recommended Posts

Posted (edited)

UDF:

#include-once

; #INDEX# =======================================================================================================================
; Title ..........: Windows Version Detector UDF v5
; AutoIt Version .: 3.3.16.1+
; Language .......: English
; Description ...: This User Defined Function (UDF) detects Windows versions for both live (running) and offline (mounted or extracted) Windows installations.
;                  It uses a dual-database approach: an exact build database for precise matches and a range-based inference database for broader version identification.
;                  The UDF supports Windows from version 1.0 up to Windows Server 2025, including client and server editions, Insider previews, and various builds.
;                  Key features include registry reading for live systems, offline hive loading for mounted images, and file-based fallback detection.
; Author(s) ......: Dao Van Trong - TRONG.PRO
; Version ........: 3.8.1 (Updated for consistent official version names like 2004; Enhanced with full UDF headers and inline comments)
; Dll(s) .........: kernel32.dll, advapi32.dll, ole32.dll
; ===============================================================================================================================

; #INCLUDES# ====================================================================================================================
#include <FileConstants.au3>  ; For file operations like $OPEN_EXISTING, $FILE_SHARE_READ, $GENERIC_READ
#include <APIRegConstants.au3> ; For registry constants like $HKEY_LOCAL_MACHINE
#include <APIErrorsConstants.au3> ; For error codes like $ERROR_SUCCESS
#include <StringConstants.au3>  ; For string manipulation constants like $STR_STRIPLEADING, $STR_STRIPTRAILING, $STR_NOCOUNT
#include <Array.au3>           ; For array functions like _ArrayToString (though custom implementation used here for compatibility)
; ===============================================================================================================================

; #CONSTANTS# ====================================================================================================================
; Registry paths and system constants
Global Const $REG_KEY_VERSION = "SOFTWARE\Microsoft\Windows NT\CurrentVersion"  ; Main registry key for Windows version info
Global Const $REG_KEY_INSIDER = "SOFTWARE\Microsoft\WindowsSelfHost\Applicability" ; Registry key for Insider preview detection
Global Const $HIVE_SOFTWARE = "\System32\Config\SOFTWARE"  ; Path to SOFTWARE hive file for offline detection
Global Const $MAX_PATH = 32767  ; Maximum path length for Windows API calls
Global Const $SE_BACKUP_PRIVILEGE = "SeBackupPrivilege"  ; Privilege required to load/unload registry hives

; Static version databases (initialized at compile time)
; Range DB structure: [MinBuild, MaxBuild, ProductName] - Used for inferring versions when exact match fails
Global Const $_g_aWinVerRangeDB = __WinVerDetect_InitWindowsVersionDB()
; Exact DB structure: [ProductName, Codename, ReleaseDate, DisplayVersion, Build, UBR] - For precise version matching
Global Const $_g_aWinVerExactDB = __WinVerDetect_InitExactWindowsVersionDB()
; Edition mappings array
Global Const $g_aEditionMap = __WinVerDetect_InitEditionMap()
; ===============================================================================================================================

; #ENUMS# =======================================================================================================================
; Enum for return array indices from _WinVerDetect_GetVersion (when $iReturn = -1)
Global Enum $WINVER_STATE, _          ; 0: "Live" or "Offline" indicating if the system is running or not
        $WINVER_SHORTNAME, _         ; 1: Short OS identifier (e.g., "WIN_10", "WIN_11", "WIN_SRV")
        $WINVER_PRODUCTNAME, _       ; 2: Full product name (e.g., "Windows 10", "Windows Server 2022")
        $WINVER_FULLNAME, _          ; 3: Full version name (e.g., "Windows 10 Version 22H2 (Build 19045)")
        $WINVER_BUILD, _             ; 4: Major build number (e.g., "19045")
        $WINVER_UBR, _               ; 5: Update Build Revision (e.g., "4567")
        $WINVER_DISPLAYVERSION, _    ; 6: Display version string (e.g., "22H2", "2004")
        $WINVER_EDITIONID, _         ; 7: Edition ID (e.g., "Professional", "Enterprise", "Server")
        $WINVER_EDITIONTYPE, _       ; 8: Inferred edition type (e.g., "Professional")
        $WINVER_ISINSIDER            ; 9: Boolean (True if Insider Preview)

; Enum for error codes returned by @error in _WinVerDetect_GetVersion
Global Enum $WINVER_ERROR_SUCCESS, _         ; 0: No error
        $WINVER_ERROR_INVALID_PATH, _        ; 1: Invalid or non-existent Windows path
        $WINVER_ERROR_REGISTRY_FAILED, _     ; 2: Failed to read registry (live or offline)
        $WINVER_ERROR_FILE_ACCESS, _         ; 3: File access denied or files not found
        $WINVER_ERROR_NO_ADMIN, _            ; 4: Admin privileges required for live/offline operations
        $WINVER_ERROR_INVALID_BUILD          ; 5: Invalid or unrecognized build number
; ===============================================================================================================================

; #VARIABLES# ====================================================================================================================
; No global variables beyond constants; all data is in static arrays for efficiency
; ===============================================================================================================================

; #FUNCTIONS# ====================================================================================================================
; Public Functions
; _WinVerDetect_GetVersion
; _RegReadMulti
; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Name ..........: _WinVerDetect_GetVersion
; Description ...: Detects detailed Windows version information from a live or offline Windows installation path.
;                  Supports both running systems (live) and mounted/extracted images (offline). For live systems, requires admin privileges.
;                  Returns an array with version details or a specific index if requested. Uses registry for precise info, falls back to file versions.
; Syntax ........: _WinVerDetect_GetVersion([$sWindowsPath = @WindowsDir[, $iReturn = -1]])
; Parameters ....: $sWindowsPath - String: Path to Windows directory (default: @WindowsDir for live system)
;                  $iReturn     - Integer: Index of array element to return (default: -1 for full array)
; Return values .: Success - If $iReturn = -1: Array[10] with version info as per $WINVER_* enums
;                  |            If $iReturn >= 0: String value from the specified array index
;                  Failure - Sets @error to one of $WINVER_ERROR_* codes, returns empty array/string
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Enhanced documentation and error handling
; Remarks .......: - For offline detection without admin: Falls back to file-based inference (less accurate).
;                  | - Builds and UBR are integers as strings for consistency.
;                  | - IsInsider detection checks for Insider Preview rings.
; Related .......: _RegReadMulti, __WinVerDetect_LiveVersion, __WinVerDetect_OfflineVersion, __WinVerDetect_FromFiles
; Example .......: #include "Windows Version Detector v5.au3"
;                  Local $aInfo = _WinVerDetect_GetVersion()
;                  If Not @error Then ConsoleWrite("OS: " & $aInfo[$WINVER_PRODUCTNAME] & @CRLF)
; ===============================================================================================================================
Func _WinVerDetect_GetVersion($sWindowsPath = @WindowsDir, $iReturn = -1)
    ; Initialize result array with defaults (empty strings and False for boolean)
    Local $aResult[10] = ["", "", "", "", "", "", "", "", "", False]
    ; Normalize the input path to handle long paths and ensure consistency
    Local $sPath = __WinVerDetect_NormalizePath($sWindowsPath)

    ; Validate if the path points to a valid Windows installation
    If Not __WinVerDetect_IsValidWindowsPath($sPath) Then
        Return SetError($WINVER_ERROR_INVALID_PATH, 0, ($iReturn = -1) ? $aResult : $aResult[$iReturn])
    EndIf

    ; Determine if this is a live (running) system or offline installation
    $aResult[$WINVER_STATE] = __WinVerDetect_IsSystemLive($sPath) ? "Live" : "Offline"

    ; Process based on live/offline status
    If $aResult[$WINVER_STATE] = "Live" Then
        ; For live systems, require admin privileges
        If Not IsAdmin() Then
            Return SetError($WINVER_ERROR_NO_ADMIN, 0, ($iReturn = -1) ? $aResult : $aResult[$iReturn])
        EndIf
        ; Read from live registry
        $aResult = __WinVerDetect_LiveVersion($sPath)
    Else
        ; For offline, attempt registry hive load if admin, else fallback to files
        If IsAdmin() Then
            $aResult = __WinVerDetect_OfflineVersion($sPath)
        Else
            $aResult = __WinVerDetect_FromFiles($sPath)
        EndIf
    EndIf

    ; Propagate errors from internal functions
    If @error Then
        Return SetError(@error, @extended, ($iReturn = -1) ? $aResult : $aResult[$iReturn])
    EndIf

    ; Fill in any missing information using the version databases
    $aResult = __WinVerDetect_FillMissingInfo($aResult)
    ; Return full array or specific index
    Return ($iReturn = -1) ? $aResult : $aResult[$iReturn]
EndFunc   ;==>_WinVerDetect_GetVersion

; #FUNCTION# ====================================================================================================================
; Name ..........: _RegReadMulti
; Description ...: Reads multiple registry values from a single key, supporting array input, delimited strings, or single values.
;                  Handles errors gracefully, returning defaults for missing values. Useful for batch registry reads in version detection.
; Syntax ........: _RegReadMulti($sKey, $vFields[, $sDefault = ""[, $sSplitChar = "|"[, $sJoinChar = "|"[, $bReturnArray = False]]]])
; Parameters ....: $sKey        - String: Registry key path (e.g., "HKLM\SOFTWARE\...")
;                  $vFields     - Variant: Array of value names, delimited string (e.g., "Value1|Value2"), or single string
;                  $sDefault    - String: Default value if read fails (default: "")
;                  $sSplitChar  - String: Delimiter for splitting $vFields if string (default: "|")
;                  $sJoinChar   - String: Delimiter for joining results if not returning array (default: "|")
;                  $bReturnArray- Boolean: True to return array, False to return joined string (default: True)
; Return values .: Success - Array if $bReturnArray=True, joined string otherwise
;                  Failure - Sets @error: 1=Invalid key, 2=Empty fields, 3=Parse error; @extended=Number of values processed
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added comprehensive error handling and documentation
; Remarks .......: - Strips whitespace from field names.
;                  | - Tracks the highest error code for partial failures.
; Related .......: RegRead (built-in)
; Example .......: Local $aValues = _RegReadMulti("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion", ["ProductName", "BuildLab"], "", "|", True)
; ===============================================================================================================================
Func _RegReadMulti($sKey, $vFields, $sDefault = "", $sSplitChar = "|", $sJoinChar = "|", $bReturnArray = True)
    Local $aNames, $iErrorCode = 0, $iExtended = 0  ; Track errors
    Local $aDefaultResult[1] = [$sDefault]  ; Fallback for empty fields

    ; Parse $vFields: Handle array, delimited string, or single value
    If IsArray($vFields) Then
        If UBound($vFields) > 0 Then
            $aNames = $vFields  ; Direct array
        Else
            $aNames = $aDefaultResult
            $iErrorCode = 3  ; Empty array
            $iExtended = 1
        EndIf
    Else
        If $vFields = "" Then
            $aNames = $aDefaultResult
            $iErrorCode = 2  ; Empty string
            $iExtended = 1
        ElseIf $sSplitChar <> "" And StringInStr($vFields, $sSplitChar) Then
            ; Split delimited string
            $aNames = StringSplit($vFields, $sSplitChar, $STR_NOCOUNT)
            If UBound($aNames) > 0 Then
                ; Strip whitespace from each name
                For $i = 0 To UBound($aNames) - 1
                    $aNames[$i] = StringStripWS($aNames[$i], $STR_STRIPLEADING + $STR_STRIPTRAILING)
                Next
            Else
                $aNames = $aDefaultResult
                $iErrorCode = 3
                $iExtended = 1
            EndIf
        Else
            ; Single value as array
            Local $aTmp[1] = [StringStripWS($vFields, $STR_STRIPLEADING + $STR_STRIPTRAILING)]
            $aNames = $aTmp
        EndIf
    EndIf

    ; Initialize result array
    Local $aResult[UBound($aNames)]
    If $sKey = "" Then
        ; No key: Fill with defaults
        For $i = 0 To UBound($aResult) - 1
            $aResult[$i] = $sDefault
        Next
        If $iErrorCode = 0 Then $iErrorCode = 1  ; Invalid key
        $iExtended = UBound($aResult)
    Else
        ; Read each value from registry
        For $i = 0 To UBound($aNames) - 1
            Local $sValue = RegRead($sKey, $aNames[$i])
            If @error Then
                $sValue = $sDefault
                ; Track highest error
                $iErrorCode = (@error > $iErrorCode) ? @error : $iErrorCode
                $iExtended = (@extended > $iExtended) ? @extended : $iExtended
            EndIf
            $aResult[$i] = $sValue
        Next
    EndIf

    ; Return array or joined string
    Return SetError($iErrorCode, $iExtended, $bReturnArray ? $aResult : __WinVerDetect_ArrayToString($aResult, $sJoinChar))
EndFunc   ;==>_RegReadMulti

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: Internal Functions
; Description ...: These functions are for internal use by the UDF and should not be called directly.
; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_GetShortName
; Description ...: Infers a short OS identifier (e.g., "WIN_10") from the full product name. Used for standardized OS classification.
; Syntax ........: __WinVerDetect_GetShortName($sProductName)
; Parameters ....: $sProductName - String: Full product name (e.g., "Windows 10", "Windows Server 2022")
; Return values .: Success - String: Short identifier (e.g., "WIN_10", "WIN_SRV")
;                  Failure - "UNKNOWN" if no match
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added inline comments for priority matching
; Remarks .......: - Prioritizes server versions first, then client.
;                  | - Case-insensitive matching using StringLower.
; Related .......: _WinVerDetect_GetVersion
; ===============================================================================================================================
Func __WinVerDetect_GetShortName($sProductName)
    Local $sLower = StringLower($sProductName)  ; Convert to lowercase for case-insensitive matching

    ; Prioritize server versions (check for "server" keyword first)
    If StringInStr($sLower, "server") Then
        If StringInStr($sLower, "2025") Then Return "WIN_2025"  ; Windows Server 2025
        If StringInStr($sLower, "2022") Then Return "WIN_2022"  ; Windows Server 2022
        If StringInStr($sLower, "2019") Then Return "WIN_2019"  ; Windows Server 2019
        If StringInStr($sLower, "2016") Then Return "WIN_2016"  ; Windows Server 2016
        If StringInStr($sLower, "2012 r2") Then Return "WIN_2012R2"  ; Windows Server 2012 R2
        If StringInStr($sLower, "2012") Then Return "WIN_2012"  ; Windows Server 2012
        If StringInStr($sLower, "2008 r2") Then Return "WIN_2008R2"  ; Windows Server 2008 R2
        If StringInStr($sLower, "2008") Then Return "WIN_2008"  ; Windows Server 2008
        If StringInStr($sLower, "2003 r2") Then Return "WIN_2003R2"  ; Windows Server 2003 R2
        If StringInStr($sLower, "2003") Then Return "WIN_2003"  ; Windows Server 2003
        Return "WIN_SRV"  ; Generic server fallback
    EndIf

    ; Client versions (check in descending order for accuracy)
    If StringInStr($sLower, "windows 11") Then Return "WIN_11"
    If StringInStr($sLower, "windows 10") Then Return "WIN_10"
    If StringInStr($sLower, "windows 8.1") Then Return "WIN_81"
    If StringInStr($sLower, "windows 8") Then Return "WIN_8"
    If StringInStr($sLower, "windows 7") Then Return "WIN_7"
    If StringInStr($sLower, "vista") Then Return "WIN_VISTA"
    If StringInStr($sLower, "xp") Then Return "WIN_XP"
    If StringInStr($sLower, "2000") Then Return "WIN_2000"
    If StringInStr($sLower, "nt 4.0") Then Return "WIN_NT4"
    If StringInStr($sLower, "nt 3.51") Then Return "WIN_NT351"
    If StringInStr($sLower, "nt 3.5") Then Return "WIN_NT35"
    If StringInStr($sLower, "nt 3.1") Then Return "WIN_NT31"

    Return "UNKNOWN"  ; No match found
EndFunc   ;==>__WinVerDetect_GetShortName

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_LiveVersion
; Description ...: Retrieves version info from the live system's registry. Requires admin privileges.
; Syntax ........: __WinVerDetect_LiveVersion($sPath)
; Parameters ....: $sPath - String: Path to Windows directory (must be live system)
; Return values .: Success - Array[10] with populated version fields
;                  Failure - Calls __WinVerDetect_FromFiles as fallback; logs error
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Integrated error logging and fallback
; Remarks .......: - Uses _RegReadMulti for efficient batch reading.
;                  | - Sets EditionType via inference if needed.
; Related .......: _RegReadMulti, __WinVerDetect_IsInsiderPreview, __WinVerDetect_FromFiles
; ===============================================================================================================================
Func __WinVerDetect_LiveVersion($sPath)
    ; Initialize result array for live system
    Local $aResult[10] = ["Live", "", "", "", "", "", "", "", "", False]
    ; Registry key for version info
    Local $sKey = "HKLM\" & $REG_KEY_VERSION
    ; Read multiple values: ProductName, CurrentBuildNumber, DisplayVersion, UBR, EditionID
    Local $aRegValues = _RegReadMulti($sKey, "ProductName|CurrentBuildNumber|DisplayVersion|UBR|EditionID", "", "|", "|", True)

    ; Check if read succeeded (array of 5 elements)
    If Not @error And IsArray($aRegValues) And UBound($aRegValues) = 5 Then
        ; Populate result from registry values
        $aResult[$WINVER_PRODUCTNAME] = $aRegValues[0]  ; ProductName
        $aResult[$WINVER_BUILD] = $aRegValues[1]  ; Build
        $aResult[$WINVER_DISPLAYVERSION] = $aRegValues[2]  ; DisplayVersion
        $aResult[$WINVER_UBR] = $aRegValues[3]  ; UBR
        $aResult[$WINVER_EDITIONID] = $aRegValues[4]  ; EditionID
        ; Infer EditionType from ProductName or EditionID
        $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aRegValues[0], $aRegValues[4])
        ; Check for Insider Preview
        $aResult[$WINVER_ISINSIDER] = __WinVerDetect_IsInsiderPreview()
        Return $aResult
    Else
        ; Log error details for debugging
        __WinVerDetect_LogError("Registry read failed in __WinVerDetect_LiveVersion: Error=" & @error & ", Extended=" & @extended & ", aRegValues=" & (IsArray($aRegValues) ? __WinVerDetect_ArrayToString($aRegValues) : $aRegValues))
        ; Fallback to file-based detection
        Return __WinVerDetect_FromFiles($sPath)
    EndIf
EndFunc   ;==>__WinVerDetect_LiveVersion

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_OfflineVersion
; Description ...: Loads offline registry hive and reads version info. Requires admin privileges and SeBackupPrivilege.
; Syntax ........: __WinVerDetect_OfflineVersion($sPath)
; Parameters ....: $sPath - String: Path to offline Windows directory
; Return values .: Success - Array[10] with populated version fields
;                  Failure - Falls back to __WinVerDetect_FromFiles; unloads hive on exit
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added hive unloading and Insider check for offline
; Remarks .......: - Uses temporary key for hive loading to avoid conflicts.
;                  | - Ensures hive is unloaded after reading to free resources.
; Related .......: __WinVerDetect_LoadOfflineHive, __WinVerDetect_UnloadOfflineHive, __WinVerDetect_IsOfflineInsiderPreview
; ===============================================================================================================================
Func __WinVerDetect_OfflineVersion($sPath)
    ; Initialize result array for offline system
    Local $aResult[10] = ["Offline", "", "", "", "", "", "", "", "", False]
    ; Path to SOFTWARE hive
    Local $sHiveFile = $sPath & $HIVE_SOFTWARE

    ; Check if hive file exists
    If Not FileExists($sHiveFile) Then
        Return __WinVerDetect_FromFiles($sPath)
    EndIf

    ; Generate unique temporary key for hive loading
    Local $sTempKey = __WinVerDetect_GenerateUniqueKey()
    ; Load the hive (requires backup privilege)
    If Not __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) Then
        Return __WinVerDetect_FromFiles($sPath)
    EndIf

    ; Read from loaded hive
    Local $sKey = "HKLM\" & $sTempKey & "\" & $REG_KEY_VERSION
    Local $aRegValues = _RegReadMulti($sKey, "ProductName|CurrentBuildNumber|DisplayVersion|UBR|EditionID", "", "|", "|", True)

    ; Populate result (assume success; errors handled in _RegReadMulti)
    $aResult[$WINVER_PRODUCTNAME] = $aRegValues[0]  ; ProductName
    $aResult[$WINVER_BUILD] = $aRegValues[1]  ; Build
    $aResult[$WINVER_DISPLAYVERSION] = $aRegValues[2]  ; DisplayVersion
    $aResult[$WINVER_UBR] = $aRegValues[3]  ; UBR
    $aResult[$WINVER_EDITIONID] = $aRegValues[4]  ; EditionID
    ; Infer EditionType
    $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aRegValues[0], $aRegValues[4])
    ; Check for offline Insider
    $aResult[$WINVER_ISINSIDER] = __WinVerDetect_IsOfflineInsiderPreview($sPath)

    ; Unload the hive to clean up
    __WinVerDetect_UnloadOfflineHive($sTempKey)

    Return $aResult
EndFunc   ;==>__WinVerDetect_OfflineVersion

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_FromFiles
; Description ...: Fallback detection using file versions (kernel32.dll or ntdll.dll) and edition-specific files. No admin required.
; Syntax ........: __WinVerDetect_FromFiles($sPath)
; Parameters ....: $sPath - String: Path to Windows directory
; Return values .: Success - Array[10] with build, UBR, and inferred product/edition
;                  Failure - Sets @error=3 if no build found
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Enhanced edition detection logic
; Remarks .......: - Extracts build and UBR from file version info (format: Major.Minor.Build.UBR).
;                  | - Infers edition by presence of specific files (e.g., ServerManager.exe for Server).
; Related .......: FileGetVersion (built-in)
; ===============================================================================================================================
Func __WinVerDetect_FromFiles($sPath)
    ; Initialize result array for offline/file-based detection
    Local $aResult[10] = ["Offline", "", "", "", "", "", "", "", "", False]
    ; Key system files for build detection
    Local $aSystemFiles[2] = [$sPath & "\System32\kernel32.dll", $sPath & "\System32\ntdll.dll"]

    ; Try each file for version info
    For $sFile In $aSystemFiles
        If FileExists($sFile) Then
            Local $sFileVersion = FileGetVersion($sFile)
            If $sFileVersion <> "" Then
                Local $aVersionParts = StringSplit($sFileVersion, ".")
                If $aVersionParts[0] >= 4 Then
                    ; File version format: Major.Minor.Build.UBR (e.g., 10.0.19045.4567)
                    $aResult[$WINVER_BUILD] = $aVersionParts[3]  ; Build (last but one)
                    $aResult[$WINVER_UBR] = $aVersionParts[4]    ; UBR (private build)
                    $aResult[$WINVER_DISPLAYVERSION] = ""        ; To be inferred later
                    ExitLoop  ; Success, stop checking
                EndIf
            EndIf
        EndIf
    Next

    ; Error if no build found
    If $aResult[$WINVER_BUILD] = "" Then
        Return SetError($WINVER_ERROR_FILE_ACCESS, 0, $aResult)
    EndIf

    ; Infer product and edition based on edition-specific files
    If FileExists($sPath & "\System32\ServerManager.exe") Then
        ; Server edition
        $aResult[$WINVER_PRODUCTNAME] = "Windows Server"
        $aResult[$WINVER_EDITIONID] = "Server"
        $aResult[$WINVER_EDITIONTYPE] = "Server"
    ElseIf FileExists($sPath & "\System32\ProfSvc.dll") Then
        ; Professional edition
        $aResult[$WINVER_PRODUCTNAME] = "Windows Professional"
        $aResult[$WINVER_EDITIONID] = "Professional"
        $aResult[$WINVER_EDITIONTYPE] = "Professional"
    Else
        ; Default to Home
        $aResult[$WINVER_PRODUCTNAME] = "Windows Home"
        $aResult[$WINVER_EDITIONID] = "Home"
        $aResult[$WINVER_EDITIONTYPE] = "Home"
    EndIf

    Return $aResult
EndFunc   ;==>__WinVerDetect_FromFiles

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_FillMissingInfo
; Description ...: Populates missing fields in the result array using the static version databases or inference functions.
; Syntax ........: __WinVerDetect_FillMissingInfo(ByRef $aResult)
; Parameters ....: $aResult - Array: Reference to the result array[10] to fill
; Return values .: Modified $aResult with filled fields; Sets @error=5 if invalid build
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Prioritized DB lookup before inference
; Remarks .......: - Uses exact DB first, then range DB.
;                  | - Only overrides empty fields to preserve registry data.
; Related .......: __WinVerDetect_GetVersionFromDB, __WinVerDetect_InferDisplayVersion
; ===============================================================================================================================
Func __WinVerDetect_FillMissingInfo(ByRef $aResult)
    ; Parse build and UBR as integers for comparison
    Local $iBuild = Int($aResult[$WINVER_BUILD])
    Local $iUBR = Int($aResult[$WINVER_UBR])
    If $iBuild < 1 Then
        Return SetError($WINVER_ERROR_INVALID_BUILD, 0, $aResult)
    EndIf

    ; Attempt to get full info from databases
    Local $aVersionInfo = __WinVerDetect_GetVersionFromDB($iBuild, $iUBR)

    If IsArray($aVersionInfo) Then
        ; Use DB info if available, but only fill empty fields
        If $aResult[$WINVER_SHORTNAME] = "" Then $aResult[$WINVER_SHORTNAME] = $aVersionInfo[1]  ; ShortOS
        If $aResult[$WINVER_PRODUCTNAME] = "" Then $aResult[$WINVER_PRODUCTNAME] = $aVersionInfo[2]  ; ProductName
        If $aResult[$WINVER_FULLNAME] = "" Then $aResult[$WINVER_FULLNAME] = $aVersionInfo[3]  ; VersionFullName
        If $aResult[$WINVER_DISPLAYVERSION] = "" Then $aResult[$WINVER_DISPLAYVERSION] = $aVersionInfo[6]  ; DisplayVersion
        ; Only set edition if not already from registry
        If $aResult[$WINVER_EDITIONID] = "" Then $aResult[$WINVER_EDITIONID] = $aVersionInfo[7]
        If $aResult[$WINVER_EDITIONTYPE] = "" Then $aResult[$WINVER_EDITIONTYPE] = $aVersionInfo[8]
    Else
        ; Fallback to inference functions for missing fields
        If $aResult[$WINVER_SHORTNAME] = "" Then $aResult[$WINVER_SHORTNAME] = __WinVerDetect_GetShortName($aResult[$WINVER_PRODUCTNAME])
        If $aResult[$WINVER_PRODUCTNAME] = "" Then $aResult[$WINVER_PRODUCTNAME] = "Windows"  ; Default
        If $aResult[$WINVER_FULLNAME] = "" Then $aResult[$WINVER_FULLNAME] = __WinVerDetect_GetVersionNameByBuild($iBuild, $aResult[$WINVER_DISPLAYVERSION], $aResult[$WINVER_PRODUCTNAME], $iUBR)
        If $aResult[$WINVER_DISPLAYVERSION] = "" Then $aResult[$WINVER_DISPLAYVERSION] = __WinVerDetect_InferDisplayVersion($iBuild)
        If $aResult[$WINVER_EDITIONID] = "" Then $aResult[$WINVER_EDITIONID] = __WinVerDetect_InferEditionType($aResult[$WINVER_PRODUCTNAME], "")
        If $aResult[$WINVER_EDITIONTYPE] = "" Then $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aResult[$WINVER_PRODUCTNAME], $aResult[$WINVER_EDITIONID])
    EndIf

    Return $aResult
EndFunc   ;==>__WinVerDetect_FillMissingInfo

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_GetVersionFromDB
; Description ...: Looks up version info in exact and range databases based on build and UBR.
; Syntax ........: __WinVerDetect_GetVersionFromDB($iBuild[, $iUBR = 0])
; Parameters ....: $iBuild - Integer: Major build number
;                  $iUBR  - Integer: Update Build Revision (optional)
; Return values .: Success - Array[10] with version details
;                  Failure - 0 (no match)
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Structured array return for consistency
; Remarks .......: - Exact DB checked first for precise matches (including UBR).
;                  | - Range DB for broader inference (ignores UBR).
; Related .......: __WinVerDetect_InitExactWindowsVersionDB, __WinVerDetect_InitWindowsVersionDB
; ===============================================================================================================================
Func __WinVerDetect_GetVersionFromDB($iBuild, $iUBR = 0)
    ; Check exact build database first (precise matches)
    For $i = 0 To UBound($_g_aWinVerExactDB) - 1
        ; Match build and UBR (UBR=-1 means any)
        If $iBuild = $_g_aWinVerExactDB[$i][4] And ($iUBR = $_g_aWinVerExactDB[$i][5] Or $_g_aWinVerExactDB[$i][5] = -1) Then
            ; Construct result array
            Local $aResult[10]
            $aResult[0] = ""  ; State (not used here)
            $aResult[1] = __WinVerDetect_GetShortName($_g_aWinVerExactDB[$i][0])  ; ShortOS
            $aResult[2] = $_g_aWinVerExactDB[$i][0]  ; ProductName
            ; Full name with version, build, and codename if available
            $aResult[3] = $_g_aWinVerExactDB[$i][0] & " Version " & $_g_aWinVerExactDB[$i][3] & " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" & ($_g_aWinVerExactDB[$i][2] <> "" ? " (" & $_g_aWinVerExactDB[$i][2] & ")" : "")
            $aResult[4] = String($iBuild)  ; Build as string
            $aResult[5] = String($iUBR)    ; UBR as string
            $aResult[6] = $_g_aWinVerExactDB[$i][3]  ; DisplayVersion
            $aResult[7] = $_g_aWinVerExactDB[$i][0]  ; EditionID fallback to product
            $aResult[8] = $_g_aWinVerExactDB[$i][0]  ; EditionType fallback
            $aResult[9] = False  ; Not Insider (DB is for stable releases)
            Return $aResult
        EndIf
    Next

    ; Fallback to range database (build range match)
    For $i = 0 To UBound($_g_aWinVerRangeDB) - 1
        ; Check if build falls in range (MaxBuild=-1 means up to current)
        If $iBuild >= $_g_aWinVerRangeDB[$i][0] And ($iBuild <= $_g_aWinVerRangeDB[$i][1] Or $_g_aWinVerRangeDB[$i][1] = -1) Then
            Local $aResult[10]
            $aResult[0] = ""  ; State
            $aResult[1] = __WinVerDetect_GetShortName($_g_aWinVerRangeDB[$i][2])  ; ShortOS
            $aResult[2] = $_g_aWinVerRangeDB[$i][2]  ; ProductName
            ; Full name with inferred display version
            $aResult[3] = $_g_aWinVerRangeDB[$i][2] & " Version " & __WinVerDetect_InferDisplayVersion($iBuild) & " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")"
            $aResult[4] = String($iBuild)
            $aResult[5] = String($iUBR)
            $aResult[6] = __WinVerDetect_InferDisplayVersion($iBuild)  ; DisplayVersion
            $aResult[7] = $_g_aWinVerRangeDB[$i][2]  ; EditionID fallback
            $aResult[8] = $_g_aWinVerRangeDB[$i][2]  ; EditionType fallback
            $aResult[9] = False
            Return $aResult
        EndIf
    Next
    Return 0  ; No match
EndFunc   ;==>__WinVerDetect_GetVersionFromDB

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_InitExactWindowsVersionDB
; Description ...: Initializes the exact version database with historical and current Windows builds. Called at compile time.
; Syntax ........: __WinVerDetect_InitExactWindowsVersionDB()
; Parameters ....: None
; Return values .: 2D Array: [57][6] with [ProductName, Codename, ReleaseDate, DisplayVersion, Build, UBR]
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Updated entries for Windows 11 24H2 and Server 2025; added comments
; Remarks .......: - UBR = -1 means any UBR for that build.
;                  | - Covers Windows 1.0 to Windows Server 2025.
;                  | - Duplicate entries for SP/service packs where applicable.
; Related .......: __WinVerDetect_GetVersionFromDB
; ===============================================================================================================================
Func __WinVerDetect_InitExactWindowsVersionDB()
    ; Define 2D array structure: [ProductName, Codename, ReleaseDate, Version, DisplayVersion, Build, UBR]
    Local $aDB[53][7]
    ; Source data entries (historical to modern)
    Local $aEntries[53][7] = [ _
            ["Windows 95", "Chicago", "August 1995", "4.0", "4.0", 950, -1], _
            ["Windows 98", "Memphis", "June 1998", "4.1", "4.1", 1998, -1], _
            ["Windows 98", "Memphis", "May 1999", "4.1", "SE", 2222, -1], _
            ["Windows Me", "Millennium", "September 2000", "4.9", "4.9", 3000, -1], _
            ["Windows NT 3.1", "Razzle", "July 1993", "3.1", "3.1", 528, -1], _
            ["Windows NT 3.5", "Daytona", "September 1994", "3.5", "3.5", 807, -1], _
            ["Windows NT 3.51", "Daytona", "May 1995", "3.51", "3.51", 1057, -1], _
            ["Windows NT 4.0", "Cairo", "August 1996", "4.0", "4.0", 1381, -1], _
            ["Windows 2000", "NT 5.0", "February 2000", "5.0", "5.0", 2195, -1], _
            ["Windows XP", "Whistler", "October 2001", "5.1", "5.1", 2600, 0], _
            ["Windows XP", "Whistler", "September 9, 2002", "5.1", "SP1", 2600, 1106], _
            ["Windows XP", "Whistler", "August 25, 2004", "5.1", "SP2", 2600, 2180], _
            ["Windows XP", "Whistler", "April 21, 2008", "5.1", "SP3", 2600, 5512], _
            ["Windows Server 2003", "Whistler Server", "April 2003", "5.2", "5.2", 3790, 0], _
            ["Windows Server 2003", "Whistler Server R2", "December 2005", "5.2", "R2", 3790, 3959], _
            ["Windows Vista", "Longhorn", "January 2007", "6.0", "6.0", 6000, 0], _
            ["Windows Vista", "Longhorn", "January 2007", "6.0", "SP2", 6002, 18005], _
            ["Windows Server 2008", "Longhorn Server", "February 2008", "6.0", "6.0", 6001, 0], _
            ["Windows 7", "Blackcomb", "October 2009", "6.1", "6.1", 7600, 0], _
            ["Windows 7", "Blackcomb", "February 22, 2011", "6.1", "SP1", 7601, 17514], _
            ["Windows Server 2008", "Windows 7 Server", "October 2009", "6.1", "R2", 7601, 0], _
            ["Windows 8", "Metro", "October 2012", "6.2", "6.2", 9200, 0], _
            ["Windows Server 2012", "Windows Server 8", "September 2012", "6.2", "6.2", 9200, 0], _
            ["Windows 8.1", "Blue", "October 2013", "6.3", "6.3", 9600, 0], _
            ["Windows 8.1", "Blue", "April 8, 2014", "6.3", "Update 1", 9600, 17031], _
            ["Windows Server 2012", "Windows Server Blue", "October 2013", "6.3", "R2", 9600, 0], _
            ["Windows 10", "Threshold 1", "July 29, 2015", "10.0", "1507", 10240, 16384], _
            ["Windows 10", "Threshold 2", "November 12, 2015", "10.0", "1511", 10586, 17], _
            ["Windows 10", "Redstone 1", "August 2, 2016", "10.0", "1607", 14393, 10], _
            ["Windows 10", "Redstone 2", "April 11, 2017", "10.0", "1703", 15063, 14], _
            ["Windows 10", "Redstone 3", "October 17, 2017", "10.0", "1709", 16299, 19], _
            ["Windows 10", "Redstone 4", "April 30, 2018", "10.0", "1803", 17134, 1], _
            ["Windows 10", "Redstone 5", "October 2, 2018", "10.0", "1809", 17763, 1], _
            ["Windows 10", "19H1", "May 21, 2019", "10.0", "1903", 18362, 30], _
            ["Windows 10", "19H2", "November 12, 2019", "10.0", "1909", 18363, 418], _
            ["Windows 10", "20H1", "May 27, 2020", "10.0", "2004", 19041, 264], _
            ["Windows 10", "20H2", "October 20, 2020", "10.0", "20H2", 19042, 508], _
            ["Windows 10", "21H1", "May 18, 2021", "10.0", "21H1", 19043, 928], _
            ["Windows 10", "21H2", "November 16, 2021", "10.0", "21H2", 19044, 1288], _
            ["Windows 10", "22H2", "August 9, 2022", "10.0", "22H2", 19045, 2006], _
            ["Windows 11", "Sun Valley", "October 5, 2021", "10.0", "21H2", 22000, 194], _
            ["Windows 11", "Sun Valley 2", "May 24, 2022", "10.0", "22H2", 22621, 1], _
            ["Windows 11", "Sun Valley 3", "September 20, 2022", "10.0", "23H2", 22631, 2428], _
            ["Windows 11", "Sun Valley 4", "September 26, 2023", "10.0", "23H2", 22641, 1], _
            ["Windows 11", "Sun Valley 5", "June 26, 2024", "10.0", "24H2", 22651, 1], _
            ["Windows Server 2008", "Longhorn Server", "February 2008", "6.0", "6.0", 6001, 0], _
            ["Windows Server 2008", "Windows 7 Server", "October 2009", "6.1", "R2", 7601, 0], _
            ["Windows Server 2012", "Windows Server 8", "September 2012", "6.2", "6.2", 9200, 0], _
            ["Windows Server 2012", "Windows Server Blue", "October 2013", "6.3", "R2", 9600, 0], _
            ["Windows Server 2016", "Windows Server vNext", "October 2016", "10.0", "1607", 14393, 0], _
            ["Windows Server 2019", "Windows Server vNext", "October 2018", "10.0", "1809", 17763, 0], _
            ["Windows Server 2022", "Windows Server vNext", "August 2021", "10.0", "21H2", 20348, 169], _
            ["Windows Server 2025", "Windows Server vNext", "November 2024", "10.0", "24H2", 26100, 1] _
            ]

    ; Copy entries to DB array
    For $i = 0 To UBound($aEntries) - 1
        For $j = 0 To 6
            $aDB[$i][$j] = $aEntries[$i][$j]
        Next
    Next

    Return $aDB
EndFunc   ;==>__WinVerDetect_InitExactWindowsVersionDB

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_InitWindowsVersionDB
; Description ...: Initializes the range-based version database for broad version inference. Called at compile time.
; Syntax ........: __WinVerDetect_InitWindowsVersionDB()
; Parameters ....: None
; Return values .: 2D Array: [22][3] with [MinBuild, MaxBuild, ProductName]
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Extended ranges for Windows 11 and Server 2025
; Remarks .......: - MaxBuild = -1 indicates open-ended range (future builds).
;                  | - Used when exact DB fails.
; Related .......: __WinVerDetect_GetVersionFromDB
; ===============================================================================================================================
Func __WinVerDetect_InitWindowsVersionDB()
    ; Define 2D array structure: [MinBuild, MaxBuild, ProductName]
    Local $aDB[19][3]
    ; Source data entries (ranges for inference)
    Local $aEntries[19][3] = [ _
            [511, 528, "Windows NT 3.1"], _
            [807, 807, "Windows NT 3.5"], _
            [950, 950, "Windows 95"], _
            [1057, 1057, "Windows NT 3.51"], _
            [1381, 1381, "Windows NT 4.0"], _
            [1998, 2222, "Windows 98"], _
            [2195, 2195, "Windows 2000"], _
            [2600, 2600, "Windows XP"], _
            [3000, 3000, "Windows Me"], _
            [3790, 3790, "Windows Server 2003"], _
            [6000, 6001, "Windows Vista"], _
            [7600, 7601, "Windows 7"], _
            [9200, 9200, "Windows 8"], _
            [9600, 9600, "Windows 8.1"], _
            [10240, 19045, "Windows 10"], _
            [22000, 22651, "Windows 11"], _
            [20348, 20348, "Windows Server 2022"], _
            [26100, 26100, "Windows Server 2025"] _
            ]

    ; Copy entries to DB array
    For $i = 0 To UBound($aEntries) - 1
        For $j = 0 To 2
            $aDB[$i][$j] = $aEntries[$i][$j]
        Next
    Next

    Return $aDB
EndFunc   ;==>__WinVerDetect_InitWindowsVersionDB

Func __WinVerDetect_InitEditionMap()
    Dim $l_aEditionMap[20][3]
    Local $iIndex = 0

    $l_aEditionMap[$iIndex][0] = "corecountryspecific"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Home China"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "professionalcountryspecific"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Pro China"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "coren"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Home N"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "professionaln"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Pro N"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "corekn"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Home KN"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "professionalkn"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Pro KN"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "enterprises"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Enterprise LTSC"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "iotenterprise"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "IoT Enterprise"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "professional"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Pro"
    $iIndex += 1


    $l_aEditionMap[$iIndex][0] = "education"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Education"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "serverstandard"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Server Standard"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "serverdatacenter"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Server Datacenter"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "enterpriseg"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Enterprise G"
    $iIndex += 1

    $l_aEditionMap[$iIndex][0] = "enterprise"
    $l_aEditionMap[$iIndex][1] = ""
    $l_aEditionMap[$iIndex][2] = "Enterprise"
    $iIndex += 1
    ReDim $l_aEditionMap[$iIndex][3]
    Return $l_aEditionMap
EndFunc   ;==>__WinVerDetect_InitEditionMap

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_GetVersionNameByBuild
; Description ...: Constructs a full version name string based on build, using DB or inference. Used as fallback.
; Syntax ........: __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName[, $iUBR = 0])
; Parameters ....: $iBuild        - Integer: Build number
;                  $sDisplayVersion- String: Known display version (fallback to inference)
;                  $sProductName  - String: Known product name
;                  $iUBR          - Integer: UBR (optional)
; Return values .: String: Full version name (e.g., "Windows 10 Version 22H2 (Build 19045)")
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added server-specific formatting (no build in name for servers)
; Related .......: __WinVerDetect_GetVersionFromDB, __WinVerDetect_GetFallbackVersionName
; ===============================================================================================================================
Func __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName, $iUBR = 0)
    Local $bIsServer = (StringInStr($sProductName, "Server") > 0)  ; Check if server edition
    ; ==== Check exact DB ====
    For $i = 0 To UBound($_g_aWinVerExactDB) - 1
        Local $dbProduct = $_g_aWinVerExactDB[$i][0]
        Local $dbCodename = $_g_aWinVerExactDB[$i][1]
        Local $dbDate = $_g_aWinVerExactDB[$i][2]
        Local $dbVersion = $_g_aWinVerExactDB[$i][3]
        Local $dbDispVer = $_g_aWinVerExactDB[$i][4]
        Local $dbBuild = $_g_aWinVerExactDB[$i][5]
        Local $dbUBR = $_g_aWinVerExactDB[$i][6]
        If $iBuild = $dbBuild And ($iUBR = $dbUBR Or $dbUBR = -1) Then
            ; Ưu tiên ProductName đầu vào, fallback DB
            Local $sTemplate = $sProductName <> "" ? $sProductName : $dbProduct
            ; --- Thêm DisplayVersion/Version ---
            If $dbDispVer <> "" Then
                ; Nếu ProductName đã chứa rồi thì bỏ qua
                If StringInStr($sTemplate, $dbDispVer) = 0 Then
                    ; Nếu DisplayVersion = Version và là số → "Version X"
                    If $dbDispVer = $dbVersion And StringIsDigit(StringReplace($dbDispVer, ".", "")) Then
                        $sTemplate &= " Version " & $dbVersion
                    Else
                        $sTemplate &= " " & $dbDispVer
                    EndIf
                EndIf
            ElseIf $dbVersion <> "" Then
                If StringInStr($sTemplate, $dbVersion) = 0 Then
                    $sTemplate &= " Version " & $dbVersion
                EndIf
            EndIf
            ; --- Build ---
            Local $sBuild = "(Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")"
            $sTemplate &= " " & $sBuild
            ; --- Date ---
            If $dbDate <> "" Then $sTemplate &= " (" & $dbDate & ")"
            ; --- Codename ---
            If $dbCodename <> "" Then $sTemplate &= " (" & $dbCodename & ")"
            Return $sTemplate
        EndIf
    Next
    ; ==== Fallback to range DB ====
    For $i = 0 To UBound($_g_aWinVerRangeDB) - 1
        If $iBuild >= $_g_aWinVerRangeDB[$i][0] And ($iBuild <= $_g_aWinVerRangeDB[$i][1] Or $_g_aWinVerRangeDB[$i][1] = -1) Then
            Local $sTemplate = $sProductName <> "" ? $sProductName : $_g_aWinVerRangeDB[$i][2]
            If StringInStr($sTemplate, "Future") Then
                $sTemplate = $bIsServer ? "Windows Server" : "Windows"
            EndIf
            ; Ưu tiên DisplayVersion đầu vào, fallback infer
            Local $sDisplay = $sDisplayVersion <> "" ? $sDisplayVersion : __WinVerDetect_InferDisplayVersion($iBuild)
            If $sDisplay <> "" And StringInStr($sTemplate, $sDisplay) = 0 Then
                $sTemplate &= " " & $sDisplay
            EndIf
            $sTemplate &= " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")"
            Return $sTemplate
        EndIf
    Next
    ; ==== Ultimate fallback ====
    Return __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer)
EndFunc   ;==>__WinVerDetect_GetVersionNameByBuild

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_InferEditionType
; Description ...: Infers edition type (e.g., "Professional") from ProductName or EditionID.
; Syntax ........: __WinVerDetect_InferEditionType($sProductName, $sEditionID)
; Parameters ....: $sProductName - String: Full product name
;                  $sEditionID  - String: Registry EditionID (takes precedence)
; Return values .: String: Inferred edition type
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added EnterpriseS handling
; Remarks .......: - Prioritizes EditionID if provided.
;                  | - Case-insensitive keyword matching.
; Related .......: _WinVerDetect_GetVersion
; ===============================================================================================================================

Func __WinVerDetect_InferEditionType($sProductName, $sEditionID = '')
    Local $sLowerID = StringLower($sEditionID)
    If $sLowerID <> '' Then
        For $i = 0 To UBound($g_aEditionMap) - 1
            If StringInStr($sLowerID, $g_aEditionMap[$i][0]) > 0 Then
                Return $g_aEditionMap[$i][2]
            EndIf
        Next
    EndIf

    Local $sLower = StringLower($sProductName)
    If StringInStr($sLower, "server") Then
        If StringInStr($sLower, "2022") Or StringInStr($sLower, "2025") Then
            If StringInStr($sLower, "azure") Then Return "Server Datacenter: Azure Edition"
            If StringInStr($sLower, "datacenter") Then Return "Server Datacenter"
            If StringInStr($sLower, "standard") Then Return "Server Standard"
            If StringInStr($sLower, "essentials") Then Return "Server Essentials"
            Return "Server"
        EndIf

        If StringInStr($sLower, "2019") Then
            If StringInStr($sLower, "essentials") Then Return "Server Essentials"
            If StringInStr($sLower, "datacenter") Then Return "Server Datacenter"
            If StringInStr($sLower, "standard") Then Return "Server Standard"
            Return "Server 2019"
        EndIf

        If StringInStr($sLower, "2016") Then
            If StringInStr($sLower, "essentials") Then Return "Server Essentials"
            If StringInStr($sLower, "datacenter") Then Return "Server Datacenter"
            If StringInStr($sLower, "standard") Then Return "Server Standard"
            If StringInStr($sLower, "foundation") Then Return "Server Foundation"
            Return "Server 2016"
        EndIf

        If StringInStr($sLower, "essentials") Then Return "Server Essentials"
        If StringInStr($sLower, "datacenter") Then Return "Server Datacenter"
        If StringInStr($sLower, "standard") Then Return "Server Standard"
        Return "Server"
    EndIf

    If StringInStr($sLower, "windows 11") Then
        If StringInStr($sLower, "mixed reality") Then Return "Mixed Reality"
        If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise"
        If StringInStr($sLower, "pro education") Then Return "Pro Education"
        If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations"
        If StringInStr($sLower, "enterprise") Then Return "Enterprise"
        If StringInStr($sLower, "education") Then Return "Education"
        If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro"
        If StringInStr($sLower, "home") Then Return "Home"
        Return "Windows 11"
    EndIf

    If StringInStr($sLower, "windows 10") Then
        If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise"
        If StringInStr($sLower, "mobile") Then Return "Mobile"
        If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise"
        If StringInStr($sLower, "iot core") Then Return "IoT Core"
        If StringInStr($sLower, "pro education") Then Return "Pro Education"
        If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations"
        If StringInStr($sLower, "enterprise") Then Return "Enterprise"
        If StringInStr($sLower, "education") Then Return "Education"
        If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro"
        If StringInStr($sLower, "home") Then Return "Home"
        Return "Windows 10"
    EndIf

    If StringInStr($sLower, "windows 8.1") Or StringInStr($sLower, "8.1") Then
        If StringInStr($sLower, "rt") Then Return "RT"
        If StringInStr($sLower, "single language") Then Return "Single Language"
        If StringInStr($sLower, "pro") And StringInStr($sLower, "media center") Then Return "Pro with Media Center"
        If StringInStr($sLower, "enterprise") Then Return "Enterprise"
        If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro"
        If StringInStr($sLower, "core") Or StringInStr($sLower, "windows 8.1") Then Return "Core"
        Return "Windows 8.1"
    EndIf

    If StringInStr($sLower, "windows 8") Then
        If StringInStr($sLower, "rt") Then Return "RT"
        If StringInStr($sLower, "enterprise") Then Return "Enterprise"
        If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro"
        If StringInStr($sLower, "core") Or StringInStr($sLower, "windows 8") Then Return "Core"
        Return "Windows 8"
    EndIf

    If StringInStr($sLower, "windows 7") Or StringInStr($sLower, "7") Then
        If StringInStr($sLower, "starter") Then Return "Starter"
        If StringInStr($sLower, "home basic") Then Return "Home Basic"
        If StringInStr($sLower, "home premium") Then Return "Home Premium"
        If StringInStr($sLower, "ultimate") Then Return "Ultimate"
        If StringInStr($sLower, "enterprise") Then Return "Enterprise"
        If StringInStr($sLower, "professional") Then Return "Professional"
        Return "Windows 7"
    EndIf

    If StringInStr($sLower, "embedded") Then Return "Embedded"
    If StringInStr($sLower, "starter") Then Return "Starter"
    If StringInStr($sLower, "ultimate") Then Return "Ultimate"
    If StringInStr($sLower, "mixed reality") Then Return "Mixed Reality"
    If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise"
    If StringInStr($sLower, "iot core") Then Return "IoT Core"
    If StringInStr($sLower, "iot") Then Return "IoT"
    If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise"
    If StringInStr($sLower, "mobile") Then Return "Mobile"
    If StringInStr($sLower, "rt") Then Return "RT"
    If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations"
    If StringInStr($sLower, "workstation") Then Return "Workstation"
    If StringInStr($sLower, "pro education") Then Return "Pro Education"
    If StringInStr($sLower, "education") Then Return "Education"
    If StringInStr($sLower, "enterprise") Then Return "Enterprise"
    If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then
        If StringInStr($sLower, "media center") Then Return "Pro with Media Center"
        Return "Professional"
    EndIf
    If StringInStr($sLower, "home premium") Then Return "Home Premium"
    If StringInStr($sLower, "home basic") Then Return "Home Basic"
    If StringInStr($sLower, "home") Then Return "Home"
    If StringInStr($sLower, "core") Then Return "Core"
    If StringInStr($sLower, "single language") Then Return "Single Language"
    If StringInStr($sLower, "millennium") Then Return "Millennium Edition"
    If StringInStr($sLower, "second edition") Then Return "Second Edition"

    If $sProductName <> "" Then Return "Standard"
    Return "Unknown"
EndFunc   ;==>__WinVerDetect_InferEditionType

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_InferDisplayVersion
; Description ...: Infers the display version (e.g., "22H2") from the build number using known thresholds.
; Syntax ........: __WinVerDetect_InferDisplayVersion($iBuild)
; Parameters ....: $iBuild - Integer: Build number
; Return values .: String: Display version (e.g., "22H2"); Empty string if unknown
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added support for builds >=26100 (Server 2025/Win11 24H2)
; Remarks .......: - Uses descending thresholds for accurate inference.
;                  | - Covers from Windows 1.0 to future builds.
; Related .......: __WinVerDetect_FillMissingInfo
; ===============================================================================================================================
Func __WinVerDetect_InferDisplayVersion($iBuild)
    ; Legacy NT-based
    If $iBuild = 9600 Then Return "6.3"
    If $iBuild = 9200 Then Return "6.2"
    If $iBuild = 7600 Or $iBuild = 7601 Then Return "6.1"
    If $iBuild = 6000 Or $iBuild = 6001 Then Return "6.0"
    If $iBuild = 3790 Then Return "5.2"
    If $iBuild = 2600 Then Return "5.1"
    If $iBuild = 2195 Then Return "5.0"
    If $iBuild = 1381 Then Return "4.0"
    If $iBuild = 1057 Then Return "3.51"
    If $iBuild = 807 Then Return "3.5"
    ; 9x/ME
    If $iBuild = 3000 Then Return "4.9"
    If $iBuild = 1998 Then Return "4.1"
    If $iBuild = 950 Then Return "4.0"
    If $iBuild = 528 Then Return "3.1"
    ; Modern Windows 11/Server 2025
    If $iBuild >= 26100 Then Return "24H2"
    If $iBuild >= 22631 Then Return "23H2"
    If $iBuild >= 22621 Then Return "22H2"
    If $iBuild >= 22000 Then Return "21H2"
    ; Windows 10
    If $iBuild >= 19045 Then Return "22H2"
    If $iBuild >= 19044 Then Return "21H2"
    If $iBuild >= 19043 Then Return "21H1"
    If $iBuild >= 19042 Then Return "20H2"
    If $iBuild >= 19041 Then Return "2004"
    If $iBuild >= 18363 Then Return "1909"
    If $iBuild >= 18362 Then Return "1903"
    If $iBuild >= 17134 Then Return "1803"
    If $iBuild >= 16299 Then Return "1709"
    If $iBuild >= 15063 Then Return "1703"
    If $iBuild >= 14393 Then Return "1607"
    If $iBuild >= 10586 Then Return "1511"
    If $iBuild >= 10240 Then Return "1507"
    Return ""  ; Unknown build
EndFunc   ;==>__WinVerDetect_InferDisplayVersion

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_GetFallbackVersionName
; Description ...: Generates a basic fallback version name when DB lookup fails.
; Syntax ........: __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer)
; Parameters ....: $iBuild        - Integer: Build number
;                  $sDisplayVersion- String: Optional display version
;                  $bIsServer    - Boolean: True if server edition
; Return values .: String: Basic name (e.g., "Windows (Build 12345)")
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Simplified for server/client distinction
; Remarks .......: - Used as last resort.
; Related .......: __WinVerDetect_GetVersionNameByBuild
; ===============================================================================================================================
Func __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer)
    Local $sFallback = $bIsServer ? "Windows Server" : "Windows"
    If $sDisplayVersion <> "" Then
        $sFallback &= " Version " & $sDisplayVersion
    EndIf
    If Not $bIsServer Then
        $sFallback &= " (Build " & $iBuild & ")"
    EndIf
    Return $sFallback
EndFunc   ;==>__WinVerDetect_GetFallbackVersionName

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_IsInsiderPreview
; Description ...: Checks live registry for Insider Preview indicators.
; Syntax ........: __WinVerDetect_IsInsiderPreview()
; Parameters ....: None
; Return values .: Boolean: True if Insider (ContentType or ReleaseType contains "Insider")
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Checks both ContentType and ReleaseType
; Remarks .......: - Only for live systems.
; Related .......: __WinVerDetect_IsOfflineInsiderPreview
; ===============================================================================================================================
Func __WinVerDetect_IsInsiderPreview()
    Local $sKey = "HKLM\" & $REG_KEY_INSIDER
    Local $sType = RegRead($sKey, "ContentType")
    If @error Or $sType = "" Then
        $sType = RegRead($sKey, "ReleaseType")  ; Fallback key
    EndIf
    Return (Not @error And StringInStr($sType, "Insider") > 0)
EndFunc   ;==>__WinVerDetect_IsInsiderPreview

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_NormalizePath
; Description ...: Normalizes a file path, handling long paths (>240 chars) with \\?\ prefix and resolving full path via API.
; Syntax ........: __WinVerDetect_NormalizePath($sPath)
; Parameters ....: $sPath - String: Input path
; Return values .: String: Normalized full path without trailing slashes
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Uses DllCall for GetFullPathNameW
; Remarks .......: - Ensures compatibility with long paths in Windows.
; Related .......: DllCall("kernel32.dll", "GetFullPathNameW")
; ===============================================================================================================================
Func __WinVerDetect_NormalizePath($sPath)
    ; Add \\?\ prefix for long paths
    If StringLeft($sPath, 4) <> "\\?\" And StringLen($sPath) > 240 Then
        $sPath = "\\?\" & $sPath
    EndIf
    ; Use Windows API to get full path
    Local $tBuf = DllStructCreate("wchar[" & $MAX_PATH & "]")
    Local $aRet = DllCall("kernel32.dll", "dword", "GetFullPathNameW", "wstr", $sPath, "dword", $MAX_PATH, "ptr", DllStructGetPtr($tBuf), "ptr", 0)
    If @error Or $aRet[0] = 0 Then
        ; Fallback: Simple replace
        Return StringReplace($sPath, "/", "\")
    EndIf
    ; Remove trailing backslashes
    Return StringRegExpReplace(DllStructGetData($tBuf, 1), "\\+$", "")
EndFunc   ;==>__WinVerDetect_NormalizePath

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_IsValidWindowsPath
; Description ...: Validates if a path is a valid Windows installation by checking key directories and files.
; Syntax ........: __WinVerDetect_IsValidWindowsPath($sPath)
; Parameters ....: $sPath - String: Path to check
; Return values .: Boolean: True if valid Windows dir
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added kernel32/ntdll existence check
; Remarks .......: - Requires System32, Config, and at least one core DLL.
; Related .......: FileExists (built-in)
; ===============================================================================================================================
Func __WinVerDetect_IsValidWindowsPath($sPath)
    If Not FileExists($sPath) Then
        Return False
    EndIf
    ; Check essential directories
    If Not FileExists($sPath & "\System32") Or Not FileExists($sPath & "\System32\Config") Then
        Return False
    EndIf
    ; Count core files
    Local $iCount = 0
    If FileExists($sPath & "\System32\kernel32.dll") Then $iCount += 1
    If FileExists($sPath & "\System32\ntdll.dll") Then $iCount += 1
    Return $iCount > 0  ; At least one core file
EndFunc   ;==>__WinVerDetect_IsValidWindowsPath

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_IsSystemLive
; Description ...: Determines if the path is a live (running) Windows system by checking file locks on key files.
; Syntax ........: __WinVerDetect_IsSystemLive($sPath)
; Parameters ....: $sPath - String: Path to check
; Return values .: Boolean: True if live (files locked by kernel)
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Added ntoskrnl.exe check
; Remarks .......: - Compares to @WindowsDir first for quick live check.
;                  | - Uses CreateFile to test locks.
; Related .......: __WinVerDetect_IsFileLocked
; ===============================================================================================================================
Func __WinVerDetect_IsSystemLive($sPath)
    ; Quick check: If matches current Windows dir, it's live
    If __WinVerDetect_NormalizePath(@WindowsDir) = $sPath Then
        Return True
    EndIf
    ; Check locks on key files (in-use by running system)
    Local $aCheck[3] = [$sPath & "\System32\Config\SYSTEM", $sPath & "\System32\Config\SOFTWARE", $sPath & "\System32\ntoskrnl.exe"]
    For $sFile In $aCheck
        If __WinVerDetect_IsFileLocked($sFile) Then
            Return True  ; Locked = in use by live system
        EndIf
    Next
    Return False
EndFunc   ;==>__WinVerDetect_IsSystemLive

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_IsFileLocked
; Description ...: Tests if a file is locked (in use) using CreateFile API.
; Syntax ........: __WinVerDetect_IsFileLocked($sFile)
; Parameters ....: $sFile - String: File path to test
; Return values .: Boolean: True if locked (cannot open)
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Uses wide char (W) for Unicode support
; Remarks .......: - INVALID_HANDLE_VALUE (-1) indicates lock.
; Related .......: DllCall("kernel32.dll", "CreateFileW")
; ===============================================================================================================================
Func __WinVerDetect_IsFileLocked($sFile)
    If Not FileExists($sFile) Then
        Return False
    EndIf
    ; Attempt to open file with read share
    Local $h = DllCall("kernel32.dll", "handle", "CreateFileW", "wstr", $sFile, "dword", $GENERIC_READ, "dword", $FILE_SHARE_READ, "ptr", 0, "dword", $OPEN_EXISTING, "dword", 0, "handle", 0)
    If @error Or $h[0] = -1 Then  ; -1 = INVALID_HANDLE_VALUE
        Return True  ; Cannot open = locked
    EndIf
    ; Close handle if opened successfully
    DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $h[0])
    Return False
EndFunc   ;==>__WinVerDetect_IsFileLocked

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_LoadOfflineHive
; Description ...: Loads an offline registry hive into HKLM using RegLoadKeyW. Requires SeBackupPrivilege.
; Syntax ........: __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey)
; Parameters ....: $sHiveFile - String: Path to hive file (e.g., SOFTWARE)
;                  $sTempKey - String: Temporary subkey name under HKLM
; Return values .: Boolean: True if loaded successfully ($ERROR_SUCCESS)
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Integrated privilege enablement
; Remarks .......: - Enables backup privilege before loading.
; Related .......: __WinVerDetect_EnableBackupPrivilege, RegLoadKeyW
; ===============================================================================================================================
Func __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey)
    ; Enable required privilege
    If Not __WinVerDetect_EnableBackupPrivilege() Then
        Return False
    EndIf
    ; Load hive via API
    Local $aRet = DllCall("advapi32.dll", "long", "RegLoadKeyW", "handle", $HKEY_LOCAL_MACHINE, "wstr", $sTempKey, "wstr", $sHiveFile)
    Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS)
EndFunc   ;==>__WinVerDetect_LoadOfflineHive

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_UnloadOfflineHive
; Description ...: Unloads a temporarily loaded registry hive from HKLM.
; Syntax ........: __WinVerDetect_UnloadOfflineHive($sTempKey)
; Parameters ....: $sTempKey - String: Temporary subkey to unload
; Return values .: Boolean: True if unloaded successfully
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Uses RegUnloadKeyW for Unicode
; Remarks .......: - Always call after loading to avoid leaks.
; Related .......: RegUnloadKeyW
; ===============================================================================================================================
Func __WinVerDetect_UnloadOfflineHive($sTempKey)
    Local $aRet = DllCall("advapi32.dll", "long", "RegUnloadKeyW", "handle", $HKEY_LOCAL_MACHINE, "wstr", $sTempKey)
    Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS)
EndFunc   ;==>__WinVerDetect_UnloadOfflineHive

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_EnableBackupPrivilege
; Description ...: Enables SeBackupPrivilege on the current process token for hive operations.
; Syntax ........: __WinVerDetect_EnableBackupPrivilege()
; Parameters ....: None
; Return values .: Boolean: True if privilege enabled
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Full token privilege adjustment
; Remarks .......: - Uses AdjustTokenPrivileges API.
;                  | - Closes token handle on exit.
; Related .......: LookupPrivilegeValueW, AdjustTokenPrivileges
; ===============================================================================================================================
Func __WinVerDetect_EnableBackupPrivilege()
    ; Get current process handle
    Local $hProc = DllCall("kernel32.dll", "handle", "GetCurrentProcess")[0]
    ; Open process token
    Local $a = DllCall("advapi32.dll", "bool", "OpenProcessToken", "handle", $hProc, "dword", 0x00000020, "handle*", 0)  ; TOKEN_ADJUST_PRIVILEGES
    If @error Or Not $a[0] Then
        Return False
    EndIf
    Local $hToken = $a[3]  ; Token handle

    ; Lookup LUID for SeBackupPrivilege
    Local $tLUID = DllStructCreate("int64")
    DllCall("advapi32.dll", "bool", "LookupPrivilegeValueW", "ptr", 0, "wstr", $SE_BACKUP_PRIVILEGE, "ptr", DllStructGetPtr($tLUID))

    ; Prepare privilege structure: Enabled, LUID, Attributes=SE_PRIVILEGE_ENABLED
    Local $tPriv = DllStructCreate("dword;int64;dword")
    DllStructSetData($tPriv, 1, 1)  ; PrivilegeCount
    DllStructSetData($tPriv, 2, DllStructGetData($tLUID, 1))  ; LUID
    DllStructSetData($tPriv, 3, 0x00000002)  ; SE_PRIVILEGE_ENABLED

    ; Adjust token privileges
    Local $aAdjust = DllCall("advapi32.dll", "bool", "AdjustTokenPrivileges", "handle", $hToken, "bool", False, "ptr", DllStructGetPtr($tPriv), "dword", 0, "ptr", 0, "ptr", 0)
    Local $bSuccess = (IsArray($aAdjust) And $aAdjust[0])
    ; Close token
    DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hToken)
    Return $bSuccess
EndFunc   ;==>__WinVerDetect_EnableBackupPrivilege

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_GenerateUniqueKey
; Description ...: Generates a unique temporary registry key name using GUID.
; Syntax ........: __WinVerDetect_GenerateUniqueKey()
; Parameters ....: None
; Return values .: String: Unique key (e.g., "TEMP_A1B2C3D4")
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Uses CoCreateGuid for randomness
; Remarks .......: - Prefix "TEMP_" for identification.
; Related .......: CoCreateGuid
; ===============================================================================================================================
Func __WinVerDetect_GenerateUniqueKey()
    ; Create GUID structure
    Local $tGUID = DllStructCreate("byte[16]")
    DllCall("ole32.dll", "int", "CoCreateGuid", "ptr", DllStructGetPtr($tGUID))
    ; Convert to hex string (first 8 chars for simplicity)
    Local $sHex = ""
    For $i = 1 To 16
        $sHex &= StringFormat("%02X", DllStructGetData($tGUID, 1, $i))
    Next
    Return "TEMP_" & StringLeft($sHex, 16)
EndFunc   ;==>__WinVerDetect_GenerateUniqueKey

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_IsOfflineInsiderPreview
; Description ...: Checks offline hive for Insider Preview, similar to live but loads hive temporarily.
; Syntax ........: __WinVerDetect_IsOfflineInsiderPreview($sPath)
; Parameters ....: $sPath - String: Offline Windows path
; Return values .: Boolean: True if Insider detected
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Mirrors live check with hive load/unload
; Remarks .......: - Requires admin; unloads hive after check.
; Related .......: __WinVerDetect_LoadOfflineHive, __WinVerDetect_UnloadOfflineHive
; ===============================================================================================================================
Func __WinVerDetect_IsOfflineInsiderPreview($sPath)
    Local $sHiveFile = $sPath & $HIVE_SOFTWARE
    If Not FileExists($sHiveFile) Then
        Return False
    EndIf

    Local $sTempKey = __WinVerDetect_GenerateUniqueKey()
    If Not __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) Then
        Return False
    EndIf

    ; Check Insider keys in loaded hive
    Local $sInsiderKey = "HKLM\" & $sTempKey & "\" & $REG_KEY_INSIDER
    Local $sType = RegRead($sInsiderKey, "ContentType")
    If @error Or $sType = "" Then
        $sType = RegRead($sInsiderKey, "ReleaseType")
    EndIf
    Local $bResult = (Not @error And StringInStr($sType, "Insider") > 0)

    ; Cleanup
    __WinVerDetect_UnloadOfflineHive($sTempKey)
    Return $bResult
EndFunc   ;==>__WinVerDetect_IsOfflineInsiderPreview

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_ArrayToString
; Description ...: Converts an array to a delimited string, starting from optional index.
; Syntax ........: __WinVerDetect_ArrayToString($aArray[, $sDelimiter = "|"[, $iStart = 0]])
; Parameters ....: $aArray    - Array: Input array
;                  $sDelimiter- String: Delimiter (default: "|")
;                  $iStart    - Integer: Starting index (default: 0)
; Return values .: String: Joined array elements
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Handles empty arrays
; Remarks .......: - Similar to _ArrayToString but custom for UDF compatibility.
; Related .......: _RegReadMulti
; ===============================================================================================================================
Func __WinVerDetect_ArrayToString($aArray, $sDelimiter = "|", $iStart = 0)
    If Not IsArray($aArray) Or UBound($aArray) <= $iStart Then
        Return ""
    EndIf
    Local $sResult = $aArray[$iStart]
    For $i = $iStart + 1 To UBound($aArray) - 1
        $sResult &= $sDelimiter & $aArray[$i]
    Next
    Return $sResult
EndFunc   ;==>__WinVerDetect_ArrayToString

; #FUNCTION# ====================================================================================================================
; Name ..........: __WinVerDetect_LogError
; Description ...: Logs error messages to console for debugging (internal use).
; Syntax ........: __WinVerDetect_LogError($sMsg)
; Parameters ....: $sMsg - String: Error message
; Return values .: None (outputs to console)
; Author ........: Dao Van Trong - TRONG.PRO
; Modified ......: Simple console output
; Remarks .......: - Prefix with "!" for visibility.
; Related .......: ConsoleWrite (built-in)
; ===============================================================================================================================
Func __WinVerDetect_LogError($sMsg)
    ConsoleWrite("! " & $sMsg & @CRLF)
EndFunc   ;==>__WinVerDetect_LogError

: TEST :

#Region TEST_SUITE
; #EXAMPLE# =====================================================================================================================
; To run the test suite, call the function: _RunTestSuite()
_RunTestSuite()
; ===============================================================================================================================

;=======================================================================================================
; Function:      _RunTestSuite()
; Description:   Runs the comprehensive test suite for the UDF and prints the results to the console.
; Return Value:  True if all tests passed, False otherwise.
;=======================================================================================================
Func _RunTestSuite()
    Local $iPassed = 0, $iFailed = 0, $iSkipped = 0, $iTotal = 0

    ; List of test functions to execute
    Local $aTestsToRun[] = [ _
            "_TestDatabaseInitialization", _
            "_TestLiveSystemDetection", _
            "_TestUtilityFunctions", _
            "_TestErrorHandling", _
            "_TestVersionInference", _
            "_TestPathValidation", _
            "_TestIndividualFieldAccess", _
            "_TestSpecificBuildsAndNames", _
            "_TestShortNameEdgeCases", _
            "_TestLiveSystemDetails", _
            "_TestSpecialEditionDetection", _  ; New Test Case 10
            "_TestComprehensiveVersionNames" _ ; New Test Case 11
            ]
    $iTotal = UBound($aTestsToRun)

    _PrintTestResult("STARTING COMPREHENSIVE TEST SUITE", 3)
    ConsoleWrite("> UDF Library: Windows Version Detector" & @CRLF)
    ConsoleWrite("=====================================================================================" & @CRLF)

    For $sTestFunc In $aTestsToRun
        Local $aResult = Call($sTestFunc)
        ; Prettify the function name for display
        Local $sTestName = StringRegExpReplace($sTestFunc, "^_Test", "")
        $sTestName = StringRegExpReplace($sTestName, "([A-Z])", " $1")
        $sTestName = StringStripWS($sTestName, 1)

        _PrintTestResult($sTestName, $aResult[0], $aResult[1])

        Switch $aResult[0]
            Case 1 ; PASSED
                $iPassed += 1
            Case 0 ; FAILED
                $iFailed += 1
            Case 2 ; SKIPPED
                $iSkipped += 1
        EndSwitch
    Next

    ConsoleWrite("=====================================================================================" & @CRLF)
    _PrintTestResult("TEST SUITE SUMMARY", 3)

    ConsoleWrite("+ Passed  :  " & $iPassed & @CRLF)
    ConsoleWrite("! Failed  :  " & $iFailed & @CRLF)
    ConsoleWrite("- Skipped :  " & $iSkipped & @CRLF)
    ConsoleWrite("> Total   :  " & $iTotal & @CRLF)

    Local $fSuccessRate = ($iTotal > 0 And $iTotal > $iSkipped) ? ($iPassed / ($iTotal - $iSkipped)) * 100 : 0
    ConsoleWrite(StringFormat("> Success Rate (excluding skipped): %.1f%%", $fSuccessRate) & @CRLF & @CRLF)

    Return $iFailed = 0
EndFunc   ;==>_RunTestSuite

;===============================================================================
; Function:      _PrintTestResult($sTestName, $iResult, $sDetails = "")
; Description:   Internal helper function to print a formatted and colored test result.
; Parameters:    $sTestName - The name of the test.
;                $iResult   - The result code: 1 (PASSED), 0 (FAILED), 2 (SKIPPED), 3 (INFO).
;                $sDetails  - [optional] Additional details to print.
;===============================================================================
Func _PrintTestResult($sTestName, $iResult, $sDetails = "")
    Local $sStatus, $sColorChar
    Local Const $iNameWidth = 35 ; Column width for the test name

    Switch $iResult
        Case 1 ; PASSED
            $sColorChar = "+ "
            $sStatus = "[  PASSED  ] "
        Case 0 ; FAILED
            $sColorChar = "! "
            $sStatus = "[  FAILED  ] "
        Case 2 ; SKIPPED
            $sColorChar = "- "
            $sStatus = "[ SKIPPED  ] "
        Case Else ; INFO
            $sColorChar = "> "
            $sStatus = "[   INFO   ] "
            $sDetails = $sTestName
            $sTestName = ""
    EndSwitch

    Local $sPaddedName = StringFormat("%-" & $iNameWidth & "s", $sTestName)
    ConsoleWrite($sColorChar & $sStatus & " " & $sPaddedName & $sDetails & @CRLF)
EndFunc   ;==>_PrintTestResult

; ------ INDIVIDUAL TEST CASE FUNCTIONS ------

;===============================================================================
; Test Case:     _TestDatabaseInitialization
; Description:   Verifies that the global database arrays are initialized correctly.
;===============================================================================
Func _TestDatabaseInitialization()
    Local $aReturn[2]
    If Not IsArray($_g_aWinVerRangeDB) Or UBound($_g_aWinVerRangeDB, 2) <> 3 Then
        $aReturn[0] = 0
        $aReturn[1] = "RangeDB database is invalid or has wrong structure."
        Return $aReturn
    EndIf
    If Not IsArray($_g_aWinVerExactDB) Or UBound($_g_aWinVerExactDB, 2) <> 7 Then
        $aReturn[0] = 0
        $aReturn[1] = "ExactDB database is invalid or has wrong structure."
        Return $aReturn
    EndIf
    $aReturn[0] = 1
    $aReturn[1] = ""
    Return $aReturn
EndFunc   ;==>_TestDatabaseInitialization

;===============================================================================
; Test Case:     _TestLiveSystemDetection
; Description:   Performs a basic check on the currently running OS.
;===============================================================================
Func _TestLiveSystemDetection()
    Local $aReturn[2]
    If Not IsAdmin() Then
        $aReturn[0] = 2
        $aReturn[1] = "No administrator rights, skipping live system test."
        Return $aReturn
    EndIf

    Local $aResult = _WinVerDetect_GetVersion()
    If @error Then
        $aReturn[0] = 0
        $aReturn[1] = "An error occurred during detection. Error code: " & @error
        Return $aReturn
    EndIf
    If Not IsArray($aResult) Or UBound($aResult) <> 10 Then
        $aReturn[0] = 0
        $aReturn[1] = "The returned result is not a valid array."
        Return $aReturn
    EndIf
    If $aResult[$WINVER_STATE] <> "Live" Then
        $aReturn[0] = 0
        $aReturn[1] = "System state was not detected as 'Live'."
        Return $aReturn
    EndIf
    If $aResult[$WINVER_BUILD] = "" Or Int($aResult[$WINVER_BUILD]) < 1000 Then
        $aReturn[0] = 0
        $aReturn[1] = "Could not retrieve a valid build number (Build: " & $aResult[$WINVER_BUILD] & ")."
        Return $aReturn
    EndIf
    $aReturn[0] = 1
    $aReturn[1] = "Current OS: " & $aResult[$WINVER_PRODUCTNAME]
    Return $aReturn
EndFunc   ;==>_TestLiveSystemDetection

;===============================================================================
; Test Case:     _TestUtilityFunctions
; Description:   Tests helper functions like GetShortName and InferDisplayVersion.
;===============================================================================
Func _TestUtilityFunctions()
    Local $aReturn[2]
    Local $sShort = __WinVerDetect_GetShortName("Windows 11 Pro")
    If $sShort <> "WIN_11" Then
        $aReturn[0] = 0
        $aReturn[1] = "GetShortName failed. Expected 'WIN_11', got '" & $sShort & "'."
        Return $aReturn
    EndIf
    Local $sDisplay = __WinVerDetect_InferDisplayVersion(22631)
    If $sDisplay <> "23H2" Then
        $aReturn[0] = 0
        $aReturn[1] = "InferDisplayVersion failed. Expected '23H2', got '" & $sDisplay & "'."
        Return $aReturn
    EndIf
    Local $sVersionName = __WinVerDetect_GetVersionNameByBuild(19045, "22H2", "Windows 10 Enterprise")
    If Not StringInStr($sVersionName, "Windows 10 Enterprise") Or Not StringInStr($sVersionName, "22H2") Then
        $aReturn[0] = 0
        $aReturn[1] = "GetVersionName failed. Result: " & $sVersionName
        Return $aReturn
    EndIf
    $aReturn[0] = 1
    $aReturn[1] = ""
    Return $aReturn
EndFunc   ;==>_TestUtilityFunctions

;===============================================================================
; Test Case:     _TestErrorHandling
; Description:   Ensures the main function correctly handles invalid inputs.
;===============================================================================
Func _TestErrorHandling()
    Local $aReturn[2]
    _WinVerDetect_GetVersion("C:\NonExistent\Path\For\Sure")
    If @error <> $WINVER_ERROR_INVALID_PATH Then
        $aReturn[0] = 0
        $aReturn[1] = "Did not catch invalid path error. Error code: " & @error
        Return $aReturn
    EndIf
    _WinVerDetect_GetVersion("")
    If @error <> $WINVER_ERROR_INVALID_PATH Then
        $aReturn[0] = 0
        $aReturn[1] = "Did not catch empty path error. Error code: " & @error
        Return $aReturn
    EndIf
    $aReturn[0] = 1
    $aReturn[1] = ""
    Return $aReturn
EndFunc   ;==>_TestErrorHandling

;===============================================================================
; Test Case:     _TestVersionInference
; Description:   Checks display version inference for specific build numbers.
;===============================================================================
Func _TestVersionInference()
    Local $aReturn[2]
    Local $aTestBuilds[3][2] = [[19041, "2004"], [22000, "21H2"], [26100, "24H2"]]
    For $i = 0 To UBound($aTestBuilds) - 1
        Local $sInferred = __WinVerDetect_InferDisplayVersion($aTestBuilds[$i][0])
        If $sInferred <> $aTestBuilds[$i][1] Then
            $aReturn[0] = 0
            $aReturn[1] = "Inference failed for Build " & $aTestBuilds[$i][0] & ". Expected '" & $aTestBuilds[$i][1] & "', got '" & $sInferred & "'."
            Return $aReturn
        EndIf
    Next
    $aReturn[0] = 1
    $aReturn[1] = ""
    Return $aReturn
EndFunc   ;==>_TestVersionInference

;===============================================================================
; Test Case:     _TestPathValidation
; Description:   Tests the __WinVerDetect_IsValidWindowsPath helper function.
;===============================================================================
Func _TestPathValidation()
    Local $aReturn[2]
    If Not __WinVerDetect_IsValidWindowsPath(@WindowsDir) Then
        $aReturn[0] = 0
        $aReturn[1] = "Failed to validate current Windows directory (" & @WindowsDir & ")."
        Return $aReturn
    EndIf
    If __WinVerDetect_IsValidWindowsPath(@TempDir) Then
        $aReturn[0] = 0
        $aReturn[1] = "Incorrectly validated Temp directory (" & @TempDir & ") as a Windows path."
        Return $aReturn
    EndIf
    $aReturn[0] = 1
    $aReturn[1] = ""
    Return $aReturn
EndFunc   ;==>_TestPathValidation

;===============================================================================
; Test Case:     _TestIndividualFieldAccess
; Description:   Tests retrieving a single field using the $iReturnIndex parameter.
;===============================================================================
Func _TestIndividualFieldAccess()
    Local $aReturn[2]
    If Not IsAdmin() Then
        $aReturn[0] = 2
        $aReturn[1] = "Admin rights required."
        Return $aReturn
    EndIf
    Local $sBuild = _WinVerDetect_GetVersion(@WindowsDir, $WINVER_BUILD)
    If @error Or $sBuild = "" Or Int($sBuild) < 1000 Then
        $aReturn[0] = 0
        $aReturn[1] = "Failed to retrieve individual Build Number. Error: " & @error
        Return $aReturn
    EndIf
    Local $sProductName = _WinVerDetect_GetVersion(@WindowsDir, $WINVER_PRODUCTNAME)
    If @error Or $sProductName = "" Then
        $aReturn[0] = 0
        $aReturn[1] = "Failed to retrieve individual ProductName. Error: " & @error
        Return $aReturn
    EndIf

    $aReturn[0] = 1
    $aReturn[1] = "Build: " & $sBuild & ", Product: " & $sProductName
    Return $aReturn
EndFunc   ;==>_TestIndividualFieldAccess

;===============================================================================
; Test Case:     _TestSpecificBuildsAndNames
; Description:   Tests version name generation against known data points.
;===============================================================================
Func _TestSpecificBuildsAndNames()
    Local $aReturn[2]
    ; Test Data Format: [Build, Expected Product Name, Expected Display Version]
    Local $aTestCases[4][3] = [ _
            [19045, "Windows 10", "22H2"], _
            [22000, "Windows 11", "21H2"], _
            [26100, "Windows Server 2025", "24H2"], _
            [20348, "Windows Server 2022", "21H2"] _
            ]

    For $aCase In $aTestCases
        Local $iBuild = $aCase[0]
        Local $sExpectedProduct = $aCase[1]
        Local $sExpectedDisplay = $aCase[2]

        Local $sFullName = __WinVerDetect_GetVersionNameByBuild($iBuild, "", $sExpectedProduct)
        If Not StringInStr($sFullName, $sExpectedProduct) Or Not StringInStr($sFullName, $sExpectedDisplay) Then
            $aReturn[0] = 0
            $aReturn[1] = StringFormat("Build %d failed. Expected '%s %s', got '%s'", $iBuild, $sExpectedProduct, $sExpectedDisplay, $sFullName)
            Return $aReturn
        EndIf
    Next

    $aReturn[0] = 1
    $aReturn[1] = ""
    Return $aReturn
EndFunc   ;==>_TestSpecificBuildsAndNames

;===============================================================================
; Test Case:     _TestShortNameEdgeCases
; Description:   Tests the GetShortName function with server and unknown values.
;===============================================================================
Func _TestShortNameEdgeCases()
    Local $aReturn[2]
    If __WinVerDetect_GetShortName("Windows Server 2022") <> "WIN_2022" Then
        $aReturn[0] = 0
        $aReturn[1] = "Failed to get short name for Server 2022."
        Return $aReturn
    EndIf
    Local $sReturn = __WinVerDetect_GetShortName("Some Unknown OS")
    If $sReturn <> "UNKNOWN" Then
        $aReturn[0] = 0
        $aReturn[1] = "Failed to return '" & $sReturn & "' for an unrecognized OS name."
        Return $aReturn
    EndIf

    $aReturn[0] = 1
    $aReturn[1] = ""
    Return $aReturn
EndFunc   ;==>_TestShortNameEdgeCases

;===============================================================================
; Test Case:     _TestLiveSystemDetails
; Description:   Displays detailed information about the live operating system.
;===============================================================================
Func _TestLiveSystemDetails()
    Local $aReturn[2]
    If Not IsAdmin() Then
        $aReturn[0] = 2
        $aReturn[1] = "Admin rights required."
        Return $aReturn
    EndIf

    Local $aResult = _WinVerDetect_GetVersion()
    If @error Then
        $aReturn[0] = 0
        $aReturn[1] = "Could not retrieve system details. Error: " & @error
        Return $aReturn
    EndIf

    Local $sDetails = @CRLF
    $sDetails &= ">          State: " & $aResult[$WINVER_STATE] & @CRLF
    $sDetails &= ">     Short Name: " & $aResult[$WINVER_SHORTNAME] & @CRLF
    $sDetails &= ">    ProductName: " & $aResult[$WINVER_PRODUCTNAME] & @CRLF
    $sDetails &= ">      Full Name: " & $aResult[$WINVER_FULLNAME] & @CRLF
    $sDetails &= ">          Build: " & $aResult[$WINVER_BUILD] & @CRLF
    $sDetails &= ">            UBR: " & $aResult[$WINVER_UBR] & @CRLF
    $sDetails &= "> DisplayVersion: " & $aResult[$WINVER_DISPLAYVERSION] & @CRLF
    $sDetails &= ">      EditionID: " & $aResult[$WINVER_EDITIONID] & @CRLF
    $sDetails &= ">    EditionType: " & $aResult[$WINVER_EDITIONTYPE] & @CRLF
    $sDetails &= ">      IsInsider: " & ($aResult[$WINVER_ISINSIDER] ? "Yes" : "No") & @CRLF

    $aReturn[0] = 1
    $aReturn[1] = $sDetails
    Return $aReturn
EndFunc   ;==>_TestLiveSystemDetails

;===============================================================================
; Test Case:     _TestSpecialEditionDetection
; Description:   Tests the __WinVerDetect_InferEditionType function for special edition detection.
;===============================================================================
Func _TestSpecialEditionDetection()
    Local $aReturn[2]
    Local $iPassEdition = 0
    ; Test Data Format: [ProductName, EditionID, Expected EditionType]
    Local $aTestCases[14][3] = [ _
            ["Windows 10 Home", "CoreCountrySpecific", "Home China"], _
            ["Windows 11 Home", "CoreCountrySpecific", "Home China"], _
            ["Windows 10 Pro", "ProfessionalCountrySpecific", "Pro China"], _
            ["Windows 10 Home N", "CoreN", "Home N"], _
            ["Windows 11 Pro N", "ProfessionalN", "Pro N"], _
            ["Windows 10 Home KN", "CoreKN", "Home KN"], _
            ["Windows 10 Enterprise G", "EnterpriseG", "Enterprise G"], _
            ["Windows 10 Enterprise LTSC", "EnterpriseS", "Enterprise LTSC"], _
            ["Windows 10 IoT Enterprise", "IoTEnterprise", "IoT Enterprise"], _
            ["Windows Server 2019", "ServerStandard", "Server Standard"], _
            ["Windows Server 2022", "ServerDatacenter", "Server Datacenter"], _
            ["Windows Server 2022", "ServerStandardCore", "Server Standard"], _
            ["Windows 11 Enterprise", "Enterprise", "Enterprise"], _
            ["Windows 10 Education", "Education", "Education"] _
            ]

    ConsoleWrite("> Testing special edition detection capabilities:" & @CRLF)
    For $i = 0 To UBound($aTestCases) - 1
        Local $sProductName = $aTestCases[$i][0]
        Local $sEditionID = $aTestCases[$i][1]
        Local $sExpected = $aTestCases[$i][2]
        Local $sResult = __WinVerDetect_InferEditionType($sProductName, $sEditionID)
        Local $sStatus = ($sResult = $sExpected) ? "+ ✓ PASS" : "! ✗ FAIL"
        ConsoleWrite($sStatus & " | ProductName: " & StringFormat("%-28s", $sProductName) & " | EditionID: " & StringFormat("%-27s", $sEditionID) & " | Result: " & $sResult & @CRLF)
        If $sResult = $sExpected Then $iPassEdition += 1
    Next
    Local $sSummary = "Result: " & $iPassEdition & "/" & UBound($aTestCases) & " passed"

    If $iPassEdition = UBound($aTestCases) Then
        $aReturn[0] = 1
        $aReturn[1] = $sSummary
    Else
        $aReturn[0] = 0
        $aReturn[1] = $sSummary
    EndIf
    ConsoleWrite("> " & $sSummary & @CRLF & @CRLF)
    Return $aReturn
EndFunc   ;==>_TestSpecialEditionDetection

;===============================================================================
; Test Case:     _TestComprehensiveVersionNames
; Description:   Tests __WinVerDetect_GetVersionNameByBuild with various build numbers and product names.
;===============================================================================
Func _TestComprehensiveVersionNames()
    Local $aReturn[2]
    Local $iPassVersion = 0
    ; Test Data Format: [Build, DisplayVersion, ProductName, Expected Full Name]
    Local $aTestCases[32][4] = [ _
            [528, "", "", "Windows NT 3.1 (Build 528) (July 1993) (Razzle)"], _
            [807, "", "", "Windows NT 3.5 (Build 807) (September 1994) (Daytona)"], _
            [1057, "", "", "Windows NT 3.51 (Build 1057) (May 1995) (Daytona)"], _
            [1381, "", "", "Windows NT 4.0 (Build 1381) (August 1996) (Cairo)"], _
            [1381, "", "Windows NT Server 4.0", "Windows NT Server 4.0 (Build 1381) (August 1996) (Cairo)"], _
            [950, "", "", "Windows 95 Version 4.0 (Build 950) (August 1995) (Chicago)"], _
            [1998, "", "", "Windows 98 Version 4.1 (Build 1998) (June 1998) (Memphis)"], _
            [2222, "", "", "Windows 98 SE (Build 2222) (May 1999) (Memphis)"], _
            [3000, "", "", "Windows Me Version 4.9 (Build 3000) (September 2000) (Millennium)"], _
            [2195, "", "", "Windows 2000 Version 5.0 (Build 2195) (February 2000) (NT 5.0)"], _
            [2195, "", "Windows 2000 Server", "Windows 2000 Server Version 5.0 (Build 2195) (February 2000) (NT 5.0)"], _
            [2600, "", "", "Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)"], _
            [2600, "5.1", "", "Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)"], _
            [2600, "5.1", "Windows XP Professional", "Windows XP Professional Version 5.1 (Build 2600) (October 2001) (Whistler)"], _
            [3790, "", "", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _
            [3790, "5.2", "", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _
            [3790, "", "Windows Server 2003", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _
            [6000, "", "", "Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)"], _
            [6000, "6.0", "", "Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)"], _
            [7600, "", "", "Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)"], _
            [7600, "6.1", "", "Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)"], _
            [9200, "", "", "Windows 8 Version 6.2 (Build 9200) (October 2012) (Metro)"], _
            [9600, "", "", "Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)"], _
            [9600, "Update1", "", "Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)"], _
            [10240, "", "", "Windows 10 1507 (Build 10240)"], _
            [10240, "1507", "Windows 10", "Windows 10 1507 (Build 10240)"], _
            [19045, "", "", "Windows 10 22H2 (Build 19045)"], _
            [19045, "22H2", "Windows 10", "Windows 10 22H2 (Build 19045)"], _
            [22000, "", "", "Windows 11 21H2 (Build 22000)"], _
            [22000, "21H2", "Windows 11", "Windows 11 21H2 (Build 22000)"], _
            [20348, "", "Windows Server 2022", "Windows Server 2022 22H2 (Build 20348)"], _
            [26100, "", "Windows Server 2025", "Windows Server 2025 24H2 (Build 26100)"] _
            ]

    ConsoleWrite("> Testing comprehensive version name generation for __WinVerDetect_GetVersionNameByBuild:" & @CRLF)
    For $i = 0 To UBound($aTestCases) - 1
        Local $iBuild = $aTestCases[$i][0]
        Local $sDisplayVersion = $aTestCases[$i][1]
        Local $sProductName = $aTestCases[$i][2]
        Local $sExpected = $aTestCases[$i][3]
        Local $sActual = __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName)
;~      ConsoleWrite('['&$iBuild&', "'&$sDisplayVersion&'", "'&$sProductName&'", "'&$sActual&'"], _' & @CRLF)
        Local $sStatus = ($sActual = $sExpected) ? "+ ✓ PASS" : "! ✗ FAIL"
        ConsoleWrite($sStatus & " | Build: " & StringFormat("%-6s", $iBuild) & " | DisplayVersion: " & StringFormat("%-10s", $sDisplayVersion) & " | ProductName: " & StringFormat("%-30s", $sProductName) & " | Result: " & $sActual & @CRLF)
        If $sActual <> $sExpected Then
            ConsoleWrite(" -> Expected: " & $sExpected & @CRLF)
            ConsoleWrite(" -> Actual: " & $sActual & @CRLF)
        EndIf
        If $sActual = $sExpected Then $iPassVersion += 1
    Next
    Local $sSummary = "Result: " & $iPassVersion & "/" & UBound($aTestCases) & " passed"

    If $iPassVersion = UBound($aTestCases) Then
        $aReturn[0] = 1
        $aReturn[1] = $sSummary
    Else
        $aReturn[0] = 0
        $aReturn[1] = $sSummary
    EndIf
    ConsoleWrite("> " & $sSummary & @CRLF & @CRLF)
    Return $aReturn
EndFunc   ;==>_TestComprehensiveVersionNames

#EndRegion TEST_SUITE

 > Result test:

> [   INFO   ]                                     STARTING COMPREHENSIVE TEST SUITE
> UDF Library: Windows Version Detector
=====================================================================================
+ [  PASSED  ]  Database Initialization            
+ [  PASSED  ]  Live System Detection              Current OS: Windows 10 Enterprise LTSC 2021
+ [  PASSED  ]  Utility Functions                  
+ [  PASSED  ]  Error Handling                     
+ [  PASSED  ]  Version Inference                  
+ [  PASSED  ]  Path Validation                    
+ [  PASSED  ]  Individual Field Access            Build: 19045, Product: Windows 10 Enterprise LTSC 2021
+ [  PASSED  ]  Specific Builds And Names          
+ [  PASSED  ]  Short Name Edge Cases              
+ [  PASSED  ]  Live System Details                
>          State: Live
>     Short Name: WIN_10
>    ProductName: Windows 10 Enterprise LTSC 2021
>      Full Name: Windows 10 Version 22H2 (Build 19045.6216)
>          Build: 19045
>            UBR: 6216
> DisplayVersion: 22H2
>      EditionID: EnterpriseS
>    EditionType: Enterprise LTSC
>      IsInsider: No

> Testing special edition detection capabilities:
+ ✓ PASS | ProductName: Windows 10 Home              | EditionID: CoreCountrySpecific         | Result: Home China
+ ✓ PASS | ProductName: Windows 11 Home              | EditionID: CoreCountrySpecific         | Result: Home China
+ ✓ PASS | ProductName: Windows 10 Pro               | EditionID: ProfessionalCountrySpecific | Result: Pro China
+ ✓ PASS | ProductName: Windows 10 Home N            | EditionID: CoreN                       | Result: Home N
+ ✓ PASS | ProductName: Windows 11 Pro N             | EditionID: ProfessionalN               | Result: Pro N
+ ✓ PASS | ProductName: Windows 10 Home KN           | EditionID: CoreKN                      | Result: Home KN
+ ✓ PASS | ProductName: Windows 10 Enterprise G      | EditionID: EnterpriseG                 | Result: Enterprise G
+ ✓ PASS | ProductName: Windows 10 Enterprise LTSC   | EditionID: EnterpriseS                 | Result: Enterprise LTSC
+ ✓ PASS | ProductName: Windows 10 IoT Enterprise    | EditionID: IoTEnterprise               | Result: IoT Enterprise
+ ✓ PASS | ProductName: Windows Server 2019          | EditionID: ServerStandard              | Result: Server Standard
+ ✓ PASS | ProductName: Windows Server 2022          | EditionID: ServerDatacenter            | Result: Server Datacenter
+ ✓ PASS | ProductName: Windows Server 2022          | EditionID: ServerStandardCore          | Result: Server Standard
+ ✓ PASS | ProductName: Windows 11 Enterprise        | EditionID: Enterprise                  | Result: Enterprise
+ ✓ PASS | ProductName: Windows 10 Education         | EditionID: Education                   | Result: Education
> Result: 14/14 passed

+ [  PASSED  ]  Special Edition Detection          Result: 14/14 passed
> Testing comprehensive version name generation for __WinVerDetect_GetVersionNameByBuild:
+ ✓ PASS | Build: 528    | DisplayVersion:            | ProductName:                                | Result: Windows NT 3.1 (Build 528) (July 1993) (Razzle)
+ ✓ PASS | Build: 807    | DisplayVersion:            | ProductName:                                | Result: Windows NT 3.5 (Build 807) (September 1994) (Daytona)
+ ✓ PASS | Build: 1057   | DisplayVersion:            | ProductName:                                | Result: Windows NT 3.51 (Build 1057) (May 1995) (Daytona)
+ ✓ PASS | Build: 1381   | DisplayVersion:            | ProductName:                                | Result: Windows NT 4.0 (Build 1381) (August 1996) (Cairo)
+ ✓ PASS | Build: 1381   | DisplayVersion:            | ProductName: Windows NT Server 4.0          | Result: Windows NT Server 4.0 (Build 1381) (August 1996) (Cairo)
+ ✓ PASS | Build: 950    | DisplayVersion:            | ProductName:                                | Result: Windows 95 Version 4.0 (Build 950) (August 1995) (Chicago)
+ ✓ PASS | Build: 1998   | DisplayVersion:            | ProductName:                                | Result: Windows 98 Version 4.1 (Build 1998) (June 1998) (Memphis)
+ ✓ PASS | Build: 2222   | DisplayVersion:            | ProductName:                                | Result: Windows 98 SE (Build 2222) (May 1999) (Memphis)
+ ✓ PASS | Build: 3000   | DisplayVersion:            | ProductName:                                | Result: Windows Me Version 4.9 (Build 3000) (September 2000) (Millennium)
+ ✓ PASS | Build: 2195   | DisplayVersion:            | ProductName:                                | Result: Windows 2000 Version 5.0 (Build 2195) (February 2000) (NT 5.0)
+ ✓ PASS | Build: 2195   | DisplayVersion:            | ProductName: Windows 2000 Server            | Result: Windows 2000 Server Version 5.0 (Build 2195) (February 2000) (NT 5.0)
+ ✓ PASS | Build: 2600   | DisplayVersion:            | ProductName:                                | Result: Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)
+ ✓ PASS | Build: 2600   | DisplayVersion: 5.1        | ProductName:                                | Result: Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)
+ ✓ PASS | Build: 2600   | DisplayVersion: 5.1        | ProductName: Windows XP Professional        | Result: Windows XP Professional Version 5.1 (Build 2600) (October 2001) (Whistler)
+ ✓ PASS | Build: 3790   | DisplayVersion:            | ProductName:                                | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)
+ ✓ PASS | Build: 3790   | DisplayVersion: 5.2        | ProductName:                                | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)
+ ✓ PASS | Build: 3790   | DisplayVersion:            | ProductName: Windows Server 2003            | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)
+ ✓ PASS | Build: 6000   | DisplayVersion:            | ProductName:                                | Result: Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)
+ ✓ PASS | Build: 6000   | DisplayVersion: 6.0        | ProductName:                                | Result: Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)
+ ✓ PASS | Build: 7600   | DisplayVersion:            | ProductName:                                | Result: Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)
+ ✓ PASS | Build: 7600   | DisplayVersion: 6.1        | ProductName:                                | Result: Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)
+ ✓ PASS | Build: 9200   | DisplayVersion:            | ProductName:                                | Result: Windows 8 Version 6.2 (Build 9200) (October 2012) (Metro)
+ ✓ PASS | Build: 9600   | DisplayVersion:            | ProductName:                                | Result: Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)
+ ✓ PASS | Build: 9600   | DisplayVersion: Update1    | ProductName:                                | Result: Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)
+ ✓ PASS | Build: 10240  | DisplayVersion:            | ProductName:                                | Result: Windows 10 1507 (Build 10240)
+ ✓ PASS | Build: 10240  | DisplayVersion: 1507       | ProductName: Windows 10                     | Result: Windows 10 1507 (Build 10240)
+ ✓ PASS | Build: 19045  | DisplayVersion:            | ProductName:                                | Result: Windows 10 22H2 (Build 19045)
+ ✓ PASS | Build: 19045  | DisplayVersion: 22H2       | ProductName: Windows 10                     | Result: Windows 10 22H2 (Build 19045)
+ ✓ PASS | Build: 22000  | DisplayVersion:            | ProductName:                                | Result: Windows 11 21H2 (Build 22000)
+ ✓ PASS | Build: 22000  | DisplayVersion: 21H2       | ProductName: Windows 11                     | Result: Windows 11 21H2 (Build 22000)
+ ✓ PASS | Build: 20348  | DisplayVersion:            | ProductName: Windows Server 2022            | Result: Windows Server 2022 22H2 (Build 20348)
+ ✓ PASS | Build: 26100  | DisplayVersion:            | ProductName: Windows Server 2025            | Result: Windows Server 2025 24H2 (Build 26100)
> Result: 32/32 passed

+ [  PASSED  ]  Comprehensive Version Names        Result: 32/32 passed
=====================================================================================
> [   INFO   ]                                     TEST SUITE SUMMARY
+ Passed  :  12
! Failed  :  0
- Skipped :  0
> Total   :  12
> Success Rate (excluding skipped): 100.0%

 

Edited by Trong
v5

Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal

Posted

Result for my PC :

!_OSVersion: WIN_11
!Offline OS: UNKNOWN Build: 0
+Current OS: WIN_11 Build: 26100.4946
- ProductName: Windows 10 Home
- BuildNumber: 26100|24H2|2009|6.3|4946
- VersionName: Windows 11 Version 24H2 (2024 Update) (Build 26100.4946)
- Edition: Home
- SystemType: Live

AutoIt 3.3.18.0 X86 - SciTE 4.4.6WIN 11 24H2 X64 - Other Examples Scripts

Posted (edited)
!Offline OS: UNKNOWN Build: 0
+Current OS: WIN_2025 Build: 26100.1742
- ProductName: Windows Server 2025 Standard
- BuildNumber: 26100|24H2|2009|6.3|1742
- VersionName: Windows Server 2025 (Build 26100.1742)
- Edition: Server Standard
- SystemType: Live

 

!Offline OS: UNKNOWN Build: 0
+Current OS: WIN_FUTURE Build: 26200.5670
- ProductName: Windows 10 Pro
- BuildNumber: 26200|25H2|2009|6.3|5670
- VersionName: Windows 11 (Insider Preview) (Build 26200.5670)
- Edition: Pro
- SystemType: Live

 

!_OSVersion: WIN_11
!Offline OS: WIN_11 Build: 22621.4387
+Current OS: WIN_11 Build: 22621.4387
- ProductName:
- BuildNumber:
- VersionName:
- Edition:
- SystemType: Offline

 

Edited by argumentum
more

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
!=== Enhanced Windows Version Detector Test ===

> 1. Testing current system detection:
-   ProductName: Windows 10 Pro for Workstations
-   BuildNumber: 22631|23H2|2009|6.3|3737
-   VersionName: Windows 11 Version 23H2 (2023 Update) (Build 22631.3737)
-   Edition: Professional
-   SystemType: Live
-   EditionID: ProfessionalWorkstation

> 2. Testing short OS version:
-   OS Version: WIN_11

> 3. Testing detailed OS version:
-   Short Version: WIN_11
-   Build with UBR: 22631.3737
-   Display Version: 23H2
-   Product Name: Windows 10 Pro for Workstations
-   Edition Type: Professional
-   System Type: Live

> 4. Testing special edition detection capabilities:
+   ✓ PASS | ProductName: Windows 10 Home | EditionID: CoreCountrySpecific | Result: Home China
+   ✓ PASS | ProductName: Windows 11 Home | EditionID: CoreCountrySpecific | Result: Home China
+   ✓ PASS | ProductName: Windows 10 Pro | EditionID: ProfessionalCountrySpecific | Result: Pro China
+   ✓ PASS | ProductName: Windows 10 Home N | EditionID: CoreN | Result: Home N
+   ✓ PASS | ProductName: Windows 11 Pro N | EditionID: ProfessionalN | Result: Pro N
+   ✓ PASS | ProductName: Windows 10 Home KN | EditionID: CoreKN | Result: Home KN
+   ✓ PASS | ProductName: Windows 10 Enterprise G | EditionID: EnterpriseG | Result: Enterprise G
+   ✓ PASS | ProductName: Windows 10 Enterprise LTSC | EditionID: EnterpriseS | Result: Enterprise LTSC
+   ✓ PASS | ProductName: Windows 10 IoT Enterprise | EditionID: IoTEnterprise | Result: IoT Enterprise

> 5. Testing offline system detection:
-   No offline Windows installations found for testing.

> 6. Testing error handling with invalid path:
-   Error code: 3
-   Result array size: 6

> 7. China-specific Windows detection capabilities:
-   ✓ CoreCountrySpecific EditionID → Home China
-   ✓ ProfessionalCountrySpecific EditionID → Pro China
-   ✓ EnterpriseG EditionID → Enterprise G (Government)
-   ✓ EnterpriseGovChina EditionID → Enterprise Government China
-   ✓ Supports N editions (Europe) and KN editions (Korea)
-   ✓ Enhanced regional market detection

!=== Test Complete ===

I had to use a MsgBox to display:

...
    Console_WriteR("!=== Test Complete ===" & @CRLF)
    Console_WriteR()

EndFunc   ;==>_TEST
#EndRegion TEST

Func Console_WriteR($sStr = Default, $iError = @error, $iExtended = @extended)
    Local Static $sBuffer = ""
    If $sStr = Default Then
        MsgBox(0, @ScriptName, StringReplace($sBuffer, @LF, ""))
        Return SetError($iError, $iExtended,"")
    Else
        $sBuffer &= $sStr
        Return SetError($iError, $iExtended, ConsoleWrite($sStr))
    EndIf
EndFunc

Are you going to have a v3 with "test 7" in the future ?
How does test 4 work ?, is it broken ?

Please don't answer the question with a reaction. I do not understand those as answers.  

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

Main Cause
Relying entirely on the ProductName string in the registry to determine the product name. But from Windows 11 onwards, Microsoft still keeps the registry label as “Windows 10 …”, even though the OS is actually Windows 11, so you will always see ProductName = "Windows 10 Pro for Workstations". Meanwhile, the build index (22631) shows that this is exactly Windows 11.

Solution: Standardize ProductName based on build
Instead of forcing Windows 10 to be assigned to every ProductName containing “Windows 10”, we should reverse the situation: if build ≥ 22000 (Windows 11), change the registry label to “Windows 11 …” to reflect reality.

 

You can try again!

Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal

Posted

Thanks, result is ok now

-   ProductName: Windows 11 Home
-   BuildNumber: 26100|24H2|2009|6.3|4946
-   VersionName: Windows 11 Version 24H2 (2024 Update) (Build 26100.4946)
-   Edition: Home
-   SystemType: Live

AutoIt 3.3.18.0 X86 - SciTE 4.4.6WIN 11 24H2 X64 - Other Examples Scripts

Posted
Spoiler
!=== Enhanced Windows Version Detector Test ===

> 1. Testing current system detection:
-   ProductName: Windows 11 Pro for Workstations
-   BuildNumber: 22631|23H2|2009|6.3|3737
-   VersionName: Windows 11 Version 23H2 (2023 Update) (Build 22631.3737)
-   Edition: Professional
-   SystemType: Live
-   EditionID: ProfessionalWorkstation

> 2. Testing short OS version:
-   OS Version: WIN_11

> 3. Testing detailed OS version:
-   Short Version: WIN_11
-   Build with UBR: 22631.3737
-   Display Version: 23H2
-   Product Name: Windows 11 Pro for Workstations
-   Edition Type: Professional
-   System Type: Live

> 4. Testing special edition detection capabilities:
+   ✓ PASS | ProductName: Windows 10 Home | EditionID: CoreCountrySpecific | Result: Home China
+   ✓ PASS | ProductName: Windows 11 Home | EditionID: CoreCountrySpecific | Result: Home China
+   ✓ PASS | ProductName: Windows 10 Pro | EditionID: ProfessionalCountrySpecific | Result: Pro China
+   ✓ PASS | ProductName: Windows 10 Home N | EditionID: CoreN | Result: Home N
+   ✓ PASS | ProductName: Windows 11 Pro N | EditionID: ProfessionalN | Result: Pro N
+   ✓ PASS | ProductName: Windows 10 Home KN | EditionID: CoreKN | Result: Home KN
+   ✓ PASS | ProductName: Windows 10 Enterprise G | EditionID: EnterpriseG | Result: Enterprise G
+   ✓ PASS | ProductName: Windows 10 Enterprise LTSC | EditionID: EnterpriseS | Result: Enterprise LTSC
+   ✓ PASS | ProductName: Windows 10 IoT Enterprise | EditionID: IoTEnterprise | Result: IoT Enterprise

> 5. Testing offline system detection:
-   No offline Windows installations found for testing.

> 6. Testing error handling with invalid path:
-   Error code: 3
-   Result array size: 6

> 7. China-specific Windows detection capabilities:
-   ✓ CoreCountrySpecific EditionID → Home China
-   ✓ ProfessionalCountrySpecific EditionID → Pro China
-   ✓ EnterpriseG EditionID → Enterprise G (Government)
-   ✓ EnterpriseGovChina EditionID → Enterprise Government China
-   ✓ Supports N editions (Europe) and KN editions (Korea)
-   ✓ Enhanced regional market detection

!=== Test Complete ===

My setup is: Keyboard:00000409  OS:WIN_11/2009  CPU:X64 OS:X64  Environment(Language:0409)
Hope that helps.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...