Module: ChildProcess::Windows::Lib

Defined in:
lib/sapphire/UI/Functions.rb

Class Method Summary collapse

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
# File 'lib/sapphire/UI/Functions.rb', line 5

def self.create_proc(cmd, opts = {})
  cmd_ptr = F.from_string cmd

  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, last_error_message

    read_pipe = read_pipe_ptr.read_pointer
    write_pipe = write_pipe_ptr.read_pointer

    si[:hStdInput] = read_pipe
  end

  si[:lpDesktop] = FFI::MemoryPointer.from_string("test") if $isVirtual

  ok = create_process(nil, cmd_ptr, nil, nil, inherit, flags, nil, nil, si, pi)
  ok or raise Error, last_error_message

  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



104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/sapphire/UI/Functions.rb', line 104

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, last_error_message

  dup.read_pointer
ensure
  close_handle proc
end

.handle_for(fd_or_io) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/sapphire/UI/Functions.rb', line 68

def self.handle_for(fd_or_io)
  case fd_or_io
  when IO
    handle = get_osfhandle(fd.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, last_error_message
  end

  handle
end

.io_for(handle, flags = File::RDONLY) ⇒ Object



95
96
97
98
99
100
101
102
# File 'lib/sapphire/UI/Functions.rb', line 95

def self.io_for(handle, flags = File::RDONLY)
  fd = open_osfhandle(handle, flags)
  if fd == -1
    raise Error, last_error_message
  end

  ::IO.for_fd fd, flags
end

.last_error_messageObject



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/sapphire/UI/Functions.rb', line 56

def self.last_error_message
  errnum = get_last_error
  buf = FFI::MemoryPointer.new :char, 512

  size = format_message(
    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
    nil, errnum, 0, buf, buf.size, nil
  )

  buf.read_string(size).strip
end