classification
Title: Finding the Windows version getting messier (detect windows 8.1?)
Type: behavior Stage: resolved
Components: Interpreter Core, Windows Versions: Python 3.4
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: steve.dower Nosy List: brian.curtin, eryksun, fredrikaverpil, giampaolo.rodola, jkloth, lemburg, loewis, pitrou, python-dev, rauaha, serhiy.storchaka, steve.dower, tim.golden, tim.peters, zach.ware
Priority: normal Keywords:

Created on 2013-10-02 00:50 by tim.peters, last changed 2018-04-18 06:14 by rauaha. This issue is now closed.

Files
File name Uploaded Description Edit
win32_ver.py steve.dower, 2015-01-02 19:15
win32_ver.py steve.dower, 2015-02-12 01:46 Added W2K, WS2K3 and XP versions
Messages (35)
msg198814 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2013-10-02 00:50
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 ;-)
msg198819 - (view) Author: Tim Golden (tim.golden) * (Python committer) Date: 2013-10-02 07:54
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)
msg198822 - (view) Author: Tim Golden (tim.golden) * (Python committer) Date: 2013-10-02 09:55
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.
msg198823 - (view) Author: Tim Golden (tim.golden) * (Python committer) Date: 2013-10-02 10:09
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.
msg198827 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-10-02 11:33
(One explanation is they did it for the enjoyment of non-Windows programmers)
msg198838 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2013-10-02 13:58
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).
msg198839 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2013-10-02 14:24
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.
msg220163 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2014-06-10 11:15
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.
msg220171 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2014-06-10 16:28
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".
msg220182 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2014-06-10 18:08
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
msg220186 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2014-06-10 18:33
> 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.
msg233268 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2014-12-31 18:59
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 #23018, I'll add the manifest required so that GetVersionEx() will recognise 8.1 and 10.
msg233272 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2014-12-31 22:14
> 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.
msg233322 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2015-01-02 19:15
Thanks for the feedback. Updated the attachment with some other tidying too.
msg233324 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2015-01-02 19:49
> 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).
msg235612 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2015-02-09 14:14
(Was reminded about this by #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?
msg235613 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2015-02-09 14:40
On 09.02.2015 15:14, Steve Dower wrote:
> 
> Steve Dower added the comment:
> 
> (Was reminded about this by #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.
msg235614 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2015-02-09 15:17
Including the one shipped in the stdlib? Python 3.5 no longer supports XP.
msg235618 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2015-02-09 15:52
@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.
msg235620 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2015-02-09 16:30
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
msg235621 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2015-02-09 16:39
@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.)
msg235787 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2015-02-12 01:46
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.
msg250841 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2015-09-16 11:48
Steve: Could you please merge your changes into platform.py ?

I think it should go into Python 2.7.
msg251370 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015-09-23 00:26
New changeset d8453733cc0c by Steve Dower in branch '2.7':
Issue #19143: platform module now reads Windows version from kernel32.dll to avoid compatibility shims.
https://hg.python.org/cpython/rev/d8453733cc0c
msg251371 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015-09-23 00:27
New changeset fa869ccf9368 by Steve Dower in branch '3.5':
Issue #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 #19143: platform module now reads Windows version from kernel32.dll to avoid compatibility shims.
https://hg.python.org/cpython/rev/2f55d73e5ad6
msg251372 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015-09-23 00:32
New changeset 2f57270374f7 by Steve Dower in branch '3.4':
Issue #19143: platform module now reads Windows version from kernel32.dll to avoid compatibility shims.
https://hg.python.org/cpython/rev/2f57270374f7
msg251373 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2015-09-23 00:33
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.
msg251413 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2015-09-23 07:33
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.
msg253730 - (view) Author: Fredrik Averpil (fredrikaverpil) * Date: 2015-10-30 13:03
Will this fix be included in python 2.7.11?
msg253731 - (view) Author: Marc-Andre Lemburg (lemburg) * (Python committer) Date: 2015-10-30 13:08
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.
msg253733 - (view) Author: Fredrik Averpil (fredrikaverpil) * Date: 2015-10-30 13:16
> 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.
msg315394 - (view) Author: Mahmud Al Hasan (rauaha) Date: 2018-04-17 12:10
The problem still exists on python 3.4 and I need to use this version.
Any solution?
msg315396 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-04-17 14:15
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.
msg315411 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2018-04-17 20:31
The attached files should work on Python 3.4. Feel free to use them.
msg315436 - (view) Author: Mahmud Al Hasan (rauaha) Date: 2018-04-18 06:14
Thanks to Steve Dower the problem is solved!
History
Date User Action Args
2018-04-18 06:14:26rauahasetmessages: + msg315436
2018-04-17 20:31:44steve.dowersetmessages: + msg315411
2018-04-17 14:15:59serhiy.storchakasetmessages: + msg315396
2018-04-17 13:04:37BreamoreBoysetnosy: - BreamoreBoy
2018-04-17 12:10:49rauahasetnosy: + rauaha

messages: + msg315394
versions: - Python 2.7, Python 3.5, Python 3.6
2015-10-30 13:16:58fredrikaverpilsetmessages: + msg253733
2015-10-30 13:08:18lemburgsetmessages: + msg253731
2015-10-30 13:03:24fredrikaverpilsetnosy: + fredrikaverpil
messages: + msg253730
2015-09-23 07:33:25lemburgsetmessages: + msg251413
2015-09-23 00:33:33steve.dowersetstatus: open -> closed

assignee: steve.dower
versions: + Python 3.6
messages: + msg251373
type: behavior
resolution: fixed
stage: resolved
2015-09-23 00:32:09python-devsetmessages: + msg251372
2015-09-23 00:27:10python-devsetmessages: + msg251371
2015-09-23 00:26:11python-devsetnosy: + python-dev
messages: + msg251370
2015-09-16 15:36:45zach.warelinkissue25140 superseder
2015-09-16 11:48:27lemburgsetmessages: + msg250841
2015-02-12 01:46:12steve.dowersetfiles: + win32_ver.py

messages: + msg235787
2015-02-09 16:39:57steve.dowersetmessages: + msg235621
2015-02-09 16:30:33lemburgsetmessages: + msg235620
2015-02-09 15:52:15BreamoreBoysetnosy: + BreamoreBoy
messages: + msg235618
2015-02-09 15:17:30steve.dowersetmessages: + msg235614
2015-02-09 14:40:14lemburgsetmessages: + msg235613
2015-02-09 14:14:04steve.dowersetmessages: + msg235612
2015-02-09 14:10:12steve.dowerlinkissue23417 superseder
2015-01-02 19:49:43eryksunsetmessages: + msg233324
2015-01-02 19:16:01steve.dowersetfiles: - win32_ver.py
2015-01-02 19:15:49steve.dowersetfiles: + win32_ver.py

messages: + msg233322
2014-12-31 22:14:24eryksunsetnosy: + eryksun
messages: + msg233272
2014-12-31 18:59:06steve.dowersetfiles: + win32_ver.py

messages: + msg233268
versions: + Python 3.5, - Python 3.3
2014-06-10 18:33:36steve.dowersetmessages: + msg220186
2014-06-10 18:08:05lemburgsetmessages: + msg220182
2014-06-10 16:28:59steve.dowersetmessages: + msg220171
2014-06-10 11:15:38lemburgsetmessages: + msg220163
2014-06-09 18:46:31pitrousetnosy: + steve.dower
2014-06-09 14:21:38vstinnersettitle: Finding the Windows version getting messier -> Finding the Windows version getting messier (detect windows 8.1?)
2014-06-09 14:21:14vstinnerlinkissue21698 superseder
2014-01-02 15:03:25zach.waresetnosy: + zach.ware
2013-12-28 15:51:02giampaolo.rodolasetnosy: + giampaolo.rodola
2013-10-03 11:14:06serhiy.storchakasetnosy: + serhiy.storchaka
2013-10-02 14:24:30loewissetmessages: + msg198839
2013-10-02 13:58:43loewissetnosy: + loewis
messages: + msg198838
2013-10-02 11:33:28pitrousetnosy: + pitrou
messages: + msg198827
2013-10-02 10:09:17tim.goldensetnosy: + lemburg
messages: + msg198823
2013-10-02 09:55:33tim.goldensetmessages: + msg198822
2013-10-02 07:54:51tim.goldensetmessages: + msg198819
2013-10-02 06:40:24pitrousetnosy: + tim.golden, brian.curtin
2013-10-02 06:37:35jklothsetnosy: + jkloth
2013-10-02 00:50:04tim.peterscreate