diff --git a/lib/childprocess/windows/lib.rb b/lib/childprocess/windows/lib.rb index d275f3b..fd7f478 100644 --- a/lib/childprocess/windows/lib.rb +++ b/lib/childprocess/windows/lib.rb @@ -55,9 +55,9 @@ module Lib # ); # - attach_function :create_process, :CreateProcessA, [ - :pointer, + attach_function :create_process, :CreateProcessW, [ :pointer, + :buffer_inout, :pointer, :pointer, :bool, diff --git a/lib/childprocess/windows/process_builder.rb b/lib/childprocess/windows/process_builder.rb index 1b30b0a..1e849d7 100644 --- a/lib/childprocess/windows/process_builder.rb +++ b/lib/childprocess/windows/process_builder.rb @@ -39,9 +39,14 @@ def start private + def to_wide_string(str) + newstr = str + "\0".encode(str.encoding) + newstr.encode!('UTF-16LE') + end + def create_command_pointer - string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join ' ' - @cmd_ptr = FFI::MemoryPointer.from_string string + string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join(' ') + @cmd_ptr = to_wide_string(string) end def create_environment_pointer @@ -59,15 +64,12 @@ def create_environment_pointer strings << "#{key}=#{val}\0" end - strings << "\0" # terminate the env block - env_str = strings.join - - @env_ptr = FFI::MemoryPointer.new(:long, env_str.bytesize) - @env_ptr.put_bytes 0, env_str, 0, env_str.bytesize + env_str = to_wide_string(strings.join) + @env_ptr = FFI::MemoryPointer.from_string(env_str) end def create_cwd_pointer - @cwd_ptr = FFI::MemoryPointer.from_string(@cwd || Dir.pwd) + @cwd_ptr = FFI::MemoryPointer.from_string(to_wide_string(@cwd || Dir.pwd)) end def create_process @@ -98,6 +100,7 @@ def process_info end def setup_flags + @flags |= CREATE_UNICODE_ENVIRONMENT @flags |= DETACHED_PROCESS if @detach @flags |= CREATE_BREAKAWAY_FROM_JOB if @leader end diff --git a/spec/childprocess_spec.rb b/spec/childprocess_spec.rb index b382122..117ed54 100644 --- a/spec/childprocess_spec.rb +++ b/spec/childprocess_spec.rb @@ -107,6 +107,23 @@ expect(child_env['CHILD_ONLY']).to eql '1' end end + + it 'allows unicode characters in the environment' do + # This test does not work on Windows for Ruby < 2.3 because ENV values will not be properly decoded + # This was fixed in Ruby 2.3 here: https://github.com/ruby/ruby/commit/5e3467c4414df815b3b00d2b0372026b069e7f7d + # TODO: Write an alternate test that does not rely on the Ruby ENV hash + skip 'Test does not work on Windows for Ruby < 2.3' if Gem.win_platform? && RUBY_VERSION =~ /^1\.|^2\.[0-2]/ + Tempfile.open("env-spec") do |file| + process = write_env(file.path) + process.environment['FOO'] = 'baör' + process.start + process.wait + + child_env = eval rewind_and_read(file) + + expect(child_env['FOO'].force_encoding('UTF-8')).to eql 'baör' + end + end it "inherits the parent's env vars also when some are overridden" do Tempfile.open("env-spec") do |file|