Class: VirtualBox::COM::XPCOMC::Binding
- Inherits:
-
Object
- Object
- VirtualBox::COM::XPCOMC::Binding
- Extended by:
- FFI::Library
- Defined in:
- lib/virtualbox/com/xpcomc-ffi/binding.rb
Overview
The Binding class hold all the FFI infrastructure
Instance Attribute Summary collapse
-
#object ⇒ Object
readonly
Returns the value of attribute object.
Class Method Summary collapse
-
.bind(model) ⇒ Object
Create the binding with the Model class This will also create the internal classes Object and Vtbl representing the FFI::Struct, all the necessary callbacks, a hash of the name/signatures.
-
.get(name) ⇒ Object
Retrieve a Binding class corresponding to the Model This will avoid polluting the model object with implementation data.
- .init ⇒ Object
Instance Method Summary collapse
-
#call(name, *args) ⇒ Object
Calls a function on the vtbl of the FFI struct.
-
#initialize(pointer) ⇒ Binding
constructor
Initializes the interface to the FFI struct with the given pointer.
Constructor Details
#initialize(pointer) ⇒ Binding
Initializes the interface to the FFI struct with the given pointer. The pointer is used to initialize the Object which is used to initialize the Vtbl itself.
75 76 77 78 |
# File 'lib/virtualbox/com/xpcomc-ffi/binding.rb', line 75 def initialize(pointer) @object = self.class::Object.new(pointer) @vtbl = self.class::Vtbl.new(@object[:vtbl]) end |
Instance Attribute Details
#object ⇒ Object (readonly)
Returns the value of attribute object.
9 10 11 |
# File 'lib/virtualbox/com/xpcomc-ffi/binding.rb', line 9 def object @object end |
Class Method Details
.bind(model) ⇒ Object
Create the binding with the Model class This will also create the internal classes Object and Vtbl representing the FFI::Struct, all the necessary callbacks, a hash of the name/signatures
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/virtualbox/com/xpcomc-ffi/binding.rb', line 36 def self.bind(model) raise "model already bound" if const_defined?(:Object, false) # self.init inherited = [] m = model.superclass # List of functions (name, signature) # Defined in the order they appear in the Model definition sigs = model.members.inject({}) do |list, spec| list.merge!(spec.signatures) end const_set(:Sig, sigs) # Register ffi callbacks sigs.each {|name, sig| callback(name, sig.to_ffi_callback, :uint) } # Object layout const_set(:Object, Class.new(::FFI::Struct)) .layout(:vtbl, :pointer) # Vtbl layout const_set(:Vtbl, Class.new(::FFI::Struct)) .layout(*sigs.map {|name,| [name, name] }.flatten) # IID const_set(:IID, model::IID.to_ffi) # Model const_set(:Model, model) self end |
.get(name) ⇒ Object
Retrieve a Binding class corresponding to the Model This will avoid polluting the model object with implementation data
25 26 27 28 29 |
# File 'lib/virtualbox/com/xpcomc-ffi/binding.rb', line 25 def self.get(name) Binding.const_get(name, false) rescue NameError const_set(name, Class.new(Binding)).bind(Model.get(name)) end |
.init ⇒ Object
11 12 13 14 15 16 17 18 19 20 |
# File 'lib/virtualbox/com/xpcomc-ffi/binding.rb', line 11 def self.init # To simplify code, use typedef for type aliasing typedef :int, :boolean typedef :pointer, :unicode_string Model.constants.each {|c| m = Model.get(c) if m <= AbstractInterface then typedef :pointer, c elsif m <= AbstractEnum then typedef :uint32, c end } end |
Instance Method Details
#call(name, *args) ⇒ Object
Calls a function on the vtbl of the FFI struct. This function handles converting the spec to proper arguments and also handles reading out the arguments, dereferencing pointers, setting up objects, etc. so that the return value is filled with nicely formatted Ruby objects.
If the vtbl function being called only has one out parameter, then the return value will be that single object. If it has multiple, then it will be an array of objects.
89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/virtualbox/com/xpcomc-ffi/binding.rb', line 89 def call(name, *args) unless sig = self.class::Sig[name] raise ArgumentError, "unknown function #{name} in Vtbl" end ffi_args = sig.prepare_args(args) result = @vtbl[name].call(@object, *ffi_args) if (result & 0x8000_0000) != 0 raise COMException, :vtbl => name, :code => result end sig.read_values(ffi_args) end |