Skip to content

Instantly share code, notes, and snippets.

@jarib
Created January 19, 2010 11:13
Show Gist options
  • Save jarib/280865 to your computer and use it in GitHub Desktop.
Save jarib/280865 to your computer and use it in GitHub Desktop.
FFI wrapper for CreateProcess()
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,
: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, :ulong,
:dwThreadId, :ulong
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 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
def create(cmd, opts = {})
cmd_ptr = FFI::MemoryPointer.from_string cmd
si = StartupInfo.new
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]
pi[:dwProcessId] # returns the wrong pid?!
else
raise Error, last_error_message
end
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
p :pid => WinProcess.create("C:\\Windows\\System32\\regedt32.exe")
@bluekeys
Copy link

Is the StartupInfo struct missing dwFlags?

http://msdn.microsoft.com/en-us/library/ms686331.aspx

@jarib
Copy link
Author

jarib commented Apr 18, 2012

@dsjbirch: It's there in the gem. I'm not maintaining the code in this gist ;)

@bluekeys
Copy link

@jarib, that is very cool!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment