Module: ChildProcess::Windows::Lib
- Extended by:
- FFI::Library
- Defined in:
- lib/childprocess/windows.rb,
lib/childprocess/windows/constants.rb,
lib/childprocess/windows/functions.rb
Class Method Summary collapse
- .create_proc(cmd, opts = {}) ⇒ Object
- .duplicate_handle(handle) ⇒ Object
- .environment_pointer_for(env) ⇒ Object
- .handle_for(fd_or_io) ⇒ Object
- .io_for(handle, flags = File::RDONLY) ⇒ Object
- .last_error_message ⇒ Object
- .msvcrt_name ⇒ Object
Class Method Details
.create_proc(cmd, opts = {}) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/childprocess/windows/functions.rb', line 5 def self.create_proc(cmd, opts = {}) cmd_ptr = FFI::MemoryPointer.from_string cmd env_ptr = environment_pointer_for(opts[:environment]) flags = 0 inherit = !!opts[:inherit] flags |= DETACHED_PROCESS if opts[:detach] si = StartupInfo.new pi = ProcessInfo.new if opts[:stdout] || opts[:stderr] si[:dwFlags] ||= 0 si[:dwFlags] |= STARTF_USESTDHANDLES inherit = true si[:hStdOutput] = handle_for(opts[:stdout].fileno) if opts[:stdout] si[:hStdError] = handle_for(opts[:stderr].fileno) if opts[:stderr] end if opts[:duplex] read_pipe_ptr = FFI::MemoryPointer.new(:pointer) write_pipe_ptr = FFI::MemoryPointer.new(:pointer) sa = SecurityAttributes.new(:inherit => true) ok = create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0) ok or raise Error, read_pipe = read_pipe_ptr.read_pointer write_pipe = write_pipe_ptr.read_pointer ok = set_handle_information(write_pipe.address, HANDLE_FLAG_INHERIT, 0) ok or raise Error, si[:hStdInput] = read_pipe end ok = create_process( nil, # application name cmd_ptr, # command line nil, # process attributes nil, # thread attributes inherit, # inherit handles flags, # creation flags env_ptr, # environment nil, # current directory si, # startup info pi # process info ) ok or raise LaunchError, close_handle pi[:hProcess] close_handle pi[:hThread] if opts[:duplex] opts[:stdin] = io_for(duplicate_handle(write_pipe), File::WRONLY) close_handle read_pipe close_handle write_pipe end pi[:dwProcessId] end |
.duplicate_handle(handle) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/childprocess/windows/functions.rb', line 119 def self.duplicate_handle(handle) dup = FFI::MemoryPointer.new(:pointer) proc = current_process ok = _duplicate_handle( proc, handle, proc, dup, 0, false, DUPLICATE_SAME_ACCESS) ok or raise Error, dup.read_pointer ensure close_handle proc end |
.environment_pointer_for(env) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/childprocess/windows/functions.rb', line 133 def self.environment_pointer_for(env) return unless env.kind_of?(Hash) && env.any? strings = ENV.map { |k,v| "#{k}=#{v}\0" } env.each do |key, value| if key.include?("=") raise InvalidEnvironmentVariableName, key end strings << "#{key}=#{value}\0" end strings << "\0" # terminate the env block env_str = strings.join ptr = FFI::MemoryPointer.new(:long, env_str.bytesize) ptr.write_bytes env_str, 0, env_str.bytesize ptr end |
.handle_for(fd_or_io) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/childprocess/windows/functions.rb', line 83 def self.handle_for(fd_or_io) case fd_or_io when IO handle = get_osfhandle(fd_or_io.fileno) when Fixnum handle = get_osfhandle(fd_or_io) else if fd_or_io.respond_to?(:to_io) io = fd_or_io.to_io unless io.kind_of?(IO) raise TypeError, "expected #to_io to return an instance of IO" end handle = get_osfhandle(io.fileno) else raise TypeError, "invalid type: #{fd_or_io.inspect}" end end if handle == INVALID_HANDLE_VALUE raise Error, end handle end |
.io_for(handle, flags = File::RDONLY) ⇒ Object
110 111 112 113 114 115 116 117 |
# File 'lib/childprocess/windows/functions.rb', line 110 def self.io_for(handle, flags = File::RDONLY) fd = open_osfhandle(handle, flags) if fd == -1 raise Error, end ::IO.for_fd fd, flags end |
.last_error_message ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/childprocess/windows/functions.rb', line 70 def self. errnum = get_last_error buf = FFI::MemoryPointer.new :char, 512 size = ( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, errnum, 0, buf, buf.size, nil ) str = buf.read_string(size).strip "#{str} (#{errnum})" end |
.msvcrt_name ⇒ Object
9 10 11 12 13 14 15 16 17 18 |
# File 'lib/childprocess/windows.rb', line 9 def self.msvcrt_name host_part = RbConfig::CONFIG['host_os'].split("_")[1] manifest = File.join(RbConfig::CONFIG['bindir'], 'ruby.exe.manifest') if host_part && host_part.to_i > 80 && File.exists?(manifest) "msvcr#{host_part}" else "msvcrt" end end |