virtualbox 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -1
- data/Gemfile +1 -1
- data/Rakefile +1 -1
- data/Readme.md +5 -21
- data/VERSION +1 -1
- data/docs/WhatsNew.md +9 -47
- data/lib/virtualbox.rb +7 -30
- data/lib/virtualbox/abstract_model.rb +25 -5
- data/lib/virtualbox/abstract_model/attributable.rb +5 -1
- data/lib/virtualbox/abstract_model/dirty.rb +2 -0
- data/lib/virtualbox/abstract_model/interface_attributes.rb +96 -0
- data/lib/virtualbox/abstract_model/relatable.rb +19 -8
- data/lib/virtualbox/appliance.rb +59 -0
- data/lib/virtualbox/audio_adapter.rb +44 -0
- data/lib/virtualbox/bios.rb +44 -0
- data/lib/virtualbox/com.rb +23 -0
- data/lib/virtualbox/com/abstract_enum.rb +42 -0
- data/lib/virtualbox/com/abstract_implementer.rb +43 -0
- data/lib/virtualbox/com/abstract_interface.rb +165 -0
- data/lib/virtualbox/com/ffi/interface.rb +141 -0
- data/lib/virtualbox/com/ffi/interfaces.rb +42 -0
- data/lib/virtualbox/com/ffi/util.rb +101 -0
- data/lib/virtualbox/com/ffi/vboxxpcomc.rb +31 -0
- data/lib/virtualbox/com/ffi_interface.rb +65 -0
- data/lib/virtualbox/com/implementer/base.rb +52 -0
- data/lib/virtualbox/com/implementer/ffi.rb +350 -0
- data/lib/virtualbox/com/implementer/mscom.rb +165 -0
- data/lib/virtualbox/com/implementer/nil.rb +10 -0
- data/lib/virtualbox/com/interface/appliance.rb +20 -0
- data/lib/virtualbox/com/interface/audio_adapter.rb +13 -0
- data/lib/virtualbox/com/interface/audio_controller_type.rb +9 -0
- data/lib/virtualbox/com/interface/audio_driver_type.rb +9 -0
- data/lib/virtualbox/com/interface/bios_boot_menu_mode.rb +9 -0
- data/lib/virtualbox/com/interface/bios_settings.rb +19 -0
- data/lib/virtualbox/com/interface/clipboard_mode.rb +9 -0
- data/lib/virtualbox/com/interface/console.rb +48 -0
- data/lib/virtualbox/com/interface/cpu_property_type.rb +9 -0
- data/lib/virtualbox/com/interface/device_type.rb +9 -0
- data/lib/virtualbox/com/interface/dhcp_server.rb +20 -0
- data/lib/virtualbox/com/interface/firmware_type.rb +9 -0
- data/lib/virtualbox/com/interface/guest_os_type.rb +21 -0
- data/lib/virtualbox/com/interface/host.rb +40 -0
- data/lib/virtualbox/com/interface/host_network_interface.rb +28 -0
- data/lib/virtualbox/com/interface/host_network_interface_medium_type.rb +9 -0
- data/lib/virtualbox/com/interface/host_network_interface_status.rb +9 -0
- data/lib/virtualbox/com/interface/host_network_interface_type.rb +9 -0
- data/lib/virtualbox/com/interface/host_usb_device.rb +11 -0
- data/lib/virtualbox/com/interface/host_usb_device_filter.rb +11 -0
- data/lib/virtualbox/com/interface/hw_virt_ex_property_type.rb +9 -0
- data/lib/virtualbox/com/interface/machine.rb +103 -0
- data/lib/virtualbox/com/interface/machine_state.rb +12 -0
- data/lib/virtualbox/com/interface/medium.rb +48 -0
- data/lib/virtualbox/com/interface/medium_attachment.rb +16 -0
- data/lib/virtualbox/com/interface/medium_format.rb +16 -0
- data/lib/virtualbox/com/interface/medium_state.rb +9 -0
- data/lib/virtualbox/com/interface/medium_type.rb +9 -0
- data/lib/virtualbox/com/interface/medium_variant.rb +9 -0
- data/lib/virtualbox/com/interface/network_adapter.rb +28 -0
- data/lib/virtualbox/com/interface/network_adapter_type.rb +9 -0
- data/lib/virtualbox/com/interface/network_attachment_type.rb +9 -0
- data/lib/virtualbox/com/interface/nsiexception.rb +21 -0
- data/lib/virtualbox/com/interface/nsisupports.rb +13 -0
- data/lib/virtualbox/com/interface/parallel_port.rb +15 -0
- data/lib/virtualbox/com/interface/port_mode.rb +9 -0
- data/lib/virtualbox/com/interface/progress.rb +58 -0
- data/lib/virtualbox/com/interface/serial_port.rb +17 -0
- data/lib/virtualbox/com/interface/session.rb +16 -0
- data/lib/virtualbox/com/interface/session_state.rb +9 -0
- data/lib/virtualbox/com/interface/session_type.rb +9 -0
- data/lib/virtualbox/com/interface/shared_folder.rb +15 -0
- data/lib/virtualbox/com/interface/snapshot.rb +18 -0
- data/lib/virtualbox/com/interface/storage_bus.rb +9 -0
- data/lib/virtualbox/com/interface/storage_controller.rb +21 -0
- data/lib/virtualbox/com/interface/storage_controller_type.rb +9 -0
- data/lib/virtualbox/com/interface/system_properties.rb +35 -0
- data/lib/virtualbox/com/interface/usb_controller.rb +18 -0
- data/lib/virtualbox/com/interface/usb_device.rb +22 -0
- data/lib/virtualbox/com/interface/usb_device_filter.rb +21 -0
- data/lib/virtualbox/com/interface/usb_device_filter_action.rb +9 -0
- data/lib/virtualbox/com/interface/usb_device_state.rb +9 -0
- data/lib/virtualbox/com/interface/virtual_box_error_info.rb +15 -0
- data/lib/virtualbox/com/interface/virtual_system_description.rb +17 -0
- data/lib/virtualbox/com/interface/virtual_system_description_type.rb +12 -0
- data/lib/virtualbox/com/interface/virtual_system_description_value_type.rb +9 -0
- data/lib/virtualbox/com/interface/virtualbox.rb +54 -0
- data/lib/virtualbox/com/interface/vrdp_auth_type.rb +9 -0
- data/lib/virtualbox/com/interface/vrdp_server.rb +17 -0
- data/lib/virtualbox/com/mscom_interface.rb +22 -0
- data/lib/virtualbox/com/util.rb +18 -0
- data/lib/virtualbox/dvd.rb +7 -94
- data/lib/virtualbox/exceptions.rb +24 -0
- data/lib/virtualbox/ext/glob_loader.rb +22 -0
- data/lib/virtualbox/ext/logger.rb +38 -0
- data/lib/virtualbox/ext/platform.rb +1 -1
- data/lib/virtualbox/extra_data.rb +25 -37
- data/lib/virtualbox/forwarded_port.rb +35 -13
- data/lib/virtualbox/global.rb +22 -80
- data/lib/virtualbox/hard_drive.rb +30 -97
- data/lib/virtualbox/lib.rb +82 -0
- data/lib/virtualbox/media.rb +7 -6
- data/lib/virtualbox/medium.rb +138 -0
- data/lib/virtualbox/medium_attachment.rb +61 -0
- data/lib/virtualbox/network_adapter.rb +134 -0
- data/lib/virtualbox/shared_folder.rb +53 -78
- data/lib/virtualbox/storage_controller.rb +76 -20
- data/lib/virtualbox/system_properties.rb +74 -0
- data/lib/virtualbox/usb_controller.rb +55 -0
- data/lib/virtualbox/version.rb +15 -0
- data/lib/virtualbox/virtual_system_description.rb +47 -0
- data/lib/virtualbox/vm.rb +160 -272
- data/test/test_helper.rb +0 -108
- data/test/virtualbox/abstract_model/attributable_test.rb +7 -1
- data/test/virtualbox/abstract_model/dirty_test.rb +1 -1
- data/test/virtualbox/abstract_model/interface_attributes_test.rb +169 -0
- data/test/virtualbox/abstract_model/relatable_test.rb +20 -0
- data/test/virtualbox/abstract_model_test.rb +40 -5
- data/test/virtualbox/appliance_test.rb +152 -0
- data/test/virtualbox/audio_adapter_test.rb +83 -0
- data/test/virtualbox/bios_test.rb +83 -0
- data/test/virtualbox/com/abstract_enum_test.rb +48 -0
- data/test/virtualbox/com/abstract_implementer_test.rb +39 -0
- data/test/virtualbox/com/abstract_interface_test.rb +139 -0
- data/test/virtualbox/com/ffi/interface_test.rb +249 -0
- data/test/virtualbox/com/ffi/util_test.rb +86 -0
- data/test/virtualbox/com/ffi_interface_test.rb +42 -0
- data/test/virtualbox/com/implementer/base_test.rb +37 -0
- data/test/virtualbox/com/implementer/ffi_test.rb +519 -0
- data/test/virtualbox/com/implementer/mscom_test.rb +208 -0
- data/test/virtualbox/com/mscom_interface_test.rb +17 -0
- data/test/virtualbox/com/util_test.rb +17 -0
- data/test/virtualbox/dvd_test.rb +4 -95
- data/test/virtualbox/ext/platform_test.rb +8 -0
- data/test/virtualbox/extra_data_test.rb +78 -102
- data/test/virtualbox/forwarded_port_test.rb +57 -7
- data/test/virtualbox/global_test.rb +25 -115
- data/test/virtualbox/hard_drive_test.rb +49 -212
- data/test/virtualbox/lib_test.rb +93 -0
- data/test/virtualbox/medium_attachment_test.rb +147 -0
- data/test/virtualbox/medium_test.rb +192 -0
- data/test/virtualbox/network_adapter_test.rb +160 -0
- data/test/virtualbox/shared_folder_test.rb +144 -160
- data/test/virtualbox/storage_controller_test.rb +166 -45
- data/test/virtualbox/system_properties_test.rb +87 -0
- data/test/virtualbox/usb_controller_test.rb +104 -0
- data/test/virtualbox/version_test.rb +34 -0
- data/test/virtualbox/virtual_system_description_test.rb +61 -0
- data/test/virtualbox/vm_test.rb +288 -322
- data/test/virtualbox_test.rb +1 -9
- data/virtualbox.gemspec +139 -23
- metadata +143 -27
- data/lib/virtualbox/attached_device.rb +0 -249
- data/lib/virtualbox/command.rb +0 -109
- data/lib/virtualbox/image.rb +0 -137
- data/lib/virtualbox/nic.rb +0 -111
- data/lib/virtualbox/system_property.rb +0 -55
- data/lib/virtualbox/usb.rb +0 -72
- data/test/virtualbox/attached_device_test.rb +0 -303
- data/test/virtualbox/command_test.rb +0 -152
- data/test/virtualbox/image_test.rb +0 -190
- data/test/virtualbox/nic_test.rb +0 -76
- data/test/virtualbox/system_property_test.rb +0 -71
- data/test/virtualbox/usb_test.rb +0 -35
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
class AudioAdapter < AbstractModel
|
|
3
|
+
attribute :parent, :readonly => true, :property => false
|
|
4
|
+
attribute :enabled
|
|
5
|
+
attribute :audio_controller
|
|
6
|
+
attribute :audio_driver
|
|
7
|
+
|
|
8
|
+
class <<self
|
|
9
|
+
# Populates a relationship with another model.
|
|
10
|
+
#
|
|
11
|
+
# **This method typically won't be used except internally.**
|
|
12
|
+
#
|
|
13
|
+
# @return [BIOS]
|
|
14
|
+
def populate_relationship(caller, imachine)
|
|
15
|
+
data = new(caller, imachine.audio_adapter)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Saves the relationship.
|
|
19
|
+
#
|
|
20
|
+
# **This method typically won't be used except internally.**
|
|
21
|
+
def save_relationship(caller, instance)
|
|
22
|
+
instance.save
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(parent, iaudio)
|
|
27
|
+
write_attribute(:parent, parent)
|
|
28
|
+
|
|
29
|
+
# Load the attributes and mark the whole thing as existing
|
|
30
|
+
load_interface_attributes(iaudio)
|
|
31
|
+
clear_dirty!
|
|
32
|
+
existing_record!
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def save
|
|
36
|
+
parent.with_open_session do |session|
|
|
37
|
+
machine = session.machine
|
|
38
|
+
|
|
39
|
+
# Save them
|
|
40
|
+
save_changed_interface_attributes(machine.audio_adapter)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
# Represents the BIOS settings of a {VM}.
|
|
3
|
+
class BIOS < AbstractModel
|
|
4
|
+
attribute :parent, :readonly => true, :property => false
|
|
5
|
+
attribute :acpi_enabled
|
|
6
|
+
attribute :io_apic_enabled
|
|
7
|
+
|
|
8
|
+
class <<self
|
|
9
|
+
# Populates a relationship with another model.
|
|
10
|
+
#
|
|
11
|
+
# **This method typically won't be used except internally.**
|
|
12
|
+
#
|
|
13
|
+
# @return [BIOS]
|
|
14
|
+
def populate_relationship(caller, imachine)
|
|
15
|
+
data = new(caller, imachine.bios_settings)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Saves the relationship.
|
|
19
|
+
#
|
|
20
|
+
# **This method typically won't be used except internally.**
|
|
21
|
+
def save_relationship(caller, instance)
|
|
22
|
+
instance.save
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(parent, bios_settings)
|
|
27
|
+
write_attribute(:parent, parent)
|
|
28
|
+
|
|
29
|
+
# Load the attributes and mark the whole thing as existing
|
|
30
|
+
load_interface_attributes(bios_settings)
|
|
31
|
+
clear_dirty!
|
|
32
|
+
existing_record!
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def save
|
|
36
|
+
parent.with_open_session do |session|
|
|
37
|
+
machine = session.machine
|
|
38
|
+
|
|
39
|
+
# Save them
|
|
40
|
+
save_changed_interface_attributes(machine.bios_settings)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
WSTRING = :unicode_string
|
|
4
|
+
T_INT32 = :int
|
|
5
|
+
T_INT64 = :long
|
|
6
|
+
T_ULONG = :ulong
|
|
7
|
+
T_UINT8 = :uchar
|
|
8
|
+
T_UINT16 = :ushort
|
|
9
|
+
T_UINT32 = :uint
|
|
10
|
+
T_UINT64 = :ulong
|
|
11
|
+
T_BOOL = :char
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# The com directory of the gem
|
|
16
|
+
comdir = File.join(File.dirname(__FILE__), 'com')
|
|
17
|
+
|
|
18
|
+
# Require the abstract interface first then glob load all
|
|
19
|
+
# of the interfaces
|
|
20
|
+
require File.expand_path("abstract_interface", comdir)
|
|
21
|
+
require File.expand_path("abstract_enum", comdir)
|
|
22
|
+
VirtualBox::GlobLoader.glob_require(File.join(comdir, "interface"))
|
|
23
|
+
VirtualBox::GlobLoader.glob_require(comdir, %w{abstract_interface abstract_implementer util ffi/interface ffi/util implementer/base})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
# Represents a C enum type. Provides functionality to easily convert
|
|
4
|
+
# an int value to its proper symbol within the enum.
|
|
5
|
+
class AbstractEnum
|
|
6
|
+
extend Enumerable
|
|
7
|
+
|
|
8
|
+
class <<self
|
|
9
|
+
# Defines the mapping of int => symbol for the given Enum.
|
|
10
|
+
# The parameter to this can be an Array or Hash or anything which
|
|
11
|
+
# can be indexed with `[]` and an integer and returns a value of
|
|
12
|
+
# some sort.
|
|
13
|
+
def map(value)
|
|
14
|
+
@map = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns the symbol associatd with the given key
|
|
18
|
+
def [](key)
|
|
19
|
+
@map[key]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns the index associated with a value
|
|
23
|
+
def index(key)
|
|
24
|
+
@map.index(key)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Iterate over the enum, yielding each item to a block.
|
|
28
|
+
def each
|
|
29
|
+
@map.each do |key|
|
|
30
|
+
yield key
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Provided mostly for testing purposes only, but resets the mapping
|
|
35
|
+
# to nil.
|
|
36
|
+
def reset!
|
|
37
|
+
@map = nil
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
# Base class for a COM interface implementer. Any child of this class is
|
|
4
|
+
# responsible for properly handling the various method and propery calls
|
|
5
|
+
# of a given {AbstractInterface} and making them do actual work.
|
|
6
|
+
#
|
|
7
|
+
# This abstraction is necessary to change the behavior of calls between
|
|
8
|
+
# Windows (COM) and Unix (XPCOM), which have different calling conventions.
|
|
9
|
+
class AbstractImplementer
|
|
10
|
+
attr_reader :interface
|
|
11
|
+
|
|
12
|
+
# Initializes an implementer for the given {AbstractInterface}. The
|
|
13
|
+
# implementor's other methods, such as {read_property} or
|
|
14
|
+
# {call_function} are responsible for executing the said action on
|
|
15
|
+
# the interface.
|
|
16
|
+
#
|
|
17
|
+
# @param [AbstractInterface] interface
|
|
18
|
+
def initialize(interface)
|
|
19
|
+
@interface = interface
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Read a property of the interface.
|
|
23
|
+
#
|
|
24
|
+
# @param [Symbol] name The propery name
|
|
25
|
+
def read_property(name, opts)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Writes a property of the interface.
|
|
29
|
+
#
|
|
30
|
+
# @param [Symbol] name The property name
|
|
31
|
+
# @param [Object] value The value to set
|
|
32
|
+
def write_property(name, value, opts)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Calls a function on the interface.
|
|
36
|
+
#
|
|
37
|
+
# @param [Symbol] name The function name
|
|
38
|
+
# @param [Array] args The arguments to the function
|
|
39
|
+
def call_function(name, args, opts)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
# Base class for a COM (component object model) interface class. This
|
|
4
|
+
# abstraction is necessary to maintain a common ground between
|
|
5
|
+
# Windows COM usage and the VirtualBox C API for unix based systems.
|
|
6
|
+
#
|
|
7
|
+
# # Defining an Interface
|
|
8
|
+
#
|
|
9
|
+
# Defining an interface is done by subclassing AbstractInterface and
|
|
10
|
+
# using the provided class methods to define the COM methods and
|
|
11
|
+
# properties. A small example class is shown below:
|
|
12
|
+
#
|
|
13
|
+
# class Time < AbstractInterface
|
|
14
|
+
# function :now, [[:out, :uint]]
|
|
15
|
+
# property :hour, :uint
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # Accessing an Interface
|
|
19
|
+
#
|
|
20
|
+
# Interfaces are never accessed directly. Instead, an {InterfaceRunner}
|
|
21
|
+
# should be used. Depending on the OS of the running system, the VirtualBox
|
|
22
|
+
# gem will automatically either load the MSCOM interface (on Windows)
|
|
23
|
+
# or the XPCOM interface (on Unix). One loaded, interfaces can simply be
|
|
24
|
+
# accessed:
|
|
25
|
+
#
|
|
26
|
+
# # Assume `time` was retrieved already
|
|
27
|
+
# puts time.foo.to_s
|
|
28
|
+
# time.hour = 20
|
|
29
|
+
# x = time.now
|
|
30
|
+
#
|
|
31
|
+
# The above example shows how the properties and functions can be used
|
|
32
|
+
# with a given interface.
|
|
33
|
+
#
|
|
34
|
+
class AbstractInterface
|
|
35
|
+
attr_reader :implementer
|
|
36
|
+
|
|
37
|
+
class <<self
|
|
38
|
+
# Adds a function to the interface with the given name and function
|
|
39
|
+
# spec. The spec determines the arguments required, the order they
|
|
40
|
+
# are required in, and any out-arguments.
|
|
41
|
+
def function(name, type, spec, opts={})
|
|
42
|
+
members << [name, {
|
|
43
|
+
:type => :function,
|
|
44
|
+
:value_type => type,
|
|
45
|
+
:spec => spec,
|
|
46
|
+
:opts => opts
|
|
47
|
+
}]
|
|
48
|
+
|
|
49
|
+
# Define the method to call the function
|
|
50
|
+
define_method(name) { |*args| call_function(name, *args) }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Adds a property to the interface with the given name, type, and
|
|
54
|
+
# options.
|
|
55
|
+
def property(name, type, opts={})
|
|
56
|
+
members << [name, {
|
|
57
|
+
:type => :property,
|
|
58
|
+
:value_type => type,
|
|
59
|
+
:opts => opts
|
|
60
|
+
}]
|
|
61
|
+
|
|
62
|
+
# Define the method to read the property
|
|
63
|
+
define_method(name) { read_property(name) }
|
|
64
|
+
|
|
65
|
+
# Define method to write the property
|
|
66
|
+
define_method("#{name}=".to_sym) { |value| write_property(name, value) } unless opts[:readonly]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns the information for a given member
|
|
70
|
+
#
|
|
71
|
+
# @return [Hash]
|
|
72
|
+
def member(name)
|
|
73
|
+
members.each do |current_name, opts|
|
|
74
|
+
if name == current_name
|
|
75
|
+
return opts
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns the members of the interface as an array.
|
|
83
|
+
#
|
|
84
|
+
# @return [Array]
|
|
85
|
+
def members
|
|
86
|
+
@members ||= []
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Returns the functions of the interface as an array in the order they
|
|
90
|
+
# were defined.
|
|
91
|
+
#
|
|
92
|
+
# @return [Array]
|
|
93
|
+
def functions
|
|
94
|
+
members.find_all do |data|
|
|
95
|
+
data[1][:type] == :function
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Returns the properties of the interface as an array in the order they
|
|
100
|
+
# were defined.
|
|
101
|
+
#
|
|
102
|
+
# @return [Array]
|
|
103
|
+
def properties
|
|
104
|
+
members.find_all do |data|
|
|
105
|
+
data[1][:type] == :property
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Initializes the interface with the given implementer
|
|
111
|
+
def initialize(implementer, *args)
|
|
112
|
+
# Instantiate the implementer and set it
|
|
113
|
+
@implementer = implementer.new(self, *args)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Reads a property with the given name by calling the read_property
|
|
117
|
+
# method on the implementer.
|
|
118
|
+
def read_property(name)
|
|
119
|
+
# Just call it on the implementer
|
|
120
|
+
@implementer.read_property(name, member(name))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Writes a property with the given name and value by calling the
|
|
124
|
+
# `write_property` method on the implementer.
|
|
125
|
+
def write_property(name, value)
|
|
126
|
+
@implementer.write_property(name, value, member(name))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Calls a function with the given name by calling call_function on the
|
|
130
|
+
# implementer.
|
|
131
|
+
def call_function(name, *args)
|
|
132
|
+
@implementer.call_function(name, args, member(name))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Returns a boolean if a given function exists or not
|
|
136
|
+
def has_function?(name)
|
|
137
|
+
info = member(name)
|
|
138
|
+
!info.nil? && info[:type] == :function
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Returns a boolean if a given property exists or not.
|
|
142
|
+
def has_property?(name)
|
|
143
|
+
info = member(name)
|
|
144
|
+
!info.nil? && info[:type] == :property
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Returns the member of the interface specified by name. This simply
|
|
148
|
+
# calls {AbstractInterface.member}
|
|
149
|
+
def member(name)
|
|
150
|
+
self.class.member(name)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Returns the members of the interface as an array. This simply calls
|
|
154
|
+
# {AbstractInterface.members}.
|
|
155
|
+
def members
|
|
156
|
+
self.class.members
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Concise inspect
|
|
160
|
+
def inspect
|
|
161
|
+
"#<#{self.class.name}>"
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require 'ffi'
|
|
2
|
+
|
|
3
|
+
module VirtualBox
|
|
4
|
+
module COM
|
|
5
|
+
module FFI
|
|
6
|
+
extend ::FFI::Library
|
|
7
|
+
|
|
8
|
+
# FFI specific types
|
|
9
|
+
NSRESULT_TYPE = :uint
|
|
10
|
+
|
|
11
|
+
# Returns a Class which creates an FFI interface to the specified
|
|
12
|
+
# com interface and potentially a parent class as well.
|
|
13
|
+
def self.create_interface(interface, parent=nil)
|
|
14
|
+
klass = Class.new(Interface)
|
|
15
|
+
const_set(interface, klass)
|
|
16
|
+
klass.com_interface(interface, parent)
|
|
17
|
+
klass
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Represents a VirtualBox XPCOM C interface, which is a C struct
|
|
21
|
+
# which emulates an object (a struct with function pointers
|
|
22
|
+
# and getters/setters). This class does **a lot** of magic which pretty
|
|
23
|
+
# much represents everything wrong about ruby programmers, but keep
|
|
24
|
+
# in mind it is well tested and well commented, and the meta-programming
|
|
25
|
+
# was done out of a need to keep things DRY between Windows and Unix
|
|
26
|
+
# operating systems.
|
|
27
|
+
class Interface
|
|
28
|
+
extend ::FFI::Library
|
|
29
|
+
|
|
30
|
+
attr_reader :vtbl_parent
|
|
31
|
+
attr_reader :vtbl
|
|
32
|
+
|
|
33
|
+
class <<self
|
|
34
|
+
# Sets up the args to the FFI::Struct `layout` method. This
|
|
35
|
+
# method defines all the callbacks necessary for working with
|
|
36
|
+
# FFI and also sets up any layout args to send in. The way the
|
|
37
|
+
# XPCOM C structs are setup, the properties are first, in
|
|
38
|
+
# `GetFoo` and `SetFoo` format. And the functions are next. They are
|
|
39
|
+
# put into the struct in the order defined in the {AbstractInterface}.
|
|
40
|
+
def com_interface(interface, parent=nil)
|
|
41
|
+
# Create the parent class and vtbl class
|
|
42
|
+
interface = ::VirtualBox::COM::Interface.const_get(interface)
|
|
43
|
+
define_vtbl_parent_for_interface(interface)
|
|
44
|
+
define_vtbl_for_interface(interface, parent)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Creates the parent of the vtbl class associated with a given
|
|
48
|
+
# interface.
|
|
49
|
+
def define_vtbl_parent_for_interface(interface)
|
|
50
|
+
@vtbl_parent_klass = Class.new(::FFI::Struct)
|
|
51
|
+
@vtbl_parent_klass.layout(:vtbl, :pointer)
|
|
52
|
+
|
|
53
|
+
# Set the constant
|
|
54
|
+
const_set("VtblParent", @vtbl_parent_klass)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Creates the vtbl class associated with a given interface.
|
|
58
|
+
def define_vtbl_for_interface(interface, parent=nil)
|
|
59
|
+
# Define the properties, then the functions, since thats the order
|
|
60
|
+
# the FFI structs are in
|
|
61
|
+
layout_args.clear
|
|
62
|
+
define_interface_parent(parent)
|
|
63
|
+
define_interface_properties(interface)
|
|
64
|
+
define_interface_functions(interface)
|
|
65
|
+
|
|
66
|
+
# Finally create the classes (the struct and the structs vtbl)
|
|
67
|
+
@vtbl_klass = Class.new(::FFI::Struct)
|
|
68
|
+
|
|
69
|
+
# Set the constant within this class
|
|
70
|
+
const_set("Vtbl", @vtbl_klass).layout(*layout_args.flatten)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Defines the parent item of the layout. Since the VirtualBox XPCOM C
|
|
74
|
+
# library emulates an object-oriented environment using structs, the parent
|
|
75
|
+
# instance is pointed to by the first member of the struct. This method
|
|
76
|
+
# sets up that member.
|
|
77
|
+
#
|
|
78
|
+
# @param [Symbol] parent The name of the parent represented by a symbol
|
|
79
|
+
def define_interface_parent(parent)
|
|
80
|
+
return if parent.nil?
|
|
81
|
+
|
|
82
|
+
parent_klass = Object.module_eval("::VirtualBox::COM::FFI::#{parent}::Vtbl")
|
|
83
|
+
layout_args << [:superklass, parent_klass]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Defines all the properties on a com interface.
|
|
87
|
+
def define_interface_properties(interface)
|
|
88
|
+
interface.properties.each do |name, opts|
|
|
89
|
+
# Define the getter
|
|
90
|
+
define_interface_function("get_#{name}".to_sym, opts[:value_type])
|
|
91
|
+
|
|
92
|
+
# Define the setter unless the property is readonly
|
|
93
|
+
define_interface_function("set_#{name}".to_sym, nil, [opts[:value_type]]) unless opts[:opts] && opts[:opts][:readonly]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Defines all the functions on a com interface.
|
|
98
|
+
def define_interface_functions(interface)
|
|
99
|
+
interface.functions.each do |name, opts|
|
|
100
|
+
# Define the function
|
|
101
|
+
define_interface_function(name, opts[:value_type], opts[:spec].dup)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Defines a single function of a com interface
|
|
106
|
+
def define_interface_function(name, return_type, spec=[])
|
|
107
|
+
# Append the return type to the spec as an out parameter (this is how
|
|
108
|
+
# the C API handles it)
|
|
109
|
+
spec << [:out, return_type] unless return_type.nil?
|
|
110
|
+
|
|
111
|
+
# Define the "callback" type for the FFI module
|
|
112
|
+
callback(name, Util.spec_to_ffi(spec), NSRESULT_TYPE)
|
|
113
|
+
|
|
114
|
+
# Add to the layout args
|
|
115
|
+
layout_args << [name, name]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Returns an array of the layout args to send to `layout` eventually.
|
|
119
|
+
#
|
|
120
|
+
# @return [Array]
|
|
121
|
+
def layout_args
|
|
122
|
+
@_layout_args ||= []
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Initializes the interface to the FFI struct with the given pointer. The
|
|
127
|
+
# pointer is used to initialize the VtblParent which is used to initialize
|
|
128
|
+
# the Vtbl itself.
|
|
129
|
+
def initialize(pointer)
|
|
130
|
+
initialize_vtbl(pointer)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def initialize_vtbl(pointer)
|
|
134
|
+
klass = self.class
|
|
135
|
+
@vtbl_parent = klass::VtblParent.new(pointer)
|
|
136
|
+
@vtbl = klass::Vtbl.new(vtbl_parent[:vtbl])
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|