查看: 3924|回复: 0

[原创发布] 【不是创意的创意】解决调用环境变量中文乱码现象

[复制链接]

精灵族の天使<

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

开拓者贵宾

发表于 2014-10-11 15:18:21 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 精灵使者 于 2015-2-1 17:44 编辑

精灵在汉化游戏的时候,发现一些使用中文用户名的游戏无法启动,症状如下:
QQ图片20141011144317.png
经检查出问题的脚本如下:
[pre lang="ruby" line="1"]# Create Path Where Folder Should Be Created
  path = " " * 256
  path = ENV['AV_APPDATA'].rstrip
  $appPath = path.to_s + "\\To the Moon - Freebird Games"   
  
  # Create Your Folder
  if !File.exists?($appPath)  
    Dir.mkdir($appPath) #出问题的那行
  end[/pre]
于是就麻烦了。
中文用户名导致EV['AV_APPDATA']产生乱码,以至于后面的建立文件夹失败。
所以就需要进行S2U转换一下。
解决脚本如下:
[pre lang="ruby" line="1"]
#Using for Non-english speaking words encoding conversion
  #quintess non-english paths
  APPNAME = "\\To the Moon - Freebird Games"
module Seiran20
  module_function
  class ::Integer; def to_ptr; self; end; def to_param; 'i'; end; def ord; self; end; end
  class ::String;def to_ptr; [self].pack('p').unpack('L').first; end; def to_param; 'p'; end; end

  def procname(a, b)
    class << a; self; end.send :define_method, :inspect do b end
    a
  end

  def api(dll,func)
    procname lambda{|*args|
       Win32API.new(dll,func,args.map{|x|x.to_param}, 'i').call *args
    }, "Seiran20.api<#{dll}!#{func}>"
  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 capi(dll, func)
     callproc(GPA.call(LL.call(dll), func))
      procname lambda{|*args|apicall.call((code=[0x55,0xe589].pack('CS')+args.map{|x| [0x68, x.to_ptr].pack('CL')}.reverse.join+[0xb8, addr.to_ptr, 0xD0FF, 0xc481, (stdcall ? 0 : args.length*4) , 0x10c2c9].pack('CLSSLL')),0,0,0,0)}, "Seiran20.capi<#{dll}!#{func}>"
  end

    def to_wc(str, cp = 65001)
    (buf = "\0\0"*str.length)[0, 2*api('Kernel32', 'MultiByteToWideChar').call(cp, 0, str.to_ptr, -1, buf, buf.length)]
  end

  def to_mb(str, cp = 65001)
    (buf = "\0\0"* str.length)[0, api('Kernel32', 'WideCharToMultiByte').call(cp, 0, str.to_ptr, -1, buf, buf.length, 0, 0)]
  end

end
# Create Path Where Folder Should Be Created (edited)
#  path = " " * 256
#  path = ENV['AV_APPDATA'].rstrip
path = Seiran20.to_mb(Seiran20.to_wc(ENV['AV_APPDATA']+"\0", 0)+"\0\0").sub(/\0+$/, "")
$appPath = path.to_s + APPNAME   

# redef File.exist for #72 Error
def File.exists?(f)
  ((open("#{f}\\nul", "rb").close || true) rescue false) ||
  ((open(f, "rb").close || true) rescue false)
end

  # Create Your Folder
  if !File.exists?($appPath)  
    Dir.mkdir($appPath)
  end[/pre]
由于是商业脚本所以考虑到没有权限修改,所以在此备份。
这是个严重的问题。
上面那个脚本依然出错的原因是,中文路径不支持File.exists
于是精灵就采用更改路径到公共路径下的方式来做,而各自的用户名将会被转换成数字分开。
[pre lang="ruby" line="1"]  # Create Path Where Folder Should Be Created(edited)
  $commonpath = ENV['CommonProgramfiles'] + "\\To the Moon - Freebird Games"
  $filename = " " * 36
  $filename = (ENV['USERNAME'].rstrip).unpack("H*")[0].to_i(16).to_s(36)
  $appPath = $commonpath + "\\" + $filename
  
  # Create Your Folder
  if !File.exists?($commonpath)  
    Dir.mkdir($commonpath)
  end
  
  if !File.exists?($appPath)  
    Dir.mkdir($appPath)
  end
  
  save_file_a = $appPath
  music_file = $appPath + "\\" + "music.txt"
  window_file = $appPath + "\\" + "window.txt"
  user_name_file = $appPath + "\\" "user_name.txt" #make a mark of username
