| 赞 | 87 |
| VIP | |
| 好人卡 | |
| 积分 | 136 |
| 经验 | |
| 最后登录 | 2021-1-24 |
| 在线时间 | 2753 小时 |
- 梦石
- 0
- 星屑
- 13562
- 在线时间
- 2753 小时
- 注册时间
- 2014-10-4
- 回帖
- 705

|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有账号?注册会员
×
本帖最后由 SixRC 于 2017-11-2 08:05 编辑
新开一主题 因为改了很多 解决了很多上一版本的问题
这次写了好多天 写到今天终于感觉 几乎是差不多了吧
果然代码还是要慢慢慢慢写 涂涂改改涂涂改改才好发布的
那么 现在由我来介绍 这次版本的优点
1.窗口独立 大小随意 这次是真独立
独立的鼠标键盘消息获取 独立的窗口焦点 独立的关闭
和主窗口没有关联了 你可能会担心窗口失去焦点带来的不刷新的问题
所以第二点
2.支持后台运行 你可以指定后台运行与否
即使失去焦点也会继续刷新
你也可以直接不要显示窗口 当作多线程来用..
3.支持消息传递
虽然只支持四个整数的传递 不过可以传指针 实际上是没什么问题的
4.内存释放优化
这个想了很久 不过大多失败了
不过后来发现简单的做法似乎是最有效的
5.使用方便 很方便了
只要给它运行的代码 告诉他窗口多大放哪里显不显示等等
用完了判断一下是否结束就可以了
具体使用说明请见脚本
[fold=RMXP多窗体 v2.0][pre lang="ruby"]#-----------------------------------------------------------------
# ----SixRC 于 2017.11.1
# 基本介绍及基本使用说明
# 这个玩意让你可以随意创建新窗口
# 每个窗口都是由RGSS脚本控制的 每个窗口都是独立的
# 窗口支持后台运行 音乐播放与主窗口不冲突
# 每个窗口可以随意打开随意关闭 没什么特别需要注意的
# 主窗口和建立的窗口可以有消息沟通
# 新建一个窗口,需要新建一个实例 不需要传参
# 然后根据需要对特定属性赋值 之后 x.run开始运行
# 不提供强杀方法 但是提供主窗口和次窗口之间消息传递的方法
# 可以在新建窗口中判断然后退出
# 判断 x.ok? true则表明已经关闭 并会自动清理资源
# 知道为true后就不用管它了
# 下面是所有的属性和简介 所有属性都有默认值 所以不太了解的可以不管
# x.code 是运行的rgss脚本 可以是脚本或rxdata文件如"Data/123.rxdata"
# x.from_rxdata bool 表明脚本是否来自 x.rxdata文件
# x.show_window bool 表明是否显示窗口
# x.title 窗口标题
# x.x x.y x.width x.height 指明新建窗口的位置和宽高
# x.exstyle x.style 是窗口风格
# x.class_style 窗口类的风格
# x.hicon x.hcursor 窗口图标和鼠标资源的句柄
# 后台运行方法
# x.back_groundrunning(bool) 不指定默认为true 不调用此方法默认不后台运行
# 下面是消息传递的方法
# 主窗口下 x.send_message x.get_message 如 x.send_message(1,2,3,4)
# 注意最多传递四个值 必须为整数 有更多需要可以传递指针然后你懂的
# 获取的消息是一个四位的数组 传值时没指定的默认为0
# 次窗口下 Ewindow.send_message Ewindow.get_message 同上
#
# 假如有任何建议和问题或者需要拓展改进的 请联系我
# https://rpg.blue/home.php?mod=space&uid=2633638
# 不过不保证修改
# 不过你大可以自行修改
#-----------------------------------------------------------------
class Ewindow
#---------------------------------------------------------------
LoadLibrary=Win32API.new('kernel32','LoadLibraryA','p','l')
GetProcAddress=Win32API.new('kernel32','GetProcAddress','lp','l')
#---------------------------------------------------------------
User32=LoadLibrary.call("user32")
DefWindowProc=GetProcAddress.call(User32,'DefWindowProcA')
CreateWindow=GetProcAddress.call(User32,'CreateWindowExA')
#---------------------------------------------------------------
Kernel32=LoadLibrary.call("kernel32")
ExitThread=GetProcAddress.call(Kernel32,'ExitThread')
#---------------------------------------------------------------
WriteProcessMemory=Win32API.new('kernel32','WriteProcessMemory','llpll','l')
CreateThread=Win32API.new('kernel32','CreateThread','llppll','l')
CloseHandle=Win32API.new('kernel32','CloseHandle','l','l')
RegisterClass=Win32API.new('user32','RegisterClassA','p','l')
GetClassInfo=Win32API.new('user32','GetClassInfo','lpp','l')
FreeLibrary=Win32API.new('kernel32','FreeLibrary','l','l')
CWP=Win32API.new('user32.dll','CallWindowProc','pppll','l')
WideCharToMultiByte=Win32API.new('kernel32','WideCharToMultiByte','llplplll','l')
MultiByteToWideChar=Win32API.new('kernel32','MultiByteToWideChar','llplpl','l')
#---------------------------------------------------------------
DLL="RGSS103J.dll"
Exit="Ewindow.dispose"
Hinstance=Win32API.new('kernel32','GetModuleHandleA','l','l').call(0)
wndclass="\0"*40
GetClassInfo.call(Hinstance,"RGSS Player",wndclass)
Hicon,Hcursor=wndclass.unpack('l*')[5,2]
#---------------------------------------------------------------
Dir.mkdir("Ewindow") unless Dir.glob("Ewindow")[0]
Dir.glob("Ewindow/*.rxdata").each{|i|File.delete(i)}
Dir.glob("Ewindow/*.dll").each{|i|File.delete(i)}
#---------------------------------------------------------------
Pre=<<EOF
$E_bitmaps=[]
$E_sprites=[]
def exit
Ewindow.exit
end
class Bitmap
alias e_initialize initialize
def initialize(*args)
$E_bitmaps.push(e_initialize(*args))
end
end
class Sprite
alias e_initialize initialize
def initialize(*args)
$E_sprites.push(e_initialize(*args))
end
end
module Ewindow
module_function
CWP=Win32API.new('user32.dll','CallWindowProc','pllll','l')
CWPlp=Win32API.new('user32.dll','CallWindowProc','plpll','l')
Get_hwnd=[139,68,36,4,139,64,4,194,16,0].pack('C*')
Hwnd=CWP.call(Get_hwnd,$E_shared,0,0,0)
Win32API.new('user32','ShowWindow','ll','l').call(Hwnd,1) if $E_show
def exit
Win32API.new('user32','SendMessageA','llll','l').call(Hwnd,0x10,0,0)
end
def dispose
$E_sprites.each{|i|i.dispose}
$E_bitmaps.each{|i|i.dispose}
Audio.bgm_stop
Audio.bgs_stop
Audio.me_stop
Audio.se_stop
end
Send=[139,124,36,4,131,199,24,139,116,36,8,185,4,0,0,0,252,243,165,195].pack('C*')
def send_message(s1=0,s2=0,s3=0,s4=0)
message=[s1,s2,s3,s4].pack('llll')
CWPlp.call(Send,$E_shared,message,0,0)
end
Get=[139,116,36,4,131,198,8,139,124,36,8,185,4,0,0,0,252,243,165,195].pack('C*')
def get_message
message=[0].pack('l')*4
CWPlp.call(Get,$E_shared,message,0,0)
message.unpack('llll')
end
end
EOF
#---------------------------------------------------------------
attr_accessor:code,:from_rxdata,:show_window,:title,:x,:y,:width,:height
attr_accessor:exstyle,:style,:class_style,:hicon,:hcursor
def initialize
@id=Time.now.to_i.to_s+Time.now.usec.to_s
@code=""
@from_rxdata=false
@show_window=true
@title="Ewindow"+@id
@x=@y=@width=@height=0
@exstyle=0x100
@style=0xca0000
@class_style=8
@hicon=Hicon
@hcursor=Hcursor
@shared="\0"*40
@ok=false
make_dll
end
#------------------------------------------------------------------
def run
inject
from_rxdata ? make_rxdata2 : make_rxdata1
start_rgss
end
#-------------------------------------------------------------------
def make_dll
dll=open("Ewindow/#{@id}.dll","wb")
dll.syswrite(open(DLL,"rb").sysread(File.size(DLL)))
dll.close
@dll=LoadLibrary.call("Ewindow/#{@id}.dll")
end
#-----------------------------------------------------------------
def inject
@window_procedure="\x83\x7C\x24\x08\x10\x74\x0D\x8B\x0D"+
[@dll+0x12B6C4].pack('l')+"\xB8"+[@dll+0x2EC0].pack('l')+"\xFF\xE0\x68"+
[Exit].pack('p')+"\xB8"+[@dll+0x3C10].pack('l')+"\xFF\xD0\x50\xC6\x05"+
[@shared].pack('p')+"\x01\xB8"+[ExitThread].pack('l')+"\xFF\xD0"
x="\xB9"+[@window_procedure].pack('p')+"\xFF\xE1"
WriteProcessMemory.call(-1,@dll+0x3190,x,7,0)
WriteProcessMemory.call(-1,@dll+0xAC25,"\x90"*5,5,0)
WriteProcessMemory.call(-1,@dll+0x87724,[0x50,0xB8,width,0xBA,height,0x90,0x90].pack('CClClCC'),13,0)
end
#-----------------------------------------------------------------
def make_rxdata1
script="$E_shared=#{[@shared].pack('p').unpack('l')[0]}\n$E_show=#{@show_window}\n"+Pre+@code
rxdata=open("Ewindow/#{@id}.rxdata","wb")
rxdata.syswrite(Marshal.dump([[0,"",Zlib::Deflate.deflate(script)],[2,"",Zlib::Deflate.deflate("exit")]]))
rxdata.close
Graphics.update
end
#-----------------------------------------------------------------
def make_rxdata2
s=load_data(@code)
script="$E_shared=#{[@shared].pack('p').unpack('l')[0]}\n$E_show=#{@show_window}\n"+Pre
s.unshift([0,"",Zlib::Deflate.deflate(script)])
s.push([1,"",Zlib::Deflate.deflate("exit")])
rxdata=open("Ewindow/#{@id}.rxdata","wb")
rxdata.syswrite(Marshal.dump(s))
rxdata.close
Graphics.update
end
#-----------------------------------------------------------------
def start_rgss
wndclass=[@class_style,DefWindowProc,0,0,@dll,@hicon,@hcursor,0,0,@id].pack("lllllllllp")
rclass=RegisterClass.call(wndclass)
rclass=[rclass].pack('l').unpack('S')[0]
@unknown="\0"*0x400
set=GetProcAddress.call(@dll,'RGSSSetupRTP')
init=GetProcAddress.call(@dll,'RGSSInitialize')
gmain=GetProcAddress.call(@dll,'RGSSGameMain')
rxdata="Ewindow/#{@id}.rxdata"
ini=utf8_to_ascii(Dir.pwd+"/Game.ini")
code="\x31\xD2\x52\x68"+[@dll].pack('l')+"\x52\x52\x52\x52\x68"+
[@y].pack('l')+"\x68"+[@x].pack('l')+"\x68"+[@style].pack('l')+"\x68"+
[@title].pack('p')+"\x68"+[rclass].pack('l')+"\x68"+[@exstyle].pack('l')+
"\xB8"+[CreateWindow].pack('l')+"\xFF\xD0\x89\xC3\xB8"+
[@shared].pack('p')+"\x89\x58\x04"+"\x68\x00\x04\x00\x00\x68"+
[@unknown].pack('p')+"\x68"+[ini].pack('p')+"\xB8"+[set].pack('l')+"\xFF\xD0\x83\xC4\x0C\x68"+
[@dll].pack('l')+"\xB8"+[init].pack('l')+"\xFF\xD0\x58\x68"+[@unknown].pack('p')+
"\x68"+[rxdata].pack('p')+"\x53\xB8"+[gmain].pack('l')+"\xFF\xD0\xC3"
CloseHandle.call(CreateThread.call(0,0,code,0,0,0))
end
#-----------------------------------------------------------------
def utf8_to_ascii(str)
len=MultiByteToWideChar.call(0xFDE9,0,str,-1,0,0)
str2="\0"*len
MultiByteToWideChar.call(0xFDE9,0,str,-1,str2,len)
len=WideCharToMultiByte.call(0,0,str2,-1,0,0,0,0)
str="\0"*len
WideCharToMultiByte.call(0,0,str2,-1,str,len,0,0)
str
end
#------------------------------------------------------------------
def ok?
return true if @ok
@ok=@shared.unpack('l')[0]==1 && clean
end
#------------------------------------------------------------------
def clean
FreeLibrary.call(@dll)
File.delete("Ewindow/#{@id}.rxdata")
File.delete("Ewindow/#{@id}.dll")
end
#------------------------------------------------------------------
def back_groundrunning(x=true)
n= x ? "\0" : "\x46"
WriteProcessMemory.call(-1,@dll+0x2E48,n,1,0)
end
#------------------------------------------------------------------
Send=[139,124,36,4,131,199,8,139,116,36,8,185,4,0,0,0,252,243,165,195].pack('C*')
def send_message(s1=0,s2=0,s3=0,s4=0)
message=[s1,s2,s3,s4].pack('llll')
CWP.call(Send,@shared,message,0,0)
end
#------------------------------------------------------------------
def get_message
@shared.unpack("llllllllll")[6,4]
end
#-------------------------------------------------------------------
end[/pre][/fold]
然后是一些实现上的细节
模仿了exe加载rgss的方式加载了新的rgss 开始问题很多 不过慢慢都解决了
在RGSSGameMain那里我直接pass掉了控制线程的建立(原来用来检查10s和关闭进程用)
注入了rgss原来的窗口消息处理机制 所以收到 0x10 的VM_CLOSE可以自己控制怎么关掉
后台运行由改掉一个跳转实现 rgss收到 0x1C WM_ACTIVATEAPP 会把一个变量改成1 判断为1则刷新否则继续循环
窗口的建立综合了createwindowex和rgss 在前者确定x和y 后面确定宽高
在加载RSS103J的时候dllmain会建立一个heap freelibrary的时候它又会释放掉 所以只需要free就能解决很大程度上的内存泄漏
位图和精灵则通过dispose 音频暂时没有处理 余下的大约是增加了3M 其中1M是实例带来的 所以实际上只有2M没释放 可以说是很少了
我猜是gdi对象 大概字体啥的 没释放吧
等等等等暂时没想那么多了就这样吧
欢迎提出建议 不过不一定会解决就是了
然后是一个范例:
RMXP多窗体v2.0范例.zip
(746.22 KB, 下载次数: 189)
能很好的帮助理解脚本的使用
范例配图
|
评分
-
查看全部评分
|