module Process

def kill(signal, *pids)


Process.kill(1, 12345, :exit_proc => 'ExitProcess', :module => 'kernel32')

Example:

block until the process is actually signaled.
you may specify Process::INFINITE, and your code will
signaled and instead returns immediately. Alternatively,
then the process does not wait if the process is not
actually die. The default is 5ms. If you specify 0 here
:wait_time => The time, in milliseconds, to wait for the process to

The default is 'kernel32'.
:dll_module => The name of the .dll (or .exe) that contains :exit_proc.

is used. The default is 'ExitProcess'.
:exit_proc => The name of the exit function called when signal 1 or 4-8

Possible options for signals 1 and 4-8.

behaves.
allow finer control over how that process is killed and how your program
When using signals 1 or 4-8 you may specify additional options that

same as the default implementation.
chance to do internal cleanup before being killed. Signal 0 behaves the
Signals 1 and 4-8 kill the process more nicely, giving the process a
process harshly, given that process no chance to do any internal cleanup.
a ctrl-c or ctrl-break event, respectively. Signal 9 terminates the
Internally, signals 2 and 3 will generate a console control event, using

behavior.
it kills processes, but this version also gives you finer control over
implementation of Process.kill. The differences mainly reside in the way
Kill a given process with a specific signal. This overrides the default
def kill(signal, *pids)
  # Match the spec, require at least 2 arguments
  if pids.length == 0
    raise ArgumentError, "wrong number of arguments (1 for at least 2)"
  end
  # Match the spec, signal may not be less than zero if numeric
  if signal.is_a?(Numeric) && signal < 0 # EINVAL
    raise SystemCallError.new(22)
  end
  # Match the spec, signal must be a numeric, string or symbol
  unless signal.is_a?(String) || signal.is_a?(Numeric) || signal.is_a?(Symbol)
    raise ArgumentError, "bad signal type #{signal.class}"
  end
  # Match the spec, making an exception for BRK/SIGBRK, if the signal name is invalid.
  # Older versions of JRuby did not include KILL, so we've made an explicit exception
  # for that here, too.
  if signal.is_a?(String) || signal.is_a?(Symbol)
    signal = signal.to_s.sub("SIG", "")
    unless Signal.list.keys.include?(signal) || %w{KILL BRK}.include?(signal)
      raise ArgumentError, "unsupported name '#{signal}'"
    end
  end
  # If the last argument is a hash, pop it and assume it's a hash of options
  if pids.last.is_a?(Hash)
    hash = pids.pop
    opts = {}
    valid = %w{exit_proc dll_module wait_time}
    hash.each { |k, v|
      k = k.to_s.downcase
      unless valid.include?(k)
        raise ArgumentError, "invalid option '#{k}'"
      end
      opts[k] = v
    }
    exit_proc  = opts["exit_proc"]  || "ExitProcess"
    dll_module = opts["dll_module"] || "kernel32"
    wait_time  = opts["wait_time"]  || 5
  else
    wait_time  = 5
    exit_proc  = "ExitProcess"
    dll_module = "kernel32"
  end
  count = 0
  pids.each { |pid|
    raise TypeError unless pid.is_a?(Numeric) # Match spec, pid must be a number
    raise SystemCallError.new(22) if pid < 0  # Match spec, EINVAL if pid less than zero
    sigint = [Signal.list["INT"], "INT", "SIGINT", :INT, :SIGINT, 2]
    # Match the spec
    if pid == 0 && !sigint.include?(signal)
      raise SystemCallError.new(22)
    end
    if signal == 0
      access = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
    elsif signal == 9
      access = PROCESS_TERMINATE
    else
      access = PROCESS_ALL_ACCESS
    end
    begin
      handle = OpenProcess(access, 0, pid)
      if signal != 0 && handle == 0
        raise SystemCallError, FFI.errno, "OpenProcess"
      end
      case signal
        when 0
          if handle != 0
            count += 1
          else
            if FFI.errno == ERROR_ACCESS_DENIED
              count += 1
            else
              raise SystemCallError.new(3) # ESRCH
            end
          end
        when Signal.list["INT"], "INT", "SIGINT", :INT, :SIGINT, 2
          if GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)
            count += 1
          else
            raise SystemCallError.new("GenerateConsoleCtrlEvent", FFI.errno)
          end
        when Signal.list["BRK"], "BRK", "SIGBRK", :BRK, :SIGBRK, 3
          if GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid)
            count += 1
          else
            raise SystemCallError.new("GenerateConsoleCtrlEvent", FFI.errno)
          end
        when Signal.list["KILL"], "KILL", "SIGKILL", :KILL, :SIGKILL, 9
          if TerminateProcess(handle, pid)
            count += 1
          else
            raise SystemCallError.new("TerminateProcess", FFI.errno)
          end
        else
          thread_id = FFI::MemoryPointer.new(:ulong)
          mod = GetModuleHandle(dll_module)
          if mod == 0
            raise SystemCallError.new("GetModuleHandle: '#{dll_module}'", FFI.errno)
          end
          proc_addr = GetProcAddress(mod, exit_proc)
          if proc_addr == 0
            raise SystemCallError.new("GetProcAddress: '#{exit_proc}'", FFI.errno)
          end
          thread = CreateRemoteThread(handle, nil, 0, proc_addr, nil, 0, thread_id)
          if thread > 0
            WaitForSingleObject(thread, wait_time)
            count += 1
          else
            raise SystemCallError.new("CreateRemoteThread", FFI.errno)
          end
      end
    ensure
      CloseHandle(handle) if handle
    end
  }
  count
end