Class: VirtualBox::COM::FFI::Interface

Inherits:
Object
  • Object
show all
Extended by:
FFI::Library
Defined in:
lib/virtualbox/com/ffi/interface.rb

Overview

Represents a VirtualBox XPCOM C interface, which is a C struct which emulates an object (a struct with function pointers and getters/setters). This class does **a lot** of magic which pretty much represents everything wrong about ruby programmers, but keep in mind it is well tested and well commented, and the meta-programming was done out of a need to keep things DRY between Windows and Unix operating systems.

Constant Summary collapse

NSRESULT_TYPE =

FFI specific types

:uint

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pointer) ⇒ Interface

Initializes the interface to the FFI struct with the given pointer. The pointer is used to initialize the VtblParent which is used to initialize the Vtbl itself.



121
122
123
# File 'lib/virtualbox/com/ffi/interface.rb', line 121

def initialize(pointer)
  initialize_vtbl(pointer)
end

Instance Attribute Details

#vtblObject (readonly)

Returns the value of attribute vtbl.



20
21
22
# File 'lib/virtualbox/com/ffi/interface.rb', line 20

def vtbl
  @vtbl
end

#vtbl_parentObject (readonly)

Returns the value of attribute vtbl_parent.



19
20
21
# File 'lib/virtualbox/com/ffi/interface.rb', line 19

def vtbl_parent
  @vtbl_parent
end

Class Method Details

.com_interface(interface) ⇒ Object

Sets up the args to the FFI::Struct ‘layout` method. This method defines all the callbacks necessary for working with FFI and also sets up any layout args to send in. The way the XPCOM C structs are setup, the properties are first, in `GetFoo` and `SetFoo` format. And the functions are next. They are put into the struct in the order defined in the AbstractInterface.



29
30
31
32
33
34
# File 'lib/virtualbox/com/ffi/interface.rb', line 29

def com_interface(interface)
  # Create the parent class and vtbl class
  interface = ::VirtualBox::COM::Util.versioned_interface(interface)
  define_vtbl_parent_for_interface(interface)
  define_vtbl_for_interface(interface)
end

.define_interface_function(name, return_type, spec = []) ⇒ Object

Defines a single function of a com interface



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/virtualbox/com/ffi/interface.rb', line 98

def define_interface_function(name, return_type, spec=[])
  # Append the return type to the spec as an out parameter (this is how
  # the C API handles it)
  spec << [:out, return_type] unless return_type.nil?

  # Define the "callback" type for the FFI module
  callback(name, Util.spec_to_ffi(spec), NSRESULT_TYPE)

  # Add to the layout args
  layout_args << [name, name]
end

.define_interface_functions(interface) ⇒ Object

Defines all the functions on a com interface.



90
91
92
93
94
95
# File 'lib/virtualbox/com/ffi/interface.rb', line 90

def define_interface_functions(interface)
  interface.functions.each do |name, opts|
    # Define the function
    define_interface_function(name, opts[:value_type], opts[:spec].dup)
  end
end

.define_interface_parent(parent) ⇒ Object

Defines the parent item of the layout. Since the VirtualBox XPCOM C library emulates an object-oriented environment using structs, the parent instance is pointed to by the first member of the struct. This method sets up that member.

Parameters:

  • parent (Symbol)

    The name of the parent represented by a symbol



71
72
73
74
75
76
# File 'lib/virtualbox/com/ffi/interface.rb', line 71

def define_interface_parent(parent)
  return if parent.nil?

  parent_klass = Util.versioned_interface(parent).const_get("Vtbl")
  layout_args << [:superklass, parent_klass]
end

.define_interface_properties(interface) ⇒ Object

Defines all the properties on a com interface.



79
80
81
82
83
84
85
86
87
# File 'lib/virtualbox/com/ffi/interface.rb', line 79

def define_interface_properties(interface)
  interface.properties.each do |name, opts|
    # Define the getter
    define_interface_function("get_#{name}".to_sym, opts[:value_type])

    # Define the setter unless the property is readonly
    define_interface_function("set_#{name}".to_sym, nil, [opts[:value_type]]) unless opts[:opts] && opts[:opts][:readonly]
  end
end

.define_vtbl_for_interface(interface) ⇒ Object

Creates the vtbl class associated with a given interface.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/virtualbox/com/ffi/interface.rb', line 47

def define_vtbl_for_interface(interface)
  # Get the parent for the interface
  parent = interface.get_parent

  # Define the properties, then the functions, since thats the order
  # the FFI structs are in
  layout_args.clear
  define_interface_parent(parent)
  define_interface_properties(interface)
  define_interface_functions(interface)

  # Finally create the classes (the struct and the structs vtbl)
  @vtbl_klass = Class.new(::FFI::Struct)

  # Set the constant within this class
  const_set("Vtbl", @vtbl_klass).layout(*layout_args.flatten)
end

.define_vtbl_parent_for_interface(interface) ⇒ Object

Creates the parent of the vtbl class associated with a given interface.



38
39
40
41
42
43
44
# File 'lib/virtualbox/com/ffi/interface.rb', line 38

def define_vtbl_parent_for_interface(interface)
  @vtbl_parent_klass = Class.new(::FFI::Struct)
  @vtbl_parent_klass.layout(:vtbl, :pointer)

  # Set the constant
  const_set("VtblParent", @vtbl_parent_klass)
end

.layout_argsArray

Returns an array of the layout args to send to ‘layout` eventually.

Returns:

  • (Array)


113
114
115
# File 'lib/virtualbox/com/ffi/interface.rb', line 113

def layout_args
  @_layout_args ||= []
end

Instance Method Details

#initialize_vtbl(pointer) ⇒ Object



125
126
127
128
129
# File 'lib/virtualbox/com/ffi/interface.rb', line 125

def initialize_vtbl(pointer)
  klass = self.class
  @vtbl_parent = klass::VtblParent.new(pointer)
  @vtbl = klass::Vtbl.new(vtbl_parent[:vtbl])
end