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 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
|
# frozen_string_literal: false
require 'win32/importer'
require 'Win32API'
module Win32
=begin rdoc
= Win32 Registry
win32/registry is registry accessor library for Win32 platform.
It uses importer 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
--- info
--- 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 the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/predefined_keys.asp] article.
=end rdoc
WCHAR = Encoding::UTF_16LE
WCHAR_NUL = "\0".encode(WCHAR).freeze
WCHAR_CR = "\r".encode(WCHAR).freeze
WCHAR_SIZE = WCHAR_NUL.bytesize
LOCALE = Encoding.find(Encoding.locale_charmap)
class Registry
#
# For detail, see the MSDN[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.
module Constants
HKEY_CLASSES_ROOT = 0x80000000
HKEY_CURRENT_USER = 0x80000001
HKEY_LOCAL_MACHINE = 0x80000002
HKEY_USERS = 0x80000003
HKEY_PERFORMANCE_DATA = 0x80000004
HKEY_PERFORMANCE_TEXT = 0x80000050
HKEY_PERFORMANCE_NLSTEXT = 0x80000060
HKEY_CURRENT_CONFIG = 0x80000005
HKEY_DYN_DATA = 0x80000006
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 < ::StandardError
FormatMessageW = Win32API.new('kernel32.dll', 'FormatMessageW', 'LPLLPLP', 'L')
def initialize(code)
@code = code
buff = WCHAR_NUL * 1024
lang = 0
begin
len = FormatMessageW.call(0x1200, 0, code, lang, buff, 1024, 0)
msg = buff.byteslice(0, len * WCHAR_SIZE)
msg.delete!(WCHAR_CR)
msg.chomp!
msg.encode!(LOCALE)
rescue EncodingError
raise unless lang == 0
lang = 0x0409 # en_US
retry
end
super msg
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 method for Registry#open, Registry#create
def class
Registry
end
# Make all
Constants.constants.grep(/^HKEY_/) do |c|
Registry.const_set c, new(Constants.const_get(c), c)
end
end
#
# Win32 APIs
#
module API
include Constants
[
%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/RegOpenKeyExW LPLLP L/,
%w/RegCreateKeyExW LPLLLLPPP L/,
%w/RegEnumValueW LLPPPPPP L/,
%w/RegEnumKeyExW LLPPLLLP L/,
%w/RegQueryValueExW LPLPPP L/,
%w/RegSetValueExW LPLLPL L/,
%w/RegDeleteValueW LP L/,
%w/RegDeleteKeyW LP L/,
%w/RegFlushKey L L/,
%w/RegCloseKey L L/,
%w/RegQueryInfoKeyW 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(1) if result != 0
end
def win64?
/^(?:x64|x86_64)/ =~ RUBY_PLATFORM
end
def packhandle(h)
win64? ? packqw(h) : packdw(h)
end
def unpackhandle(h)
win64? ? unpackqw(h) : unpackdw(h)
end
def packdw(dw)
[dw].pack('V')
end
def unpackdw(dw)
dw += [0].pack('V')
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 make_wstr(str)
str.encode(WCHAR) + 0.chr.encode(WCHAR)
end
def OpenKey(hkey, name, opt, desired)
result = packhandle(0)
check RegOpenKeyExW.call(hkey, make_wstr(name), opt, desired, result)
unpackhandle(result)
end
def CreateKey(hkey, name, opt, desired)
result = packhandle(0)
disp = packdw(0)
check RegCreateKeyExW.call(hkey, make_wstr(name), 0, 0, opt, desired,
0, result, disp)
[ unpackhandle(result), unpackdw(disp) ]
end
def EnumValue(hkey, index)
name = WCHAR_NUL * Constants::MAX_KEY_LENGTH
size = packdw(Constants::MAX_KEY_LENGTH)
check RegEnumValueW.call(hkey, index, name, size, 0, 0, 0, 0)
name.byteslice(0, unpackdw(size) * WCHAR_SIZE)
end
def EnumKey(hkey, index)
name = WCHAR_NUL * Constants::MAX_KEY_LENGTH
size = packdw(Constants::MAX_KEY_LENGTH)
wtime = ' ' * 8
check RegEnumKeyExW.call(hkey, index, name, size, 0, 0, 0, wtime)
[ name.byteslice(0, unpackdw(size) * WCHAR_SIZE), unpackqw(wtime) ]
end
def QueryValue(hkey, name)
type = packdw(0)
size = packdw(0)
name = make_wstr(name)
check RegQueryValueExW.call(hkey, name, 0, type, 0, size)
data = "\0".force_encoding('ASCII-8BIT') * unpackdw(size)
check RegQueryValueExW.call(hkey, name, 0, type, data, size)
[ unpackdw(type), data[0, unpackdw(size)] ]
end
def SetValue(hkey, name, type, data, size)
case type
when REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ
data = data.encode(WCHAR)
size ||= data.bytesize + WCHAR_SIZE
end
check RegSetValueExW.call(hkey, make_wstr(name), 0, type, data, size)
end
def DeleteValue(hkey, name)
check RegDeleteValueW.call(hkey, make_wstr(name))
end
def DeleteKey(hkey, name)
check RegDeleteKeyW.call(hkey, make_wstr(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
#
# Replace %\w+% into the environment value of what is contained between the %'s
# This method is used for REG_EXPAND_SZ.
#
# For detail, see expandEnvironmentStrings[http://msdn.microsoft.com/library/en-us/sysinfo/base/expandenvironmentstrings.asp] \Win32 \API.
#
def self.expand_environ(str)
str.gsub(Regexp.compile("%([^%]+)%".encode(str.encoding))) {
v = $1.encode(LOCALE)
(e = ENV[v] || ENV[v.upcase]; e.encode(str.encoding) if e) ||
$&
}
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
].inject([]) do |ary, type|
type.freeze
ary[Constants.const_get(type)] = type
ary
end.freeze
#
# Convert registry type value to readable string.
#
def self.type2name(type)
@@type2name[type] || type.to_s
end
#
# Convert 64-bit FILETIME integer into Time object.
#
def self.wtime2time(wtime)
Time.at((wtime - 116444736000000000) / 10000000)
end
#
# Convert Time object or Integer object into 64-bit FILETIME.
#
def self.time2wtime(time)
time.to_i * 10000000 + 116444736000000000
end
#
# constructor
#
private_class_method :new
#
# --- 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 the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/regopenkeyex.asp].
# If block is given, the key is closed automatically.
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
#
# --- 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.
#
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
# Returns key handle value.
attr_reader :hkey
# Win32::Registry object of parent key, or nil if predefeined key.
attr_reader :parent
# Same as subkey value of Registry.open or
# Registry.create method.
attr_reader :keyname
# Disposition value (REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY).
attr_reader :disposition
#
# Returns if key is created ((*newly*)).
# (see Registry.create) -- basically you call create
# then when you call created? on the instance returned
# it will tell if it was successful or not
#
def created?
@disposition == REG_CREATED_NEW_KEY
end
#
# Returns if key is not closed.
#
def open?
!@hkey.nil?
end
#
# Full path of key such as 'HKEY_CURRENT_USER\SOFTWARE\foo\bar'.
#
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 is not allowed
#
def _dump(depth)
raise TypeError, "can't dump Win32::Registry"
end
#
# Same as Win32::Registry.open (self, subkey, desired, opt)
#
def open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED, &blk)
self.class.open(self, subkey, desired, opt, &blk)
end
#
# Same as Win32::Registry.create (self, subkey, desired, opt)
#
def create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED, &blk)
self.class.create(self, subkey, desired, opt, &blk)
end
#
# Close key.
#
# After close, most method raise an error.
#
def close
API.CloseKey(@hkey)
@hkey = @parent = @keyname = nil
@hkeyfinal[0] = nil
end
#
# Enumerate values.
#
def each_value
index = 0
while true
begin
subkey = API.EnumValue(@hkey, index)
rescue Error
break
end
subkey = export_string(subkey)
begin
type, data = read(subkey)
rescue Error
next
end
yield subkey, type, data
index += 1
end
index
end
alias each each_value
#
# return values as an array
#
def values
vals_ary = []
each_value { |*, val| vals_ary << val }
vals_ary
end
#
# Enumerate subkeys.
#
# subkey is String which contains name of subkey.
# wtime is last write time as FILETIME (64-bit integer).
# (see Registry.wtime2time)
#
def each_key
index = 0
while true
begin
subkey, wtime = API.EnumKey(@hkey, index)
rescue Error
break
end
subkey = export_string(subkey)
yield subkey, wtime
index += 1
end
index
end
#
# return keys as an array
#
def keys
keys_ary = []
each_key { |key,| keys_ary << key }
keys_ary
end
# 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, REG_NONE
# String (contains binary data)
#
# When rtype is specified, the value type must be included by
# rtype array, or TypeError is raised.
def read(name, *rtype)
type, data = API.QueryValue(@hkey, name)
unless rtype.empty? or rtype.include?(type)
raise TypeError, "Type mismatch (expect [#{
rtype.map{|t|Registry.type2name(t)}.join(', ')}] but #{
Registry.type2name(type)} present)"
end
case type
when REG_SZ, REG_EXPAND_SZ
[ type, data.encode(name.encoding, WCHAR).chop ]
when REG_MULTI_SZ
[ type, data.encode(name.encoding, WCHAR).split(/\0/) ]
when REG_BINARY, REG_NONE
[ 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 #{Registry.type2name(type)} is not supported."
end
end
#
# 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.
#
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 #{Registry.type2name(type)} is not supported."
end
end
# 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.
def read_s(name)
read(name, REG_SZ)[1]
end
#
# 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.
#
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
#
# 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.
#
def read_i(name)
read(name, REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD)[1]
end
#
# 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.
#
def read_bin(name)
read(name, REG_BINARY)[1]
end
#
# 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.
#
def write(name, type, data)
termsize = 0
case type
when REG_SZ, REG_EXPAND_SZ
data = data.encode(WCHAR)
termsize = WCHAR_SIZE
when REG_MULTI_SZ
data = data.to_a.map {|s| s.encode(WCHAR)}.join(WCHAR_NUL) << WCHAR_NUL
termsize = WCHAR_SIZE
when REG_BINARY, REG_NONE
data = data.to_s
when REG_DWORD
data = API.packdw(data.to_i)
when REG_DWORD_BIG_ENDIAN
data = [data.to_i].pack('N')
when REG_QWORD
data = API.packqw(data.to_i)
else
raise TypeError, "Unsupported type #{Registry.type2name(type)}"
end
API.SetValue(@hkey, name, type, data, data.bytesize + termsize)
end
#
# 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
#
def []=(name, rtype, value = nil)
if value
write name, rtype, value
else
case value = rtype
when Integer
write name, REG_DWORD, value
when String
write name, REG_SZ, value
when Array
write name, REG_MULTI_SZ, value
else
raise TypeError, "Unexpected type #{value.class}"
end
end
value
end
#
# 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).
#
def write_s(name, value)
write name, REG_SZ, value.to_s
end
#
# 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).
#
def write_i(name, value)
write name, REG_DWORD, value.to_i
end
#
# 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).
#
def write_bin(name, value)
write name, REG_BINARY, value.to_s
end
#
# Delete a registry value named name.
# We can not delete the `default' value.
#
def delete_value(name)
API.DeleteValue(@hkey, name)
end
alias delete delete_value
#
# 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.
#
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
#
# Write all the attributes into the registry file.
#
def flush
API.FlushKey @hkey
end
#
# 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[http://msdn.microsoft.com/library/en-us/sysinfo/base/regqueryinfokey.asp] Win32 API.
#
def info
API.QueryInfoKey(@hkey)
end
#
# Returns an item of key information.
#
%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
private
def export_string(str, enc = Encoding.default_internal || LOCALE) # :nodoc:
str.encode(enc)
end
end
end
|