virtualbox-com 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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