8.22. platformids.dist.windows

The platformids.dist.windows module implements the API for the evaluation of the data for the windows platform [doc].

The access to the platform information requires different interfaces for the various implementations. The information is primarily contained in the windows registry, with some additional information to be added gathered by the kernel32 API. In case of Jython the access to the registry requires native access to the platform APIs, while the remaining support access via standard libraries _winreg / winreg. Additional information by the kernel32 DLL has to be acquired in both cases via system wrapper libraries, here by ctypes or the various Java APIs.

8.22.1. Module

This module platformids.dist.windows provides the generic API for NT systems and loads specific plugins for the actual Python implementation.

MS-Windows releases for the WindowsNT family based on the registry information. This includes the IoT products, e.g. Windows-NT-10.0-IoT-core on the RaspberryPi.

8.22.2. Data Acquisition

The Windows NT platform supports the central configuration data base Windows-Registry, which stores under the root key HKEY__LOCAL_MACHINE the information for the local platform. The required detailed platform information of all members of the NT family is available by the key

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

The access is on almost any platform and Python implementation supported by the standard library _winreg [WINREG2] / winreg [WINREG3]. The standard implementations are

implementation

Syntax

_winreg

winreg

WindowsPreferences

JNA

JNI

reg.exe

CPython

Python2, Python3

x

x

(x)

IPython

Python2, Python3

x

x

(x)

IronPython

Python2

x

(x)

Jython

Python2

x

x

x

x

PyPy

Python2, Python3

x

x

(x)

WindowsPreferences - java.util.prefs.WindowsPreferences:

The java.util.prefs.WindowsPreferences is an inoffical internal class providing free registry access, which is used by the official storage for preferences java.util.prefs.Preferences with limited access to HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs.

JNA

The java native access framework, relevant for Java only.

JNI

The java native interface, relevant for Java only.

reg.exe

The official command line interface provided by WindowsNT. This could be used as a subprocess with post-filtering of the standard output. The interface is available for all implementations, but of actual relevance for Java only, where it is used by platformids as a fallback spare solution.

The implementation of CPython for Cygwin does not support _winreg / winreg. Jython does not support these, nor pywin32. Thus some specific solutions are required.

The provided library modules are:

Access

module

valid implementation

CPython

Jython

Java

C/C++

stdlib

winreg [WINREG3]

x

_winreg [WINREG2]

x

windows_kernel32_dll

x

reg.exe

windows_subprocess_reg_exe

x

x

JNA

Advapi32GetCurrentVersion

x

x

Kernel32GetProductInfo

x

x

WindowsPrefs

ReadCurrentVersionWinPrefs

x

x

JNI

available soon

x

x

x

shared utility

windows_products

x

x

8.22.2.1. Python

  • winreg

    The Python implementation of the standard libraries provide two releases of libraries for the registry access. For Python2 _winreg [WINREG2], for Python3 winreg [WINREG3]. The libraries are available for the implementations CPython, IPython, ItonPython, and PyPy.

  • kernel32

    Additional product information is acquired by the API GetProductInfo and GetVersionEx / GetVersionExA provided by the kernel32 DLL. The inteface is used here via the external native access of ctypes. When the data is not accessible it is estimated by multiple parameters.

    For deatils see dist.nt.windows_kernel32_dll and dist.nt.windows_products.

8.22.2.2. Jython

The Jython implementation lacks some ctypes completeness, and the standard Java interface for the storage of it’s own properties by java.util.prefs.Preferences serves with the official interface for the special branch ‘JavaSoft’ only. Some other solutions exist.

  1. WindowsPreferences

    Using the unofficial internal interface of java.util.prefs, which is java.util.prefs.WindowsPreferences [SOVFLJAVAREG].

  2. reg.exe

    Using a subprocess to call reg.exe, scan and fetch the standard output [REGEXE] / [SOVFLJAVAREG], [SOVFLJAVASUBREG].

  3. JNI

    Using JNI, requires a bit more prerequisites [JNI] / [SOVFLJNIREG].

  4. JNA

    Using JNA - a wrapper for JNI, simplifies coding, build, and deploymentr [JNA].

  5. third-party library

    Using a third-party library, which basically relay on one of the former.

  6. platform.System

    Using the provided Java API by Jython - platform.System [Jython]. provides a limited set of the Windows NT release and build information.

Each of the solutions has it’s own drawback.

The platfoirmids supports them all - in a hierachical call order based on the most common reliability, availability, and best performance.

jythonwinreg zoom

  1. JNA - Java + Jython

    Try the JNA, which is an official library including official interfaces. The installation is pretty simple - for standard OS, just needs for Windows the following jars in the classpath.

    1. jna.jar

    2. jna-platform.jar

    3. win32-x86-64.jar

    When this fails continue with the next.

  2. WindowsPreferences - Java + Jython

    Try the unofficial interface, which may be almost as stable as an official java.util.prefs.WindowsPreferences. This is currently available within any standard java installation of jre.

    When this fails - eg. in case of internal API changes - continue with the next.

  3. JNI - Java + C++ + Jython

    Try the JNI, probably the fastest, but requires extra build and deployment steps, introduces a third type of module in a single call chain. Requires some compilation of C++ modules for each platform, thus may not be available on all platforms.

    When this fails continue with the next.

  4. reg.exe - Jython ( + reg.exe)

    Using the official Microsoft commandline tool reg.exe. This is available for almost sure, but requires a subprocess call and some regular expressions. So is the slowest of all.

    When this fails continue with the next.

  5. platform.System - Jython

    Using the provided Java API by Jython - platform.System. for a limited poor set of information.

Third party libraries are currently not considered.

This layered approach promisses reliability of the acquisition, while providing the fastest possible access too. In case of missing API’s a layered fallback is performed by accepting performance degradation, or in worst case even information reduction - while this is basically out of probability.

  • java.util.prefs.WindowsPreferences

    The disadvantage of the java.util.prefs.WindowsPreferences is the fact, that it is an inofficial interface used by reflection. Thus hist may fail, even though it could basically be said that this is unlikely.

    The advantage is the simple use without required additional native access modules, and the fact that it is available on any Windows.NT platform where the java.util.prefs.Preferences class is available - so on any with Java. This also implies, that the java packages required for Jython have to be deployed only.

    For implementation details see jy.dist.nt.ReadCurrentVersionWinPrefs(.java).

  • JNA

    The community framework Java Native Access - JNA - [JNA] wraps the standard JNI framework in order to provide access by a Java interface only. This has in addition the adavantage of a simplified deployment process though no platform specific C/C++ build is required. The project delivers a wide range of supported platforms, including ARM platforms. The only required platforms for platformids are the Windows platforms.

    The installation of the Windows-NT platform requires the packages - within the CLASSPATH:

    1. jna.jar

    2. jna-platform.jar

    3. win32-x86-64.jar and/or win32-x86.jar - depends on the architectecture of the used JVM

    For implementation details see jy.dist.nt.Advapi32GetCurrentVersion an jy.dist.nt.Kernel32GetProductInfo.

    The startup requires the pass of the jar-files by one of the following patterns:

    • direct call of jython.exe

      c:\jython270\binjython.exe -J-cp %cd%;c:\jna\jna.jar;c:\jna\jna-platform.jar;c:\jna\win32-x86-64.jar <your-script>
    • call of java.exe with jython.jar

      c:\jdk1.8.0_131\bin\java.exe -cp %cd%;c:\jna\jna.jar;c:\jna\jna-platform.jar;c:\jna\win32-x86-64.jar;c:\Jython270\jython.jar org.python.util.jython <your-script>

    The codepage has to be set appropriately for Jython, e.g. for UTF:

    chcp 1252
    
  • JNI

    Available soon.

  • reg.exe

    The call interface for reg.exe. For implementation details see dist.nt.windows_subprocess_reg_exe.

  • java.util.System

8.22.2.3. Cygwin

The native Python installed by Cygwin comes currently without registry support by winreg. A port exists as cygwinreg, else the he standard Python implamentations for Windows could be called either directly, or by wrapping with cmd.exe from a Cygwin logon. Thus no additional special treatment is forseen.

The solution provided by the Python based call of the reg.exe utility as a subprocess works, but should be avoided.

8.22.3. Data Structures

8.22.3.1. Product Types

The product type information of the data structure OSVERSIONINFOEXA.wProductType is provided by the following predefined values with a proprietary extension:

VER_NT_WORKSTATION       = 0x0000001  #: see wProductType
VER_NT_DOMAIN_CONTROLLER = 0x0000002  #: see wProductType
VER_NT_SERVER            = 0x0000003  #: see wProductType

VER_NT_IOT               = 0x0000004  #: non standard enum
  • VER_NT_WORKSTATION

    Serves as a workstation for interactive desktops.

  • VER_NT_DOMAIN_CONTROLLER

    Dedicated server with a major task to control a domain of machines.

  • VER_NT_SERVER

    Server accessed by clients.

  • VER_NT_IOT

    Proprietary definition by platformids for a new type of interconnected small devices.

8.22.3.2. Product Identifiers

For the productidentifiers refer to dist.nt.windows_products.

8.22.4. dist.windows.WinVersion

class platformids.dist.windows.WinVersion(*args, **kargs)[source]

Scans and represents the standard windows version information from the Windows Registry as defined by the “CurrentVersion” key.

hklm = HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

Detects the product type information optionally by the kernel32.dll, else by some heuristics. The technical product data is provided as the consolidated productcategory attribute.

8.22.4.1. __init__

WinVersion.__init__(*args, **kargs)[source]

Initialize self. See help(type(self)) for accurate signature.

Initializes the object and initially calls fetch_current_version_raw.

Args:

none.

Returns:

An initialized object containing the version information of the current platform.

Raises:

pass-through

8.22.4.2. __repr__

WinVersion.__repr__()[source]

Return repr(self).

Standard representation of current contents.

8.22.4.3. __str__

WinVersion.__str__()[source]

Return str(self).

Standard print of current contents.

8.22.4.4. fetch_current_version_raw

WinVersion.fetch_current_version_raw(**kargs)[source]

Reads the complete data from the registry key CurrentVersion and processes the provided attributes into the self.raw dictionary. The product data is either read out by interfaces from kernel32.dll, of constructed by some heuristics.

This is - hopefully - the only and one place, where the actual Python implementation matters for the platfromids on NT. The function utilizes in dependence of the current implementation:

Args:

none.

Returns:

In case of success a dictionary containing the raw values, else None.

Raises

pass-through

8.22.4.5. readout_versioninfo_ext

WinVersion.readout_versioninfo_ext()[source]

Reads the canonical version information (0) from the raw data. The data comprises the common canonical values for the bitmask representation and in addition some context specific attributes optionally provided for special handling within the context of WindowsNT - (1) + (2) + (3).

consolidated attributes

source

source

arbitrary example values

type

self.ntmajor

(0)

CurrentMajorVersionNumber

REG_SZ

0xa

self.ntminor

(0)

CurrentMinorVersionNumber

REG_DWORD

0x0

self.release

(0)

ReleaseId

REG_SZ

1511

self.productcategory

(1)

multiple

self.build

(2)

CurrentBuildNumber

REG_DWORD

17763

self.ubr

(2)

UBR

REG_DWORD

0x6b

self.sp

(2)

CSDVersion

REG_SZ

0x0

self.dwProdType

(3)

self.editionid

(3)

EditionID

REG_SZ

Professional

self.installationtype

(3)

InstallationType

REG_SZ

IoTCore

self.sourcepath

(3)

SourcePath

REG_SZ

D:/GERMAN/WINXP/PRO/I386

self.productname

(3)

ProductName

REG_SZ

Windows 10 Pro

(0): part of the common numeric bitmask representation of the distribution

(1): part of the common PlatformParameters class with commonly very

weak semantic weight e.g. for Posix platforms, defaults to generic

(2): part of the WinVersion class for the context of WindowsNT and

the numeric bitmask representation of the build release

(3): special open internal data or the context of WindowsNT for further

context specific processing

Args:

none.

Returns:

Reads and consolidates the data from self.raw into the canonical attributes and returns the sum-up as a dict.

ret = {
    "ntmajor":          self.ntmajor,
    "ntminor":          self.ntminor,
    "release":          self.release,  # (1)

    "build":            self.build,    # (1)
    "ubr":              self.ubr,      # (2)
    "sp":               self.sp,       # (2) - legacy

    "productcategory":  self.productcategory,

    "InstallationType": self.installationtype,
    "ProductName":      self.productname,
    "EditionID":        self.editionid
}

(1): semantics changed for NT-10.0
     dist >= NT-10.0: release version and incremental build number combined with ubr
     dist <  NT-10.0: release == build

(2): changed for NT-10.0
     dist >= NT-10.0: ubr
     dist <  NT-10.0: sp   # the CSDVersion for release <= 7601(Windows-7)
ntmajor:

The major version number of the NT distribution.

ntminor:

The major version number of the NT distribution.

release:

The release version of the NT distribution, the semantics ha changed with NT-10.0:

ntmajor < 10:

Same as the build id.

ntmajor == 10:

Different from build id, an increment of a release number specifying a group of updates for a specific set of features maked by build and ubr:

.. parsed-literal::

   ntmajor.ntminor.build.ubr
productcategory:

The technical category of the product. This implies some typical features and services required for the defined categories. This is mainly relevant for WindowsNT, and eventually for OS-X, Ubuntu, Fedora(?) - which are actually almost all for now :-).

productcategory := (
      VER_NT_WORKSTATION        | "workstation"
    | VER_NT_DOMAIN_CONTROLLER  | "controller"
    | VER_NT_SERVER             | "server"
    | VER_NT_IOT                | "iot"
)

default := generic

build:

The semantics has changed for NT-10.0.

ntmajor < 10:

The incremental build number.

ntmajor == 10:

The incremental build number with the additional sub-numbering by ubr for a specific “versionless” context.

The increment of the build number for a specific set of features grouped by build and ubr:

ntmajor.ntminor.build.ubr
ubr:

The relative enummeration of build for group of features assigned to a specific “versionless” context:

ntmajor.ntminor.build.ubr = (ntmajor, ntminor, build, ubr)
sp:

The service pack based on CSDVersion. This is valid for the old releases only, and even changed once at the kernel32.dll API.

ntmajor, ntminor <= 6.3:

Missing in >= Windows-8.1 (8?).

The service pack is generally not further processed by the platformids.

InstallationType:

The type of the installation, some found examples are:

Server
Client
IoTCore
ProductName:

The public marketing name of the product, some found examples are:

Windows 10 Pro
Windows 7 Ultimate
Microsoft Windows XP
Windows Server 2008 R2 Standard
Windows Server 2019 Essentials
IoTUAP
EditionID:

The product edition as a marketing label, some found examples are:

Professional
Ultimate
ServerSolution
IoTUAP
Raises

pass-through

8.22.5. Source

8.22.5.1. platformids.dist.windows

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# -*- coding: utf-8 -*-
"""MS-Windows releases for the *WindowsNT* family based on the registry information.
This includes the IoT products, e.g. *Windows-NT-10.0-IoT-core* on the *RaspberryPi*.
"""
from __future__ import absolute_import
from __future__ import print_function

import os
import re

from platformids import _debug, _verbose
from platformids import RTE_NT, RTE_WIN, RTE_WINDOWS, \
    rte2num, num2rte, num2pretty, \
    decode_version_str_to_segments, \
    PlatformIDsError, PlatformIDsFileCheck

__author__ = 'Arno-Can Uestuensoez'
__license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints"
__copyright__ = "Copyright (C) 2010-2018 Arno-Can Uestuensoez" \
                " @Ingenieurbuero Arno-Can Uestuensoez"
__version__ = '0.1.29'
__uuid__ = "7add5ded-c39b-4b6e-8c87-1b3a1c150ee9"

__docformat__ = "restructuredtext en"

if __debug__:

    # this is for unittests only
    class PlatformIDsUnittestTriggered(PlatformIDsError):
        pass

#
# The handled versions are of the "nt' technology, historic pre-versions and others
# are not supported.
#
# set: win32
# currently no sub-categories, some are contained in
# the 'set: generic': drives, shares
#
#
# RTE_DOS = RTE_WIN32 + 1  #: MS-DOS - frozen

#
# dist - the base versions of major and minor numbers
#
RTE_NT35 = RTE_NT + 0x001d0000  # : Windows NT-3.5
RTE_NT40 = RTE_NT + 0x00200000  # : Windows NT-4.0
RTE_NT50 = RTE_NT + 0x00280000  # : Windows NT-5.0 - W2000
RTE_NT51 = RTE_NT + 0x00290000  # : Windows NT-5.1 - WXP - 32bit
RTE_NT52 = RTE_NT + 0x002a0000  # : Windows NT-5.2 - W2003 / 2003 / 2003R2
RTE_NT60 = RTE_NT + 0x00300000  # : Windows NT-6.0 - vista / 2008
RTE_NT61 = RTE_NT + 0x00310000  # : Windows NT-6.1 - win7 / 2008R2
RTE_NT62 = RTE_NT + 0x00320000  # : Windows NT-6.2 - win8 / 2012
RTE_NT63 = RTE_NT + 0x00330000  # : Windows NT-6.3 - win8.1 / 2012R2
RTE_NT100 = RTE_NT + 0x00500000  # : Windows NT-10.0 - win10 / 2016

#
# distrel - some predefined constant values of the complete versions
#
# the values could be easily calculated dynamically by
#  old-scheme: adding the build number
#  new-scheme: adding the date based product version
#
# frozen history
#
RTE_WINNT35 = RTE_NT35 + 807  # : WindowsNT-4.0 Workstation - 32bit
RTE_WINNT40 = RTE_NT40 + 1381  # : WindowsNT-4.0 Workstation - 32bit
RTE_WIN2000 = RTE_NT50 + 2195  # : Windows2000

RTE_WINXP = RTE_NT51 + 2600  # : WindowsXP - 32bit

RTE_WINXP64 = RTE_NT52 + 3790  # : WindowsXP - 64bit
RTE_WIN2003 = RTE_NT52 + 3790  # : Windows2003
RTE_WIN2003R2 = RTE_NT52 + 3790  # : Windows2003R2 - exception: same build as 2003

RTE_WIN2008 = RTE_NT60 + 6001  # : Windows2008 RTM
RTE_WIN2008SP2 = RTE_NT60 + 6002  # : Windows2008 SP1

RTE_WIN7 = RTE_NT61 + 7600  # : Windows7
RTE_WIN2008R2 = RTE_NT61 + 7600  # : Windows2008R2

RTE_WIN7SP1 = RTE_NT61 + 7601  # : Windows7 SP1
RTE_WIN2008R2SP1 = RTE_NT61 + 7601  # : Windows2008R2 SP1

RTE_WIN8 = RTE_NT62 + 9200  # : Windows8
RTE_WIN2012 = RTE_NT62 + 9200  # : Windows2012

RTE_WIN81 = RTE_NT63 + 9600  # : Windows81
RTE_WIN2012R2 = RTE_NT63 + 9600  # : Windows2012R2

#
# for generic NT-10.0 releases
# simply add the numeric version to the base value RTE_NT100
#
# RTE_WINNT100_1703 =  RTE_NT100   + 1703           #: NT-10.0 - 2017.03
# RTE_WINNT100_1803 =  RTE_NT100   + 1803           #: NT-10.0 - 2018.03
# RTE_WINNT100_1809 =  RTE_NT100   + 1809           #: NT-10.0 - 2018.09

# : mapping of the rte string and numeric representation to the numeric value
rte2num.update(
    {
        '7 Server': RTE_WIN2008R2,
        '7': RTE_WIN7,
        '8 Server': RTE_WIN2012,
        '8': RTE_WIN8,
        'Blackcomb': RTE_WIN7,
        'Blue Server': RTE_WIN2012R2,
        'Blue': RTE_WIN81,
        'Longhorn Server' : RTE_NT61 + 6002,  # W2008 SP2
        'Threshold 1': RTE_NT100 + 1507,
        'Threshold 2': RTE_NT100 + 1511,
        'Redstone 1': RTE_NT100 + 1607,
        'Redstone 2': RTE_NT100 + 1703,
        'Redstone 3': RTE_NT100 + 1709,
        'Redstone 4': RTE_NT100 + 1803,
        'Redstone 5': RTE_NT100 + 1809,
        'Vienna': RTE_WIN7,
        'winxp': RTE_WINXP,
        'win2000': RTE_WIN2000,
        'winnt40': RTE_WINNT40,
        'win10': RTE_NT100,
        'win7': RTE_WIN7,
        'win8': RTE_WIN8,
        'win81': RTE_WIN81,
        'win2008': RTE_WIN2008,
        'win2008r2': RTE_WIN2008R2,
        'win2012': RTE_WIN2012,
        'win2012r2': RTE_WIN2012R2,
        'win2016': RTE_NT100,
        'win2019': RTE_NT100,
        'win2019se': RTE_NT100,
        RTE_WIN2000: RTE_WIN2000,
        RTE_WIN2008: RTE_WIN2008,
        RTE_WIN2008R2: RTE_WIN2008R2,
        RTE_WIN2012: RTE_WIN2012,
        RTE_WIN2012R2: RTE_WIN2012R2,
        RTE_WIN7: RTE_WIN7,
        RTE_WIN81: RTE_WIN81,
        RTE_WIN8: RTE_WIN8,
        RTE_WINNT40: RTE_WINNT40,
        RTE_WINXP: RTE_WINXP,

        'nt40': RTE_NT40,

        'nt50': RTE_NT50,
        'nt51': RTE_NT51,
        'nt52': RTE_NT52,

        'nt60': RTE_NT60,
        'nt61': RTE_NT61,
        'nt62': RTE_NT62,
        'nt63': RTE_NT63,
        'nt100': RTE_NT100,

        RTE_NT40: RTE_NT40,

        RTE_NT50: RTE_NT50,
        RTE_NT51: RTE_NT51,
        RTE_NT52: RTE_NT52,

        RTE_NT60: RTE_NT60,
        RTE_NT61: RTE_NT61,
        RTE_NT62: RTE_NT62,
        RTE_NT63: RTE_NT63,
        RTE_NT100: RTE_NT100,

    }
)

# : mapping of the rte numeric representation to the string value
num2rte.update(
    {
#         RTE_WINNT40: 'winnt40',
#         RTE_WIN2000: 'win2000',
#         RTE_WINXP: 'winxp',
#         RTE_WIN7: 'win7',
#         RTE_WIN81: 'win81',
#         RTE_WIN8: 'win8',
#         RTE_WIN2008: 'win2008',
#         RTE_WIN2008R2: 'win2008r2',  # the release is actually a different NT
#         RTE_WIN2012: 'win2012',
#         RTE_WIN2012R2: 'win2012r2',

        RTE_WINNT40: 'nt401381',
        RTE_WIN2000: 'nt502195',
        RTE_WINXP: 'nt512600',
        RTE_WIN7: 'nt617601',
        RTE_WIN81: 'nt639600',
        RTE_WIN8: 'nt629200',
        RTE_WIN2008: 'nt606002',
        RTE_WIN2008R2: 'nt617601',  # the release is actually a different NT
        RTE_WIN2012: 'nt629200',
        RTE_WIN2012R2: 'nt639600',

        RTE_NT40: 'nt40',
        RTE_NT50: 'nt50',
        RTE_NT51: 'nt51',
        RTE_NT52: 'nt52',
        RTE_NT60: 'nt60',
        RTE_NT61: 'nt61',
        RTE_NT62: 'nt62',
        RTE_NT63: 'nt63',
        RTE_NT100: 'nt100',

    }
)

# : mapping of the rte numeric representation to the pretty string value
num2pretty.update(
    {
        RTE_WIN: 'Windows',
        RTE_WINDOWS: 'Windows',

        RTE_WIN2000: 'Windows 2000',
        RTE_WIN2008: 'Windows Server 2008',
        RTE_WIN2008R2: 'Windows Server 2008R2',
        RTE_WIN2012: 'Windows Server 2012',
        RTE_WIN2012R2: 'Windows Server 2012R2',
        RTE_WIN7: 'Windows 7',
        RTE_WIN81: 'Windows 8.1',
        RTE_WIN8: 'Windows 8',
        RTE_WINNT40: 'WindowsNT-4.0',
        RTE_WINXP: 'Windows XP',

        RTE_NT40: 'NT-4.0',

        RTE_NT50: 'NT-5.0',
        RTE_NT51: 'NT-5.1',
        RTE_NT52: 'NT-5.2',

        RTE_NT60: 'NT-6.0',
        RTE_NT61: 'NT-6.1',
        RTE_NT62: 'NT-6.2',
        RTE_NT63: 'NT-6.3',
        RTE_NT100: 'NT-10.0',

    }
)

versions = {
    RTE_WINNT40: '4.0.1381',
    RTE_WIN2000: '5.0.2195',
    RTE_WINXP: '5.1.2600',
    RTE_WIN7: '6.1.7601',
    RTE_WIN81: '6.3.9600',
    RTE_WIN8: '6.2.9200',

    RTE_WIN2008: '6.0.6002',
    RTE_WIN2008R2: '6.1.7601',
    RTE_WIN2012: '6.2.9200',
    RTE_WIN2012R2: '6.3.9600',

    RTE_NT40: '4.0',

    RTE_NT50: '5.0',
    RTE_NT51: '5.1',
    RTE_NT52: '5.2',

    RTE_NT60: '6.0',
    RTE_NT61: '6.1',
    RTE_NT62: '6.2',
    RTE_NT63: '6.3',
    RTE_NT100: '10.0',

}

#
# Microsoft: OSVERSIONINFOEXA.wProductType
#
VER_NT_GENERIC = 0x0000000  # : non standard enum

VER_NT_WORKSTATION = 0x0000001  # : see wProductType
VER_NT_DOMAIN_CONTROLLER = 0x0000002  # : see wProductType
VER_NT_SERVER = 0x0000003  # : see wProductType

VER_NT_IOT = 0x0000004  # : non standard enum


class WinVersion(object):

    def __init__(self, *args, **kargs):

        self.ntmajor = self.ntminor = self.release = self.build = 0
        self.editionid = self.installationtype = self.sourcepath = self.productname = ''
        self.productcategory = VER_NT_GENERIC  # 0x0000000  #: non standard enum
        self.sp = self.ubr = None

        self.raw = {}
        self.fetch_current_version_raw()

        pass  # 4debugging

    def  fetch_current_version_raw(self, **kargs):

        use_nt_native = kargs.get('usetest', 255)  # : for unittests only
        
        if os.name == 'java':
            # it is Jython - use Java for access to native system data

            try:
                if __debug__:
                    # this is for unittests only
                    if (use_nt_native & 1) == 0:
                        raise PlatformIDsUnittestTriggered('use_nt_native_1(%d)' % (use_nt_native) )

                #
                # 1. try JNA
                if _verbose:
                    print("VERB:platformids:scan:try:JNA:jy.platformids.dist.nt.Kernel32GetProductInfo")
                from jy.platformids.dist.nt import Kernel32GetProductInfo  # @UnresolvedImport

                if _verbose:
                    print("VERB:platformids:scan:try:JNA:jy.platformids.dist.nt.Advapi32GetCurrentVersion")
                from jy.platformids.dist.nt import Advapi32GetCurrentVersion  # @UnresolvedImport

                if _verbose:
                    print("VERB:platformids:scan:JNA:LOADED")

                currentversion = Advapi32GetCurrentVersion().getCurrentVersionValues()
                for k, v in currentversion.items():
                    self.raw[k] = v

            except Exception as e:
                if _debug:
                    print("VERB:platformids:scan:JNA:failed with:" + str(e))

                try:
                    if __debug__:
                        # this is for unittests only
                        if (use_nt_native & 2) == 0:
                            raise PlatformIDsUnittestTriggered('use_nt_native_2(%d)' % (use_nt_native) )

                    #
                    # 2. try java.util.WindowsPreferences...
                    #
                    if _verbose:
                        print("VERB:platformids:scan:try:WindowsPreferences:jy.platformids.dist.nt.ReadCurrentVersionWinPrefs")
                    from jy.platformids.dist.nt import ReadCurrentVersionWinPrefs  # @UnresolvedImport

                    if _verbose:
                        print("VERB:platformids:scan:WindowsPreferences:LOADED")

                    currentversion = ReadCurrentVersionWinPrefs()
                    for k, v in currentversion:
                        self.raw[k] = v

                except Exception as e:
                    if _debug:
                        print("VERB:platformids:scan:WindowsPreferences:failed with:" + str(e))

                    #
                    # 4. try JNI next... coming soon
                    #
                    
                    try:
                        if __debug__:
                            # this is for unittests only
                            if (use_nt_native & 8) == 0:
                                raise PlatformIDsUnittestTriggered('use_nt_native_8(%d)' % (use_nt_native) )

                        #
                        # 8. try REG.EXE next...
                        #
                        if _verbose:
                            print("VERB:platformids:scan:try:platformids.dist.nt.RegistryByExe")
                        from platformids.dist.nt.windows_subprocess_reg_exe import RegistryByExe  # @UnresolvedImport
                        if _verbose:
                            print("VERB:platformids:scan:RegistryByExe:LOADED")

                        currentversion = RegistryByExe().read_CurrentVersion()
                        for k, v in currentversion.items():
                            self.raw[k] = v

                    except:
                        if __debug__:
                            # this is for unittests only
                            if (use_nt_native & 16) == 0:
                                raise PlatformIDsUnittestTriggered('use_nt_native_16(%d)' % (use_nt_native) )

                        #
                        # 16. try min-info
                        #
                        import platform
                        self.raw['ProductName'] = platform.System.getProperty('os.name').lower()  # @UndefinedVariable  # seems 2.0+
                        self.raw['CurrentMajorVersionNumber'], self.raw['CurrentMajorVersionNumber'], self.raw['CurrentMajorVersionNumber'] = decode_version_str_to_segments(
                            platform.System.getProperty('os.version').lower())  # @UndefinedVariable

        elif os.name == 'posix':
            # for document generation by introspection on posix platform
            # avoids exception with generator error for sphinx-apidoc
            pass

        else:

            #
            # read registry
            #

            # use standard libs _winreg / winreg
            try:
                import winreg  # @UnresolvedImport @UnusedImport
                validxError = WindowsError  # @UndefinedVariable
            except:
                import _winreg as winreg  # @UnresolvedImport @Reimport
                validxError = OSError

            hklm = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)  # @UndefinedVariable  - win32 only

            # rnumerate CurrentVersion attribute values
            curvers_key = winreg.OpenKey(hklm, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion")  # @UndefinedVariable  - win32 only
            for i in range(1024):
                try:
                    n, v, t = winreg.EnumValue(curvers_key, i)  # @UndefinedVariable  - win32 only @UnusedVariable
                    self.raw[n] = v
                except validxError:
                    break

            winreg.CloseKey(curvers_key)  # @UndefinedVariable  - win32 only

            #
            # fetch product category
            #
            try:
                #
                # use API
                #

                # post winxp supports simple access to product type
                from platformids.dist.nt.windows_kernel32dll import get_win32_OSProductInfo, get_win32_OSVersionInfoExa
                from platformids.dist.nt.windows_products import prod_ext, prod_type_categories

                osver = get_win32_OSVersionInfoExa()
                pinfo = get_win32_OSProductInfo()
                self.productcategory = pinfo.pdwReturnedProductType

                # TODO: check it
                if self.raw['InstallationType'].startswith('IoT'):
                    # superposes others if defined as IoT
                    self.productcategory = VER_NT_IOT

            except:
                #
                # estimate by data - default is GENERIC
                #
                try:
                    if self.raw['InstallationType'].startswith('Client'):
                        self.productcategory = VER_NT_WORKSTATION

                    elif self.raw['InstallationType'].startswith('Server'):
                        self.productcategory = VER_NT_SERVER

                    elif self.raw['InstallationType'].startswith('IoT'):
                        self.productcategory = VER_NT_IOT

                    elif re.match(r'.*omain.*', self.raw['InstallationType'], flags=re.MULTILINE):  # @UndefinedVariable
                        self.productcategory = VER_NT_DOMAIN_CONTROLLER

                    else:
                        # matches for almost all systems, which in nowadays
                        # could be used in multiple roles - without variation
                        self.productcategory = VER_NT_GENERIC

                except:
                    self.productcategory = VER_NT_GENERIC  # should already be from init

        self.raw['productcategory'] = self.productcategory

        return self.raw

    def readout_versioninfo_ext(self):

        #
        # Major-Minor-Version
        #
        try:
            # >= Win10
            self.ntmajor = int(self.raw['CurrentMajorVersionNumber'])  # REG_SZ    17763
            self.ntminor = int(self.raw['CurrentMinorVersionNumber'])  # REG_DWORD    0xa
            self.release = int(self.raw['ReleaseId'])  # REG_SZ    1511
            self.build = self.raw['CurrentBuildNumber']  # REG_DWORD    0x0

        except KeyError:
            # < Win10
            try:
                self.ntmajor, self.ntminor = self.raw['CurrentVersion'].split('.')  # REG_SZ    6.3
                self.ntmajor = int(self.ntmajor)
                self.ntminor = int(self.ntminor)
            except KeyError:
                # ooops...
                pass

            try:
                self.release = self.build = int(self.raw['CurrentBuildNumber'])  # REG_DWORD    0x0
            except:
                pass

            try:
                # WinXP < x < Win10
                self.sp = re.sub(r'^[^0-9]*', '', self.raw['CSDVersion'])  # REG_SZ
                self.sp = int(self.sp)
            except KeyError:
                pass

        try:
            self.ubr = int(self.raw['UBR'])  # REG_DWORD    0x6b
        except KeyError:
            pass

        try:
            self.editionid = self.raw['EditionID']  # REG_SZ    IoTUAP
        except KeyError:
            self.editionid = ''

        try:
            self.installationtype = self.raw['InstallationType']  # REG_SZ    IoTUAP
        except KeyError:
            self.installationtype = ''

            try:
                #
                # a weak criteria as the last resort,
                # the installation source path with some encoding
                # into the path name, e.g.:
                #
                #   D:\GERMAN\WIN2000\SERVER\I386
                #   D:\GERMAN\WINXP\PRO\I386
                #
                self.sourcepath = self.raw['SourcePath']  # REG_SZ D:\GERMAN\WINXP\PRO\I386
                self.sourcepath = re.sub(r'', r'', self.sourcepath)
            except KeyError:
                self.sourcepath = ''

        try:
            self.productname = self.raw['ProductName']  # REG_SZ    IoTUAP
        except:
            pass

        ret = {
            "ntmajor":          self.ntmajor,
            "ntminor":          self.ntminor,
            "release":          self.release,

            "build":            self.build,

            "productcategory":  self.productcategory,

            "InstallationType": self.installationtype,
            "ProductName":      self.productname,
            "EditionID":        self.editionid
        }

        if self.sp != None:
            ret["sp"] = self.sp

        if self.ubr != None:
            ret["ubr"] = self.ubr

        return ret

    def readout_distribution(self):

        self.readout_versioninfo_ext()
        return [
            'nt%d%d%d' % (self.ntmajor, self.ntminor, self.release),
            '%d.%d.%d' % (self.ntmajor, self.ntminor, self.release),
            'NT-%d.%d.%d' % (self.ntmajor, self.ntminor, self.release),
            'NT',
             (self.ntmajor, self.ntminor, self.release),
             'nt'
        ]

    def __str__(self):
        try:
            res = ''
            res += "ntmajor          = %s\n" % (str(self.ntmajor))
            res += "ntminor          = %s\n" % (str(self.ntminor))
            res += "release          = %s\n" % (str(self.release))
            res += "build            = %s\n" % (str(self.build))

            res += "productcategory  = %s\n" % (str(self.productcategory))

            try:
                res += "sp               = %s\n" % (str(self.sp))
            except AttributeError:
                res += "ubr              = %s\n" % (str(self.ubr))

            res += "InstallationType = %s\n" % (str(self.installationtype))
            res += "EditionID        = %s\n" % (str(self.editionid))
            res += "ProductName      = %s\n" % (str(self.productname))

            return res
        except:

            return

    def __repr__(self):
        try:
            res = "{"
            res += "ntmajor: %s, " % (str(self.ntmajor))
            res += "ntminor: %s, " % (str(self.ntminor))
            res += "release: %s, " % (str(self.release))
            res += "build: %s, " % (str(self.build))

            res += "productcategory: %s, " % (str(self.productcategory))

            try:
                res += "sp: %s, " % (str(self.sp))
            except AttributeError:
                res += "ubr: %s, " % (str(self.ubr))

            res += "InstallationType: %s, " % (str(self.installationtype))
            res += "EditionID: %s, " % (str(self.editionid))
            res += "ProductName: %s, " % (str(self.productname))
            res += "}"

            return res

        except:
            return

dist = ['', '', '', 'NT', '', '']

try:
    WINVERSION = WinVersion()
    WINVERSION.fetch_current_version_raw()
    dist = WINVERSION.readout_distribution()

except PlatformIDsFileCheck:
    # not on MS-Windows platform, so scan will fail
    pass    


if dist[5] != 'nt':
    # does not actually match MS-Windows
    dist = ['nt', '0.0.0', 'NT-0.0.0', 'NT', (0, 0, 0,), 'nt']


if __name__ == "__main__":
    winv = WinVersion()
    vinfo = winv.readout_versioninfo_ext()
    print(vinfo)

8.22.6. Download

windows.py

8.22.7. Resources