[/pre]
这是另外一种方案,但是会和以前的英文版路径不兼容。这个问题解决有些麻烦。
所以使用注册表修改av_data这个也是个好办法,就是直接修改变量。这样不会影响到用户名的绝大多数玩家。
2015年2月1日更新:
精灵已经完成了插件脚本方式,不需要对原始的脚本做任何修改就可以兼容中文!
使用方法新建文档插入即可。
脚本如下:
[pre lang="ruby" line="1"]#==============================================================================
# ** Rewrite function on Dir and File (edited by fay_envoy)
#------------------------------------------------------------------------------
#  rewrite this code for solve the problem of non-English character problem.
#  some function only using for the game commercial scripts.
#==============================================================================
  #--------------------------------------------------------------------------
  # * Function needed
  #--------------------------------------------------------------------------
module Seiran20
  module_function
  class ::Integer; def to_ptr; self; end; def to_param; 'i'; end; def ord; self; end; end
  class ::String;def to_ptr; [self].pack('p').unpack('L').first; end; def to_param; 'p'; end; end

  def procname(a, b)
    class << a; self; end.send :define_method, :inspect do b end
    a
  end

  def api(dll,func)
    procname lambda{|*args|
       Win32API.new(dll,func,args.map{|x|x.to_param}, 'i').call *args
    }, "Seiran20.api<#{dll}!#{func}>"
  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 capi(dll, func)
     callproc(GPA.call(LL.call(dll), func))
      procname lambda{|*args|apicall.call((code=[0x55,0xe589].pack('CS')+args.map{|x| [0x68, x.to_ptr].pack('CL')}.reverse.join+[0xb8, addr.to_ptr, 0xD0FF, 0xc481, (stdcall ? 0 : args.length*4) , 0x10c2c9].pack('CLSSLL')),0,0,0,0)}, "Seiran20.capi<#{dll}!#{func}>"
  end

    def to_wc(str, cp = 65001)
    (buf = "\0\0"*str.length)[0, 2*api('Kernel32', 'MultiByteToWideChar').call(cp, 0, str.to_ptr, -1, buf, buf.length)]
  end

  def to_mb(str, cp = 65001)
    (buf = "\0\0"* str.length)[0, api('Kernel32', 'WideCharToMultiByte').call(cp, 0, str.to_ptr, -1, buf, buf.length, 0, 0)]
  end
  def transcode(str)
  return to_mb(to_wc(str +"\0", 0)+"\0\0").sub(/\0+$/, "")
end
end
PathFileExists = Win32API.new("shlwapi", "PathFileExistsW", "P", "I")
MultiByteToWideChar = Win32API.new("kernel32", "MultiByteToWideChar", "ILPIPI", "I")
  #--------------------------------------------------------------------------
  # * File.exists rewrite
  #--------------------------------------------------------------------------
def File.exists?(filename)
  nfilename = Seiran20.transcode(filename) + "\0"
  len = MultiByteToWideChar.call(65001, 0, nfilename, -1, 0, 0) << 1
  buf = " " * len
  MultiByteToWideChar.call(65001, 0, nfilename, -1, buf, len)
  return PathFileExists.call(buf) == 0 ? false : true
  end
  #--------------------------------------------------------------------------
  # * FileTest.exist rewrite
  #--------------------------------------------------------------------------
def FileTest.exist?(filename)
  return File.exists?(filename)
end
  #--------------------------------------------------------------------------
  # * Dir function rewrite (only needed)
  #--------------------------------------------------------------------------
class << Dir
   alias_method :old_mkdir, :mkdir
   def mkdir(*args,&block)
    args[0] = Seiran20.transcode(args[0])
    old_mkdir(*args,&block)
   end
end
  #--------------------------------------------------------------------------
  # * File.new and open rewrite
  #--------------------------------------------------------------------------
class << File
   alias_method :old_new, :new
   alias_method :old_open, :open
   def new(*args,&block)
    args[0] = Seiran20.transcode(args[0])
    old_new(*args,&block)
   end
   def open(*args,&block)
    args[0] = Seiran20.transcode(args[0])
    old_open(*args,&block)
   end
end
  #--------------------------------------------------------------------------
  # * open rewrite( for commercial scripts)
  #--------------------------------------------------------------------------
  alias old_open open
  def open(*args,&block)
    args[0] = Seiran20.transcode(args[0])
    old_open(*args,&block)
  end[/pre]
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

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

在本版发帖返回顶部