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
72
73
74
75
76
# 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 Exception => e
    if jruby_exception && e.instance_of?(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)
    else
      # Reraise the exception since we're not interested in it
      raise
    end
  end

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

#read_array_of_interface(value, type) ⇒ Object



200
201
202
203
204
205
206
207
# File 'lib/virtualbox/com/implementer/mscom.rb', line 200

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



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

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

#read_char(value, type) ⇒ Object



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

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

#read_enum(value, type) ⇒ Object



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

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

#read_int(value, type) ⇒ Object



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

def read_int(value, type)
  value.to_i
end

#read_interface(value, type) ⇒ Object



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

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

#read_long(value, type) ⇒ Object



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

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



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

def read_uint(value, type)
  value.to_i
end

#read_ulong(value, type) ⇒ Object



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

def read_ulong(value, type)
  value.to_i
end

#read_unicode_string(value, type) ⇒ Object



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

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

#read_ushort(value, type) ⇒ Object



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

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.



145
146
147
148
149
150
151
152
153
154
# File 'lib/virtualbox/com/implementer/mscom.rb', line 145

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



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
137
138
139
140
141
# File 'lib/virtualbox/com/implementer/mscom.rb', line 104

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.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/virtualbox/com/implementer/mscom.rb', line 85

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