-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdynamic.rb
158 lines (140 loc) · 4.17 KB
/
dynamic.rb
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
=begin
#
# module Roost::Dynamic
#
# $Id: Roost::Dynamic $
#
# Created by Hana Seiran
#
# Documentation by Hana Seiran
#
=end
# == Overview
#
# Roost Dynamic is mainly purposed on dynamically calling DLLs,
# i.e. without explicitly specifying DLL name and types function arguments
# unlike that in Win32API.new(..)
#
module Roost
module Dynamic
#if AUTOIMPORT is on, the following statement:
# Roost::Dynamic.user32.MessageBoxA(0, "Hello", "World", 16)
# can be easily used, otherwise, you should always
# Roost::Dynamic.import('user32')
# before the first time you call the function MessageBoxA
AUTOIMPORT = true
if AUTOIMPORT
def method_missing arg
self.defdyn arg
return send arg
end
def self.method_missing arg
self.defdyn arg
return send arg
end
end
# defdyn(*syms)
# import(*syms)
# if AUTOIMPORT is off, when using a DLL,
# defdyn(DLLNAME) is required
#
# example: defdyn('user32', 'kernel32', 'gdi32')
#
def self.defdyn(*syms)
syms.each{|sym|
unless Roost::Dynamic.respond_to? sym
x = sym.to_s
Roost::Dynamic.instance_eval "@@#{x} = Dyn.new('#{x}')"
Roost::Dynamic.instance_eval "def self.#{x}; @@#{x}; end;"
Roost::Dynamic.instance_eval "def #{x}; @@#{x}; end;"
end
}
extend Roost::Dynamic
end
def self.import(*syms)
self.defdyn(*syms)
end
# class Dyn
# Roost::Dynamic::Dyn is the class to hold the informations
# for an individual DLL
# You can use this class individually to call arbitary DLLs
# example:
# Suppose you have a DLL, named 'math.dll'
# exporting 'int add(int a, int b);' and want to use it
# here in RGSS or normal Ruby, simply:
#
# udf = Dyn.new('math.dll')
# print udf.add(3,5)
#
# the exporting form of symbol 'add' can be one of the following:
# (there are 2 arguments, so '@8' may be generated by certain compiler)
# 1. add
# 2. add@8
# 3. _add
# 4. _add@8
# But any of them must be 'stdcall' convention, not 'cdecl'.
class Dyn
# name is the dll's name
# opt is the options, is reserved currently.
# example: udfdll = Dyn.new('userdefined.dll')
def initialize(name, opt={})
@name = name
@params = {}
@api = {}
@opt = opt
end
def inspect
"#{@api.keys.dup.unshift([@name]).join("\n- ")}"
end
def marshal_dump
[@name, @params, @opt]
end
def marshal_load arg
@name, @params, @opt = arg
@params.keys.each{|x|
@api[x] = Win32API.new(@name, x, @params[x], "i")
}
end
def guess(name, params)
begin
return Win32API.new(@name, name, params, "i")
rescue
return nil
end
end
def method_missing(sym, *args)
x = sym.to_s
if @params[x] == nil
@params[x] = args.inject(""){|str, i|
if i.is_a?(Integer)
str += "L"
elsif i.is_a?(String)
str += "p"
end
}
@params[x]||=""
par = @params[x]
@api[sym.to_s] ||= guess(x, par)
@api[sym.to_s] ||= guess("#{x}@#{@params[x].length*4}", par)
@api[sym.to_s] ||= guess("_#{x}", par)
@api[sym.to_s] ||= guess("_#{x}@#{@params[x].length*4}", par)
unless @api[sym.to_s]
throw "Can't find #{@name}.#{sym.to_s} with #{@params[x]} with #{args.inspect}"
end
self.instance_eval ("def #{sym}(*args); @api['#{sym}'].call(*args); end;")
@api[sym.to_s].call(*args)
end
end
end
end
end
Dyn = Roost::Dynamic::Dyn
class CDyn < Roost::Dynamic::Dyn
def guess(name, params)
begin
return Seiran20.callproc(Seiran20.funcaddr(@name, name))
rescue
return nil
end
end
end