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.

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.



138
139
140
# File 'lib/virtualbox/com/ffi/interface.rb', line 138

def initialize(pointer)
  initialize_vtbl(pointer)
end

Instance Attribute Details

#vtblObject (readonly)

Returns the value of attribute vtbl.



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

def vtbl
  @vtbl
end

#vtbl_parentObject (readonly)

Returns the value of attribute vtbl_parent.



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

def vtbl_parent
  @vtbl_parent
end

Class Method Details

.com_interface(interface, parent = nil) ⇒ 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.



49
50
51
52
53
54
# File 'lib/virtualbox/com/ffi/interface.rb', line 49

def com_interface(interface, parent=nil)
  # 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, parent)
end

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

Defines a single function of a com interface



115
116
117
118
119
120
121
122
123
124
125
# File 'lib/virtualbox/com/ffi/interface.rb', line 115

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.



107
108
109
110
111
112
# File 'lib/virtualbox/com/ffi/interface.rb', line 107

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



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

def define_interface_parent(parent)
  return if parent.nil?

  parent_klass = Object.module_eval("::VirtualBox::COM::FFI::#{::VirtualBox::COM::Util.version_const}::#{parent}::Vtbl")
  layout_args << [:superklass, parent_klass]
end

.define_interface_properties(interface) ⇒ Object

Defines all the properties on a com interface.



96
97
98
99
100
101
102
103
104
# File 'lib/virtualbox/com/ffi/interface.rb', line 96

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, parent = nil) ⇒ Object

Creates the vtbl class associated with a given interface.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/virtualbox/com/ffi/interface.rb', line 67

def define_vtbl_for_interface(interface, parent=nil)
  # 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.



58
59
60
61
62
63
64
# File 'lib/virtualbox/com/ffi/interface.rb', line 58

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)


130
131
132
# File 'lib/virtualbox/com/ffi/interface.rb', line 130

def layout_args
  @_layout_args ||= []
end

Instance Method Details

#initialize_vtbl(pointer) ⇒ Object



142
143
144
145
146
# File 'lib/virtualbox/com/ffi/interface.rb', line 142

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