Module: QDA::Filters::Win32Process
- Defined in:
- lib/weft/filters/win32backtick.rb
Overview
Used only on windows to enable calling other executables without the annoying command-prompt box that pops up when using Ruby backticks in a script running under rubyw.
Note - most of this code written by S Kroeger, see blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/155684
Defined Under Namespace
Classes: Win32popenIO
Constant Summary collapse
- NORMAL_PRIORITY_CLASS =
0x00000020
- STARTUP_INFO_SIZE =
68
- PROCESS_INFO_SIZE =
16
- SECURITY_ATTRIBUTES_SIZE =
12
- ERROR_SUCCESS =
0x00
- FORMAT_MESSAGE_FROM_SYSTEM =
0x1000
- FORMAT_MESSAGE_ARGUMENT_ARRAY =
0x2000
- HANDLE_FLAG_INHERIT =
1
- HANDLE_FLAG_PROTECT_FROM_CLOSE =
2
- STARTF_USESHOWWINDOW =
0x00000001
- STARTF_USESTDHANDLES =
0x00000100
Class Method Summary collapse
-
.backtick(command) ⇒ Object
The only useful public method in this class - receives a command line, and returns the output content and error content as a pair of strings.
- .close_handle(handle) ⇒ Object
-
.create_pipe ⇒ Object
returns read and write handle.
- .create_process(command, stdin, stdout, stderror) ⇒ Object
- .peek_named_pipe(hFile) ⇒ Object
- .raise_last_win_32_error ⇒ Object
- .read_file(hFile) ⇒ Object
- .set_handle_information(handle, flags, value) ⇒ Object
- .write_file(hFile, buffer) ⇒ Object
Class Method Details
.backtick(command) ⇒ Object
The only useful public method in this class - receives a command line, and returns the output content and error content as a pair of strings. No shell expansion is carried out on the command line string.
output, errors = Win32Process::backtick('ls')
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/weft/filters/win32backtick.rb', line 218 def self.backtick(command) # create 3 pipes child_in_r, child_in_w = create_pipe child_out_r, child_out_w = create_pipe child_error_r, child_error_w = create_pipe # Ensure the write handle to the pipe for STDIN is not inherited. set_handle_information(child_in_w, HANDLE_FLAG_INHERIT, 0) set_handle_information(child_out_r, HANDLE_FLAG_INHERIT, 0) set_handle_information(child_error_r, HANDLE_FLAG_INHERIT, 0) processId, threadId = create_process( command, child_in_r, child_out_w, child_error_w ) # we have to close the handles, so the pipes terminate with the process close_handle(child_in_r) close_handle(child_out_w) close_handle(child_error_w) close_handle(child_in_w) io = Win32popenIO.new(child_out_r, child_in_w, child_error_r) out = io.read_all().gsub(/\r/, '') err = io.read_all_err().gsub(/\r/, '') return out, err end |
.close_handle(handle) ⇒ Object
85 86 87 88 |
# File 'lib/weft/filters/win32backtick.rb', line 85 def close_handle(handle) closeHandle = Win32API.new("kernel32", "CloseHandle", ['L'], 'I') raise_last_win_32_error if closeHandle.call(handle).zero? end |
.create_pipe ⇒ Object
returns read and write handle
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/weft/filters/win32backtick.rb', line 54 def create_pipe # returns read and write handle params = [ 'P', # pointer to read handle 'P', # pointer to write handle 'P', # pointer to security attributes 'L'] # pipe size createPipe = Win32API.new("kernel32", "CreatePipe", params, 'I') read_handle, write_handle = [0].pack('I'), [0].pack('I') sec_attrs = [SECURITY_ATTRIBUTES_SIZE, 0, 1].pack('III') raise_last_win_32_error if createPipe.Call(read_handle, write_handle, sec_attrs, 0).zero? [read_handle.unpack('I')[0], write_handle.unpack('I')[0]] end |
.create_process(command, stdin, stdout, stderror) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/weft/filters/win32backtick.rb', line 90 def create_process(command, stdin, stdout, stderror) params = [ 'L', # IN LPCSTR lpApplicationName 'P', # IN LPSTR lpCommandLine 'L', # IN LPSECURITY_ATTRIBUTES lpProcessAttributes 'L', # IN LPSECURITY_ATTRIBUTES lpThreadAttributes 'L', # IN BOOL bInheritHandles 'L', # IN DWORD dwCreationFlags 'L', # IN LPVOID lpEnvironment 'L', # IN LPCSTR lpCurrentDirectory 'P', # IN LPSTARTUPINFOA lpStartupInfo 'P'] # OUT LPPROCESS_INFORMATION lpProcessInformation startupInfo = [STARTUP_INFO_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW, 0, 0, 0, stdin, stdout, stderror].pack('IIIIIIIIIIIISSIIII') processInfo = [0, 0, 0, 0].pack('IIII') command << 0 createProcess = Win32API.new("kernel32", "CreateProcess", params, 'I') cp_args = [ 0, command, 0, 0, 1, 0, 0, 0, startupInfo, processInfo ] raise_last_win_32_error if createProcess.call(*cp_args).zero? hProcess, hThread, dwProcessId, dwThreadId = processInfo.unpack('LLLL') close_handle(hProcess) close_handle(hThread) [dwProcessId, dwThreadId] end |
.peek_named_pipe(hFile) ⇒ Object
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/weft/filters/win32backtick.rb', line 157 def peek_named_pipe(hFile) params = [ 'L', # handle to pipe to copy from 'L', # pointer to data buffer 'L', # size, in bytes, of data buffer 'L', # pointer to number of bytes read 'P', # pointer to total number of bytes available 'L'] # pointer to unread bytes in this message available = [0].pack('I') peekNamedPipe = Win32API.new("kernel32", "PeekNamedPipe", params, 'I') return -1 if peekNamedPipe.Call(hFile, 0, 0, 0, available, 0).zero? available.unpack('I')[0] end |
.raise_last_win_32_error ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/weft/filters/win32backtick.rb', line 28 def raise_last_win_32_error errorCode = Win32API.new("kernel32", "GetLastError", [], 'L').call if errorCode != ERROR_SUCCESS params = [ 'L', # IN DWORD dwFlags, 'P', # IN LPCVOID lpSource, 'L', # IN DWORD dwMessageId, 'L', # IN DWORD dwLanguageId, 'P', # OUT LPSTR lpBuffer, 'L', # IN DWORD nSize, 'P', # IN va_list *Arguments ] formatMessage = Win32API.new("kernel32", "FormatMessage", params, 'L') msg = ' ' * 255 msgLength = formatMessage.call(FORMAT_MESSAGE_FROM_SYSTEM + FORMAT_MESSAGE_ARGUMENT_ARRAY, '', errorCode, 0, msg, 255, '') msg.gsub!(/\000/, '') msg.strip! raise msg else raise 'GetLastError returned ERROR_SUCCESS' end end |
.read_file(hFile) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/weft/filters/win32backtick.rb', line 140 def read_file(hFile) params = [ 'L', # handle of file to read 'P', # pointer to buffer that receives data 'L', # number of bytes to read 'P', # pointer to number of bytes read 'L'] #pointer to structure for data number = [0].pack('I') buffer = ' ' * 255 readFile = Win32API.new("kernel32", "ReadFile", params, 'I') return '' if readFile.call(hFile, buffer, 255, number, 0).zero? buffer[0...number.unpack('I')[0]] end |
.set_handle_information(handle, flags, value) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/weft/filters/win32backtick.rb', line 72 def set_handle_information(handle, flags, value) params = [ 'L', # handle to an object 'L', # specifies flags to change 'L'] # specifies new values for flags setHandleInformation = Win32API.new("kernel32", "SetHandleInformation", params, 'I') raise_last_win_32_error if setHandleInformation.Call(handle, flags, value).zero? nil end |
.write_file(hFile, buffer) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/weft/filters/win32backtick.rb', line 123 def write_file(hFile, buffer) params = [ 'L', # handle to file to write to 'P', # pointer to data to write to file 'L', # number of bytes to write 'P', # pointer to number of bytes written 'L'] # pointer to structure for overlapped I/O written = [0].pack('I') writeFile = Win32API.new("kernel32", "WriteFile", params, 'I') raise_last_win_32_error if writeFile.call(hFile, buffer, buffer.size, written, 0).zero? written.unpack('I')[0] end |