Project1
标题: 【不是创意的创意】解决调用环境变量中文乱码现象 [打印本页]
作者: 精灵使者 时间: 2014-10-11 15:18
标题: 【不是创意的创意】解决调用环境变量中文乱码现象
本帖最后由 精灵使者 于 2015-2-1 17:44 编辑
精灵在汉化游戏的时候,发现一些使用中文用户名的游戏无法启动,症状如下:
经检查出问题的脚本如下:
# 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
# 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
于是就麻烦了。
中文用户名导致EV['AV_APPDATA']产生乱码,以至于后面的建立文件夹失败。
所以就需要进行S2U转换一下。
解决脚本如下:
#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
#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
由于是商业脚本所以考虑到没有权限修改,所以在此备份。
这是个严重的问题。
上面那个脚本依然出错的原因是,中文路径不支持File.exists
于是精灵就采用更改路径到公共路径下的方式来做,而各自的用户名将会被转换成数字分开。
# 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
# 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
这是另外一种方案,但是会和以前的英文版路径不兼容。这个问题解决有些麻烦。
所以使用注册表修改av_data这个也是个好办法,就是直接修改变量。这样不会影响到用户名的绝大多数玩家。
2015年2月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
#==============================================================================
# ** 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
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |