8.45. dist.nt.windows_subprocess_reg_exe

Module for the registry access by calling standard Windows registry editor reg.exe.

8.45.1. Module

Reads the MS-Windows registry by calling a subprocess for reg.exe.

This is a fallback solution when neither winreg / _winreg, nor in case of Jython the Java APIs such as WindowsPref, JNA, or JNI are not available. This works also on Cygwin, when e.g. the path for kernel32.dll does not match for the ctypes.

Avoid using it due to serious performance impact compared to the others - but do when nothing else helps and the version information matters.

8.45.1.1. RegistryByExe

class platformids.dist.nt.windows_subprocess_reg_exe.RegistryByExe[source]

Registry read access by reg.exe to

"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"

8.45.1.1.1. __init__

RegistryByExe.__init__()[source]

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

8.45.1.1.2. read_CurrentVersion

RegistryByExe.read_CurrentVersion()[source]

Reads the constant - thus hardcoded - key from

"HKLM\Software\Microsoft\Windows NT\CurrentVersion"
Parameters

None

Returns

The dictionary of the CurrentVersion.

Raises

8.45.1.1.3. get_win32_OSProductInf

RegistryByExe.get_win32_OSProductInfo()[source]

Estimates the product type, because this is a fallback when nothing else is available.

Parameters

None

Returns

The estimated product type as a reduction of the original

”pdwReturnedProductType”

Raises

pass-through

8.45.1.2. Exceptions

exception platformids.dist.nt.windows_subprocess_reg_exe.PlatformIDsReadRegExeError[source]

8.45.2. Source

  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
# -*- coding: utf-8 -*-
"""Reads the MS-Windows registry by calling a subprocess for reg.exe.

This is a fallback solution when neither *winreg* / *_winreg*, nor in case 
of Jython the Java APIs such as *WindowsPref*, *JNA*, or *JNI* are not
available.
This works also on *Cygwin*, when e.g. the path for *kernel32.dll* does not
match for the *ctypes*.

Avoid using it due to serious performance impact compared to 
the others - but do when nothing else helps and the 
version information matters. 
"""
from __future__ import absolute_import

import re

from subprocess import Popen, PIPE

from platformids import PlatformIDsError
from platformids.dist.windows import VER_NT_SERVER, VER_NT_WORKSTATION, \
    VER_NT_DOMAIN_CONTROLLER, VER_NT_IOT, VER_NT_GENERIC


__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.2'
__uuid__ = "7add5ded-c39b-4b6e-8c87-1b3a1c150ee9"

__docformat__ = "restructuredtext en"


class PlatformIDsReadRegExeError(PlatformIDsError):
    pass


class RegistryByExe(object):
    """Registry read access by *reg.exe* to ::

       "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"

    """

    def __init__(self):
        
        #: used as cache for following calls
        #: the cache represents this platform, so may not be altered
        self.result = {}
        
        # cached product type
        self.product_type = None


    def read_CurrentVersion(self):
        """Reads the constant - thus hardcoded - key from :: 

             "HKLM\Software\Microsoft\Windows NT\CurrentVersion"

        Args:
            None
        
        Returns:
            The dictionary of the *CurrentVersion*.
        
        Raises:
            PlatformIDsReadRegExeError
            
            pass-through
            
        """
        cmd = 'c:\Windows\\system32\\reg.exe query '
        cmd += '"HKLM\Software\Microsoft\Windows NT\CurrentVersion"'

        p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
        out = p.communicate()
        
        if not out[0]:
            raise PlatformIDsReadRegExeError("read registry failed: " + str(out))
        
        for k,v in re.findall('^ *([^ ]+) *REG_[^ ]* *(.*)[\r][\n]*$',  out[0], flags=re.MULTILINE):  # @UndefinedVariable
            try:
                self.result[k] = int(v)
            except ValueError:
                try:
                    self.result[k] = int(v, 16)
                except ValueError:
                    self.result[k] = v
        
        return self.result


    def get_win32_OSProductInfo(self):   
        """Estimates the product type, because this is a fallback
        when nothing else is available.
         
        Args:
            None
        
        Returns:
            The estimated product type as a reduction of the
            original 
            
                "pdwReturnedProductType"
        
        Raises:
            pass-through

        """
        if not self.result:
            # set cache
            self.read_CurrentVersion()
        
        if self.product_type != None:
            # use cached product type
            return self.product_type
        
        try:
            #
            # for NT >= 6.0
            #
            eid = self.resultp['EditionID']  
            if re.match(r'.*[Ss]erver', eid):
                self.product_type = VER_NT_SERVER  # 0x0000003 #: see wProductType 
                return VER_NT_SERVER
                
            elif self.resultp['InstallationType'] == 'Client':  # has to be present when *EditionID* is
                self.product_type = VER_NT_WORKSTATION  # 0x0000001 #: see wProductType 
                return VER_NT_WORKSTATION

            elif re.match(r'.*[Dd]omain', eid):
                self.product_type = VER_NT_DOMAIN_CONTROLLER  # 0x0000002 #: see wProductType 
                return VER_NT_DOMAIN_CONTROLLER


            elif re.match(r'.*[Ii][Oo][Tt]', eid):
                self.product_type = VER_NT_IOT  # 0x0000004 #: non standard enum 
                return VER_NT_IOT

            else:
                self.product_type = VER_NT_GENERIC  # 0x0000000 #: non standard enum 
                return VER_NT_GENERIC

        except:
            #
            # for NT < 6.0
            #
            # do not want spend much effort for legacy has past EOL, so...
            #
            
            pnam = self.resultp['ProductName']  
            if re.match(r'.*XP', pnam):
                # WindowsXP
                self.product_type = VER_NT_WORKSTATION  # 0x0000001 #: see wProductType 
                return VER_NT_WORKSTATION

            elif re.match(r'.*SERVER', self.resultp['SourcePath']):  # not reliable...
                # WindowsXP
                self.product_type = VER_NT_SERVER  # 0x0000003 #: see wProductType 
                return VER_NT_SERVER
            
            else:
                #
                # may match a lot...
                #
                self.product_type = VER_NT_GENERIC  # 0x0000000 #: non standard enum 
                return VER_NT_GENERIC