设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 621|回复: 3

[已经解决] GetClipboardData(CF_UNICODETEXT) 从第一个ascii字符后内容半随机

[复制链接]

Lv1.梦旅人

梦石
0
星屑
50
在线时间
194 小时
注册时间
2010-10-12
帖子
281
发表于 2017-8-12 17:16:20 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 新手小白 于 2017-8-12 17:36 编辑

代码:
# 参考: https://github.com/janlelis/clip ... lipboard/windows.rb
module Clipboard
  
  # kernel32
  # (hMem: HGLOBAL) -> LPVOID
  @GlobalLock = Win32API.new("kernel32", "GlobalLock",%(p), %(p))
  @GlobalUnlock = Win32API.new("kernel32", "GlobalUnlock",%(l), %(l))
  @GlobalSize = Win32API.new("kernel32", "GlobalSize",%(l), %(l))

  @WideCharToMultiByte = Win32API.new('kernel32', 'WideCharToMultiByte', 'ilpipipp', 'i')  
  @GetACP = Win32API.new("kernel32", "GetACP", %(v), %(i))
  # Maps a character string to a UTF-16 (wide character) string. The character string is not necessarily from a multibyte character set.
  @MultiByteToWideChar = Win32API.new('kernel32', 'MultiByteToWideChar', 'ilpipi', 'i')

  @CopyMemory = Win32API.new('msvcrt', 'memcpy', %(p, p, l), %(p)) #Win32API.new('kernel32', 'CopyMemory', %(p, p, l), %(v))

  # user32
  # (hWndNewOwner: HWND) -> BOOL
  @OpenCLipboard = Win32API.new("user32", "OpenClipboard",%(l), %(l))
  @CloseClipboard = Win32API.new("user32", "CloseClipboard",'', %(l))
  # (uFormat: UINT) -> HANDLE
  @GetClipboardData = Win32API.new("user32", "GetClipboardData",%(i), %(l))

  @FindWindow   = Win32API.new("user32", "FindWindow", 'pp', 'i')

  
  CF_TEXT = 1
  CF_UNICODETEXT = 13 # UTF-16

  CP_UTF8 = 65001
  CP_ACP = 0
  #CP_MACCP = 2
  CP_THREAD_ACP = 3
  CP_GBK = 936

  # CF_UNICODETEXT -> WideCharToMultiByte
  def self.GetContent(limit=3*6)
    begin
            
      if @OpenCLipboard.call(0) != 0
        hClip = @GetClipboardData.call(CF_UNICODETEXT)
        if hClip && hClip != 0
          pData = @GlobalLock.call(hClip)
          size = @GlobalSize.call(hClip)
                    
          #@CopyMemory.call(buf, pData, size)
         
          #acp = @GetACP.call()
          #p acp
          #p CP_THREAD_ACP
         
          #utf16Len = @MultiByteToWideChar.call(CP_ACP, 0, pData, size, nil, 0)
          #p utf16Len
          #utf16Str = "\0" * (limit * 2)
          #@MultiByteToWideChar.call(CP_ACP, 0, pData, size, utf16Str, limit)
          str = "\0" * (limit < size/2 ? limit : size)
          @WideCharToMultiByte.call (CP_UTF8, 0, pData, size/2, str, limit, nil, nil)
         
          #str.delete!("\0")
          p str
         
          @GlobalUnlock.call(hClip)
        end
        @CloseClipboard.call()
      end
      return str || ""   
    #rescue
    #  return nil
    end
  end
   
end

作用: 获取剪贴板中的内容. 游戏中角色名字不能随便起, 想workaround一下
现象:
"糖葫芦""啊啊啊""あああ" => 正常
"abc""RMXP""#123" => 只有第一个字符显示正常, 后面都是垃圾, 每次调用都有部分会变, 而且有时能能出现某部分脚本的代码...
"牛肉面abc""可达鸭###" => 从第一个ASCII字符开始出现上述垃圾内容

顺便, 我电脑的系统不是Windows, 所以我用XP虚拟机运行RMXP.
我发现如果把参数设成CF_TEXT, 在虚拟机内复制的文本会返回utf-8编码的字符串, 在虚拟机外复制的文本会返回GBK, 因为无法直接判断是从哪里复制的, 所以就放弃了... 而且, wine下获取到的字符串中的Unicode字符会显示成"?"...

