| 赞 | 2 |
| VIP | 0 |
| 好人卡 | 0 |
| 积分 | 10 |
| 经验 | 0 |
| 最后登录 | 2026-6-4 |
| 在线时间 | 166 小时 |
Lv3.寻梦者
- 梦石
- 0
- 星屑
- 1046
- 在线时间
- 166 小时
- 注册时间
- 2025-5-6
- 帖子
- 22
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
- #===============================================================
- # Vx ace Fiddle
- #
- #===============================================================
- module Fiddle
-
- TYPE_VOID = DL::TYPE_VOID
- TYPE_INT = DL::TYPE_INT
- TYPE_LONG = DL::TYPE_LONG
- TYPE_VOIDP = DL::TYPE_VOIDP
- TYPE_FLOAT = DL::TYPE_FLOAT
- TYPE_DOUBLE = DL::TYPE_DOUBLE
- TYPE_CHAR = DL::TYPE_CHAR
- TYPE_SHORT = DL::TYPE_SHORT
- TYPE_UCHAR = -TYPE_CHAR
- TYPE_USHORT = -TYPE_SHORT
- TYPE_UINT = -TYPE_INT
- TYPE_ULONG = -TYPE_LONG
- #调用约定
- DEFAULT = :stdcall
- #========== 函数封装 ==========
- class Function
- def initialize(ptr, args, ret, abi = DEFAULT)
- @ptr = ptr
- @args = args
- @ret = ret
- @calltype = case abi
- when :stdcall, :STDCALL, 1 then :stdcall
- when :cdecl, :CDECL, 0 then :cdecl
- else :stdcall
- end
- @cfunc = DL::CFunc.new(ptr, ret, 'fiddle_func', @calltype)
- end
- def call(*args)
- temp_ptrs = []
- converted = args.zip(@args).map do |val, type|
- if type == TYPE_VOIDP
- if val.nil?
- 0
- elsif val.is_a?(String)
- #转为 UTF-16LE(Unicode)
- utf16 = val.encode("UTF-16LE") + "\0\0".encode("UTF-16LE")
- bin = utf16.force_encoding("ASCII-8BIT")
- ptr = DL::CPtr[bin]
- temp_ptrs << ptr
- ptr.to_i
- elsif val.is_a?(DL::CPtr)
- val.to_i
- else
- val
- end
- else
- val
- end
- end
- @cfunc.call(converted)
- end
- end
- Pointer = DL::CPtr
- #========== 签名解析器=========================
- module CParser
-
- def self.parse_signature(signature, tymap = nil)
- tymap ||= {}
- signature = signature.gsub(/\s+/, " ").strip
- case signature
- when /^([\w@\*\s]+)\(([\w\*\s\,\[\]]*)\)$/
- ret_part = $1
- args_part = $2.strip
- ret_tokens = ret_part.split(/\s+/)
- args_list = args_part.split(/\s*,\s*/)
- func_name = ret_tokens.pop
- if func_name =~ /^\*/
- func_name.gsub!(/^\*+/, "")
- ret_tokens.push("*")
- end
- ret_type = join_types(ret_tokens)
- [func_name, parse_ctype(ret_type, tymap), args_list.map { |a| parse_ctype(a.strip, tymap) }]
- else
- raise "无法解析函数原型: #{signature}"
- end
- end
- #解析单个类型字符串
- def self.parse_ctype(ty, tymap = nil)
- tymap ||= {}
- case ty
- when Array
- [parse_ctype(ty[0], tymap), ty[1]]
- when "void"
- TYPE_VOID
- when "char"
- TYPE_CHAR
- when "unsigned char"
- -TYPE_CHAR
- when "short"
- TYPE_SHORT
- when "unsigned short"
- -TYPE_SHORT
- when "int"
- TYPE_INT
- when "unsigned int", "uint"
- -TYPE_INT
- when "long"
- TYPE_LONG
- when "unsigned long"
- -TYPE_LONG
- when "long long"
- if defined?(TYPE_LONG_LONG)
- TYPE_LONG_LONG
- else
- raise "不支持 long long 类型"
- end
- when "unsigned long long"
- if defined?(TYPE_LONG_LONG)
- -TYPE_LONG_LONG
- else
- raise "不支持 unsigned long long 类型"
- end
- when "float"
- TYPE_FLOAT
- when "double"
- TYPE_DOUBLE
- when /\*/, /\[\s*\]/
- TYPE_VOIDP
- else
- if tymap[ty]
- parse_ctype(tymap[ty], tymap)
- else
- raise "未知类型: #{ty}"
- end
- end
- end
-
- def self.join_types(tokens)
- tokens.join(" ")
- end
- end
- class Handle
- def initialize(lib)
- @handle = DL.dlopen(lib)
- end
- def [](func)
- @handle[func]
- end
-
- def extern(signature, call_type = DEFAULT)
- func_name, ret_type, arg_types = CParser.parse_signature(signature)
- ptr = self[func_name]
- if ptr.nil? || ptr == 0
- raise "找不到函数: #{func_name}"
- end
- Function.new(ptr, arg_types, ret_type, call_type)
- end
- end
- end
- #===============================================================
- # 实际上是DL伪装Fiddle而已。
- #===============================================================
- user32 = Fiddle::Handle.new('user32')
- msgbox_ptr = user32['MessageBoxW']
- msgbox = Fiddle::Function.new(msgbox_ptr,
- [Fiddle::TYPE_LONG, Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_LONG],
- Fiddle::TYPE_LONG) #使用 DEFAULT (stdcall)
- msgbox.call(0, "我自由了!", "FFI", 0)
- #===============================================================
- user32 = Fiddle::Handle.new('user32')
- msgbox = user32.extern('int MessageBoxW(long, void*, void*, long)')
- msgbox.call(0, "我再也不用win32api了!", "FFI", 0)
复制代码 |
|