Win Pipes and IO

Hi all,

I hope there is a guru out there today.
I create a new Pipe on Windows using 'CreatePipe'. This yields two
handles (for input and output) which can be converted to C run-time file
handles with _open_osfhandle. I can call fdopen on the returned values
and write and read to the pipe.

What I wanted to do was creating new IO objects instead of calling
fdopen myself, but I can't get it to work. The implementation of IO.new
calls fdopen so I realy have no clue why this should not do the trick.

(Yes I can call IO.pipe, but I need the handles from CreatePipe because
CreateProcess needs them and this is the only way to start childs
without unwanted shell windows)

The other way would be to write a C extension but I'm so close....

please help

Simon

···

---------------------------------------------------------------
require 'Win32API'

SECURITY_ATTRIBUTES_SIZE = 12

O_RDONLY = 0x0000 # open for reading only
O_WRONLY = 0x0001 # open for writing only
O_TEXT = 0x4000 # file mode is text (translated)
O_BINARY = 0x8000 # file mode is binary (untranslated)

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')

return [0, 0] if createPipe.Call(read_handle, write_handle, sec_attrs,
0).zero?

[read_handle.unpack('I')[0], write_handle.unpack('I')[0]]
end

open_osfhandle = Win32API.new("msvcrt", "_open_osfhandle", ['L','L'],
'L')
fdopen = Win32API.new("msvcrt", "_fdopen", ['L','P'], 'L')
fgets = Win32API.new("msvcrt", "fgets", ['P', 'L', 'L'], 'L')
fputs = Win32API.new("msvcrt", "fputs", ['P', 'L'], 'L')
fclose = Win32API.new("msvcrt", "fclose", ['L'], 'L')

h_in, h_out = create_pipe

f_in = open_osfhandle.call(h_in, O_RDONLY | O_BINARY)
f_out = open_osfhandle.call(h_out, O_WRONLY | O_BINARY)

if true
  # This code DOES work, so everything is fine up to this point
  stream_in = fdopen.call(f_in, 'rb')
  stream_out = fdopen.call(f_out, 'wb')
  
  fputs.call("Hellooooo\000", stream_out)
  fclose.call(stream_out)
  
  buffer = "\000" * 200
  fgets.call(buffer, 200, stream_in)
  puts buffer[0..8]
else
  # This does NOT work, why oh why?
  IO.new(f_in, 'rb')
  #=> No such file or directory (Errno::ENOENT)
  IO.new(f_out, 'wb')
end
---------------------------------------------------------------

Hi,

At Wed, 14 Sep 2005 18:56:56 +0900,
Kroeger Simon (ext) wrote in [ruby-talk:156055]:

What I wanted to do was creating new IO objects instead of calling
fdopen myself, but I can't get it to work. The implementation of IO.new
calls fdopen so I realy have no clue why this should not do the trick.

It worked successfully, with both of mswin32 and mingw32 ruby.

  $ tail -5 pipe.rb
  inp = IO.new(f_in, 'rb')
  outp = IO.new(f_out, 'wb')
  outp.print("Hellooooo\000")
  outp.close
  p inp.gets

  $ ruby18-mswin32.exe -v pipe.rb
  ruby 1.8.3 (2005-07-03) [i386-mswin32]
  "Hellooooo\000"

  $ ruby18-mingw32.exe -v pipe.rb
  ruby 1.8.3 (2005-09-12) [i386-mingw32]
  "Hellooooo\000"

···

--
Nobu Nakada