Skip to content

Instantly share code, notes, and snippets.

@rdp
Forked from jarib/file.rb
Last active December 6, 2019 07:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdp/8229520 to your computer and use it in GitHub Desktop.
Save rdp/8229520 to your computer and use it in GitHub Desktop.
require "rubygems"
require "ffi"
module WinProcess
extend FFI::Library
ffi_lib "kernel32"
ffi_convention :stdcall
class Error < StandardError
end
# typedef struct _STARTUPINFO {
# DWORD cb;
# LPTSTR lpReserved;
# LPTSTR lpDesktop;
# LPTSTR lpTitle;
# DWORD dwX;
# DWORD dwY;
# DWORD dwXSize;
# DWORD dwYSize;
# DWORD dwXCountChars;
# DWORD dwYCountChars;
# DWORD dwFillAttribute;
# DWORD dwFlags;
# WORD wShowWindow;
# WORD cbReserved2;
# LPBYTE lpReserved2;
# HANDLE hStdInput;
# HANDLE hStdOutput;
# HANDLE hStdError;
# } STARTUPINFO, *LPSTARTUPINFO;
class StartupInfo < FFI::Struct
layout :cb, :ulong,
:lpReserved, :pointer,
:lpDesktop, :pointer,
:lpTitle, :pointer,
:dwX, :ulong,
:dwY, :ulong,
:dwXSize, :ulong,
:dwYSize, :ulong,
:dwXCountChars, :ulong,
:dwYCountChars, :ulong,
:dwFillAttribute, :ulong,
:dwFlags, :ulong,
:wShowWindow, :ushort,
:cbReserved2, :ushort,
:lpReserved2, :pointer,
:hStdInput, :pointer, # void ptr
:hStdOutput, :pointer, # void ptr
:hStdError, :pointer # void ptr
end
# typedef struct _PROCESS_INFORMATION {
# HANDLE hProcess;
# HANDLE hThread;
# DWORD dwProcessId;
# DWORD dwThreadId;
# } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
class ProcessInfo < FFI::Struct
layout :hProcess, :pointer, # void ptr
:hThread, :pointer, # void ptr
:dwProcessId, :uint,
:dwThreadId, :uint
end
# BOOL WINAPI CreateProcess(
# __in_opt LPCTSTR lpApplicationName,
# __inout_opt LPTSTR lpCommandLine,
# __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
# __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
# __in BOOL bInheritHandles,
# __in DWORD dwCreationFlags,
# __in_opt LPVOID lpEnvironment,
# __in_opt LPCTSTR lpCurrentDirectory,
# __in LPSTARTUPINFO lpStartupInfo,
# __out LPPROCESS_INFORMATION lpProcessInformation
# );
attach_function :create_process, :CreateProcessA,
[:pointer, :pointer, :pointer, :pointer, :bool,
:ulong, :pointer, :pointer, :pointer, :pointer], :bool
attach_function :get_last_error, :GetLastError, [], :ulong
# DWORD WINAPI WaitForSingleObject(
# _In_ HANDLE hHandle,
# _In_ DWORD dwMilliseconds
# );
# TODO attach_function wait_for_single_object ...
# DWORD WINAPI FormatMessage(
# __in DWORD dwFlags,
# __in_opt LPCVOID lpSource,
# __in DWORD dwMessageId,
# __in DWORD dwLanguageId,
# __out LPTSTR lpBuffer,
# __in DWORD nSize,
# __in_opt va_list *Arguments
# );
attach_function :format_message, :FormatMessageA, [:ulong, :pointer, :ulong, :ulong,
:pointer, :ulong, :pointer], :ulong
attach_function :close_handle, :CloseHandle, [:pointer], :bool
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
module_function
STARTF_USESHOWWINDOW = 0x00000001
SW_HIDE = 0
def create(cmd, opts = {})
cmd_ptr = FFI::MemoryPointer.from_string cmd
si = StartupInfo.new
si[:dwFlags] |= STARTF_USESHOWWINDOW
si[:wShowWindow] |= SW_HIDE
pi = ProcessInfo.new
if create_process(nil, cmd_ptr, nil, nil, !!opts[:inherit], 0, nil, nil, si, pi)
close_handle pi[:hProcess]
close_handle pi[:hThread]
# to wait for termination, something like WaitForSingleObject(pi[:hProcess], INFINITE), since ruby's
pi[:dwProcessId]
else
raise Error, last_error_message
end
end
def wait_for_terminate pid
end
def last_error_message
errnum = get_last_error()
buf = FFI::MemoryPointer.new :char, 512
flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
size = format_message(flags, nil, errnum, 0, buf, buf.size, nil)
buf.read_string(size).strip
end
end
pid = WinProcess.create("curl www.google.com") # this doesn't use any shellword expansion, so no way to get output, request it in a comment!
begin
loop { Process.kill(0, pid); sleep 1; puts 'still alive'}
rescue Errno::ESRCH
# it's dead
end
puts 'done'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment