Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finding the Windows version getting messier (detect windows 8.1?) #63342

Closed
tim-one opened this issue Oct 2, 2013 · 35 comments
Closed

Finding the Windows version getting messier (detect windows 8.1?) #63342

tim-one opened this issue Oct 2, 2013 · 35 comments
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) OS-windows type-bug An unexpected behavior, bug, or error

Comments

@tim-one
Copy link
Member

tim-one commented Oct 2, 2013

BPO 19143
Nosy @malemburg, @tim-one, @loewis, @pitrou, @giampaolo, @tjguk, @jkloth, @briancurtin, @zware, @serhiy-storchaka, @eryksun, @zooba, @fredrikaverpil
Files
  • win32_ver.py
  • win32_ver.py: Added W2K, WS2K3 and XP versions
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/zooba'
    closed_at = <Date 2015-09-23.00:33:33.202>
    created_at = <Date 2013-10-02.00:50:04.086>
    labels = ['interpreter-core', 'type-bug', 'OS-windows']
    title = 'Finding the Windows version getting messier (detect windows 8.1?)'
    updated_at = <Date 2018-04-18.06:14:26.284>
    user = 'https://github.com/tim-one'

    bugs.python.org fields:

    activity = <Date 2018-04-18.06:14:26.284>
    actor = 'rauaha'
    assignee = 'steve.dower'
    closed = True
    closed_date = <Date 2015-09-23.00:33:33.202>
    closer = 'steve.dower'
    components = ['Interpreter Core', 'Windows']
    creation = <Date 2013-10-02.00:50:04.086>
    creator = 'tim.peters'
    dependencies = []
    files = ['37586', '38102']
    hgrepos = []
    issue_num = 19143
    keywords = []
    message_count = 35.0
    messages = ['198814', '198819', '198822', '198823', '198827', '198838', '198839', '220163', '220171', '220182', '220186', '233268', '233272', '233322', '233324', '235612', '235613', '235614', '235618', '235620', '235621', '235787', '250841', '251370', '251371', '251372', '251373', '251413', '253730', '253731', '253733', '315394', '315396', '315411', '315436']
    nosy_count = 15.0
    nosy_names = ['lemburg', 'tim.peters', 'loewis', 'pitrou', 'giampaolo.rodola', 'tim.golden', 'jkloth', 'brian.curtin', 'python-dev', 'zach.ware', 'serhiy.storchaka', 'eryksun', 'steve.dower', 'fredrikaverpil', 'rauaha']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue19143'
    versions = ['Python 3.4']

    @tim-one
    Copy link
    Member Author

    tim-one commented Oct 2, 2013

    This question:

    http://stackoverflow.com/questions/19128219/detect-windows-8-1-in-python
    

    reports that Python is returning incorrect version info under Windows 8.1.

    Alas, it appears MS is "deprecating" GetVersionEx():

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx
    

    and replacing it with a whole slew of annoying "yes or no?" functions:

    http://msdn.microsoft.com/en-us/library/windows/desktop/dn424972(v=vs.85).aspx
    

    Heh ;-)

    @tim-one tim-one added interpreter-core (Objects, Python, Grammar, and Parser dirs) OS-windows labels Oct 2, 2013
    @tjguk
    Copy link
    Member

    tjguk commented Oct 2, 2013

    I was surprised that GetVersionEx would lie. But sure enough. Here:

    http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/c471de52-611f-435d-ab44-56064e5fd7d5/windows-81-preview-getversionex-reports-629200

    (Including a heartfelt comment by long-time Python developer Tim Roberts)

    @tjguk
    Copy link
    Member

    tjguk commented Oct 2, 2013

    I've just installed a Win 8.1 VM and can (unsurprisingly) confirm the
    report: The "ver" command shows 6.3.9600 while GetVersionEx and
    consequently sys.getwindowsversion report 6.2.9200

    We do use GetVersionEx in a few other places (timemodule.c,
    unicodeobject.c, install.c) but they're limited to checking that we're
    running at least XP or at least Vista which will continue work as such.

    I'm not really sure what to propose: we could simply sit back and say
    "We're telling you what Windows tells us". It's unappealing, but I'm not
    sure there's a clear alternative.

    @tjguk
    Copy link
    Member

    tjguk commented Oct 2, 2013

    platform.platform & platform.uname are also affected although they already use "ver"-parsing in some circumstances so could presumably fallback to that approach here as well.

    @pitrou
    Copy link
    Member

    pitrou commented Oct 2, 2013

    (One explanation is they did it for the enjoyment of non-Windows programmers)

    @loewis
    Copy link
    Mannequin

    loewis mannequin commented Oct 2, 2013

    tim.peters: looking at the implementation of the proposed annoying functions with names like IsWindows8Point1OrGreater, it turns out that they all go back to VerifyVersionInfoW, which is available since W2k (but still doesn't tell the actual version).

    tim.golden: a work-around is documented in

    http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx

    Put

    <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>

    into the manifest of python.exe, and it should report the correct version. Of course

    a) this would fail for somebody embedding Python (unless they have that in their exe's manifest), and
    b) we don't know the Id of upcoming windows versions, so the binaries produced today might still lie on future Windows releases.

    It seems possible to query the compatibility using QueryActCtxW and CompatibilityInformationInActivationContext, but I couldn't find a way to put the compatibility into a new activation context (which would allow to claim compatibility dynamically).

    @loewis
    Copy link
    Mannequin

    loewis mannequin commented Oct 2, 2013

    According to

    http://stackoverflow.com/questions/17399302/how-can-i-detect-windows-8-1-in-a-desktop-application

    another strategy is to directly read the version out of the registry, from

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
    (values CurrentVersion, CurrentBuild)

    Not sure where to get service pack information from, though.

    @vstinner vstinner changed the title Finding the Windows version getting messier Finding the Windows version getting messier (detect windows 8.1?) Jun 9, 2014
    @malemburg
    Copy link
    Member

    I don't have a Windows 8.1 handy, but if "ver" reports the correct version, why not have platform.win32_ver() use _syscmd_ver() in case the other APIs report "6.2.9200" and then have win32_ver() the higher version ?!

    FWIW: I don't think we should add anything to the python.exe manifest to have it report the correct version. This could potentially break other APIs. AFAIK, MS just used this "trick" to prevent having existing 8.0 applications fail on 8.1 due to the minor version bump. I suppose they'll undo this with the next official Windows release.

    @zooba
    Copy link
    Member

    zooba commented Jun 10, 2014

    The two 'correct' options are adding the manifest or doing nothing (based on a number of very passionate internal discussions I was able to dig up).

    Without the manifest, various APIs may behave differently - it's the new way that Windows decides whether to apply compatibility settings. If sys.getwindowsversion() reports the actual version number and people are getting old APIs through ctypes, more problems are caused than solved. The theory is that if you apply the manifest, you are stating that you have tested the application against that version (helped by having an unpredictable scheme without supersets).

    Without the manifest, Python is always going to be run in compatibility mode for Windows 8, even as breaking changes are made in the future.

    It would be quite a reasonable position (compatibility-wise) for Python to only manifest for the earliest version it supported. That way, all Python scripts are going to behave the same on later versions of Windows, even as the API behaviours change. (Note that I'm not advocating this - I'm just trying to explain the rationale better than our docs have done it.)

    But basically, the result of sys.getwindowsversion() should return the behaviour that the program is going to get. If python.exe itself is manifested to support Windows 8.1, or if it isn't, both the behaviour and the version will match. IMO, and the Windows dev's opinion, this is correct.

    The one concession that the Windows dev is willing to make is for logging, in which case the version number should be read as a string from a standard DLL like kernel32.dll. This would be appropriate for platform.win32_ver(), but as discussed above, not for sys.getwindowsversion().

    Reading the registry is not recommended - the argument is roughly "GetVersionEx was being misused so we 'fixed' it, and when the registry starts being misused we'll 'fix' that too".

    @malemburg
    Copy link
    Member

    On 10.06.2014 18:28, Steve Dower wrote:

    The one concession that the Windows dev is willing to make is for logging, in which case the version number should be read as a string from a standard DLL like kernel32.dll. This would be appropriate for platform.win32_ver(), but as discussed above, not for sys.getwindowsversion().

    So have platform.win32_ver() return the true version is acceptable ?

    Note that the platform module is meant for identifying the platform,
    not the runtime compatibility environment, so it has a slightly
    different target audience.

    Thanks,

    Marc-Andre Lemburg
    eGenix.com

    @zooba
    Copy link
    Member

    zooba commented Jun 10, 2014

    So have platform.win32_ver() return the true version is acceptable ?

    Note that the platform module is meant for identifying the platform,
    not the runtime compatibility environment, so it has a slightly
    different target audience

    Yes, and that's exactly the reason it's acceptable.

    @zooba
    Copy link
    Member

    zooba commented Dec 31, 2014

    I've attached a replacement for the win32_ver function in platform.py that will get the actual version number from kernel32.dll's resources. Originally I was just writing a helper function, but it seemed easy enough to replace the entire function.

    The attached function only really supports Python 3.5 as it assumes that the earliest Windows version will be Vista (6.0). The comments in platform.py suggest backwards compatibility is important for this file, so my win32_ver() may be a better reference for someone who wants to add this functionality in a backwards-compatible way. Though if it's okay for the stdlib platform.py to not support pre-3.5 this should be fine (and I'll do the extra work to make sure).

    It's probably also easy to support 3.4 and Windows XP/WS2K3 as well, but I don't have any machines handy to test it.

    As part of my patch for bpo-23018, I'll add the manifest required so that GetVersionEx() will recognise 8.1 and 10.

    @eryksun
    Copy link
    Contributor

    eryksun commented Dec 31, 2014

    actual_len = kernel32.GetModuleFileNameW(kernel32._handle, name, len(name))

    A module handle is the module's base address. kernel32 is loaded at a 32-bit base address in a 64-bit process, but I don't know whether that will always be true in current and future versions. It's safer to use HANDLE(kernel32._handle) instead of the default C int conversion.

    ver_block = byref(c_buffer(size))

    byref is unnecessary. An array gets passed as a pointer.

    maj = int(pvi.contents.dwProductVersionMS >> 16)
    min = int(pvi.contents.dwProductVersionMS & 0xFFFF)
    build = int(pvi.contents.dwProductVersionLS >> 16)

    pvi.contents.dwProductVersionMS is already an int, else the bitshift would fail.

    @zooba
    Copy link
    Member

    zooba commented Jan 2, 2015

    Thanks for the feedback. Updated the attachment with some other tidying too.

    @eryksun
    Copy link
    Contributor

    eryksun commented Jan 2, 2015

    if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
    not ver_block):

    Arrays don't implement __bool__ and have fixed __len__, so ver_block is always True. You could look at ver_block[0] or ver_block.value (i.e. the C string value).

    @zooba
    Copy link
    Member

    zooba commented Feb 9, 2015

    (Was reminded about this by bpo-23417)

    Any word on the back compat issues in platform.py? Can we make the version in 3.5 only work with Vista+, or do I need to handle XP in case someone takes the file onto an earlier Python version?

    @malemburg
    Copy link
    Member

    On 09.02.2015 15:14, Steve Dower wrote:

    Steve Dower added the comment:

    (Was reminded about this by bpo-23417)

    Any word on the back compat issues in platform.py? Can we make the version in 3.5 only work with Vista+, or do I need to handle XP in case someone takes the file onto an earlier Python version?

    platform.py has to work on as many platforms as possible (by design),
    so as long as Python still runs on Windows XP, we cannot leave that
    version behind.

    @zooba
    Copy link
    Member

    zooba commented Feb 9, 2015

    Including the one shipped in the stdlib? Python 3.5 no longer supports XP.

    @BreamoreBoy
    Copy link
    Mannequin

    BreamoreBoy mannequin commented Feb 9, 2015

    @Steve just in case you didn't know the rules are given here https://www.python.org/dev/peps/pep-0011/#microsoft-windows. I find it a nuisance that you have to follow an external link to get the status of Python, but maybe it's the lesser of two evils? An aside, at some point the fourth paragraph will need changing to reflect that VS 2015 and later versions will be maintaining backward compatibility.

    @malemburg
    Copy link
    Member

    On 09.02.2015 16:17, Steve Dower wrote:

    Steve Dower added the comment:

    Including the one shipped in the stdlib? Python 3.5 no longer supports XP.

    We normally have the platform.py module support multiple Python
    versions (at least that's how we did this in Python 2). The reason
    is that we'd like to make it possible to easily backport the module
    to earlier versions.

    This has generally not been a major problem, so if possible,
    let's keep it that way for Python 3 as well.

    Thanks,

    Marc-Andre Lemburg
    eGenix.com

    @zooba
    Copy link
    Member

    zooba commented Feb 9, 2015

    @Marc-Andre: Okay, I'll make it easier to backport. You're listed as maintainer - would you like me to post updates here and let you merge them in?

    @mark - yep, I'm aware of that. That's how I know that 3.5 doesn't support XP anymore :) (I think we're even past the 3 years on keeping old project files around for VS 2008, which is good since they're already gone from tip.)

    @zooba
    Copy link
    Member

    zooba commented Feb 12, 2015

    The newer attachment should handle back to Windows 2000. Unfortunately, I have no machines to test this on, but all of the API calls existed at least on XP and the version numbers are correct.

    It runs correctly back to Python 2.7, works on 2.6 but gives the wrong result (possibly a ctypes bug?), and is fine on Python 3.

    @malemburg
    Copy link
    Member

    Steve: Could you please merge your changes into platform.py ?

    I think it should go into Python 2.7.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Sep 23, 2015

    New changeset d8453733cc0c by Steve Dower in branch '2.7':
    Issue bpo-19143: platform module now reads Windows version from kernel32.dll to avoid compatibility shims.
    https://hg.python.org/cpython/rev/d8453733cc0c

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Sep 23, 2015

    New changeset fa869ccf9368 by Steve Dower in branch '3.5':
    Issue bpo-19143: platform module now reads Windows version from kernel32.dll to avoid compatibility shims.
    https://hg.python.org/cpython/rev/fa869ccf9368

    New changeset 2f55d73e5ad6 by Steve Dower in branch 'default':
    Issue bpo-19143: platform module now reads Windows version from kernel32.dll to avoid compatibility shims.
    https://hg.python.org/cpython/rev/2f55d73e5ad6

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Sep 23, 2015

    New changeset 2f57270374f7 by Steve Dower in branch '3.4':
    Issue bpo-19143: platform module now reads Windows version from kernel32.dll to avoid compatibility shims.
    https://hg.python.org/cpython/rev/2f57270374f7

    @zooba
    Copy link
    Member

    zooba commented Sep 23, 2015

    Done. As this is (meant to be) a purely informational/diagnostic module, seems like a good idea to fix every version we're supporting in any way.

    @zooba zooba closed this as completed Sep 23, 2015
    @zooba zooba self-assigned this Sep 23, 2015
    @zooba zooba added the type-bug An unexpected behavior, bug, or error label Sep 23, 2015
    @malemburg
    Copy link
    Member

    On 23.09.2015 02:33, Steve Dower wrote:

    Done.

    Thanks.

    As this is (meant to be) a purely informational/diagnostic module, seems like a good idea to fix every version we're supporting in any way.

    Yep, that's the intention behind the platform module.

    @fredrikaverpil
    Copy link
    Mannequin

    fredrikaverpil mannequin commented Oct 30, 2015

    Will this fix be included in python 2.7.11?

    @malemburg
    Copy link
    Member

    On 30.10.2015 14:03, Fredrik Averpil wrote:

    Will this fix be included in python 2.7.11?

    Yes. Steve also checked in the patch to Python 2.7.

    @fredrikaverpil
    Copy link
    Mannequin

    fredrikaverpil mannequin commented Oct 30, 2015

    Yes. Steve also checked in the patch to Python 2.7.

    Excellent. I'll sit tight until the 2.7.11 comes out then (hopefully December), as platform.release() did not return "10" on Windows 10 for me.

    @rauaha
    Copy link
    Mannequin

    rauaha mannequin commented Apr 17, 2018

    The problem still exists on python 3.4 and I need to use this version.
    Any solution?

    @serhiy-storchaka
    Copy link
    Member

    Does the problem still exist on Python 3.6? Python 3.4 is now in security fixes only mode. The only solution for you may be upgrading to Python 3.6.

    @zooba
    Copy link
    Member

    zooba commented Apr 17, 2018

    The attached files should work on Python 3.4. Feel free to use them.

    @rauaha
    Copy link
    Mannequin

    rauaha mannequin commented Apr 18, 2018

    Thanks to Steve Dower the problem is solved!

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    interpreter-core (Objects, Python, Grammar, and Parser dirs) OS-windows type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    7 participants