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