1# -*- ruby -*-
2# frozen_string_literal: true
3
4# for backward compatibility
5warn "Win32API is deprecated after Ruby 1.9.1; use fiddle directly instead", uplevel: 2
6
7require 'fiddle/import'
8
9class Win32API
10  DLL = {}
11  TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
12  POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
13
14  WIN32_TYPES = "VPpNnLlIi"
15  DL_TYPES = "0SSI"
16
17  def initialize(dllname, func, import, export = "0", calltype = :stdcall)
18    @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
19    import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
20    export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
21    calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
22
23    handle = DLL[dllname] ||=
24             begin
25               Fiddle.dlopen(dllname)
26             rescue Fiddle::DLError
27               raise unless File.extname(dllname).empty?
28               Fiddle.dlopen(dllname + ".dll")
29             end
30
31    @func = Fiddle::Function.new(handle[func], import, export, calltype)
32  rescue Fiddle::DLError => e
33    raise LoadError, e.message, e.backtrace
34  end
35
36  def call(*args)
37    import = @proto.split("")
38    args.each_with_index do |x, i|
39      args[i], = [x == 0 ? nil : x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
40      args[i], = [x].pack("I").unpack("i") if import[i] == "I"
41    end
42    ret, = @func.call(*args)
43    return ret || 0
44  end
45
46  alias Call call
47end
48