查看: 2615|回复: 23

[已经过期] 如何让这个截图脚本在全屏模式下可以截图

[复制链接]
梦石
0
星屑
3053
在线时间
441 小时
注册时间
2014-11-21
回帖
103
发表于 2017-9-20 17:55:24 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
我用了站内的不会因为窗口被遮挡导致截图不全的脚本,但是发现在全屏模式下无法正常截图,
请问该如何更改使它在全屏模式下也能截图?
[pre lang="ruby"]#--------------------------------------------------------------------------
# ● RMXP用 Graphics.snap_to_bitmap
#
#    就算窗口被遮盖或者显示不全也可以正常截图
#
#    附赠: Graphics.snap_to_clipboard
#
#          截图到剪贴板
#
#
# ● 作者:晴兰 @ 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[/pre]

精灵族の天使<

梦石
0
星屑
1712
在线时间
3039 小时
注册时间
2007-3-16
回帖
33092

开拓者贵宾

发表于 2017-9-21 13:15:05 | 显示全部楼层
#    备注:如果你因为任何原因改变了窗口大小(或者常说的分辨率)
#
#    搜索并且修改"# 如果屏幕宽度改变请折腾下面这两处"附近
回复

使用道具 举报

梦石
0
星屑
3053
在线时间
441 小时
注册时间
2014-11-21
回帖
103
 楼主| 发表于 2017-9-21 19:08:36 | 显示全部楼层
精灵使者 发表于 2017-9-21 13:15
#    备注:如果你因为任何原因改变了窗口大小(或者常说的分辨率)
#
#    搜索并且修改"# 如果屏幕宽度 ...

唔,我说的是游戏自带的alt+enter,这个也需要改吗?
如果改的话该怎么判定现在是否处于全屏啊……

点评

XP吗。 回头我试试看  发表于 2017-10-7 18:26
是XP  发表于 2017-10-7 11:57
对了,你的操作系统是?  发表于 2017-10-6 17:27
你把那段脚本随便拉进一个工程然后p一下应该行吧……  发表于 2017-10-6 15:15
如果有范例工程的话我试试测试一下……  发表于 2017-10-3 18:24
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部