Class: VirtualBox::COM::Implementer::MSCOM

Inherits:
Base show all
Defined in:
lib/virtualbox/com/implementer/mscom.rb

Instance Attribute Summary collapse

Attributes inherited from AbstractImplementer

#interface, #lib

Instance Method Summary collapse

Methods inherited from Base

#infer_type, #interface_klass, #ruby_version

Methods included from Logger

included, #logger, #logger_output=

Constructor Details

#initialize(interface, lib_base, object) ⇒ MSCOM

Initializes the MSCOM implementer.

Parameters:



11
12
13
14
15
# File 'lib/virtualbox/com/implementer/mscom.rb', line 11

def initialize(interface, lib_base, object)
  super(interface, lib_base)

  @object = object
end

Instance Attribute Details

#objectObject (readonly)

Returns the value of attribute object.



5
6
7
# File 'lib/virtualbox/com/implementer/mscom.rb', line 5

def object
  @object
end

Instance Method Details

#call_function(name, args, opts) ⇒ Object

Calls a function from the interface with the given name



47
48
49
50
51
52
53
54
# File 'lib/virtualbox/com/implementer/mscom.rb', line 47

def call_function(name, args, opts)
  # Convert args to proper values to send and send em!
  args = spec_to_args(opts[:spec], args)
  value = @object.send(COM::FFI::Util.camelize(name.to_s), *args)

  # TODO: Multiple return values
  returnable_value(value, opts[:value_type])
end

#read_array_of_interface(value, type) ⇒ Object



178
179
180
181
182
183
184
185
# File 'lib/virtualbox/com/implementer/mscom.rb', line 178

def read_array_of_interface(value, type)
  klass = interface_klass(type.first)
  value.collect do |item|
    if !item.nil?
      klass.new(self.class, lib, item)
    end
  end
end

#read_array_of_unicode_string(value, type) ⇒ Object



173
174
175
176
# File 'lib/virtualbox/com/implementer/mscom.rb', line 173

def read_array_of_unicode_string(value, type)
  # Return as-is, since MSCOM returns ruby strings!
  value
end

#read_char(value, type) ⇒ Object



139
140
141
142
# File 'lib/virtualbox/com/implementer/mscom.rb', line 139

def read_char(value, type)
  # Convert to a boolean
  !(value.to_s == "0")
end

#read_enum(value, type) ⇒ Object



164
165
166
# File 'lib/virtualbox/com/implementer/mscom.rb', line 164

def read_enum(value, type)
  interface_klass(type)[value]
end

#read_int(value, type) ⇒ Object



156
157
158
# File 'lib/virtualbox/com/implementer/mscom.rb', line 156

def read_int(value, type)
  value.to_i
end

#read_interface(value, type) ⇒ Object



168
169
170
171
# File 'lib/virtualbox/com/implementer/mscom.rb', line 168

def read_interface(value, type)
  return nil if value.nil?
  interface_klass(type).new(self.class, lib, value)
end

#read_long(value, type) ⇒ Object



160
161
162
# File 'lib/virtualbox/com/implementer/mscom.rb', line 160

def read_long(value, type)
  value.to_i
end

#read_property(name, opts) ⇒ Object

Reads a property from the interface with the given name.



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/virtualbox/com/implementer/mscom.rb', line 18

def read_property(name, opts)
  # First get the basic value from the COM object
  method = COM::FFI::Util.camelize(name.to_s)
  value = if ruby_version >= 1.9
    @object.send(method)
  else
    @object[method]
  end

  # Then depending on the value type, we either return as-is or
  # must wrap it up in another interface class
  returnable_value(value, opts[:value_type])
end

#read_uint(value, type) ⇒ Object



148
149
150
# File 'lib/virtualbox/com/implementer/mscom.rb', line 148

def read_uint(value, type)
  value.to_i
end

#read_ulong(value, type) ⇒ Object



152
153
154
# File 'lib/virtualbox/com/implementer/mscom.rb', line 152

def read_ulong(value, type)
  value.to_i
end

#read_unicode_string(value, type) ⇒ Object



134
135
136
137
# File 'lib/virtualbox/com/implementer/mscom.rb', line 134

def read_unicode_string(value, type)
  # Return as-is
  value
end

#read_ushort(value, type) ⇒ Object



144
145
146
# File 'lib/virtualbox/com/implementer/mscom.rb', line 144

def read_ushort(value, type)
  value.to_i
end

#returnable_value(value, type) ⇒ Object

Takes a value (returned from a WIN32OLE object) and a type and converts to a proper ruby return value type.



123
124
125
126
127
128
129
130
131
132
# File 'lib/virtualbox/com/implementer/mscom.rb', line 123

def returnable_value(value, type)
  # Types which are void or nil just return
  return nil if type.nil? || type == :void

  klass = type.is_a?(Array) ? type.first : type
  ignore, inferred_type = infer_type(klass)

  array_of = type.is_a?(Array) ? "array_of_" : ""
  send("read_#{array_of}#{inferred_type}", value, type)
end

#single_type_to_arg(args, item, results) ⇒ Object

Converts a single type and args list to the proper formal args list



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/virtualbox/com/implementer/mscom.rb', line 82

def single_type_to_arg(args, item, results)
  if item.is_a?(Array) && item.length == 1
    # Array argument
    data = args.shift

    # If its a regular type (int, bool, etc.) then just make it an
    # array of that
    results << data.inject([]) do |converted_data, single|
      single_type_to_arg([single], item[0], converted_data)
    end
  elsif item.to_s[0,1] == item.to_s[0,1].upcase
    # Try to get the class from the interfaces
    interface = interface_klass(item.to_sym)

    if interface.superclass == COM::AbstractInterface
      # For interfaces, get the instance, then dig deep to get the pointer
      # to the VtblParent, which is what the API expects
      instance = args.shift

      results << if !instance.nil?
        # Get the actual MSCOM object, rather than the AbstractInterface
        instance.implementer.object
      else
        # If the argument was nil, just pass a nil pointer as the argument
        nil
      end
    elsif interface.superclass == COM::AbstractEnum
      # For enums, we need the value of the enum
      results << interface.index(args.shift.to_sym)
    end
  elsif item == T_BOOL
    results << (args.shift ? 1 : 0)
  else
    # Simply replace spec item with next item in args
    # list
    results << args.shift
  end
end

#spec_to_args(spec, args) ⇒ Object

Takes a function spec and an argument list. This handles properly converting enums to ints and AbstractInterfaces to proper MSCOM interfaces.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/virtualbox/com/implementer/mscom.rb', line 63

def spec_to_args(spec, args)
  args = args.dup

  # First remove all :out parameters from the spec, since those are of no
  # concern for MSCOM at this point
  spec = spec.collect do |item|
    if item.is_a?(Array) && item[0] == :out
      nil
    else
      item
    end
  end.compact

  spec = spec.inject([]) do |results, item|
    single_type_to_arg(args, item, results)
  end
end

#write_property(name, value, opts) ⇒ Object

Writes a property from the interface with the given name and value.



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/virtualbox/com/implementer/mscom.rb', line 34

def write_property(name, value, opts)
  # Set the property with a prepared value
  method = COM::FFI::Util.camelize(name.to_s)
  value = spec_to_args([opts[:value_type]], [value]).first

  if ruby_version >= 1.9
    @object.send("#{method}=", value)
  else
    @object[method] = value
  end
end