virtualbox-com 0.9.6

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.
@@ -0,0 +1,97 @@
1
+ require_relative '4.2-gen'
2
+
3
+ module VirtualBox
4
+ module COM
5
+ module Model
6
+
7
+ class Progress < AbstractInterface
8
+ # This method blocks the execution while the operations represented
9
+ # by this {Progress} object execute, but yields a block every `x`
10
+ # percent (interval given in parameters).
11
+ def wait(interval_percent=1)
12
+ # If no block is given we just wait until completion, not worrying
13
+ # about tracking percentages.
14
+ if !block_given?
15
+ wait_for_completion(-1)
16
+ return
17
+ end
18
+
19
+ # Initial value forces the 0% yield
20
+ last_reported = -100
21
+
22
+ while true
23
+ delta = percent - last_reported
24
+ last_reported += delta
25
+ yield self if delta >= interval_percent
26
+
27
+ # This either sleeps for half a second or returns on completion
28
+ wait_for_completion(500)
29
+
30
+ break if completed || canceled
31
+
32
+ # Pass off execution so other threads can run
33
+ Thread.pass
34
+ end
35
+ end
36
+ end
37
+
38
+
39
+ class EventSource < AbstractInterface
40
+ MODEL_MAP = {
41
+ :machine_event => :MachineEvent,
42
+ :snapshot_event => :SnapshotEvent,
43
+ :on_machine_state_changed => :MachineStateChangedEvent,
44
+ :on_machine_data_changed => :MachineDataChangedEvent,
45
+ :on_extra_data_changed => :ExtraDataChangedEvent,
46
+ :on_extra_data_can_change => :ExtraDataCanChangeEvent,
47
+ :on_medium_registered => :MediumRegisteredEvent,
48
+ :on_machine_registered => :MachineRegisteredEvent,
49
+ :on_session_state_changed => :SessionStateChangedEvent,
50
+ :on_snapshot_taken => :SnapshotTakenEvent,
51
+ :on_snapshot_deleted => :SnapshotDeletedEvent,
52
+ :on_snapshot_changed => :SnapshotChangedEvent,
53
+ :on_guest_property_changed => :GuestPropertyChangedEvent,
54
+ :on_mouse_pointer_shape_changed => :MousePointerShapEvent,
55
+ :on_mouse_capability_changed => :MouseCapabilityChangedEvent,
56
+ :on_keyboard_leds_changed => :KeyboardLedsChangedEvent,
57
+ :on_state_changed => :StateChangedEvent,
58
+ :on_additions_state_changed => :AdditionsStateChangedEvent,
59
+ :on_network_adapter_changed => :NetworkAdapterChangedEvent,
60
+ :on_serial_port_changed => :SerialPortChangedEvent,
61
+ :on_parallel_port_changed => :ParallelPortChangedEvent,
62
+ :on_storage_controller_changed => :StorageControllerChangedEvent,
63
+ :on_medium_changed => :MediumChangedEvent,
64
+ :on_vrde_server_changed => :VRDEServerChangedEvent,
65
+ :on_usb_controller_changed => :USBControllerChangedEvent,
66
+ :on_usb_device_state_changed => :USBDeviceStateChangedEvent,
67
+ :on_shared_folder_changed => :SharedFolderChangedEvent,
68
+ :on_runtime_error => :RuntimeErrorEvent,
69
+ :on_can_show_window => :CanShowWindowEvent,
70
+ :on_show_window => :ShowWindowEvent,
71
+ :on_cpu_changed => :CPUChangedEvent,
72
+ :on_vrde_server_info_changed => :VRDEServerInfoChangedEvent,
73
+ :on_event_source_changed => :EventSourceChangedEvent,
74
+ :on_cpu_execution_cap_changed => :CPUExecutionCapChangedEvent,
75
+ :on_guest_keyboard => :GuestKeyboardEvent,
76
+ :on_guest_mouse => :GuestMouseEvent,
77
+ :on_nat_redirect => :NATRedirectEvent,
78
+ :on_host_pci_device_plug => :HostPCIDevicePlugEvent,
79
+ :on_vbox_svc_availability_changed => :VBoxSVCAvailabilityChangedEvent,
80
+ :on_bandwidth_group_changed => :BandwidthGroupChangedEvent,
81
+ :on_guest_monitor_changed => :GuestMonitorChangedEvent,
82
+ :on_storage_device_changed => :StorageDeviceChangedEvent,
83
+ :on_clipboard_mode_changed => :ClipboardModeChangedEvent,
84
+ :on_drag_and_drop_mode_changed => :DragAndDropModeChangedEvent,
85
+ }
86
+
87
+ def getEvent(*args)
88
+ if e = get_event(*args)
89
+ (model = MODEL_MAP[e.type]) ? e.cast(model) : e
90
+ end
91
+ end
92
+ end
93
+
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,119 @@
1
+ module VirtualBox
2
+ module COM
3
+
4
+ module Util
5
+ def self.platform
6
+ case RbConfig::CONFIG["host_os"].downcase
7
+ when /darwin/ then :mac
8
+ when /mswin|mingw|cygwin/ then :windows
9
+ when /linux/ then :linux
10
+ when /solaris/ then :solaris
11
+ when /freebsd/ then :freebsd
12
+ else :unknown
13
+ end
14
+ end
15
+ def self.jruby?
16
+ RbConfig::CONFIG["ruby_install_name"] == "jruby"
17
+ end
18
+
19
+
20
+ # An "almost complete" camel-caser. Camel cases a string with a few
21
+ # exceptions. For example: `get_foo` becomes `GetFoo`, but `get_os_type`
22
+ # becomes `GetOSType` since `os` is a special case.
23
+ #
24
+ # @param [String] string The string to camel case
25
+ # @return [String]
26
+ def self.camelize(string)
27
+ string.to_s.split(/_/).map {|part|
28
+ CAMELCASE_SPECIALS[part] || part.capitalize }.join
29
+ end
30
+
31
+ def self.uncamelize(name)
32
+ CAMELCASE_SPECIALS.each{|k,v|
33
+ name = name.gsub(v, k.capitalize) }
34
+ name.gsub(/([A-Z])/, "_\\0").downcase.gsub(/^_/, '')
35
+ end
36
+
37
+ CAMELCASE_SPECIALS = { # Order is important
38
+ "fourcc_rgb" => "FOURCC_RGB",
39
+ "am79c970a" => "Am79C970A",
40
+ "am79c973" => "Am79C973",
41
+ "i82540em" => "I82540EM",
42
+ "i82543gc" => "I82543GC",
43
+ "i82545em" => "I82545EM",
44
+ "efidual" => "EFIDUAL",
45
+ "split2g" => "Split2G",
46
+ "cpuid" => "CPUID",
47
+ "cdrom" => "CDROM",
48
+ "efi32" => "EFI32",
49
+ "efi64" => "EFI64",
50
+ "piix3" => "PIIX3",
51
+ "piix4" => "PIIX4",
52
+ "winmm" => "WinMM",
53
+ "ac97" => "AC97",
54
+ "acpi" => "ACPI",
55
+ "alsa" => "ALSA",
56
+ "apic" => "APIC",
57
+ "bios" => "BIOS",
58
+ "csam" => "CSAM",
59
+ "dhcp" => "DHCP",
60
+ "fifo" => "FIFO",
61
+ "ich6" => "ICH6",
62
+ "ich9" => "ICH9",
63
+ "macs" => "MACs",
64
+ "mmpm" => "MMPM",
65
+ "patm" => "PATM",
66
+ "sata" => "SATA",
67
+ "sb16" => "SB16",
68
+ "scsi" => "SCSI",
69
+ "slip" => "SLIP",
70
+ "tftp" => "TFTP",
71
+ "vbox" => "VBox",
72
+ "vpid" => "VPID",
73
+ "vram" => "VRAM",
74
+ "vrde" => "VRDE",
75
+ "vrdp" => "VRDP",
76
+ "api" => "API",
77
+ "cpu" => "CPU",
78
+ "dns" => "DNS",
79
+ "dvd" => "DVD",
80
+ "efi" => "EFI",
81
+ "esx" => "ESX",
82
+ "gid" => "GID",
83
+ "hda" => "HDA",
84
+ "hdd" => "HDD",
85
+ "ide" => "IDE",
86
+ "irq" => "IRQ",
87
+ "mac" => "MAC",
88
+ "nat" => "NAT",
89
+ "oss" => "OSS",
90
+ "pae" => "PAE",
91
+ "pci" => "PCI",
92
+ "pid" => "PID",
93
+ "png" => "PNG",
94
+ "ppp" => "PPP",
95
+ "ps2" => "PS2",
96
+ "pxe" => "PXE",
97
+ "ram" => "RAM",
98
+ "rtc" => "RTC",
99
+ "sas" => "SAS",
100
+ "svc" => "SVC",
101
+ "tcp" => "TCP",
102
+ "udp" => "UDP",
103
+ "uid" => "UID",
104
+ "usb" => "USB",
105
+ "utc" => "UTC",
106
+ "vdi" => "VDI",
107
+ "vfs" => "VFS",
108
+ "3d" => "3D",
109
+ "hw" => "HW",
110
+ "io" => "IO",
111
+ "ip" => "IP",
112
+ "os" => "OS",
113
+ "vm" => "VM",
114
+ }
115
+
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,5 @@
1
+ module VirtualBox
2
+ module COM
3
+ VERSION = "0.9.6"
4
+ end
5
+ end
@@ -0,0 +1,76 @@
1
+ # Load FFI support
2
+ if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
3
+ require 'ffi'
4
+ end
5
+
6
+
7
+ # Add model types to fit XPCOMC FFI implementation:
8
+ # INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64, WSTRING, BOOL
9
+ require_relative 'xpcomc-ffi/model-types'
10
+
11
+ module VirtualBox
12
+ module COM
13
+ class IID
14
+ class FFIStruct < ::FFI::Struct
15
+ layout :m0, :uint32,
16
+ :m1, :uint16,
17
+ :m2, :uint16,
18
+ :m3, [:uint8, 8]
19
+ end
20
+
21
+ def to_ffi
22
+ @ffi ||= begin
23
+ data = FFIStruct.new
24
+ data[:m0] = to_a[0]
25
+ data[:m1] = to_a[1]
26
+ data[:m2] = to_a[2]
27
+ to_a[3..-1].each_index{|i| data[:m3][i] = to_a[3..-1][i] }
28
+ data.freeze
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ module VirtualBox
36
+ module COM
37
+ class AbstractInterface
38
+ def self.to_ffi
39
+ :pointer
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+
46
+ module VirtualBox
47
+ module COM
48
+ class AbstractEnum
49
+ def self.to_ffi
50
+ UINT32
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+ # Load FFI implementation
58
+ require_relative 'xpcomc-ffi/xpcomc-vbox'
59
+ require_relative 'xpcomc-ffi/binding'
60
+ require_relative 'xpcomc-ffi/implementer'
61
+ require_relative 'xpcomc-ffi/spec'
62
+ require_relative 'xpcomc-ffi/lib'
63
+
64
+ # Patch VirtualBox::COM
65
+ module VirtualBox
66
+ module COM
67
+ Implementer = XPCOMC::Implementer
68
+ Spec = XPCOMC::Spec
69
+
70
+ def self.virtualbox ; XPCOMC::Lib.virtualbox ; end
71
+ def self.session ; XPCOMC::Lib.session ; end
72
+ end
73
+ end
74
+
75
+ # Init library
76
+ VirtualBox::COM::XPCOMC::Lib.init
@@ -0,0 +1,87 @@
1
+ module VirtualBox
2
+ module COM
3
+ module XPCOMC
4
+
5
+ # The Binding class hold all the FFI infrastructure
6
+ class Binding
7
+ extend ::FFI::Library
8
+ attr_reader :object
9
+
10
+
11
+ # Retrieve a Binding class corresponding to the Model
12
+ # This will avoid polluting the model object with implementation data
13
+ def self.get(name)
14
+ Binding.const_get(name, false)
15
+ rescue NameError
16
+ const_set(name, Class.new(Binding)).bind(Model.get(name))
17
+ end
18
+
19
+
20
+ # Create the binding with the Model class
21
+ # This will also create the internal classes Object and Vtbl
22
+ # representing the FFI::Struct, all the necessary callbacks,
23
+ # a hash of the name/signatures
24
+ def self.bind(model)
25
+ raise "model already bound" if const_defined?(:Object, false)
26
+
27
+ # List of functions (name, signature)
28
+ # Defined in the order they appear in the Model definition
29
+ sigs = model.members.inject({}) do |list, spec|
30
+ list.merge!(spec.signatures)
31
+ end
32
+ const_set(:Sig, sigs)
33
+
34
+ # Register ffi callbacks
35
+ sigs.each {|name, sig| callback(name, sig.to_ffi, :uint) }
36
+
37
+ # Object layout
38
+ const_set(:Object, Class.new(::FFI::Struct))
39
+ .layout(:vtbl, :pointer)
40
+
41
+ # Vtbl layout
42
+ const_set(:Vtbl, Class.new(::FFI::Struct))
43
+ .layout(*sigs.map {|name,| [name, name] }.flatten)
44
+
45
+ # IID
46
+ const_set(:IID, model::IID.to_ffi)
47
+
48
+ # Model
49
+ const_set(:Model, model)
50
+
51
+ self
52
+ end
53
+
54
+
55
+ # Initializes the interface to the FFI struct with the given pointer. The
56
+ # pointer is used to initialize the Object which is used to initialize
57
+ # the Vtbl itself.
58
+ def initialize(pointer)
59
+ @object = self.class::Object.new(pointer)
60
+ @vtbl = self.class::Vtbl.new(@object[:vtbl])
61
+ end
62
+
63
+
64
+ # Calls a function on the vtbl of the FFI struct. This function handles
65
+ # converting the spec to proper arguments and also handles reading out
66
+ # the arguments, dereferencing pointers, setting up objects, etc. so that
67
+ # the return value is filled with nicely formatted Ruby objects.
68
+ #
69
+ # If the vtbl function being called only has one out parameter, then the
70
+ # return value will be that single object. If it has multiple, then it will
71
+ # be an array of objects.
72
+ def call(name, *args)
73
+ unless sig = self.class::Sig[name]
74
+ raise ArgumentError, "unknown function #{name} in Vtbl"
75
+ end
76
+ ffi_args = sig.prepare_args(args)
77
+ result = @vtbl[name].call(@object, *ffi_args)
78
+ if (result & 0x8000_0000) != 0
79
+ raise COMException, :vtbl => name, :code => result
80
+ end
81
+ sig.retrieve_values(ffi_args)
82
+ end
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,86 @@
1
+ module VirtualBox
2
+ module COM
3
+ module XPCOMC
4
+
5
+ # Implementer is a wrapper for the Binding class.
6
+ # Performs lazy initialisation and enhance function call
7
+ class Implementer
8
+ EXCEPTION_MAP = Hash.new(COMException).merge!({
9
+ 0x8000_4001 => NotImplementedException,
10
+ 0x8000_4002 => NoInterfaceException,
11
+ 0x80BB_0001 => ObjectNotFoundException,
12
+ 0x80BB_0002 => InvalidVMStateException,
13
+ 0x80BB_0003 => VMErrorException,
14
+ 0x80BB_0004 => FileErrorException,
15
+ 0x80BB_0005 => SubsystemException,
16
+ 0x80BB_0006 => PDMException,
17
+ 0x80BB_0007 => InvalidObjectStateException,
18
+ 0x80BB_0008 => HostErrorException,
19
+ 0x80BB_0009 => NotSupportedException,
20
+ 0x80BB_000A => XMLErrorException,
21
+ 0x80BB_000B => InvalidSessionStateException,
22
+ 0x80BB_000C => ObjectInUseException,
23
+ 0x8007_0057 => InvalidArgException
24
+ }).freeze
25
+
26
+
27
+ # Initialize implementation of the COM interface
28
+ def initialize(interface, pointer)
29
+ unless interface.kind_of?(AbstractInterface)
30
+ raise ArgumentError, "only COM interface can be implemented"
31
+ end
32
+ @interface = interface # For lazy creation of the
33
+ @pointer = pointer # "binding" attribute
34
+ end
35
+
36
+
37
+ # Cast to another interface.
38
+ # Will raise NoInterfaceException if not supported
39
+ def cast(interface, pointer)
40
+ iid = Binding.get(interface)::IID
41
+ Model.create(interface, binding.call(:QueryInterface, iid))
42
+ rescue COMException => e
43
+ e.data.merge!(:mode => :cast)
44
+ raise EXCEPTION_MAP[e.data[:code]], e.data
45
+ end
46
+
47
+ # Reads a property
48
+ def read_property(spec)
49
+ binding.call(spec.getter)
50
+ rescue COMException => e
51
+ e.data.merge!(:property => spec.name, :mode => :read)
52
+ raise EXCEPTION_MAP[e.data[:code]], e.data
53
+ end
54
+
55
+ # Writes a property
56
+ def write_property(spec, value)
57
+ binding.call(spec.setter, [value])
58
+ rescue COMException => e
59
+ e.data.merge!(:property => spec.name, :mode => :write)
60
+ raise EXCEPTION_MAP[e.data[:code]], e.data
61
+ end
62
+
63
+ # Calls a function
64
+ def call_function(spec, *args)
65
+ binding.call(spec.name, *args)
66
+ rescue COMException => e
67
+ e.data.merge!(:function => spec.name, :mode => :call)
68
+ raise EXCEPTION_MAP[e.data[:code]], e.data
69
+ end
70
+
71
+
72
+ #--[ Private ]---------------------------------------------------------
73
+ # private
74
+
75
+ # Lazy initialisation of the binding attribute
76
+ def binding
77
+ @binding ||= begin
78
+ name = @interface.class.name.split("::").last
79
+ Binding.get(name).new(@pointer)
80
+ end
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+ end