1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 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 77 78
|
require 'ffi'
module Win32
class API < Module
CONVENTION = FFI::Platform.windows? ? :stdcall : :default
if RUBY_VERSION =~ /1\.9/
SUFFIXES = Encoding.default_internal == Encoding::UTF_8 ? [ '', 'W', 'A' ] : [ '', 'A', 'W' ]
else
SUFFIXES = $KCODE == 'UTF8' ? [ '', 'W', 'A' ] : [ '', 'A', 'W' ]
end
TypeDefs = {
'V' => :void,
'S' => :string,
'P' => :pointer,
'I' => :int,
'L' => :long,
}
def self.find_type(name)
code = TypeDefs[name]
raise TypeError, "Unable to resolve type '#{name}'" unless code
return code
end
def self.map_types(spec)
types = []
for i in 0..(spec.length - 1)
if spec[i].chr == 'V'
return []
end
types[i] = self.find_type(spec.slice(i,1))
end
types
end
def initialize(func, params, ret='L', lib='kernel32')
#
# Attach the method as 'call', so it gets all the froody arity-splitting optimizations
#
extend FFI::Library
ffi_lib lib
ffi_convention CONVENTION
attached = false
SUFFIXES.each { |suffix|
begin
attach_function(:call, func.to_s + suffix, API.map_types(params), API.map_types(ret)[0])
attached = true
break
rescue FFI::NotFoundError => ex
end
}
raise FFI::NotFoundError, "Could not locate #{func}" if !attached
end
end
end
unless FFI::Platform.windows?
cputs = Win32::API.new("puts", "S", 'L', 'c')
cputs.call("Hello, World")
exit 0
end
beep = Win32::API.new("MessageBeep", 'L', 'L', 'user32')
2.times { beep.call(0) }
buf = 0.chr * 260
GetComputerName = Win32::API.new("GetComputerName", 'PP', 'L', 'kernel32')
ret = GetComputerName.call(buf, [buf.length].pack("V"))
puts "GetComputerName returned #{ret}"
puts "computer name=#{buf.strip}"
len = [buf.length].pack('V')
GetUserName = Win32::API.new("GetUserName", 'PP', 'I', 'advapi32')
ret = GetUserName.call(buf, len)
puts "GetUserName returned #{ret}"
puts "username=#{buf.strip}"
puts "len=#{len.unpack('V')}"
getcwd = Win32::API.new("GetCurrentDirectory", 'LP')
buf = 0.chr * 260
getcwd.call(buf.length, buf)
puts "current dir=#{buf.strip}"
|