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

Daniel Berger djberg96 at gmail.com
Mon Jul 2 21:45:18 UTC 2012


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


More information about the win32utils-devel mailing list