Module: WinWindow::AttachLib

Included in:
WinGDI, WinKernel, WinUser
Defined in:
lib/vapir-common/win_window.rb

Overview

this module exists because I’ve implemented this library for DL, for FFI, and for Win32::API. Getting tired of changing everything everywhere, now it just takes changes to Types, and a few methods (use_lib, attach, callback) to switch to another library.

Constant Summary collapse

IsWin64 =

TODO/FIX: detect this!

nil
Types =

types that FFI recognizes

[:char, :uchar, :int, :uint, :short, :ushort, :long, :ulong, :void, :pointer, :string].inject({}) do |type_hash, type|
  type_hash[type]=type
  type_hash
end

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add_type(hash) ⇒ Object

# here begins the Win32::API version. this one doesn’t work because of a hard-coded limit on

# callbacks in win32/api.c combined with a lack of any capacity to remove any callbacks. 
require 'win32/api'

# basic types that Win32::API recognizes
Types={ :char => 'I', # no 8-bit type in Win32::API?
        :uchar => 'I', # no unsigned types in Win32::API?
        :int => 'I',
        :uint => 'I',
        :long => 'L',
        :ulong => 'L',
        :void => 'V',
        :pointer => 'P',
        :callback => 'K',
        :string => 'P', # 'S' works here on mingw32, but not on mswin32 
      }

def use_lib(lib)
  @lib=lib
end
# this takes arguments in the order that they're given in c/c++ so that signatures look kind of like the source
def attach(return_type, function_name, *arg_types)
  the_function=Win32::API.new(function_name.to_s, arg_types.map{|arg_type| Types[arg_type] }.join(''), Types[return_type], @lib)
  metaclass=class << self;self;end
  metaclass.send(:define_method, function_name) do |*args|
    the_function.call(*args)
  end
  nil
end
# this takes arguments like #attach, but with a name for the callback's type on the front. 
def callback(callback_type_name, return_type, callback_method_name, *arg_types)
  Types[callback_type_name]=Types[:callback]

  # perform some hideous class_eval'ing to dynamically define the callback method such that it will take a block 
  metaclass=class << self;self;end
  metaclass.class_eval("def #{callback_method_name}(&block)
    #{callback_method_name}_with_arg_stuff_in_scope(block)
  end")
  types=Types
  metaclass.send(:define_method, callback_method_name.to_s+"_with_arg_stuff_in_scope") do |block|
    return Win32::API::Callback.new(arg_types.map{|t| types[t]}.join(''), types[return_type], &block)
  end
  def remove_#{callback_method_name}(callback_method)
    # Win32::API has no support for removing callbacks? 
    nil
  end")
  # don't use define_method as this will be called from an ensure block which segfaults ruby 1.9.1. see http://redmine.ruby-lang.org/issues/show/2728
  #metaclass.send(:define_method, "remove_"+callback_method_name.to_s) do |callback_method|
  #  nil
  #end
  nil
end


156
157
158
159
160
161
162
163
# File 'lib/vapir-common/win_window.rb', line 156

def self.add_type(hash)
  hash.each_pair do |key, value|
    unless Types.key?(value)
      raise "unrecognized type #{value.inspect}"
    end
    Types[key]=Types[value]
  end
end

.extended(extender) ⇒ Object



39
40
41
42
43
# File 'lib/vapir-common/win_window.rb', line 39

def self.extended(extender)
  ffi_module=Module.new
  ffi_module.send(:extend, FFI::Library)
  extender.send(:instance_variable_set, '@ffi_module', ffi_module)
end

Instance Method Details

#attach(return_type, function_name, *arg_types) ⇒ Object

this takes arguments in the order that they’re given in c/c++ so that signatures look kind of like the source



49
50
51
52
53
54
55
56
57
# File 'lib/vapir-common/win_window.rb', line 49

def attach(return_type, function_name, *arg_types)
  @ffi_module.attach_function(function_name, arg_types.map{|arg_type| Types[arg_type] }, Types[return_type])
  metaclass=class << self;self;end
  ffi_module=@ffi_module
  metaclass.send(:define_method, function_name) do |*args|
    ffi_module.send(function_name, *args)
  end
  nil
end

#callback(callback_type_name, return_type, callback_method_name, *arg_types) ⇒ Object

this takes arguments like #attach, but with a name for the callback’s type on the front.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/vapir-common/win_window.rb', line 59

def callback(callback_type_name, return_type, callback_method_name, *arg_types)
  
  Types[callback_type_name]=callback_type_name
  
  #@ffi_module.callback(callback_type_name, arg_types.map{|type| Types[type]}, Types[return_type])
  
  # we do not call @ffi_module.callback here, because it is broken. we need to pass the convention ourselves in the options hash. 
  # this is adapted from: http://gist.github.com/256660
  options={}
  types=Types
  @ffi_module.instance_eval do
    options[:convention] = defined?(@ffi_convention) ? @ffi_convention : :default
    options[:enums] = @ffi_enums if defined?(@ffi_enums)

    cb = FFI::CallbackInfo.new(find_type(types[return_type]), arg_types.map{|e| find_type(types[e]) }, options)

    @ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
    @ffi_callbacks[callback_type_name] = cb
  end
  #options[:convention] = @ffi_module.instance_variable_defined?('@ffi_convention') ? @ffi_module.instance_variable_get('@ffi_convention') : :default
  #options[:enums] = @ffi_module.instance_variable_get('@ffi_enums') if @ffi_module.instance_variable_defined?('@ffi_enums')
  #unless @ffi_module.instance_variable_defined?('@ffi_callbacks')
  #  @ffi_module.instance_variable_set('@ffi_callbacks', cb)
  #end
  
  # perform some hideous class_eval'ing to dynamically define the callback method such that it will take a block 
  metaclass=class << self;self;end

  # FFI just takes the block itself. don't need anything fancy here. 
  metaclass.class_eval("def #{callback_method_name}(&block)
    block
  end
  def remove_#{callback_method_name}(callback_method)
    # FFI has no support for removing callbacks? 
    nil
  end")
  # don't use define_method as this will be called from an ensure block which segfaults ruby 1.9.1. see http://redmine.ruby-lang.org/issues/show/2728
  #metaclass.send(:define_method, "remove_"+callback_method_name.to_s) do |callback_method|
  #  nil
  #end
  nil
end

#use_lib(lib) ⇒ Object



44
45
46
47
# File 'lib/vapir-common/win_window.rb', line 44

def use_lib(lib)
  @ffi_module.ffi_lib lib
  @ffi_module.ffi_convention :stdcall
end