[Win32utils-devel] Trouble getting a callback to work with FFI

Heesob Park phasis at gmail.com
Tue Jul 3 15:15:28 UTC 2012


Hi,

2012/7/3 Daniel Berger <djberg96 at gmail.com>

> On Mon, Jul 2, 2012 at 6:43 PM, Heesob Park <phasis at gmail.com> wrote:
> > Hi,
> >
> > 2012/7/3 Daniel Berger <djberg96 at gmail.com>
> >>
> >> Hi,
> >>
> >> I'm getting a segfault when I try to pass a callback proc to
> >> ReadFileEx. The proc fires, then the interpreter segfaults.
> >>
> >> Any ideas? I tried a blocking callback, too, but that didn't help.
> >>
> >> require 'ffi'
> >>
> >> class Windows
> >>  extend FFI::Library
> >>  ffi_lib :kernel32
> >>
> >>  class Overlapped < FFI::Struct
> >>    layout(
> >>      :Internal, :ulong,
> >>      :InternalHigh, :ulong,
> >>      :Offset, :ulong,
> >>      :OffsetHigh, :ulong,
> >>      :hEvent, :ulong
> >>    )
> >>  end
> >>
> >>  callback :completion_proc, [:ulong, :ulong, Overlapped], :void
> >>
> >>  attach_function :CloseHandle, [:ulong], :bool
> >>  attach_function :CreateFileA, [:string, :ulong, :ulong, :pointer,
> >> :ulong, :ulong, :ulong], :ulong
> >>  attach_function :ReadFileEx, [:ulong, :buffer_out, :ulong,
> >> Overlapped, :completion_proc], :bool
> >>  attach_function :GetOverlappedResult, [:ulong, :pointer, :pointer,
> >> :bool], :bool
> >>  attach_function :SleepEx, [:ulong, :bool], :ulong
> >>
> >>  OPEN_EXISTING             = 3
> >>  GENERIC_READ              = 0x80000000
> >>  FILE_SHARE_READ           = 0x00000001
> >>  FILE_FLAG_OVERLAPPED      = 0x40000000
> >>  FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000
> >>  INVALID_HANDLE_VALUE      = 0xFFFFFFFF
> >>  ERROR_IO_PENDING          = 997
> >>
> >>  def self.read(file)
> >>    flags = FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN
> >>
> >>    begin
> >>      handle = CreateFileA(
> >>        file,
> >>        GENERIC_READ,
> >>        FILE_SHARE_READ,
> >>        nil,
> >>        OPEN_EXISTING,
> >>        flags,
> >>        0
> >>      )
> >>
> >>      if handle == INVALID_HANDLE_VALUE
> >>        raise SystemCallError, FFI.errno, "CreateFile"
> >>      end
> >>
> >>      buf   = 0.chr * File.size(file)
> >>      olap  = Overlapped.new
> >>
> >>      cproc = Proc.new do |error, bytes, overlapped|
> >>        puts "Error: #{error}"
> >>        puts "Bytes: #{bytes}"
> >>        p overlapped
> >>      end
> >>
> >>      ### FAIL: cproc fires, but then I get a segfault
> >>      bool  = ReadFileEx(handle, buf, buf.size, olap, cproc)
> >>      errno = FFI.errno
> >>
> >>      SleepEx(1, true)
> >>
> >>      unless bool
> >>        if errno == ERROR_IO_PENDING
> >>          bytes = FFI::MemoryPointer.new(:ulong)
> >>          unless GetOverlappedResult(handle, olap, bytes, true)
> >>            raise SystemCallError, FFI.errno, "GetOverlappedResult"
> >>          end
> >>        else
> >>          raise SystemCallError, errno, "ReadFileEx"
> >>        end
> >>      end
> >>
> >>      buf.delete(0.chr)
> >>    ensure
> >>      CloseHandle(handle) if handle
> >>    end
> >>  end
> >> end
> >>
> >> File.open('small.txt', 'w'){ |fh| fh.puts "Hello World" }
> >> p Windows.read('small.txt')
> >>
> >
> > I guess this is due to the calling convention mismatch.
> >
> > If you add ffi_convention line, it will work.
> >
> > ...
> > class Windows
> >  extend FFI::Library
> >  ffi_lib :kernel32
> >  ffi_convention :stdcall  # add this line
>
> Thanks, I was thinking this was the default. However, I still noticed
> issues.
>
> First, it only seems to work with mingw. If I used the MSVC++ version
> it still bombs.
>
> Second, it only seems to work if I declare a callback in the function
> prototype and use a Proc. If I try to use a :pointer + FFI::Function,
> it still segfaults. In other words this works:
>
> callback :completion_proc, [:ulong, :ulong, Overlapped], :void
> attach_function :ReadFileEx, [:ulong, :buffer_out, :ulong, Overlapped,
> :completion_proc], :bool
> cproc = Proc.new{ |x,y,z| }
>
> But this does not:
>
> attach_function :ReadFileEx, [:ulong, :buffer_out, :ulong, Overlapped,
> :pointer], :bool
> cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer]){ |x,y,z| }
>
> Do you see the same thing?
>
>
First, I can see segfaults with MSVC++ version.
Yet, I have no idea what is the cause.

Second, the calling convention is the matter.

cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer]){ |x,y,z| }
should be
cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer],{:convention
=>:stdcall}){ |x,y,z| }

Regards,

Park Heesob
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/win32utils-devel/attachments/20120704/5ef9c641/attachment.html>


More information about the win32utils-devel mailing list