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:



13
14
15
16
17
18
19
# File 'lib/virtualbox/com/implementer/mscom.rb', line 13

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

  @object = object

  require 'java' if Platform.jruby?
end

Instance Attribute Details

#objectObject (readonly)

Returns the value of attribute object.



7
8
9
# File 'lib/virtualbox/com/implementer/mscom.rb', line 7

def object
  @object
end

Instance Method Details

#call_function(name, args, opts) ⇒ Object

Calls a function from the interface with the given name



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/virtualbox/com/implementer/mscom.rb', line 51

def call_function(name, args, opts)
  # This is a special exception only if we're on JRuby
  jruby_exception = nil
  jruby_exception = org.racob.com.ComFailException if Platform.jruby?

  # Convert args to proper values to send and send em!
  args = spec_to_args(opts[:spec], args)

  value = nil
  begin
    value = @object.send(COM::FFI::Util.camelize(name.to_s), *args)
  rescue jruby_exception
    # JRuby exception is screwed up. We just throw a generic
    # COMException and call it good.
    raise Exceptions::COMException.new(:function => name,
                                       :result_code => 0)
  end

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

#read_array_of_interface(value, type) ⇒ Object



195
196
197
198
199
200
201
202
# File 'lib/virtualbox/com/implementer/mscom.rb', line 195

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



190
191
192
193
# File 'lib/virtualbox/com/implementer/mscom.rb', line 190

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

#read_char(value, type) ⇒ Object



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

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

#read_enum(value, type) ⇒ Object



181
182
183
# File 'lib/virtualbox/com/implementer/mscom.rb', line 181

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

#read_int(value, type) ⇒ Object



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

def read_int(value, type)
  value.to_i
end

#read_interface(value, type) ⇒ Object



185
186
187
188
# File 'lib/virtualbox/com/implementer/mscom.rb', line 185

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

#read_long(value, type) ⇒ Object



177
178
179
# File 'lib/virtualbox/com/implementer/mscom.rb', line 177

def read_long(value, type)
  value.to_i
end

#read_property(name, opts) ⇒ Object

Reads a property from the interface with the given name.



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/virtualbox/com/implementer/mscom.rb', line 22

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



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

def read_uint(value, type)
  value.to_i
end

#read_ulong(value, type) ⇒ Object



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

def read_ulong(value, type)
  value.to_i
end

#read_unicode_string(value, type) ⇒ Object



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

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

#read_ushort(value, type) ⇒ Object



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

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.



140
141
142
143
144
145
146
147
148
149
# File 'lib/virtualbox/com/implementer/mscom.rb', line 140

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



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/virtualbox/com/implementer/mscom.rb', line 99

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.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/virtualbox/com/implementer/mscom.rb', line 80

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.



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/virtualbox/com/implementer/mscom.rb', line 38

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