Project1
标题:
在RMVA使用Fiddle代替win32api
[打印本页]
作者:
lifrtam
时间:
2026-4-26 00:09
标题:
在RMVA使用Fiddle代替win32api
#===============================================================
# 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)
复制代码
作者:
lifrtam
时间:
2026-4-26 00:11
其实是把DL当作Fiddle来用
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1