If you run into an issue spawning process and getting command prompts
that pop up, Simon Kroger gave me a very nice fix.. Here's the code
for future reference:
[...]
hmmm ... i will read through the mentioned section ....
I did.
Ok, here is the 'solution': one has to use CreateProcess to spawn the
child. Unfortunately this is a bit more complicated but thanks to
Win32API its all achievable in pure ruby.
The stuff in $0 =3D=3D __FILE__ builds a simple fox gui and starts cmd.exe
if a button is pressed. It uses a pipe to write to the stdin of the
child ('dir\n') and reads back the childs stdout via another pipe and
dumps it to a text control. (The stderror is also mapped but not used)
It's still some work to make it look as easy as popen, but definitaly
possible.
Here is the code:
(some lines are copied from this list and the net)
--------------------------------------------------------------------
require 'Win32API'
NORMAL_PRIORITY_CLASS =3D 0x00000020
STARTUP_INFO_SIZE =3D 68
PROCESS_INFO_SIZE =3D 16
SECURITY_ATTRIBUTES_SIZE =3D 12
ERROR_SUCCESS =3D 0x00
FORMAT_MESSAGE_FROM_SYSTEM =3D 0x1000
FORMAT_MESSAGE_ARGUMENT_ARRAY =3D 0x2000
HANDLE_FLAG_INHERIT =3D 1
HANDLE_FLAG_PROTECT_FROM_CLOSE =3D2
STARTF_USESHOWWINDOW =3D 0x00000001
STARTF_USESTDHANDLES =3D 0x00000100
def raise_last_win_32_error
errorCode =3D Win32API.new("kernel32", "GetLastError", [], 'L').call
if errorCode !=3D ERROR_SUCCESS
params =3D [
'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 =3D Win32API.new("kernel32", "FormatMessage", params, 'L'=
)
msg =3D ' ' * 255
msgLength =3D 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
def create_pipe # returns read and write handle
params =3D [
'P', # pointer to read handle
'P', # pointer to write handle
'P', # pointer to security attributes
'L'] # pipe size
createPipe =3D Win32API.new("kernel32", "CreatePipe", params, 'I')
read_handle, write_handle =3D [0].pack('I'), [0].pack('I')
sec_attrs =3D [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
def set_handle_information(handle, flags, value)
params =3D [
'L', # handle to an object
'L', # specifies flags to change
'L'] # specifies new values for flags
setHandleInformation =3D Win32API.new("kernel32",
"SetHandleInformation", params, 'I')
raise_last_win_32_error if setHandleInformation.Call(handle,
flags, value).zero?
nil
end
def close_handle(handle)
closeHandle =3D Win32API.new("kernel32", "CloseHandle", ['L'], 'I')
raise_last_win_32_error if closeHandle.call(handle).zero?
end
def create_process(command, stdin, stdout, stderror)
params =3D [
'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 =3D [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 =3D [0, 0, 0, 0].pack('IIII')
command << 0
createProcess =3D Win32API.new("kernel32", "CreateProcess", params, 'I')
raise_last_win_32_error if createProcess.call(0,
command, 0, 0, 1, 0, 0, 0, startupInfo, processInfo).zero?
hProcess, hThread, dwProcessId, dwThreadId =3D processInfo.unpack('LLLL')
close_handle(hProcess)
close_handle(hThread)
[dwProcessId, dwThreadId]
end
def write_file(hFile, buffer)
params =3D [
'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 =3D [0].pack('I')
writeFile =3D Win32API.new("kernel32", "WriteFile", params, 'I')
raise_last_win_32_error if writeFile.call(hFile, buffer, buffer.size,
written, 0).zero?
written.unpack('I')
end
def read_file(hFile)
params =3D [
'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 =3D [0].pack('I')
buffer =3D ' ' * 255
readFile =3D Win32API.new("kernel32", "ReadFile", params, 'I')
return '' if readFile.call(hFile, buffer, 255, number, 0).zero?
buffer[0...number.unpack('I')[0]]
end
if $0 =3D=3D __FILE__
require 'fox12'
include Fox
application =3D FXApp.new("popen", "popen")
main =3D FXMainWindow.new(application, "popen", nil, nil, DECOR_ALL,
0, 0, 500, 500, 10, 10, 10, 10, 10, 10)
button =3D FXButton.new(main, "&Do it!", nil, nil, 0,
FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT,
0, 0, 0, 0, 10, 10, 5, 5)
frame =3D FXHorizontalFrame.new(main,
FRAME_THICK|FRAME_SUNKEN|LAYOUT_FILL_X|LAYOUT_FILL_Y,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
edit =3D FXText.new(frame, nil, 0,
LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_READONLY, 0, 0, 0, 0)
edit.textColor, edit.backColor =3D 0xFFFFFF, 0
button.connect(SEL_COMMAND) do
cmd =3D 'cmd.exe'
input =3D "dir\nexit\n"
# create 3 pipes
child_in_r, child_in_w =3D create_pipe
child_out_r, child_out_w =3D create_pipe
child_error_r, child_error_w =3D 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 =3D create_process(cmd, 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_out_w)
close_handle(child_error_w)
write_file(child_in_w, input)
while !(buffer =3D read_file(child_out_r)).empty?
edit.appendText(buffer.gsub("\r", ''))
end
end
application.create()
main.show(PLACEMENT_SCREEN)
application.run()
end
----------------------------------------------------------------------