class ChildProcess::Windows::ProcessBuilder
Attributes
cwd[RW]
detach[RW]
duplex[RW]
environment[RW]
leader[RW]
stderr[RW]
stdin[R]
stdout[RW]
Public Class Methods
new(args)
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 7 def initialize(args) @args = args @detach = false @duplex = false @environment = nil @cwd = nil @stdout = nil @stderr = nil @stdin = nil @flags = 0 @job_ptr = nil @cmd_ptr = nil @env_ptr = nil @cwd_ptr = nil end
Public Instance Methods
start()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 26 def start create_command_pointer create_environment_pointer create_cwd_pointer setup_flags setup_io pid = create_process close_handles pid end
Private Instance Methods
close_handles()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 155 def close_handles Lib.close_handle process_info[:hProcess] Lib.close_handle process_info[:hThread] if @duplex @stdin = Lib.io_for(Lib.duplicate_handle(@write_pipe), File::WRONLY) Lib.close_handle @read_pipe Lib.close_handle @write_pipe end end
create_command_pointer()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 47 def create_command_pointer string = @args.map { |arg| quote_if_necessary(arg.to_s) }.join(' ') @cmd_ptr = to_wide_string(string) end
create_cwd_pointer()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 71 def create_cwd_pointer @cwd_ptr = FFI::MemoryPointer.from_string(to_wide_string(@cwd || Dir.pwd)) end
create_environment_pointer()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 52 def create_environment_pointer return unless @environment.kind_of?(Hash) && @environment.any? strings = [] ENV.to_hash.merge(@environment).each do |key, val| next if val.nil? if key.to_s =~ /=|\0/ || val.to_s.include?("\0") raise InvalidEnvironmentVariable, "#{key.inspect} => #{val.inspect}" end strings << "#{key}=#{val}\0" end env_str = to_wide_string(strings.join) @env_ptr = FFI::MemoryPointer.from_string(env_str) end
create_process()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 75 def create_process ok = Lib.create_process( nil, # application name @cmd_ptr, # command line nil, # process attributes nil, # thread attributes true, # inherit handles @flags, # creation flags @env_ptr, # environment @cwd_ptr, # current directory startup_info, # startup info process_info # process info ) ok or raise LaunchError, Lib.last_error_message process_info[:dwProcessId] end
process_info()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 98 def process_info @process_info ||= ProcessInfo.new end
quote_if_necessary(str)
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 166 def quote_if_necessary(str) quote = str.start_with?('"') ? "'" : '"' case str when /[\s\\'"]/ [quote, str, quote].join else str end end
setup_flags()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 102 def setup_flags @flags |= CREATE_UNICODE_ENVIRONMENT @flags |= DETACHED_PROCESS if @detach @flags |= CREATE_BREAKAWAY_FROM_JOB if @leader end
setup_io()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 108 def setup_io startup_info[:dwFlags] ||= 0 startup_info[:dwFlags] |= STARTF_USESTDHANDLES if @stdout startup_info[:hStdOutput] = std_stream_handle_for(@stdout) end if @stderr startup_info[:hStdError] = std_stream_handle_for(@stderr) end if @duplex read_pipe_ptr = FFI::MemoryPointer.new(:pointer) write_pipe_ptr = FFI::MemoryPointer.new(:pointer) sa = SecurityAttributes.new(:inherit => true) ok = Lib.create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0) Lib.check_error ok @read_pipe = read_pipe_ptr.read_pointer @write_pipe = write_pipe_ptr.read_pointer Lib.set_handle_inheritance @read_pipe, true Lib.set_handle_inheritance @write_pipe, false startup_info[:hStdInput] = @read_pipe else startup_info[:hStdInput] = std_stream_handle_for(STDIN) end end
startup_info()
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 94 def startup_info @startup_info ||= StartupInfo.new end
std_stream_handle_for(io)
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 140 def std_stream_handle_for(io) handle = Lib.handle_for(io) begin Lib.set_handle_inheritance handle, true rescue ChildProcess::Error # If the IO was set to close on exec previously, this call will fail. # That's probably OK, since the user explicitly asked for it to be # closed (at least I have yet to find other cases where this will # happen...) end handle end
to_wide_string(str)
click to toggle source
# File lib/childprocess/windows/process_builder.rb, line 42 def to_wide_string(str) newstr = str + "\0".encode(str.encoding) newstr.encode!('UTF-16LE') end