Currently, the enableTrueColors function in terminal does the following to 
check for Windows 10:
    
    
    ver.dwOSVersionInfoSize = sizeof(ver).DWORD
        let res = getVersionExW(addr ver)
        if res == 0:
          term.trueColorIsSupported = false
        else:
          term.trueColorIsSupported = ver.dwMajorVersion > 10 or
            (ver.dwMajorVersion == 10 and (ver.dwMinorVersion > 0 or
            (ver.dwMinorVersion == 0 and ver.dwBuildNumber >= 10586)))
    
    
    Run

This is wrong.

As of Windows 8, the GetVersionEx functions have been deprecated and this 
function will return the wrong version information as it pulls from the 
manifest which isn't updated (read: if upgrading from Windows 8 to 10, it 
returns a major version of 6 instead of 10). And lest someone think that the 
VerifyVersionInfo functions in the WINAPI will work, just know that they won't; 
they are now subject to the same manifest "bug": 
[https://msdn.microsoft.com/en-us/library/windows/desktop/dn424972.aspx](https://msdn.microsoft.com/en-us/library/windows/desktop/dn424972.aspx).

The best way to try and get the version of Windows is via the registry. Sadly, 
Window 10 introduced new keys that hold the version, so getting it would look 
something like this:
    
    
    proc regOpenKey(root: HANDLE, subKey: WideCString, opts: DWORD, access: 
DWORD, key: ptr HANDLE): LONG
        {.stdcall, dynlib: "advapi32", importc: "RegOpenKeyExW".}
    proc regCloseKey(key: HANDLE): LONG
        {.stdcall, dynlib: "advapi32", importc: "RegCloseKey".}
    proc regQueryValueEx(key: HANDLE, subKey: WideCString, res: pointer, kind: 
pointer, data: pointer, dataSize: ptr DWORD): LONG
        {.stdcall, dynlib: "advapi32", importc: "RegQueryValueExW".}
    
    let HKEY_LOCAL_MACHINE = 0x80000002.HANDLE
    let KEY_READ = 0x20019.DWORD
    let KEY_WOW64_64KEY = 0x0100.DWORD
    let VERSION_KEY = newWideCString(r"SOFTWARE\Microsoft\Windows 
NT\CurrentVersion".cstring)
    
    proc getWindowsVersion(): tuple[major, minor: Option[int]] =
        var major, minor = none[int]()
        var key: HANDLE
        
        if regOpenKey(HKEY_LOCAL_MACHINE, VERSION_KEY, 0.DWORD, KEY_READ or 
KEY_WOW64_64KEY, addr(key)) == 0:
            let majorKey = newWideCString("CurrentMajorVersionNumber")
            let minorKey = newWideCString("CurrentMinorVersionNumber")
            
            # output from query values
            var value: DWORD = 0
            var size: DWORD = sizeof(value).DWORD
            
            # get version key values
            if regQueryValueEx(key, majorKey, nil.pointer, nil.pointer, 
addr(value), addr(size)) == 0:
                major = some(value.int)
            if regQueryValueEx(key, minorKey, nil.pointer, nil.pointer, 
addr(value), addr(size)) == 0:
                minor = some(value.int)
            
            discard regCloseKey(key)
        
        (major, minor)
    
    
    Run

But, again, this only works on Windows 10. On versions < 10, you need to get 
the "CurrentVersion" key (a string), and parse it:
    
    
    # ... similar to above, opening the key, but the sub key being read is 
different
    var value = newStringOfCap(100)
    var size = 100.DWORD
    
    # get version key values
    if regQueryValueEx(key, versionKey, nil.pointer, nil.pointer, 
value.cstring, addr(size)) == 0:
        echo value
        let ver = split(value.strip(), '.')
        
        major = some(ver[0].parseInt())
        minor = some(ver[1].parseInt())
    
    
    Run

I haven't gotten this half to work (it segfaults attempting to read from nil). 
I assume I'm loading the value wrong. My time with Nim so far has only been a 
couple days, so hopefully it's a quick/easy fix for someone here.

Anyway, I don't know if there are other places in the standard library that are 
testing against the Windows version (specifically looking for Windows 10 or 
higher), but the check in terminal is wrong and should be changed. And there it 
might be beneficial - in general - to just have an os.getVersion(): 
tuple[major, minor: int] method available that's cross-platform and can be used 
for these sorts of things.

As the above relates specifically to the terminal module, there shouldn't 
really be a need to test for Windows 10. It should be possible to just set the 
ENABLE_VIRTUAL_TERMINAL_PROCESSING mode flag on STDOUT and it either works or 
not. If not, it's not supported. If so, then great. Making this change would be 
no different (to the end user) than the current behavior. Right now it silently 
just doesn't even try to set it and the end result is the same: it's as if the 
console didn't support it. 

Reply via email to