赞 | 1 |
VIP | 0 |
好人卡 | 0 |
积分 | 29 |
经验 | 16245 |
最后登录 | 2024-10-5 |
在线时间 | 435 小时 |
Lv3.寻梦者
- 梦石
- 0
- 星屑
- 2932
- 在线时间
- 435 小时
- 注册时间
- 2014-11-21
- 帖子
- 145
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
我用了站内的不会因为窗口被遮挡导致截图不全的脚本,但是发现在全屏模式下无法正常截图,
请问该如何更改使它在全屏模式下也能截图?
#-------------------------------------------------------------------------- # ● RMXP用 Graphics.snap_to_bitmap # # 就算窗口被遮盖或者显示不全也可以正常截图 # # 附赠: Graphics.snap_to_clipboard # # 截图到剪贴板 # # # ● 作者:晴兰 [url=home.php?mod=space&uid=67509]@[/url] rpg.blue # # 使用到紫苏前辈的获取窗口句柄脚本,其他部分为原创 # # ● 备注:如果你因为任何原因改变了窗口大小(或者常说的分辨率) # # 搜索并且修改"# 如果屏幕宽度改变请折腾下面这两处"附近 #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- # ● 紫苏前辈的获取窗口句柄 # 部分细节已修改 #-------------------------------------------------------------------------- module Kernel #-------------------------------------------------------------------------- # ● 需要的 Windows API 函数 #-------------------------------------------------------------------------- GetWindowThreadProcessId = Win32API.new("user32", "GetWindowThreadProcessId", "LP", "L") GetWindow = Win32API.new("user32", "GetWindow", "LL", "L") GetClassName = Win32API.new("user32", "GetClassName", "LPL", "L") GetCurrentThreadId = Win32API.new("kernel32", "GetCurrentThreadId", "V", "L") GetForegroundWindow = Win32API.new("user32", "GetForegroundWindow", "V", "L") #-------------------------------------------------------------------------- # ● 获取窗口句柄 #-------------------------------------------------------------------------- def hwnd # 获取调用线程(RM 的主线程)的进程标识 threadID = GetCurrentThreadId.call # 获取 Z 次序中最靠前的窗口 hWnd = GetWindow.call(GetForegroundWindow.call, 0) # 枚举所有窗口 while hWnd != 0 # 如果创建该窗口的线程标识匹配本线程标识 if threadID == GetWindowThreadProcessId.call(hWnd, 0) # 分配一个 11 个字节的缓冲区 className = " " * 12 # ● # 获取该窗口的类名 GetClassName.call(hWnd, className, 12) # ● # 如果匹配 RGSS Player 则跳出循环 break if className[0, 11] == "RGSS Player" end # 获取下一个窗口 hWnd = GetWindow.call(hWnd, 2) end return hWnd end end module SAFX module_function class ::Integer; def pack; self; end; def to_param; 'i'; end; def ord; self; end; end class ::String;def pack; [self].pack('p').unpack('L').first; end; def to_param; 'p'; end; end def api(dll,func) lambda{|*args| Win32API.new(dll,func,args.map{|x|x.to_param}, 'i').call *args } end def callproc(addr, type = :cdecl) stdcall = type == :stdcall raise "addr == 0 " if addr.pack == 0 apicall = api('user32', 'CallWindowProcW') lambda{|*args|apicall.call((code=[0x55,0xe589].pack('CS')+args.map{|x| [0x68, x.pack].pack('CL')}.reverse.join+[0xb8, addr.pack, 0xD0FF, 0xc481, (stdcall ? 0 : args.length*4) , 0x10c2c9].pack('CLSSLL')),0,0,0,0)} end LL = api("kernel32", "LoadLibrary") GPA = api("kernel32", "GetProcAddress") def funcaddr(dll, func) x = GPA.call(LL.call(dll), func) x == 0 ? nil : x end def readmem(start, len) api('kernel32', 'RtlMoveMemory').call buf = "\0"*len, start, len buf end def writemem(start, len, value) api('kernel32', 'RtlMoveMemory').call start, value, [len, value.length].min end end class << Graphics # 如果屏幕宽度改变请折腾下面这两处 def width 640 end def height 480 end def do_screen_stuff hwnd = self.hwnd src = SAFX.api('user32', 'GetDC').call(hwnd) memdc = SAFX.api('gdi32', 'CreateCompatibleDC').call(src) hb = SAFX.api('gdi32', 'CreateCompatibleBitmap').call(src, width, height) ho = SAFX.api('gdi32', 'SelectObject').call(memdc, hb) bp = SAFX.funcaddr("user32", "GetDC") ov = "\0"*4 str = [0xb8, memdc, 0xc2, 0x04, 0x00].pack("CLC*") # magic, touch SAFX.api('Kernel32', 'VirtualProtect').call(bp, str.length, 0x40, ov) oldstr = SAFX.readmem(bp, str.length) SAFX.writemem bp, str.length, str SAFX.api('user32', 'UpdateWindow').call(hwnd) Graphics.update SAFX.writemem bp, str.length, oldstr yield hb ensure SAFX.api('user32', 'ReleaseDC').call(hwnd, src) hb = SAFX.api('gdi32', 'SelectObject').call(memdc, ho) SAFX.api('gdi32', 'DeleteObject').call(ho) SAFX.api('gdi32', 'DeleteDC').call(memdc) end def snap_to_bitmap bm = Bitmap.new(width, height) addr = bm.object_id * 2 addr, = SAFX.readmem(addr + 16, 4).unpack("L") addr, = SAFX.readmem(addr + 8, 4).unpack("L") addr, = SAFX.readmem(addr + 16, 4).unpack("L") do_screen_stuff do |hb| bits = "\0"*(width * height * 4) SAFX.api('gdi32', 'GetBitmapBits').call(hb, bits.length, bits) r = SAFX.api('kernel32', 'RtlMoveMemory') a = bits.pack stride = width * 4 h = height (h-1).downto(0){|i| r.call addr + i * stride, a + (h - i - 1)*stride, stride } bm end end def snap_to_clipboard return false if SAFX.api('user32', 'OpenClipboard').call(hwnd) == 0 do_screen_stuff do |hb| SAFX.api('user32', 'SetClipboardData').call(2, hb) SAFX.api('user32', 'CloseClipboard').call true end end end
#--------------------------------------------------------------------------
# ● RMXP用 Graphics.snap_to_bitmap
#
# 就算窗口被遮盖或者显示不全也可以正常截图
#
# 附赠: Graphics.snap_to_clipboard
#
# 截图到剪贴板
#
#
# ● 作者:晴兰 [url=home.php?mod=space&uid=67509]@[/url] rpg.blue
#
# 使用到紫苏前辈的获取窗口句柄脚本,其他部分为原创
#
# ● 备注:如果你因为任何原因改变了窗口大小(或者常说的分辨率)
#
# 搜索并且修改"# 如果屏幕宽度改变请折腾下面这两处"附近
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# ● 紫苏前辈的获取窗口句柄
# 部分细节已修改
#--------------------------------------------------------------------------
module Kernel
#--------------------------------------------------------------------------
# ● 需要的 Windows API 函数
#--------------------------------------------------------------------------
GetWindowThreadProcessId = Win32API.new("user32", "GetWindowThreadProcessId", "LP", "L")
GetWindow = Win32API.new("user32", "GetWindow", "LL", "L")
GetClassName = Win32API.new("user32", "GetClassName", "LPL", "L")
GetCurrentThreadId = Win32API.new("kernel32", "GetCurrentThreadId", "V", "L")
GetForegroundWindow = Win32API.new("user32", "GetForegroundWindow", "V", "L")
#--------------------------------------------------------------------------
# ● 获取窗口句柄
#--------------------------------------------------------------------------
def hwnd
# 获取调用线程(RM 的主线程)的进程标识
threadID = GetCurrentThreadId.call
# 获取 Z 次序中最靠前的窗口
hWnd = GetWindow.call(GetForegroundWindow.call, 0)
# 枚举所有窗口
while hWnd != 0
# 如果创建该窗口的线程标识匹配本线程标识
if threadID == GetWindowThreadProcessId.call(hWnd, 0)
# 分配一个 11 个字节的缓冲区
className = " " * 12 # ●
# 获取该窗口的类名
GetClassName.call(hWnd, className, 12) # ●
# 如果匹配 RGSS Player 则跳出循环
break if className[0, 11] == "RGSS Player"
end
# 获取下一个窗口
hWnd = GetWindow.call(hWnd, 2)
end
return hWnd
end
end
module SAFX
module_function
class ::Integer; def pack; self; end; def to_param; 'i'; end; def ord; self; end; end
class ::String;def pack; [self].pack('p').unpack('L').first; end; def to_param; 'p'; end; end
def api(dll,func)
lambda{|*args|
Win32API.new(dll,func,args.map{|x|x.to_param}, 'i').call *args
}
end
def callproc(addr, type = :cdecl)
stdcall = type == :stdcall
raise "addr == 0 " if addr.pack == 0
apicall = api('user32', 'CallWindowProcW')
lambda{|*args|apicall.call((code=[0x55,0xe589].pack('CS')+args.map{|x| [0x68, x.pack].pack('CL')}.reverse.join+[0xb8, addr.pack, 0xD0FF, 0xc481, (stdcall ? 0 : args.length*4) , 0x10c2c9].pack('CLSSLL')),0,0,0,0)}
end
LL = api("kernel32", "LoadLibrary")
GPA = api("kernel32", "GetProcAddress")
def funcaddr(dll, func)
x = GPA.call(LL.call(dll), func)
x == 0 ? nil : x
end
def readmem(start, len)
api('kernel32', 'RtlMoveMemory').call buf = "\0"*len, start, len
buf
end
def writemem(start, len, value)
api('kernel32', 'RtlMoveMemory').call start, value, [len, value.length].min
end
end
class << Graphics
# 如果屏幕宽度改变请折腾下面这两处
def width
640
end
def height
480
end
def do_screen_stuff
hwnd = self.hwnd
src = SAFX.api('user32', 'GetDC').call(hwnd)
memdc = SAFX.api('gdi32', 'CreateCompatibleDC').call(src)
hb = SAFX.api('gdi32', 'CreateCompatibleBitmap').call(src, width, height)
ho = SAFX.api('gdi32', 'SelectObject').call(memdc, hb)
bp = SAFX.funcaddr("user32", "GetDC")
ov = "\0"*4
str = [0xb8, memdc, 0xc2, 0x04, 0x00].pack("CLC*") # magic, touch
SAFX.api('Kernel32', 'VirtualProtect').call(bp, str.length, 0x40, ov)
oldstr = SAFX.readmem(bp, str.length)
SAFX.writemem bp, str.length, str
SAFX.api('user32', 'UpdateWindow').call(hwnd)
Graphics.update
SAFX.writemem bp, str.length, oldstr
yield hb
ensure
SAFX.api('user32', 'ReleaseDC').call(hwnd, src)
hb = SAFX.api('gdi32', 'SelectObject').call(memdc, ho)
SAFX.api('gdi32', 'DeleteObject').call(ho)
SAFX.api('gdi32', 'DeleteDC').call(memdc)
end
def snap_to_bitmap
bm = Bitmap.new(width, height)
addr = bm.object_id * 2
addr, = SAFX.readmem(addr + 16, 4).unpack("L")
addr, = SAFX.readmem(addr + 8, 4).unpack("L")
addr, = SAFX.readmem(addr + 16, 4).unpack("L")
do_screen_stuff do |hb|
bits = "\0"*(width * height * 4)
SAFX.api('gdi32', 'GetBitmapBits').call(hb, bits.length, bits)
r = SAFX.api('kernel32', 'RtlMoveMemory')
a = bits.pack
stride = width * 4
h = height
(h-1).downto(0){|i|
r.call addr + i * stride, a + (h - i - 1)*stride, stride
}
bm
end
end
def snap_to_clipboard
return false if SAFX.api('user32', 'OpenClipboard').call(hwnd) == 0
do_screen_stuff do |hb|
SAFX.api('user32', 'SetClipboardData').call(2, hb)
SAFX.api('user32', 'CloseClipboard').call
true
end
end
end
|
|