1'''
2This script gets the version number from ucrtbased.dll and checks
3whether it is a version with a known issue.
4'''
5
6import sys
7
8from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
9                    Structure, WinDLL)
10from ctypes.wintypes import DWORD, HANDLE
11
12class VS_FIXEDFILEINFO(Structure):
13    _fields_ = [
14        ("dwSignature", DWORD),
15        ("dwStrucVersion", DWORD),
16        ("dwFileVersionMS", DWORD),
17        ("dwFileVersionLS", DWORD),
18        ("dwProductVersionMS", DWORD),
19        ("dwProductVersionLS", DWORD),
20        ("dwFileFlagsMask", DWORD),
21        ("dwFileFlags", DWORD),
22        ("dwFileOS", DWORD),
23        ("dwFileType", DWORD),
24        ("dwFileSubtype", DWORD),
25        ("dwFileDateMS", DWORD),
26        ("dwFileDateLS", DWORD),
27    ]
28
29kernel32 = WinDLL('kernel32')
30version = WinDLL('version')
31
32if len(sys.argv) < 2:
33    print('Usage: validate_ucrtbase.py <ucrtbase|ucrtbased>')
34    sys.exit(2)
35
36try:
37    ucrtbased = WinDLL(sys.argv[1])
38except OSError:
39    print('Cannot find ucrtbased.dll')
40    # This likely means that VS is not installed, but that is an
41    # obvious enough problem if you're trying to produce a debug
42    # build that we don't need to fail here.
43    sys.exit(0)
44
45# We will immediately double the length up to MAX_PATH, but the
46# path may be longer, so we retry until the returned string is
47# shorter than our buffer.
48name_len = actual_len = 130
49while actual_len == name_len:
50    name_len *= 2
51    name = create_unicode_buffer(name_len)
52    actual_len = kernel32.GetModuleFileNameW(HANDLE(ucrtbased._handle),
53                                             name, len(name))
54    if not actual_len:
55        print('Failed to get full module name.')
56        sys.exit(2)
57
58size = version.GetFileVersionInfoSizeW(name, None)
59if not size:
60    print('Failed to get size of version info.')
61    sys.exit(2)
62
63ver_block = c_buffer(size)
64if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
65    not ver_block):
66    print('Failed to get version info.')
67    sys.exit(2)
68
69pvi = POINTER(VS_FIXEDFILEINFO)()
70if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
71    print('Failed to get version value from info.')
72    sys.exit(2)
73
74ver = (
75    pvi.contents.dwProductVersionMS >> 16,
76    pvi.contents.dwProductVersionMS & 0xFFFF,
77    pvi.contents.dwProductVersionLS >> 16,
78    pvi.contents.dwProductVersionLS & 0xFFFF,
79)
80
81print('{} is version {}.{}.{}.{}'.format(name.value, *ver))
82
83if ver < (10, 0, 10586):
84    print('WARN: ucrtbased contains known issues. '
85          'Please update the Windows 10 SDK.')
86    print('See:')
87    print('  http://bugs.python.org/issue27705')
88    print('  https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk')
89    sys.exit(1)
90