D
Daniel Berger
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:
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));
// Return a bonafide File object, based on the file descriptor
return rb_class_new_instance(1,args,rb_cFile);
}
For read operations, this works. I can do this:
fh = File.nopen("C:\\somefile")
p fh.readlines # works fine
fh.close
I can even read from a directory:
fh = File.nopen("C:\\TESTDIR",nil,nil,nil,File::BACKUP_SEMANTICS)
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?
Regards,
Dan
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:
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));
// Return a bonafide File object, based on the file descriptor
return rb_class_new_instance(1,args,rb_cFile);
}
For read operations, this works. I can do this:
fh = File.nopen("C:\\somefile")
p fh.readlines # works fine
fh.close
I can even read from a directory:
fh = File.nopen("C:\\TESTDIR",nil,nil,nil,File::BACKUP_SEMANTICS)
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?
Regards,
Dan