From: mfletch at vrtelecom.com (Mike Fletcher)
Date: Sat, 24 Apr 1999 22:08:00 GMT
Subject: Some win32 registry functions (black, dangerous magic)
Message-ID: <EE90ACF2E054D211A9EC00600841DC0D1641E9@vrtmail.vrtelecom.com>
Content-Length: 7147
X-UID: 1683                                                  

I often have the desire to create/modify registry entries which are not the
"default" entries, and until today I've always considered this stuff very
black magic (why two types of every function, why do I need to open a key,
yada, yada).

The following is a module which provides a few features beyond the
regutil.py package distributed with win32all...

	1)  You specify keys as single paths, not root-key+path
	2)  You can store non-int/non-string objects (pickled)
	3)  You can store named values with the same command as default
values
	4)  Has a "register python scripts as executables" function
(example, NT only)
	5)  Has an "add directory to system path" function (example, NT
only)

I'd appreciate it if the Windows gurus could take a look and point out
anything I've done which might scramble someone's registry.  This is a
blatant rip-off of Mark Hammond's regutil.py .

Hereby released for whatever purpose, but at your own risk.  No warranties
expressed, implied or scandalised.

8<____________________ regutilsex.py _____

import win32api, win32con, string, types

def _getDataType( data, coerce = 1 ):
    '''
    Return a tuple of dataType, data for a given object
    automatically converts non-string-or-tuple-data into
    strings by calling pickle.dumps
    '''
    if type( data ) is types.StringType:
        return win32con.REG_SZ, data
    elif type( data ) is types.IntType:
        return win32con.REG_DWORD, data
    # what about attempting to convert Longs, floats, etceteras to ints???
    elif coerce:
        import pickle
        return win32con.REG_SZ, pickle.dumps( data )
    else:
        raise TypeError, '''Unsupported datatype for registry, use
getDataType( data, coerce=1) to store types other than string/int.'''

def _getBaseKey( fullPathSpec ):
    '''
    Split a "full path specification" registry key
    into its root and subpath components
    '''
    key = ''
    subkey = fullPathSpec
    # while loop will strip off preceding \\ characters
    while subkey and not key:
        key, subkey = string.split( fullPathSpec, '\\', 1 )
    try:
        return getattr( win32con, key ), subkey
    except AttributeError:
        raise '''Unknown root key %s in registry path %s'''% (key,
fullPathSpec)

def RegSetValue( key, valuename='', data='', allowPickling=1 ):
    '''
    Set a registry value by providing a fully-specified
    registry key (and an optional sub-key/value name),
    and a data element.  If allowPickling is true, the
    data element can be any picklable element, otherwise
    data element must be a string or integer.
    '''
    root, subkey = _getBaseKey( key )
    dataType, data = _getDataType( data, allowPickling )
    try:
        hKey = win32api.RegOpenKeyEx( root , subkey, 0,
win32con.KEY_ALL_ACCESS) # could we use a lesser access model?
    except:
        hKey = win32api.RegCreateKey( root, subkey )
    try:
        if not valuename: # the default value
            win32api.RegSetValue( hKey, valuename, dataType, data )
        else: # named sub-value
            win32api.RegSetValueEx( hKey, valuename, 0, dataType, data )
    finally:
        win32api.RegCloseKey( hKey)

def RegQueryValue( key, valuename='', pickling=0 ):
    '''
    Get a registry value by providing a fully-specified
    registry key (and an optional sub-key/value name)
    If pickling is true, the data element will be 
    unpickled before being returned.
    '''
    #print 'key', key
    root, subkey = _getBaseKey( key )
    if not valuename: # the default value
        data, type = win32api.RegQueryValue( root , subkey)
    else:
        try:
            #print root, subkey
            hKey = win32api.RegOpenKeyEx( root, subkey, 0,
win32con.KEY_READ)
            #print hKey, valuename
            try:
                data, type = win32api.RegQueryValueEx( hKey, valuename )
            except: #
                data, type = None, 0 # value is not available... should we
raise an error here instead???
                pickling = None
        finally:
            win32api.RegCloseKey( hKey)
    if pickling:
        import pickle
        data = pickle.loads( data )
    return data


################## EXAMPLES FOLLOW    
def AddPathEntry( newEntry, user = 1, prepend=0 ):
    '''
    Add or remove path entry on NT, use prepend == -1 for removal,
    use prepend == 0 for append, prepend= 1 for prepending to the
    current path.
    '''
    if user:
        user = 'USER'
    else:
        user = 'MACHINE'
    key, valuename = COMMON_KEYS[ (user, 'PATH') ]
    _PathManager( key, valuename, newEntry, prepend )

def PyExecutables( user = 1, prepend=0 ):
    '''
    Register/Deregister Python files as executables
    '''
    if user:
        user = 'USER'
    else:
        user = 'MACHINE'
    key, valuename = COMMON_KEYS[ (user, 'PYEXECUTABLES') ]
    # the default executables + Python scripts...
    if prepend < 0: # are to eliminate only .py
        newEntry = '.PY'
    else:
        newEntry = '.PY;.COM;.EXE;.BAT;.CMD'
    _PathManager( key, valuename, newEntry, prepend )

def _PathManager( key, valuename, newEntry, prepend=0,
eliminate_duplicates=1 ):
    '''
    Create a new Path entry on NT machines (or kill an old one)
    user determines whether to alter the USER or the Machine's path
    prepend
         1 -> add newEntry to start
         0 -> add newEntry to end
        -1 -> don't add newEntry 
    eliminate_duplicates determines whether to kill equal paths
    
    All values are converted to lower case
    '''
    # get current value...
    curval = RegQueryValue( key, valuename ) or ''
    # split into elements
    curval = string.split( string.lower(curval), ';' )
    if type( newEntry ) not in (types.ListType, types.TupleType):
        newEntry = string.split( string.lower(newEntry), ';' )
    # eliminate duplicates of the newEntry
    curval = map( None, curval) # strip out null entries
    if eliminate_duplicates:
        newval = []
        for p in curval:
            if p not in newEntry: 
                newval.append( p )
        curval = newval
    if prepend == 1:
        curval = list(newEntry) + curval
    elif prepend == 0:
        curval = curval + list( newEntry )
    elif prepend == -1: # this call is just killing the path entry
        pass
    #now do the recombination
    curval = string.join( curval, ';' )
    RegSetValue( key, valuename, curval )

# following constants seem to reflect where path data is stored on NT
machines
# no idea if it'll work on a 95 machine

COMMON_KEYS = {
('USER','PATH') : ('''HKEY_CURRENT_USER\\Environment''', 'path'), 
('MACHINE','PATH') :
('''HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session
Manager\\Environment''', 'path'),
('USER','PYEXECUTABLES') : ('''HKEY_CURRENT_USER\\Environment''',
'pathext'),
('MACHINE','PYEXECUTABLES') :
('''HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session
Manager\\Environment''', 'pathext')
}

____________________________________________________
  Mike C. Fletcher -- Virtual Environment Designer
                         mcfletch at vrtelecom.com
                        http://www.vrtelecom.com