心好累... 已经快浪费两天时间了...

Lv1.梦旅人

梦石
0
星屑
176
在线时间
119 小时
注册时间
2009-12-16
帖子
153
发表于 2017-8-13 14:50:20 | 显示全部楼层
帮你修正顺便精简了,目测你的问题出在pData,由于是utf-16,因此第二个字节通常会是0x00(null),於是ruby就停止读取了,直接用hclip把相对应需要的数据及长度复制到ruby里的字符串就行了,至于转码pack和unpack可以使utf-16与utf-8之间的转码变得轻松
  1. module Clipboard
  2.   
  3.   # kernel32
  4.   # (hMem: HGLOBAL) -> LPVOID
  5.   @GlobalLock = Win32API.new("kernel32", "GlobalLock",%(p), %(p))
  6.   @GlobalUnlock = Win32API.new("kernel32", "GlobalUnlock",%(l), %(l))
  7.   @GlobalSize = Win32API.new("kernel32", "GlobalSize",%(l), %(l))

  8.   @wcslen = Win32API.new('msvcrt', 'wcslen', %(i), %(I))
  9.   @memmove = Win32API.new('msvcrt', 'memmove', %(p, l, l), %(p))
  10.   
  11.   # user32
  12.   # (hWndNewOwner: HWND) -> BOOL
  13.   @OpenCLipboard = Win32API.new("user32", "OpenClipboard",%(l), %(l))
  14.   @CloseClipboard = Win32API.new("user32", "CloseClipboard",'', %(l))
  15.   # (uFormat: UINT) -> HANDLE
  16.   @GetClipboardData = Win32API.new("user32", "GetClipboardData",%(i), %(l))

  17.   CF_UNICODETEXT = 13 # UTF-16

  18.   # CF_UNICODETEXT -> WideCharToMultiByte
  19.   def self.GetContent(limit=3*6)
  20.     begin
  21.             
  22.       if @OpenCLipboard.call(0) != 0
  23.         hClip = @GetClipboardData.call(CF_UNICODETEXT)
  24.         if hClip && hClip != 0
  25.           pData = @GlobalLock.call(hClip)
  26.           size = @wcslen.call(hClip)
  27.           buff = ([0]*[size,limit].min).pack('S*')
  28.           @memmove.call(buff, hClip, buff.unpack('C*').size)
  29.           str = buff.unpack('S*').pack('U*')
  30.           #size = @GlobalSize.call(hClip)
  31.                     
  32.           #@CopyMemory.call(buf, pData, size)
  33.          
  34.           #acp = @GetACP.call()
  35.           #p acp
  36.           #p CP_THREAD_ACP
  37.          
  38.           #utf16Len = @MultiByteToWideChar.call(CP_ACP, 0, pData, size, nil, 0)
  39.           #p utf16Len
  40.           #utf16Str = "\0" * (limit * 2)
  41.           #@MultiByteToWideChar.call(CP_ACP, 0, pData, size, utf16Str, limit)
  42.           #str = "\0" * (limit < size/2 ? limit : size)
  43.           #@WideCharToMultiByte.call (CP_UTF8, 0, pData, size/2, str, limit, nil, nil)
  44.          
  45.           #str.delete!("\0")
  46.           p str
  47.          
  48.           @GlobalUnlock.call(hClip)
  49.         end
  50.         @CloseClipboard.call()
  51.       end
  52.       return str || ""   
  53.     #rescue
  54.     #  return nil
  55.     end
  56.   end
  57.    
  58. end

  59. Clipboard.GetContent
复制代码

假设粘帖板的数据是“ABCD”那么在内存里hClip所在的数据为:[0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00],因为每个字符是2字节,因此在这里的一切没用widechar来操作的话根本不行。

点评

不用客气,回答的奖励版主已经给了  发表于 2017-8-14 21:59
不知道为什么评分没有输分值的框, 只能先以点评感谢. 十分十分感谢!  发表于 2017-8-14 21:04

评分

参与人数 1星屑 +66 梦石 +1 收起 理由
guoxiaomi + 66 + 1 醋虾

查看全部评分

⎝(゚∀。)⎠
回复 支持 反对

使用道具 举报

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

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2022-1-17 13:15

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表