ext/win32ole/sample/olegen.rb


DEFINITIONS

This source file includes following functions.


   1  #-----------------------------
   2  # olegen.rb
   3  # $Date: 2002/06/01 12:34:29 $
   4  # $Revision: 1.1 $
   5  #-----------------------------
   6  
   7  require 'win32ole'
   8  
   9  class WIN32COMGen
  10    def initialize(typelib)
  11      @typelib = typelib
  12      @reciever = ""
  13    end
  14    attr_reader :typelib
  15  
  16    def ole_classes(typelib)
  17      begin
  18        @ole = WIN32OLE.new(typelib)
  19        [@ole.ole_obj_help]
  20      rescue
  21        WIN32OLE_TYPE.ole_classes(typelib)
  22      end
  23    end
  24  
  25    def generate_args(method)
  26      args = []
  27      if method.size_opt_params >= 0
  28        size_required_params = method.size_params - method.size_opt_params
  29      else
  30        size_required_params = method.size_params - 1
  31      end
  32      size_required_params.times do |i|
  33        if method.params[i] && method.params[i].optional?
  34          args.push "arg#{i}=nil"
  35        else
  36          args.push "arg#{i}"
  37        end
  38      end
  39      if method.size_opt_params >= 0
  40        method.size_opt_params.times do |i|
  41          args.push "arg#{i + size_required_params}=nil"
  42        end
  43      else
  44        args.push "*arg"
  45      end
  46      args.join(", ")
  47    end
  48  
  49    def generate_argtype(typedetails)
  50      ts = ''
  51      typedetails.each do |t|
  52        case t
  53        when 'CARRAY', 'VOID', 'UINT', 'RESULT', 'DECIMAL', 'I8', 'UI8' 
  54  #         raise "Sorry type\"" + t + "\" not supported"
  55        ts << "\"??? NOT SUPPORTED TYPE:`#{t}'\""
  56        when 'USERDEFINED', 'Unknown Type 9'
  57          ts << 'VT_DISPATCH'
  58          break;
  59        when 'SAFEARRAY'
  60          ts << 'VT_ARRAY|'
  61        when 'PTR'
  62          ts << 'VT_BYREF|'
  63        when 'INT'
  64          ts << 'VT_I4'
  65        else
  66          if String === t
  67            ts << 'VT_' + t
  68          end
  69        end
  70      end
  71      if ts.empty?
  72        ts = 'VT_VARIANT'
  73      elsif ts[-1] == ?|
  74          ts += 'VT_VARIANT'
  75      end
  76      ts
  77    end
  78  
  79    def generate_argtypes(method, proptypes)
  80      types = method.params.collect{|param|
  81        generate_argtype(param.ole_type_detail)
  82      }.join(", ")
  83      if proptypes
  84        types += ", " if types.size > 0 
  85        types += generate_argtype(proptypes)
  86      end
  87      types
  88    end
  89  
  90    def generate_method_body(method, disptype, types=nil)
  91      "    ret = #{@reciever}#{disptype}(#{method.dispid}, [" +
  92      generate_args(method).gsub("=nil", "") +
  93      "], [" +
  94      generate_argtypes(method, types) +
  95      "])\n" +
  96      "    @lastargs = WIN32OLE::ARGV\n" +
  97      "    ret"
  98    end
  99  
 100    def generate_method_help(method, type = nil)
 101      str = "  # "  
 102      if type 
 103        str += type
 104      else
 105        str += method.return_type
 106      end
 107      str += " #{method.name}"
 108      if method.event?
 109        str += " EVENT"
 110        str += " in #{method.event_interface}"
 111      end
 112      if method.helpstring && method.helpstring != ""
 113        str += "\n  # "
 114        str += method.helpstring
 115      end
 116      args_help = generate_method_args_help(method)
 117      if args_help
 118        str += "\n"
 119        str += args_help
 120      end
 121      str
 122    end
 123  
 124    def generate_method_args_help(method)
 125      args = []
 126      method.params.each_with_index {|param, i|
 127        h = "  #   #{param.ole_type} arg#{i} --- #{param.name}" 
 128        inout = []
 129        inout.push "IN" if param.input?
 130        inout.push "OUT" if param.output?
 131        h += " [#{inout.join('/')}]"
 132        h += " ( = #{param.default})" if param.default
 133        args.push h
 134      }
 135      if args.size > 0
 136        args.join("\n")
 137      else
 138        nil
 139      end
 140    end
 141  
 142    def generate_method(method, disptype, io = STDOUT, types = nil)
 143      io.puts "\n"
 144      io.puts  generate_method_help(method)
 145      if method.invoke_kind == 'PROPERTYPUT'
 146        io.print "  def #{method.name}=("
 147      else
 148        io.print "  def #{method.name}("
 149      end
 150      io.print generate_args(method)
 151      io.puts ")"
 152      io.puts generate_method_body(method, disptype, types)
 153      io.puts "  end"
 154    end
 155  
 156    def generate_propputref_methods(klass, io = STDOUT)
 157      klass.ole_methods.select {|method|
 158        method.invoke_kind == 'PROPERTYPUTREF' && method.visible?
 159      }.each do |method|
 160        generate_method(method, io)
 161      end
 162    end
 163  
 164    def generate_properties_with_args(klass, io = STDOUT)
 165      klass.ole_methods.select {|method|
 166        method.invoke_kind == 'PROPERTYGET' &&
 167        method.visible? &&
 168        method.size_params > 0
 169      }.each do |method|
 170        types = method.return_type_detail 
 171        io.puts "\n"
 172        io.puts  generate_method_help(method, types[0])
 173        io.puts  "  def #{method.name}"
 174        if klass.ole_type == "Class"
 175          io.print "    OLEProperty.new(@dispatch, #{method.dispid}, [" 
 176        else
 177          io.print "    OLEProperty.new(self, #{method.dispid}, [" 
 178        end
 179        io.print generate_argtypes(method, nil)
 180        io.print "], ["
 181        io.print generate_argtypes(method, types)
 182        io.puts "])"
 183        io.puts  "  end"
 184      end
 185    end
 186  
 187    def generate_propput_methods(klass, io = STDOUT)
 188      klass.ole_methods.select {|method|
 189        method.invoke_kind == 'PROPERTYPUT' && method.visible? &&
 190        method.size_params == 1
 191      }.each do |method|
 192        ms = klass.ole_methods.select {|m|
 193          m.invoke_kind == 'PROPERTYGET' &&
 194          m.dispid == method.dispid
 195        }
 196        types = []
 197        if ms.size == 1
 198          types = ms[0].return_type_detail
 199        end
 200        generate_method(method, '_setproperty', io, types)
 201      end
 202    end
 203  
 204    def generate_propget_methods(klass, io = STDOUT)
 205      klass.ole_methods.select {|method|
 206        method.invoke_kind == 'PROPERTYGET' && method.visible? &&
 207        method.size_params == 0
 208      }.each do |method|
 209        generate_method(method, '_getproperty', io)
 210      end
 211    end
 212  
 213    def generate_func_methods(klass, io = STDOUT)
 214      klass.ole_methods.select {|method|
 215        method.invoke_kind == "FUNC" && method.visible?
 216      }.each do |method|
 217        generate_method(method, '_invoke', io)
 218      end
 219    end
 220  
 221    def generate_methods(klass, io = STDOUT)
 222      generate_propget_methods(klass, io)
 223      generate_propput_methods(klass, io)
 224      generate_properties_with_args(klass, io)
 225      generate_func_methods(klass, io)
 226  #   generate_propputref_methods(klass, io)
 227    end
 228  
 229    def generate_constants(klass, io = STDOUT)
 230      klass.variables.select {|v|
 231        v.visible? && v.variable_kind == 'CONSTANT'
 232      }.each do |v|
 233        io.print "  "
 234        io.print v.name.sub(/^./){|c| c.upcase}
 235        io.print " = "
 236        io.puts  v.value
 237      end
 238    end
 239  
 240    def class_name(klass)
 241      klass_name = klass.name
 242      if klass.ole_type == "Class" &&
 243         klass.guid &&
 244         klass.progid
 245         klass_name = klass.progid.gsub(/\./, '_')
 246      end
 247      if /^[A-Z]/ !~ klass_name || Module.constants.include?(klass_name)
 248        klass_name = 'OLE' + klass_name
 249      end
 250      klass_name
 251    end
 252  
 253    def define_initialize(klass)
 254      <<STR
 255  
 256    def initialize(obj = nil)
 257      @clsid = "#{klass.guid}"
 258      @progid = "#{klass.progid}"
 259      if obj.nil?
 260        @dispatch = WIN32OLE.new @progid
 261      else
 262        @dispatch = obj
 263      end
 264    end
 265  STR
 266    end
 267  
 268    def define_include
 269      "  include WIN32OLE::VARIANT"
 270    end
 271  
 272    def define_instance_variables
 273      "  attr_reader :lastargs"
 274    end
 275  
 276    def define_method_missing
 277      <<STR
 278  
 279    def method_missing(cmd, *arg)
 280      @dispatch.method_missing(cmd, *arg)
 281    end
 282  STR
 283    end
 284  
 285    def define_class(klass, io = STDOUT)
 286      io.puts "class #{class_name(klass)} # #{klass.name}"
 287      io.puts define_include
 288      io.puts define_instance_variables
 289      io.puts "  attr_reader :dispatch"
 290      io.puts "  attr_reader :clsid"
 291      io.puts "  attr_reader :progid"
 292      io.puts define_initialize(klass)
 293      io.puts define_method_missing
 294    end
 295  
 296    def define_module(klass, io = STDOUT)
 297      io.puts "module #{class_name(klass)}"
 298      io.puts define_include
 299      io.puts define_instance_variables
 300    end
 301  
 302    def generate_class(klass, io = STDOUT)
 303      io.puts "\n# #{klass.helpstring}"
 304      if klass.ole_type == "Class" &&
 305         klass.guid &&
 306         klass.progid
 307        @reciever = "@dispatch."
 308        define_class(klass, io)
 309      else
 310        @reciever = ""
 311        define_module(klass, io)
 312      end
 313      generate_constants(klass, io)
 314      generate_methods(klass, io)
 315      io.puts "end"
 316    end
 317  
 318    def generate(io = STDOUT)
 319      io.puts "require 'win32ole'"
 320      io.puts "require 'win32ole/property'"
 321  
 322      ole_classes(typelib).select{|klass|
 323        klass.visible? &&
 324        (klass.ole_type == "Class" || 
 325         klass.ole_type == "Interface" || 
 326         klass.ole_type == "Dispatch" ||
 327         klass.ole_type == "Enum")
 328      }.each do |klass|
 329        generate_class(klass, io)
 330      end
 331      begin
 332        @ole.quit if @ole
 333      rescue 
 334      end
 335    end
 336  end
 337  
 338  require 'win32ole'
 339  if __FILE__ == $0
 340    if ARGV.size == 0
 341      $stderr.puts "usage: #{$0} Type Library [...]"
 342      exit 1
 343    end
 344    ARGV.each do |typelib|
 345      comgen = WIN32COMGen.new(typelib)
 346      comgen.generate
 347    end
 348  end