Created
January 19, 2010 11:13
-
-
Save jarib/280865 to your computer and use it in GitHub Desktop.
FFI wrapper for CreateProcess()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@dsjbirch: It's there in the gem. I'm not maintaining the code in this gist ;)