Project1
标题: RGSS的C/C++扩展 [打印本页]
作者: guoxiaomi 时间: 2017-10-26 21:59
标题: RGSS的C/C++扩展
本帖最后由 RyanBern 于 2017-10-27 00:20 编辑
最近花了比较多的时间去思考用 C 扩展 ruby/rgss 的事情,也去各种奇怪的网站查找了很多的资料,最后却发现真正有用的东西居然就沉睡在这里:https://rpg.blue/thread-127979-1-1.html
之中的探索过程真的一言难尽,这里写一段 C++ 代码,表示一下我也是在努力着追寻大神们的脚步
,但是似乎到此为止了……(遇到了太多的知识空白)
#include <windows.h>
using namespace std;
static HMODULE hRGSSPatch = ::LoadLibraryA("RGSS102JPatch.dll");
typedef unsigned long VALUE;
#define def(f, o, ...) \
typedef o (*f##F) (__VA_ARGS__); \
static f##F f = (f##F)::GetProcAddress(hRGSSPatch, #f);
// fetch function address from the Patch DLL.
def(rb_define_module, VALUE, const char* name);
def(rb_define_module_function, void, VALUE, const char*, VALUE, int);
def(rb_num2ulong, unsigned long, VALUE);
// copy from ruby.h with a little change.
#define FIX2INT(x) ((int)rb_num2ulong((VALUE)(x)))
#define RUBY_FIXNUM_FLAG 0x01
#define RB_INT2FIX(i) (((VALUE)(i))<<1 | RUBY_FIXNUM_FLAG)
#define INT2FIX(i) RB_INT2FIX(i)
#define RUBY_METHOD_FUNC(func) ((VALUE) (*func))
// dll export function
extern "C" {
__declspec(dllexport) void Init_Test(void);
}
VALUE add(VALUE self, VALUE a, VALUE b) {
int aa = FIX2INT(a);
int bb = FIX2INT(b);
return INT2FIX(aa + bb);
}
void Init_Test(void) {
VALUE Test = rb_define_module("Test");
rb_define_module_function(Test, "add", RUBY_METHOD_FUNC(add), 2);
}
#include <windows.h>
using namespace std;
static HMODULE hRGSSPatch = ::LoadLibraryA("RGSS102JPatch.dll");
typedef unsigned long VALUE;
#define def(f, o, ...) \
typedef o (*f##F) (__VA_ARGS__); \
static f##F f = (f##F)::GetProcAddress(hRGSSPatch, #f);
// fetch function address from the Patch DLL.
def(rb_define_module, VALUE, const char* name);
def(rb_define_module_function, void, VALUE, const char*, VALUE, int);
def(rb_num2ulong, unsigned long, VALUE);
// copy from ruby.h with a little change.
#define FIX2INT(x) ((int)rb_num2ulong((VALUE)(x)))
#define RUBY_FIXNUM_FLAG 0x01
#define RB_INT2FIX(i) (((VALUE)(i))<<1 | RUBY_FIXNUM_FLAG)
#define INT2FIX(i) RB_INT2FIX(i)
#define RUBY_METHOD_FUNC(func) ((VALUE) (*func))
// dll export function
extern "C" {
__declspec(dllexport) void Init_Test(void);
}
VALUE add(VALUE self, VALUE a, VALUE b) {
int aa = FIX2INT(a);
int bb = FIX2INT(b);
return INT2FIX(aa + bb);
}
void Init_Test(void) {
VALUE Test = rb_define_module("Test");
rb_define_module_function(Test, "add", RUBY_METHOD_FUNC(add), 2);
}
用 g++ 编译后的DLL文件,可以用 Win32API 调用 Init_Test:
Win32API.new('Test', 'Init_Test', 'v', 'v').call
p Test.add(10, 20) #=> 30
Win32API.new('Test', 'Init_Test', 'v', 'v').call
p Test.add(10, 20) #=> 30
当然,游戏的 Game.ini 设置必须是 102J.dll,我不知道为什么……
没有必要存在的东西
作者: SixRC 时间: 2017-10-27 00:54
点评原来有隐含的长度限制..
最近也有想着优化rgss的
不过能力不足 有了知识才好实践各种乱七八糟的想法
好想有大把时间拿来学习
虽然时间是有 不过却是拿来玩了..
作者: 余烬之中 时间: 2017-10-28 00:40
本帖最后由 余烬之中 于 2017-10-28 00:47 编辑
来了兴趣,折腾了一阵
以前只给 VA 写过 Bitmap 功能拓展之类的,完全用不上什么 rb_define_module
不过写起来倒也不难,毕竟半云都搞出了 ProjectGap,函数地址直接抄来就行了(由醋瞎黄姬友情提供)
搞了一下午+一晚上,其实主要时间都花在修玄学 msys2 的 mingw32 g++(并且没修好改用 msvc cl 了)
仍然是给 VA 写的,也没什么好解释的,还是一个雏形,只要能够给猫叔提供一点启发我就满足了(逃
编辑:RGSS301.dll,不过理论上自己能搞到函数地址的话通用(逃
未严格测试
// License: RBLv1(https://rpg.blue/thread-403387-1-1.html)
// headers
#include <windows.h>
#include <climits>
#include <tchar.h>
// defines
#define RGSSAPI extern "C" __declspec(dllexport)
typedef unsigned long VALUE;
typedef unsigned long ID;
typedef long SIGNED_VALUE;
#define RUBY_FIXNUM_FLAG 0x01
#define Qfalse ((VALUE)0)
#define QTrue ((VALUE)2)
#define Qnil ((VALUE)4)
#define Qundef ((VALUE)6)
#define FIX2LONG(x) ((long)(((SIGNED_VALUE)x)>>1))
#define FIX2ULONG(x) (((x>>1))&LONG_MAX)
#define FIX2INT(x) ((int)FIX2LONG(x))
#define FIX2UINT(x) ((unsigned int)FIX2ULONG(x))
#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1|RUBY_FIXNUM_FLAG))
#define FIXNUM_MAX ((unsigned long)(LONG_MAX>>1))
#define FIXNUM_MIN ((long)LONG_MIN>>(int)1)
#define FIXNUM_P(x) ((((SIGNED_VALUE)(x))&RUBY_FIXNUM_FLAG)!=0)
#define POSFIXABLE(ul) (ul<=FIXNUM_MAX)
#define NEGFIXABLE(l) ( l>=FIXNUM_MIN)
#define FIXABLE(l) (NEGFIXABLE(l)&&(l<=0||POSFIXABLE(l)))
#define def(func, ret, ...) typedef ret(*T##func)(__VA_ARGS__); T##func func
// function return type arguments
def(RGSSEval, int, const char*);
def(rb_define_module, VALUE, const char*);
def(rb_define_module_function, void, VALUE, const char*, void*, int);
#undef def
// extension main
VALUE add(VALUE self, VALUE a, VALUE b) {
return INT2FIX(FIX2INT(a)+FIX2INT(b));
}
RGSSAPI void Test() {
VALUE Test = rb_define_module("Test");
rb_define_module_function(Test, "add", add, 2);
}
// Initialize
void Initialize() {
HMODULE hRGSSLIB;
TCHAR PATH[MAX_PATH];
TCHAR RGSSLIB[MAX_PATH];
GetCurrentDirectory(MAX_PATH, PATH);
_tcsncat_s(PATH, MAX_PATH, _T("\\Game.ini"), MAX_PATH);
GetPrivateProfileString(_T("Game"), _T("Library"), NULL, RGSSLIB, MAX_PATH, PATH);
hRGSSLIB = GetModuleHandle(RGSSLIB);
#define setproc(proc, func) func = (T##func)GetProcAddress(hRGSSLIB, #proc)
#define setaddr(addr, func) func = (T##func)((DWORD)addr+(DWORD)hRGSSLIB)
// set function
setproc(RGSSEval, RGSSEval);
setaddr(0x5E990, rb_define_module);
setaddr(0x5F1E0, rb_define_module_function);
#undef setaddr
#undef setproc
}
class Init {
public:
Init() {
Initialize();
}
} init;
// License: RBLv1(https://rpg.blue/thread-403387-1-1.html)
// headers
#include <windows.h>
#include <climits>
#include <tchar.h>
// defines
#define RGSSAPI extern "C" __declspec(dllexport)
typedef unsigned long VALUE;
typedef unsigned long ID;
typedef long SIGNED_VALUE;
#define RUBY_FIXNUM_FLAG 0x01
#define Qfalse ((VALUE)0)
#define QTrue ((VALUE)2)
#define Qnil ((VALUE)4)
#define Qundef ((VALUE)6)
#define FIX2LONG(x) ((long)(((SIGNED_VALUE)x)>>1))
#define FIX2ULONG(x) (((x>>1))&LONG_MAX)
#define FIX2INT(x) ((int)FIX2LONG(x))
#define FIX2UINT(x) ((unsigned int)FIX2ULONG(x))
#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1|RUBY_FIXNUM_FLAG))
#define FIXNUM_MAX ((unsigned long)(LONG_MAX>>1))
#define FIXNUM_MIN ((long)LONG_MIN>>(int)1)
#define FIXNUM_P(x) ((((SIGNED_VALUE)(x))&RUBY_FIXNUM_FLAG)!=0)
#define POSFIXABLE(ul) (ul<=FIXNUM_MAX)
#define NEGFIXABLE(l) ( l>=FIXNUM_MIN)
#define FIXABLE(l) (NEGFIXABLE(l)&&(l<=0||POSFIXABLE(l)))
#define def(func, ret, ...) typedef ret(*T##func)(__VA_ARGS__); T##func func
// function return type arguments
def(RGSSEval, int, const char*);
def(rb_define_module, VALUE, const char*);
def(rb_define_module_function, void, VALUE, const char*, void*, int);
#undef def
// extension main
VALUE add(VALUE self, VALUE a, VALUE b) {
return INT2FIX(FIX2INT(a)+FIX2INT(b));
}
RGSSAPI void Test() {
VALUE Test = rb_define_module("Test");
rb_define_module_function(Test, "add", add, 2);
}
// Initialize
void Initialize() {
HMODULE hRGSSLIB;
TCHAR PATH[MAX_PATH];
TCHAR RGSSLIB[MAX_PATH];
GetCurrentDirectory(MAX_PATH, PATH);
_tcsncat_s(PATH, MAX_PATH, _T("\\Game.ini"), MAX_PATH);
GetPrivateProfileString(_T("Game"), _T("Library"), NULL, RGSSLIB, MAX_PATH, PATH);
hRGSSLIB = GetModuleHandle(RGSSLIB);
#define setproc(proc, func) func = (T##func)GetProcAddress(hRGSSLIB, #proc)
#define setaddr(addr, func) func = (T##func)((DWORD)addr+(DWORD)hRGSSLIB)
// set function
setproc(RGSSEval, RGSSEval);
setaddr(0x5E990, rb_define_module);
setaddr(0x5F1E0, rb_define_module_function);
#undef setaddr
#undef setproc
}
class Init {
public:
Init() {
Initialize();
}
} init;
作者: 浮云半仙 时间: 2017-10-28 10:12
瑟瑟发抖,留下沟中的项目地址:gitHub.com/sxysxy/ProjectGap
[del]应该是比较科学的给rgss写c扩展的方法,也不需要魔改原有的二进制文件。[/del]
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |