From: Park Heesob Date: 2004-11-13T10:21:39+09:00 Subject: Re: Win32, file descriptors and rb_io_check_writable() Hi, > > Hi all, > > Windows 2000/XP > VC++ 6.0 or 7.0 > Ruby 1.8.2 (Installer RC9) > > I'm trying to write an extension for the win32-file package. > Specifically, I want to write a wrapper for CreateFile() called > File.nopen (for 'native open'). I thought this would be nice for two > reasons. First, it would give you finer control over HANDLE creation > on the Win32 platform. Second, it would allow you to open > directories, since you cannot currently call File.open on a directory > on Windows. > > So, the API would look like this: > > File.nopen(file, access, share, creation, flags) > > The underlying C code looks like this: > ... > For read operations, this works. I can do this: > > fh = File.nopen("C:\\somefile") > p fh.readlines # works fine > fh.close > > > But, I cannot write to the filehandle: > > fh = File.nopen("C:\\somefile") > fh.puts "Hello" > > test.rb:13:in `write': not opened for writing (IOError) > from test.rb:13:in `puts' > from test.rb:13 > > That error appears to be coming from the rb_io_check_writable() > function, which in turn is checking the mode of the OpenFile struct > defined in rubyio.h. > > How do I deal with this? Am I doing something wrong? Or would it > take a modification of io.c for this to work? If so, what should be > done? > Following code will work: #define OpenFile WINAPI_OpenFile #include ... #undef OpenFile #include "ruby.h" #include "rubyio.h" ... static VALUE file_nopen(int argc, VALUE *argv, VALUE klass){ HANDLE h; int rv; VALUE args[1]; VALUE rbFile, rbAccess, rbShare, rbCreation, rbFlags; DWORD dwAccess = FILE_ALL_ACCESS; // I tried various flags here DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE; DWORD dwCreation = OPEN_EXISTING; DWORD dwFlags = FILE_ATTRIBUTE_NORMAL; rb_scan_args(argc,argv,"14",&rbFile,&rbAccess,&rbShare,&rbCreation,&rbFlags); // Override default values with user supplied values if(Qnil != rbAccess) dwAccess = (DWORD)NUM2UINT(rbAccess); if(Qnil != rbShare) dwShare = (DWORD)NUM2UINT(rbShare); if(Qnil != rbCreation) dwCreation = (DWORD)NUM2UINT(rbCreation); if(Qnil != rbFlags) dwFlags = (DWORD)NUM2UINT(rbFlags); h = CreateFile( StringValuePtr(rbFile), dwAccess, dwShare, NULL, // Cannot be inherited dwCreation, dwFlags, NULL // No template ); if(h == INVALID_HANDLE_VALUE) rb_raise(cFileError,ErrorDescription(GetLastError())); // Convert HANDLE to file descriptor args[0] = UINT2NUM(_open_osfhandle((long)h,O_RDWR)); RFILE(self)->fptr->mode = rb_io_mode_flags("w+"); // mode string correspond to dwAccess RFILE(self)->fptr->f = rb_fdopen(NUM2INT(args[0]),"w+"); // mode string correspond to dwAccess // Return a bonafide File object, based on the file descriptor return rb_class_new_instance(1,args,rb_cFile); } > Regards, > > Dan > > Regards, Park Heesob