mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/Win32API/lib/win32/registry.rb: added. [new]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3312 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
d6cba99ea5
commit
c65638ce29
2 changed files with 832 additions and 0 deletions
|
@ -1,3 +1,7 @@
|
|||
Wed Jan 08 17:10:32 2003 NAKAMURA Usaku <usa@ruby-lang.org>
|
||||
|
||||
* ext/Win32API/lib/win32/registry.rb: added. [new]
|
||||
|
||||
Wed Jan 8 15:54:05 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* eval.c: remove ruby_last_node and assignments seems to be
|
||||
|
|
828
ext/Win32API/lib/win32/registry.rb
Normal file
828
ext/Win32API/lib/win32/registry.rb
Normal file
|
@ -0,0 +1,828 @@
|
|||
=begin
|
||||
= Win32 Registry I/F
|
||||
win32/registry is registry accessor library for Win32 platform.
|
||||
It uses Win32API to call Win32 Registry APIs.
|
||||
|
||||
== example
|
||||
Win32::Registry::HKEY_CURRENT_USER.open('SOFTWARE\foo') do |reg|
|
||||
value = reg['foo'] # read a value
|
||||
value = reg['foo', Win32::Registry::REG_SZ] # read a value with type
|
||||
type, value = reg.read('foo') # read a value
|
||||
reg['foo'] = 'bar' # write a value
|
||||
reg['foo', Win32::Registry::REG_SZ] = 'bar' # write a value with type
|
||||
reg.write('foo', Win32::Registry::REG_SZ, 'bar') # write a value
|
||||
|
||||
reg.each_value { |name, type, data| ... } # Enumerate values
|
||||
reg.each_key { |key, wtime| ... } # Enumerate subkeys
|
||||
|
||||
reg.delete_value(name) # Delete a value
|
||||
reg.delete_key(name) # Delete a subkey
|
||||
reg.delete_key(name, true) # Delete a subkey recursively
|
||||
end
|
||||
|
||||
= Reference
|
||||
|
||||
== Win32::Registry class
|
||||
|
||||
=== including modules
|
||||
|
||||
* Enumerable
|
||||
* Registry::Constants
|
||||
|
||||
=== class methods
|
||||
--- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
|
||||
--- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED) { |reg| ... }
|
||||
Open the registry key ((|subkey|)) under ((|key|)).
|
||||
((|key|)) is Win32::Registry object of parent key.
|
||||
You can use predefined key HKEY_* (see ((<constants>)))
|
||||
|
||||
((|desired|)) and ((|opt|)) is access mask and key option.
|
||||
For detail, see ((<MSDN Library|URL:http://msdn.microsoft.com/library/en-us/sysinfo/base/regopenkeyex.asp>)).
|
||||
|
||||
If block is given, the key is closed automatically.
|
||||
|
||||
--- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
|
||||
--- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED) { |reg| ... }
|
||||
Create or open the registry key ((|subkey|)) under ((|key|)).
|
||||
You can use predefined key HKEY_* (see ((<constants>)))
|
||||
|
||||
If subkey is already exists, key is opened and Registry#((<created?>))
|
||||
method will return false.
|
||||
|
||||
If block is given, the key is closed automatically.
|
||||
|
||||
--- Registry.expand_environ(str)
|
||||
Replace (({%\w+%})) into the environment value of ((|str|)).
|
||||
This method is used for REG_EXPAND_SZ.
|
||||
|
||||
For detail, see ((<ExpandEnvironmentStrings|URL:http://msdn.microsoft.com/library/en-us/sysinfo/base/expandenvironmentstrings.asp>)) Win32 API.
|
||||
|
||||
--- Registry.type2name(type)
|
||||
Convert registry type value to readable string.
|
||||
|
||||
--- Registry.wtime2time(wtime)
|
||||
Convert 64-bit FILETIME integer into Time object.
|
||||
|
||||
--- Registry.time2wtime(time)
|
||||
Convert Time object or Integer object into 64-bit FILETIME.
|
||||
|
||||
=== instance methods
|
||||
--- open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
|
||||
Same as (({Win32::((<Registry.open>))(self, subkey, desired, opt)}))
|
||||
|
||||
--- create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
|
||||
Same as (({Win32::((<Registry.create>))(self, subkey, desired, opt)}))
|
||||
|
||||
--- close
|
||||
Close key.
|
||||
|
||||
After closed, most method raises error.
|
||||
|
||||
--- read(name, *rtype)
|
||||
Read a registry value named ((|name|)) and return array of
|
||||
[ ((|type|)), ((|data|)) ].
|
||||
When name is nil, the `default' value is read.
|
||||
|
||||
((|type|)) is value type. (see ((<Win32::Registry::Constants module>)))
|
||||
((|data|)) is value data, its class is:
|
||||
:REG_SZ, REG_EXPAND_SZ
|
||||
String
|
||||
:REG_MULTI_SZ
|
||||
Array of String
|
||||
:REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD
|
||||
Integer
|
||||
:REG_BINARY
|
||||
String (contains binary data)
|
||||
|
||||
When ((|rtype|)) is specified, the value type must be included by
|
||||
((|rtype|)) array, or TypeError is raised.
|
||||
|
||||
--- self[name, *rtype]
|
||||
Read a registry value named ((|name|)) and return its value data.
|
||||
The class of value is same as ((<read>)) method returns.
|
||||
|
||||
If the value type is REG_EXPAND_SZ, returns value data whose environment
|
||||
variables are replaced.
|
||||
If the value type is neither REG_SZ, REG_MULTI_SZ, REG_DWORD,
|
||||
REG_DWORD_BIG_ENDIAN, nor REG_QWORD, TypeError is raised.
|
||||
|
||||
The meaning of ((|rtype|)) is same as ((<read>)) method.
|
||||
|
||||
--- read_s(name)
|
||||
--- read_i(name)
|
||||
--- read_bin(name)
|
||||
Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
|
||||
registry value named ((|name|)).
|
||||
|
||||
If the values type does not match, TypeError is raised.
|
||||
|
||||
--- read_s_expand(name)
|
||||
Read a REG_SZ or REG_EXPAND_SZ registry value named ((|name|)).
|
||||
|
||||
If the value type is REG_EXPAND_SZ, environment variables are replaced.
|
||||
Unless the value type is REG_SZ or REG_EXPAND_SZ, TypeError is raised.
|
||||
|
||||
--- write(name, type, data)
|
||||
Write ((|data|)) to a registry value named ((|name|)).
|
||||
When name is nil, write to the `default' value.
|
||||
|
||||
((|type|)) is type value. (see ((<Registry::Constants module>)))
|
||||
Class of ((|data|)) must be same as which ((<read>))
|
||||
method returns.
|
||||
|
||||
--- self[name, wtype = nil] = value
|
||||
Write ((|value|)) to a registry value named ((|name|)).
|
||||
|
||||
If ((|wtype|)) is specified, the value type is it.
|
||||
Otherwise, the value type is depend on class of ((|value|)):
|
||||
:Integer
|
||||
REG_DWORD
|
||||
:String
|
||||
REG_SZ
|
||||
:Array
|
||||
REG_MULTI_SZ
|
||||
|
||||
--- write_s(name, value)
|
||||
--- write_i(name, value)
|
||||
--- write_bin(name, value)
|
||||
Write ((|value|)) to a registry value named ((|name|)).
|
||||
|
||||
The value type is REG_SZ(write_s), REG_DWORD(write_i), or
|
||||
REG_BINARY(write_bin).
|
||||
|
||||
--- each { |name, type, value| ... }
|
||||
--- each_value { |name, type, value| ... }
|
||||
Enumerate values.
|
||||
|
||||
--- each_key { |subkey, wtime| ... }
|
||||
Enumerate subkeys.
|
||||
|
||||
((|subkey|)) is String which contains name of subkey.
|
||||
((|wtime|)) is last write time as FILETIME (64-bit integer).
|
||||
(see ((<Registry.wtime2time>)))
|
||||
|
||||
--- delete(name)
|
||||
--- delete_value(name)
|
||||
Delete a registry value named ((|name|)).
|
||||
We can not delete the `default' value.
|
||||
|
||||
--- delete_key(name, recursive = false)
|
||||
Delete a subkey named ((|name|)) and all its values.
|
||||
|
||||
If ((|recursive|)) is false, the subkey must not have subkeys.
|
||||
Otherwise, this method deletes all subkeys and values recursively.
|
||||
|
||||
--- flush
|
||||
Write all the attributes into the registry file.
|
||||
|
||||
--- created?
|
||||
Returns if key is created ((*newly*)).
|
||||
(see ((<Registry.create>)))
|
||||
|
||||
--- open?
|
||||
Returns if key is not closed.
|
||||
|
||||
--- hkey
|
||||
Returns key handle value.
|
||||
|
||||
--- parent
|
||||
Win32::Registry object of parent key, or nil if predefeined key.
|
||||
|
||||
--- keyname
|
||||
Same as ((|subkey|)) value of ((<Registry.open>)) or
|
||||
((<Registry.create>)) method.
|
||||
|
||||
--- disposition
|
||||
Disposition value (REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY).
|
||||
|
||||
--- name
|
||||
--- to_s
|
||||
Full path of key such as (({'HKEY_CURRENT_USER\SOFTWARE\foo\bar'})).
|
||||
|
||||
--- info
|
||||
Returns key information as Array of:
|
||||
:num_keys
|
||||
The number of subkeys.
|
||||
:max_key_length
|
||||
Maximum length of name of subkeys.
|
||||
:num_values
|
||||
The number of values.
|
||||
:max_value_name_length
|
||||
Maximum length of name of values.
|
||||
:max_value_length
|
||||
Maximum length of value of values.
|
||||
:descriptor_length
|
||||
Length of security descriptor.
|
||||
:wtime
|
||||
Last write time as FILETIME(64-bit integer)
|
||||
|
||||
For detail, see ((<RegQueryInfoKey|URL:http://msdn.microsoft.com/library/en-us/sysinfo/base/regqueryinfokey.asp>)) Win32 API.
|
||||
|
||||
--- num_keys
|
||||
--- max_key_length
|
||||
--- num_values
|
||||
--- max_value_name_length
|
||||
--- max_value_length
|
||||
--- descriptor_length
|
||||
--- wtime
|
||||
Returns an item of key information.
|
||||
|
||||
=== constants
|
||||
--- HKEY_CLASSES_ROOT
|
||||
--- HKEY_CURRENT_USER
|
||||
--- HKEY_LOCAL_MACHINE
|
||||
--- HKEY_PERFORMANCE_DATA
|
||||
--- HKEY_CURRENT_CONFIG
|
||||
--- HKEY_DYN_DATA
|
||||
Win32::Registry object whose key is predefined key.
|
||||
For detail, see ((<MSDN Library|URL:http://msdn.microsoft.com/library/en-us/sysinfo/base/predefined_keys.asp>)).
|
||||
|
||||
== Win32::Registry::Constants module
|
||||
|
||||
For detail, see ((<MSDN Library|URL:http://msdn.microsoft.com/library/en-us/sysinfo/base/registry.asp>)).
|
||||
|
||||
--- HKEY_*
|
||||
Predefined key ((*handle*)).
|
||||
These are Integer, not Win32::Registry.
|
||||
|
||||
--- REG_*
|
||||
Registry value type.
|
||||
|
||||
--- KEY_*
|
||||
Security access mask.
|
||||
|
||||
--- KEY_OPTIONS_*
|
||||
Key options.
|
||||
|
||||
--- REG_CREATED_NEW_KEY
|
||||
--- REG_OPENED_EXISTING_KEY
|
||||
If the key is created newly or opened existing key.
|
||||
See also Registry#((<disposition>)) method.
|
||||
|
||||
=end
|
||||
|
||||
require 'Win32API'
|
||||
|
||||
module Win32
|
||||
class Registry
|
||||
module Constants
|
||||
HKEY_CLASSES_ROOT = 0x80000000
|
||||
HKEY_CURRENT_USER = 0x80000001
|
||||
HKEY_LOCAL_MACHINE = 0x80000002
|
||||
HKEY_PERFORMANCE_DATA = 0x80000003
|
||||
HKEY_CURRENT_CONFIG = 0x80000004
|
||||
HKEY_DYN_DATA = 0x80000005
|
||||
|
||||
REG_NONE = 0
|
||||
REG_SZ = 1
|
||||
REG_EXPAND_SZ = 2
|
||||
REG_BINARY = 3
|
||||
REG_DWORD = 4
|
||||
REG_DWORD_LITTLE_ENDIAN = 4
|
||||
REG_DWORD_BIG_ENDIAN = 5
|
||||
REG_LINK = 6
|
||||
REG_MULTI_SZ = 7
|
||||
REG_RESOURCE_LIST = 8
|
||||
REG_FULL_RESOURCE_DESCRIPTOR = 9
|
||||
REG_RESOURCE_REQUIREMENTS_LIST = 10
|
||||
REG_QWORD = 11
|
||||
REG_QWORD_LITTLE_ENDIAN = 11
|
||||
|
||||
STANDARD_RIGHTS_READ = 0x00020000
|
||||
STANDARD_RIGHTS_WRITE = 0x00020000
|
||||
KEY_QUERY_VALUE = 0x0001
|
||||
KEY_SET_VALUE = 0x0002
|
||||
KEY_CREATE_SUB_KEY = 0x0004
|
||||
KEY_ENUMERATE_SUB_KEYS = 0x0008
|
||||
KEY_NOTIFY = 0x0010
|
||||
KEY_CREATE_LINK = 0x0020
|
||||
KEY_READ = STANDARD_RIGHTS_READ |
|
||||
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY
|
||||
KEY_WRITE = STANDARD_RIGHTS_WRITE |
|
||||
KEY_SET_VALUE | KEY_CREATE_SUB_KEY
|
||||
KEY_EXECUTE = KEY_READ
|
||||
KEY_ALL_ACCESS = KEY_READ | KEY_WRITE | KEY_CREATE_LINK
|
||||
|
||||
REG_OPTION_RESERVED = 0x0000
|
||||
REG_OPTION_NON_VOLATILE = 0x0000
|
||||
REG_OPTION_VOLATILE = 0x0001
|
||||
REG_OPTION_CREATE_LINK = 0x0002
|
||||
REG_OPTION_BACKUP_RESTORE = 0x0004
|
||||
REG_OPTION_OPEN_LINK = 0x0008
|
||||
REG_LEGAL_OPTION = REG_OPTION_RESERVED |
|
||||
REG_OPTION_NON_VOLATILE | REG_OPTION_CREATE_LINK |
|
||||
REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK
|
||||
|
||||
REG_CREATED_NEW_KEY = 1
|
||||
REG_OPENED_EXISTING_KEY = 2
|
||||
|
||||
REG_WHOLE_HIVE_VOLATILE = 0x0001
|
||||
REG_REFRESH_HIVE = 0x0002
|
||||
REG_NO_LAZY_FLUSH = 0x0004
|
||||
REG_FORCE_RESTORE = 0x0008
|
||||
|
||||
MAX_KEY_LENGTH = 514
|
||||
MAX_VALUE_LENGTH = 32768
|
||||
end
|
||||
include Constants
|
||||
include Enumerable
|
||||
|
||||
#
|
||||
# Error
|
||||
#
|
||||
class Error < ::SystemCallError
|
||||
FormatMessageA = Win32API.new('kernel32.dll', 'FormatMessageA', 'LPLLPLP', 'L')
|
||||
def initialize(code)
|
||||
@code = code
|
||||
|
||||
msg = "\0" * 1024
|
||||
len = FormatMessageA.call(0x1200, 0, code, 0, msg, 1024, 0)
|
||||
super msg[0, len].tr("\r", '').chomp
|
||||
end
|
||||
attr_reader :code
|
||||
end
|
||||
|
||||
#
|
||||
# Predefined Keys
|
||||
#
|
||||
class PredefinedKey < Registry
|
||||
def initialize(hkey, keyname)
|
||||
@hkey = hkey
|
||||
@parent = nil
|
||||
@keyname = keyname
|
||||
@disposition = REG_OPENED_EXISTING_KEY
|
||||
end
|
||||
|
||||
# Predefined keys cannot be closed
|
||||
def close
|
||||
raise Error.new(5) ## ERROR_ACCESS_DENIED
|
||||
end
|
||||
|
||||
# Fake class for Registry#open, Registry#create
|
||||
def class
|
||||
Registry
|
||||
end
|
||||
|
||||
# Make all
|
||||
Constants.constants.select { |c| /^HKEY_/ =~ c }.each do |c|
|
||||
Registry.const_set c, new(Constants.const_get(c), c)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Win32 APIs
|
||||
#
|
||||
module API
|
||||
[
|
||||
%w/RegOpenKeyExA LPLLP L/,
|
||||
%w/RegCreateKeyExA LPLLLLPPP L/,
|
||||
%w/RegEnumValueA LLPPPPPP L/,
|
||||
%w/RegEnumKeyExA LLPPLLLP L/,
|
||||
%w/RegQueryValueExA LPLPPP L/,
|
||||
%w/RegSetValueExA LPLLPL L/,
|
||||
%w/RegDeleteValue LP L/,
|
||||
%w/RegDeleteKey LP L/,
|
||||
%w/RegFlushKey L L/,
|
||||
%w/RegCloseKey L L/,
|
||||
%w/RegQueryInfoKey LPPPPPPPPPPP L/,
|
||||
].each do |fn|
|
||||
const_set fn[0].intern, Win32API.new('advapi32.dll', *fn)
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
def check(result)
|
||||
raise Error, result, caller(2) if result != 0
|
||||
end
|
||||
|
||||
def packdw(dw)
|
||||
[dw].pack('V')
|
||||
end
|
||||
|
||||
def unpackdw(dw)
|
||||
dw.unpack('V')[0]
|
||||
end
|
||||
|
||||
def packqw(qw)
|
||||
[ qw & 0xFFFFFFFF, qw >> 32 ].pack('VV')
|
||||
end
|
||||
|
||||
def unpackqw(qw)
|
||||
qw = qw.unpack('VV')
|
||||
(qw[1] << 32) | qw[0]
|
||||
end
|
||||
|
||||
def OpenKey(hkey, name, opt, desired)
|
||||
result = packdw(0)
|
||||
check RegOpenKeyExA.call(hkey, name, opt, desired, result)
|
||||
unpackdw(result)
|
||||
end
|
||||
|
||||
def CreateKey(hkey, name, opt, desired)
|
||||
result = packdw(0)
|
||||
disp = packdw(0)
|
||||
check RegCreateKeyExA.call(hkey, name, 0, 0, opt, desired,
|
||||
0, result, disp)
|
||||
[ unpackdw(result), unpackdw(disp) ]
|
||||
end
|
||||
|
||||
def EnumValue(hkey, index)
|
||||
name = ' ' * Constants::MAX_KEY_LENGTH
|
||||
size = packdw(Constants::MAX_KEY_LENGTH)
|
||||
check RegEnumValueA.call(hkey, index, name, size, 0, 0, 0, 0)
|
||||
name[0, unpackdw(size)]
|
||||
end
|
||||
|
||||
def EnumKey(hkey, index)
|
||||
name = ' ' * Constants::MAX_KEY_LENGTH
|
||||
size = packdw(Constants::MAX_KEY_LENGTH)
|
||||
wtime = ' ' * 8
|
||||
check RegEnumKeyExA.call(hkey, index, name, size, 0, 0, 0, wtime)
|
||||
[ name[0, unpackdw(size)], unpackqw(wtime) ]
|
||||
end
|
||||
|
||||
def QueryValue(hkey, name)
|
||||
type = packdw(0)
|
||||
size = packdw(0)
|
||||
check RegQueryValueExA.call(hkey, name, 0, type, 0, size)
|
||||
data = ' ' * unpackdw(size)
|
||||
check RegQueryValueExA.call(hkey, name, 0, type, data, size)
|
||||
[ unpackdw(type), data[0, unpackdw(size)] ]
|
||||
end
|
||||
|
||||
def SetValue(hkey, name, type, data, size)
|
||||
check RegSetValueExA.call(hkey, name, 0, type, data, size)
|
||||
end
|
||||
|
||||
def DeleteValue(hkey, name)
|
||||
check RegDeleteValue.call(hkey, name)
|
||||
end
|
||||
|
||||
def DeleteKey(hkey, name)
|
||||
check RegDeleteKey.call(hkey, name)
|
||||
end
|
||||
|
||||
def FlushKey(hkey)
|
||||
check RegFlushKey.call(hkey)
|
||||
end
|
||||
|
||||
def CloseKey(hkey)
|
||||
check RegCloseKey.call(hkey)
|
||||
end
|
||||
|
||||
def QueryInfoKey(hkey)
|
||||
subkeys = packdw(0)
|
||||
maxsubkeylen = packdw(0)
|
||||
values = packdw(0)
|
||||
maxvaluenamelen = packdw(0)
|
||||
maxvaluelen = packdw(0)
|
||||
secdescs = packdw(0)
|
||||
wtime = ' ' * 8
|
||||
check RegQueryInfoKey.call(hkey, 0, 0, 0, subkeys, maxsubkeylen, 0,
|
||||
values, maxvaluenamelen, maxvaluelen, secdescs, wtime)
|
||||
[ unpackdw(subkeys), unpackdw(maxsubkeylen), unpackdw(values),
|
||||
unpackdw(maxvaluenamelen), unpackdw(maxvaluelen),
|
||||
unpackdw(secdescs), unpackqw(wtime) ]
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# utility functions
|
||||
#
|
||||
def self.expand_environ(str)
|
||||
str.gsub(/%([^%]+)%/) { ENV[$1] || $& }
|
||||
end
|
||||
|
||||
@@type2name = { }
|
||||
%w[
|
||||
REG_NONE REG_SZ REG_EXPAND_SZ REG_BINARY REG_DWORD
|
||||
REG_DWORD_BIG_ENDIAN REG_LINK REG_MULTI_SZ
|
||||
REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR
|
||||
REG_RESOURCE_REQUIREMENTS_LIST REG_QWORD
|
||||
].each do |type|
|
||||
@@type2name[Constants.const_get(type)] = type
|
||||
end
|
||||
|
||||
def self.type2name(type)
|
||||
@@type2name[type] || type.to_s
|
||||
end
|
||||
|
||||
def self.wtime2time(wtime)
|
||||
Time.at((wtime - 116444736000000000) / 10000000)
|
||||
end
|
||||
|
||||
def self.time2wtime(time)
|
||||
time.to_i * 10000000 + 116444736000000000
|
||||
end
|
||||
|
||||
#
|
||||
# constructors
|
||||
#
|
||||
private_class_method :new
|
||||
|
||||
def self.open(hkey, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
|
||||
subkey = subkey.chomp('\\')
|
||||
newkey = API.OpenKey(hkey.hkey, subkey, opt, desired)
|
||||
obj = new(newkey, hkey, subkey, REG_OPENED_EXISTING_KEY)
|
||||
if block_given?
|
||||
begin
|
||||
yield obj
|
||||
ensure
|
||||
obj.close
|
||||
end
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
def self.create(hkey, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
|
||||
newkey, disp = API.CreateKey(hkey.hkey, subkey, opt, desired)
|
||||
obj = new(newkey, hkey, subkey, disp)
|
||||
if block_given?
|
||||
begin
|
||||
yield obj
|
||||
ensure
|
||||
obj.close
|
||||
end
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# finalizer
|
||||
#
|
||||
@@final = proc { |hkey| proc { API.CloseKey(hkey[0]) if hkey[0] } }
|
||||
|
||||
#
|
||||
# initialize
|
||||
#
|
||||
def initialize(hkey, parent, keyname, disposition)
|
||||
@hkey = hkey
|
||||
@parent = parent
|
||||
@keyname = keyname
|
||||
@disposition = disposition
|
||||
@hkeyfinal = [ hkey ]
|
||||
ObjectSpace.define_finalizer self, @@final.call(@hkeyfinal)
|
||||
end
|
||||
attr_reader :hkey, :parent, :keyname, :disposition
|
||||
|
||||
#
|
||||
# attributes
|
||||
#
|
||||
def created?
|
||||
@disposition == REG_CREATED_NEW_KEY
|
||||
end
|
||||
|
||||
def open?
|
||||
!@hkey.nil?
|
||||
end
|
||||
|
||||
def name
|
||||
parent = self
|
||||
name = @keyname
|
||||
while parent = parent.parent
|
||||
name = parent.keyname + '\\' + name
|
||||
end
|
||||
name
|
||||
end
|
||||
|
||||
def inspect
|
||||
"\#<Win32::Registry key=#{name.inspect}>"
|
||||
end
|
||||
|
||||
#
|
||||
# marshalling
|
||||
#
|
||||
def _dump(depth)
|
||||
raise TypeError, "can't dump Win32::Registry"
|
||||
end
|
||||
|
||||
#
|
||||
# open/close
|
||||
#
|
||||
def open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED, &blk)
|
||||
self.class.open(self, subkey, desired, opt, &blk)
|
||||
end
|
||||
|
||||
def create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED, &blk)
|
||||
self.class.create(self, subkey, desired, opt, &blk)
|
||||
end
|
||||
|
||||
def close
|
||||
API.CloseKey(@hkey)
|
||||
@hkey = @parent = @keyname = nil
|
||||
@hkeyfinal[0] = nil
|
||||
end
|
||||
|
||||
#
|
||||
# iterator
|
||||
#
|
||||
def each_value
|
||||
index = 0
|
||||
while true
|
||||
begin
|
||||
subkey = API.EnumValue(@hkey, index)
|
||||
rescue Error
|
||||
break
|
||||
end
|
||||
begin
|
||||
type, data = read(subkey)
|
||||
rescue Error
|
||||
next
|
||||
end
|
||||
yield subkey, type, data
|
||||
index += 1
|
||||
end
|
||||
index
|
||||
end
|
||||
alias each each_value
|
||||
|
||||
def each_key
|
||||
index = 0
|
||||
while true
|
||||
begin
|
||||
subkey, wtime = API.EnumKey(@hkey, index)
|
||||
rescue Error
|
||||
break
|
||||
end
|
||||
yield subkey, wtime
|
||||
index += 1
|
||||
end
|
||||
index
|
||||
end
|
||||
|
||||
def keys
|
||||
keys_ary = []
|
||||
each_key { |key,| keys_ary << key }
|
||||
keys_ary
|
||||
end
|
||||
|
||||
#
|
||||
# reader
|
||||
#
|
||||
def read(name, *rtype)
|
||||
type, data = API.QueryValue(@hkey, name)
|
||||
unless rtype.empty? or rtype.include?(type)
|
||||
raise TypeError, "Type mismatch (expect #{rtype.inspect} but #{type} present)"
|
||||
end
|
||||
case type
|
||||
when REG_SZ, REG_EXPAND_SZ
|
||||
[ type, data.chop ]
|
||||
when REG_MULTI_SZ
|
||||
[ type, data.split(/\0/) ]
|
||||
when REG_BINARY
|
||||
[ type, data ]
|
||||
when REG_DWORD
|
||||
[ type, API.unpackdw(data) ]
|
||||
when REG_DWORD_BIG_ENDIAN
|
||||
[ type, data.unpack('N')[0] ]
|
||||
when REG_QWORD
|
||||
[ type, API.unpackqw(data) ]
|
||||
else
|
||||
raise TypeError, "Type #{type} is not supported."
|
||||
end
|
||||
end
|
||||
|
||||
def [](name, *rtype)
|
||||
type, data = read(name, *rtype)
|
||||
case type
|
||||
when REG_SZ, REG_DWORD, REG_QWORD, REG_MULTI_SZ
|
||||
data
|
||||
when REG_EXPAND_SZ
|
||||
Registry.expand_environ(data)
|
||||
else
|
||||
raise TypeError, "Type #{type} is not supported."
|
||||
end
|
||||
end
|
||||
|
||||
def read_s(name)
|
||||
read(name, REG_SZ)[1]
|
||||
end
|
||||
|
||||
def read_s_expand(name)
|
||||
type, data = read(name, REG_SZ, REG_EXPAND_SZ)
|
||||
if type == REG_EXPAND_SZ
|
||||
Registry.expand_environ(data)
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
def read_i(name)
|
||||
read(name, REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD)[1]
|
||||
end
|
||||
|
||||
def read_bin(name)
|
||||
read(name, REG_BINARY)[1]
|
||||
end
|
||||
|
||||
#
|
||||
# writer
|
||||
#
|
||||
def write(name, type, data)
|
||||
case type
|
||||
when REG_SZ, REG_EXPAND_SZ
|
||||
data += "\0"
|
||||
when REG_MULTI_SZ
|
||||
data = data.join("\0") + "\0\0"
|
||||
when REG_BINARY
|
||||
#
|
||||
when REG_DWORD
|
||||
data = API.packdw(data)
|
||||
when REG_DWORD_BIG_ENDIAN
|
||||
data = [data].pack('N')
|
||||
when REG_QWORD
|
||||
data = API.packqw(data)
|
||||
else
|
||||
raise TypeError, "Unsupported type #{type}"
|
||||
end
|
||||
API.SetValue(@hkey, name, type, data, data.length)
|
||||
end
|
||||
|
||||
def []=(name, rtype, value = nil)
|
||||
if value
|
||||
write name, rtype, value
|
||||
else
|
||||
case value = rtype
|
||||
when Integer
|
||||
write name, REG_DWORD, value.to_i
|
||||
when String
|
||||
write name, REG_SZ, value.to_s
|
||||
when Array
|
||||
write name, REG_MULTI_SZ, value
|
||||
else
|
||||
raise TypeError, "Unexpected type #{value.class}"
|
||||
end
|
||||
end
|
||||
value
|
||||
end
|
||||
|
||||
def write_s(name, value)
|
||||
write name, REG_SZ, value.to_s
|
||||
end
|
||||
|
||||
def write_i(name, value)
|
||||
write name, REG_DWORD, value.to_i
|
||||
end
|
||||
|
||||
def write_bin(name, value)
|
||||
write name, REG_BINARY, value.to_s
|
||||
end
|
||||
|
||||
#
|
||||
# delete
|
||||
#
|
||||
def delete_value(name)
|
||||
API.DeleteValue(@hkey, name)
|
||||
end
|
||||
alias delete delete_value
|
||||
|
||||
def delete_key(name, recursive = false)
|
||||
if recursive
|
||||
open(name, KEY_ALL_ACCESS) do |reg|
|
||||
reg.keys.each do |key|
|
||||
begin
|
||||
reg.delete_key(key, true)
|
||||
rescue Error
|
||||
#
|
||||
end
|
||||
end
|
||||
end
|
||||
API.DeleteKey(@hkey, name)
|
||||
else
|
||||
begin
|
||||
API.EnumKey @hkey, 0
|
||||
rescue Error
|
||||
return API.DeleteKey(@hkey, name)
|
||||
end
|
||||
raise Error.new(5) ## ERROR_ACCESS_DENIED
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# flush
|
||||
#
|
||||
def flush
|
||||
API.FlushKey @hkey
|
||||
end
|
||||
|
||||
#
|
||||
# key information
|
||||
#
|
||||
def info
|
||||
API.QueryInfoKey(@hkey)
|
||||
end
|
||||
%w[
|
||||
num_keys max_key_length
|
||||
num_values max_value_name_length max_value_length
|
||||
descriptor_length wtime
|
||||
].each_with_index do |s, i|
|
||||
eval <<-__END__
|
||||
def #{s}
|
||||
info[#{i}]
|
||||
end
|
||||
__END__
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue