Module: ChildProcess::Windows::Lib

Extended by:
FFI::Library
Defined in:
lib/childprocess/windows.rb,
lib/childprocess/windows/lib.rb

Class Method Summary collapse

Class Method Details

.alive?(pid) ⇒ Boolean

Returns:

  • (Boolean)


389
390
391
392
393
394
395
396
397
398
# File 'lib/childprocess/windows/lib.rb', line 389

def alive?(pid)
  handle = Lib.open_process(PROCESS_ALL_ACCESS, false, pid)
  if handle.null?
    false
  else
    ptr = FFI::MemoryPointer.new :ulong
    Lib.check_error Lib.get_exit_code(handle, ptr)
    ptr.read_ulong == PROCESS_STILL_ACTIVE
  end
end

.check_error(bool) ⇒ Object



385
386
387
# File 'lib/childprocess/windows/lib.rb', line 385

def check_error(bool)
  bool or raise Error, last_error_message
end

.dont_inherit(file) ⇒ Object



266
267
268
269
270
271
272
# File 'lib/childprocess/windows/lib.rb', line 266

def dont_inherit(file)
  unless file.respond_to?(:fileno)
    raise ArgumentError, "expected #{file.inspect} to respond to :fileno"
  end

  set_handle_inheritance(handle_for(file.fileno), false)
end

.duplicate_handle(handle) ⇒ Object



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/childprocess/windows/lib.rb', line 341

def duplicate_handle(handle)
  dup  = FFI::MemoryPointer.new(:pointer)
  proc = current_process

  ok = Lib._duplicate_handle(
    proc,
    handle,
    proc,
    dup,
    0,
    false,
    DUPLICATE_SAME_ACCESS
  )

  check_error ok

  dup.read_pointer
ensure
  close_handle proc
end

.each_child_of(pid, &blk) ⇒ Object

Raises:

  • (NotImplementedError)


292
293
294
295
296
297
298
299
300
301
302
# File 'lib/childprocess/windows/lib.rb', line 292

def each_child_of(pid, &blk)
  raise NotImplementedError

  # http://stackoverflow.com/questions/1173342/terminate-a-process-tree-c-for-windows?rq=1

  # for each process entry
  #  if pe.th32ParentProcessID == pid
  #    Handle.open(pe.pe.th32ProcessId, &blk)
  #  end
  #
end

.get_handle_inheritance(handle) ⇒ Object



372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/childprocess/windows/lib.rb', line 372

def get_handle_inheritance(handle)
  flags = FFI::MemoryPointer.new(:uint)

  status = get_handle_information(
    handle,
    flags
  )

  check_error status

  flags.read_uint
end

.handle_for(fd_or_io) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/childprocess/windows/lib.rb', line 304

def handle_for(fd_or_io)
  if fd_or_io.kind_of?(IO) || fd_or_io.respond_to?(:fileno)
    if ChildProcess.jruby?
      handle = ChildProcess::JRuby.windows_handle_for(fd_or_io)
    else
      handle = get_osfhandle(fd_or_io.fileno)
    end
  elsif fd_or_io.kind_of?(Integer)
    handle = get_osfhandle(fd_or_io)
  elsif 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

  if handle == INVALID_HANDLE_VALUE
    raise Error, last_error_message
  end

  FFI::Pointer.new handle
end

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



332
333
334
335
336
337
338
339
# File 'lib/childprocess/windows/lib.rb', line 332

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

  FFI::IO.for_fd fd, flags
end

.kill(signal, *pids) ⇒ Object



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/childprocess/windows/lib.rb', line 239

def kill(signal, *pids)
  case signal
  when 'SIGINT', 'INT', :SIGINT, :INT
    signal = WIN_SIGINT
  when 'SIGBRK', 'BRK', :SIGBREAK, :BRK
    signal = WIN_SIGBREAK
  when 'SIGKILL', 'KILL', :SIGKILL, :KILL
    signal = WIN_SIGKILL
  when 0..9
    # Do nothing
  else
    raise Error, "invalid signal #{signal.inspect}"
  end

  pids.map { |pid| pid if Lib.send_signal(signal, pid) }.compact
end

.last_error_messageObject



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/childprocess/windows/lib.rb', line 274

def last_error_message
  errnum = FFI.errno

  buf = FFI::MemoryPointer.new :char, 512

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

  str = buf.read_string(size).strip
  if errnum == 0
    "Unknown error (Windows says #{str.inspect}, but it did not.)"
  else
    "#{str} (#{errnum})"
  end
end

.msvcrt_nameObject



14
15
16
17
18
19
20
21
22
23
# File 'lib/childprocess/windows.rb', line 14

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

.no_hang?(flags) ⇒ Boolean

Returns:

  • (Boolean)


400
401
402
# File 'lib/childprocess/windows/lib.rb', line 400

def no_hang?(flags)
  (flags & Process::WNOHANG) == Process::WNOHANG
end

.set_handle_inheritance(handle, bool) ⇒ Object



362
363
364
365
366
367
368
369
370
# File 'lib/childprocess/windows/lib.rb', line 362

def set_handle_inheritance(handle, bool)
  status = set_handle_information(
    handle,
    HANDLE_FLAG_INHERIT,
    bool ? HANDLE_FLAG_INHERIT : 0
  )

  check_error status
end

.wait_for_pid(pid, no_hang) ⇒ Object



404
405
406
407
408
409
410
411
# File 'lib/childprocess/windows/lib.rb', line 404

def wait_for_pid(pid, no_hang)
  code = Handle.open(pid) { |handle|
    handle.wait unless no_hang
    handle.exit_code
  }

  code if code != PROCESS_STILL_ACTIVE
end

.waitpid(pid, flags = 0) ⇒ Object



256
257
258
# File 'lib/childprocess/windows/lib.rb', line 256

def waitpid(pid, flags = 0)
  wait_for_pid(pid, no_hang?(flags))
end

.waitpid2(pid, flags = 0) ⇒ Object



260
261
262
263
264
# File 'lib/childprocess/windows/lib.rb', line 260

def waitpid2(pid, flags = 0)
  code = wait_for_pid(pid, no_hang?(flags))

  [pid, code] if code
end