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.
Files changed (162) hide show
  1. data/.gitignore +2 -1
  2. data/Gemfile +1 -1
  3. data/Rakefile +1 -1
  4. data/Readme.md +5 -21
  5. data/VERSION +1 -1
  6. data/docs/WhatsNew.md +9 -47
  7. data/lib/virtualbox.rb +7 -30
  8. data/lib/virtualbox/abstract_model.rb +25 -5
  9. data/lib/virtualbox/abstract_model/attributable.rb +5 -1
  10. data/lib/virtualbox/abstract_model/dirty.rb +2 -0
  11. data/lib/virtualbox/abstract_model/interface_attributes.rb +96 -0
  12. data/lib/virtualbox/abstract_model/relatable.rb +19 -8
  13. data/lib/virtualbox/appliance.rb +59 -0
  14. data/lib/virtualbox/audio_adapter.rb +44 -0
  15. data/lib/virtualbox/bios.rb +44 -0
  16. data/lib/virtualbox/com.rb +23 -0
  17. data/lib/virtualbox/com/abstract_enum.rb +42 -0
  18. data/lib/virtualbox/com/abstract_implementer.rb +43 -0
  19. data/lib/virtualbox/com/abstract_interface.rb +165 -0
  20. data/lib/virtualbox/com/ffi/interface.rb +141 -0
  21. data/lib/virtualbox/com/ffi/interfaces.rb +42 -0
  22. data/lib/virtualbox/com/ffi/util.rb +101 -0
  23. data/lib/virtualbox/com/ffi/vboxxpcomc.rb +31 -0
  24. data/lib/virtualbox/com/ffi_interface.rb +65 -0
  25. data/lib/virtualbox/com/implementer/base.rb +52 -0
  26. data/lib/virtualbox/com/implementer/ffi.rb +350 -0
  27. data/lib/virtualbox/com/implementer/mscom.rb +165 -0
  28. data/lib/virtualbox/com/implementer/nil.rb +10 -0
  29. data/lib/virtualbox/com/interface/appliance.rb +20 -0
  30. data/lib/virtualbox/com/interface/audio_adapter.rb +13 -0
  31. data/lib/virtualbox/com/interface/audio_controller_type.rb +9 -0
  32. data/lib/virtualbox/com/interface/audio_driver_type.rb +9 -0
  33. data/lib/virtualbox/com/interface/bios_boot_menu_mode.rb +9 -0
  34. data/lib/virtualbox/com/interface/bios_settings.rb +19 -0
  35. data/lib/virtualbox/com/interface/clipboard_mode.rb +9 -0
  36. data/lib/virtualbox/com/interface/console.rb +48 -0
  37. data/lib/virtualbox/com/interface/cpu_property_type.rb +9 -0
  38. data/lib/virtualbox/com/interface/device_type.rb +9 -0
  39. data/lib/virtualbox/com/interface/dhcp_server.rb +20 -0
  40. data/lib/virtualbox/com/interface/firmware_type.rb +9 -0
  41. data/lib/virtualbox/com/interface/guest_os_type.rb +21 -0
  42. data/lib/virtualbox/com/interface/host.rb +40 -0
  43. data/lib/virtualbox/com/interface/host_network_interface.rb +28 -0
  44. data/lib/virtualbox/com/interface/host_network_interface_medium_type.rb +9 -0
  45. data/lib/virtualbox/com/interface/host_network_interface_status.rb +9 -0
  46. data/lib/virtualbox/com/interface/host_network_interface_type.rb +9 -0
  47. data/lib/virtualbox/com/interface/host_usb_device.rb +11 -0
  48. data/lib/virtualbox/com/interface/host_usb_device_filter.rb +11 -0
  49. data/lib/virtualbox/com/interface/hw_virt_ex_property_type.rb +9 -0
  50. data/lib/virtualbox/com/interface/machine.rb +103 -0
  51. data/lib/virtualbox/com/interface/machine_state.rb +12 -0
  52. data/lib/virtualbox/com/interface/medium.rb +48 -0
  53. data/lib/virtualbox/com/interface/medium_attachment.rb +16 -0
  54. data/lib/virtualbox/com/interface/medium_format.rb +16 -0
  55. data/lib/virtualbox/com/interface/medium_state.rb +9 -0
  56. data/lib/virtualbox/com/interface/medium_type.rb +9 -0
  57. data/lib/virtualbox/com/interface/medium_variant.rb +9 -0
  58. data/lib/virtualbox/com/interface/network_adapter.rb +28 -0
  59. data/lib/virtualbox/com/interface/network_adapter_type.rb +9 -0
  60. data/lib/virtualbox/com/interface/network_attachment_type.rb +9 -0
  61. data/lib/virtualbox/com/interface/nsiexception.rb +21 -0
  62. data/lib/virtualbox/com/interface/nsisupports.rb +13 -0
  63. data/lib/virtualbox/com/interface/parallel_port.rb +15 -0
  64. data/lib/virtualbox/com/interface/port_mode.rb +9 -0
  65. data/lib/virtualbox/com/interface/progress.rb +58 -0
  66. data/lib/virtualbox/com/interface/serial_port.rb +17 -0
  67. data/lib/virtualbox/com/interface/session.rb +16 -0
  68. data/lib/virtualbox/com/interface/session_state.rb +9 -0
  69. data/lib/virtualbox/com/interface/session_type.rb +9 -0
  70. data/lib/virtualbox/com/interface/shared_folder.rb +15 -0
  71. data/lib/virtualbox/com/interface/snapshot.rb +18 -0
  72. data/lib/virtualbox/com/interface/storage_bus.rb +9 -0
  73. data/lib/virtualbox/com/interface/storage_controller.rb +21 -0
  74. data/lib/virtualbox/com/interface/storage_controller_type.rb +9 -0
  75. data/lib/virtualbox/com/interface/system_properties.rb +35 -0
  76. data/lib/virtualbox/com/interface/usb_controller.rb +18 -0
  77. data/lib/virtualbox/com/interface/usb_device.rb +22 -0
  78. data/lib/virtualbox/com/interface/usb_device_filter.rb +21 -0
  79. data/lib/virtualbox/com/interface/usb_device_filter_action.rb +9 -0
  80. data/lib/virtualbox/com/interface/usb_device_state.rb +9 -0
  81. data/lib/virtualbox/com/interface/virtual_box_error_info.rb +15 -0
  82. data/lib/virtualbox/com/interface/virtual_system_description.rb +17 -0
  83. data/lib/virtualbox/com/interface/virtual_system_description_type.rb +12 -0
  84. data/lib/virtualbox/com/interface/virtual_system_description_value_type.rb +9 -0
  85. data/lib/virtualbox/com/interface/virtualbox.rb +54 -0
  86. data/lib/virtualbox/com/interface/vrdp_auth_type.rb +9 -0
  87. data/lib/virtualbox/com/interface/vrdp_server.rb +17 -0
  88. data/lib/virtualbox/com/mscom_interface.rb +22 -0
  89. data/lib/virtualbox/com/util.rb +18 -0
  90. data/lib/virtualbox/dvd.rb +7 -94
  91. data/lib/virtualbox/exceptions.rb +24 -0
  92. data/lib/virtualbox/ext/glob_loader.rb +22 -0
  93. data/lib/virtualbox/ext/logger.rb +38 -0
  94. data/lib/virtualbox/ext/platform.rb +1 -1
  95. data/lib/virtualbox/extra_data.rb +25 -37
  96. data/lib/virtualbox/forwarded_port.rb +35 -13
  97. data/lib/virtualbox/global.rb +22 -80
  98. data/lib/virtualbox/hard_drive.rb +30 -97
  99. data/lib/virtualbox/lib.rb +82 -0
  100. data/lib/virtualbox/media.rb +7 -6
  101. data/lib/virtualbox/medium.rb +138 -0
  102. data/lib/virtualbox/medium_attachment.rb +61 -0
  103. data/lib/virtualbox/network_adapter.rb +134 -0
  104. data/lib/virtualbox/shared_folder.rb +53 -78
  105. data/lib/virtualbox/storage_controller.rb +76 -20
  106. data/lib/virtualbox/system_properties.rb +74 -0
  107. data/lib/virtualbox/usb_controller.rb +55 -0
  108. data/lib/virtualbox/version.rb +15 -0
  109. data/lib/virtualbox/virtual_system_description.rb +47 -0
  110. data/lib/virtualbox/vm.rb +160 -272
  111. data/test/test_helper.rb +0 -108
  112. data/test/virtualbox/abstract_model/attributable_test.rb +7 -1
  113. data/test/virtualbox/abstract_model/dirty_test.rb +1 -1
  114. data/test/virtualbox/abstract_model/interface_attributes_test.rb +169 -0
  115. data/test/virtualbox/abstract_model/relatable_test.rb +20 -0
  116. data/test/virtualbox/abstract_model_test.rb +40 -5
  117. data/test/virtualbox/appliance_test.rb +152 -0
  118. data/test/virtualbox/audio_adapter_test.rb +83 -0
  119. data/test/virtualbox/bios_test.rb +83 -0
  120. data/test/virtualbox/com/abstract_enum_test.rb +48 -0
  121. data/test/virtualbox/com/abstract_implementer_test.rb +39 -0
  122. data/test/virtualbox/com/abstract_interface_test.rb +139 -0
  123. data/test/virtualbox/com/ffi/interface_test.rb +249 -0
  124. data/test/virtualbox/com/ffi/util_test.rb +86 -0
  125. data/test/virtualbox/com/ffi_interface_test.rb +42 -0
  126. data/test/virtualbox/com/implementer/base_test.rb +37 -0
  127. data/test/virtualbox/com/implementer/ffi_test.rb +519 -0
  128. data/test/virtualbox/com/implementer/mscom_test.rb +208 -0
  129. data/test/virtualbox/com/mscom_interface_test.rb +17 -0
  130. data/test/virtualbox/com/util_test.rb +17 -0
  131. data/test/virtualbox/dvd_test.rb +4 -95
  132. data/test/virtualbox/ext/platform_test.rb +8 -0
  133. data/test/virtualbox/extra_data_test.rb +78 -102
  134. data/test/virtualbox/forwarded_port_test.rb +57 -7
  135. data/test/virtualbox/global_test.rb +25 -115
  136. data/test/virtualbox/hard_drive_test.rb +49 -212
  137. data/test/virtualbox/lib_test.rb +93 -0
  138. data/test/virtualbox/medium_attachment_test.rb +147 -0
  139. data/test/virtualbox/medium_test.rb +192 -0
  140. data/test/virtualbox/network_adapter_test.rb +160 -0
  141. data/test/virtualbox/shared_folder_test.rb +144 -160
  142. data/test/virtualbox/storage_controller_test.rb +166 -45
  143. data/test/virtualbox/system_properties_test.rb +87 -0
  144. data/test/virtualbox/usb_controller_test.rb +104 -0
  145. data/test/virtualbox/version_test.rb +34 -0
  146. data/test/virtualbox/virtual_system_description_test.rb +61 -0
  147. data/test/virtualbox/vm_test.rb +288 -322
  148. data/test/virtualbox_test.rb +1 -9
  149. data/virtualbox.gemspec +139 -23
  150. metadata +143 -27
  151. data/lib/virtualbox/attached_device.rb +0 -249
  152. data/lib/virtualbox/command.rb +0 -109
  153. data/lib/virtualbox/image.rb +0 -137
  154. data/lib/virtualbox/nic.rb +0 -111
  155. data/lib/virtualbox/system_property.rb +0 -55
  156. data/lib/virtualbox/usb.rb +0 -72
  157. data/test/virtualbox/attached_device_test.rb +0 -303
  158. data/test/virtualbox/command_test.rb +0 -152
  159. data/test/virtualbox/image_test.rb +0 -190
  160. data/test/virtualbox/nic_test.rb +0 -76
  161. data/test/virtualbox/system_property_test.rb +0 -71
  162. 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