Module: WinWindow::AttachLib
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
-
.add_type(hash) ⇒ Object
# here begins the Win32::API version.
- .extended(extender) ⇒ Object
Instance Method Summary collapse
-
#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.
-
#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.
- #use_lib(lib) ⇒ Object
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]) =class << self;self;end ffi_module=@ffi_module .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 ={} types=Types @ffi_module.instance_eval do [:convention] = defined?(@ffi_convention) ? @ffi_convention : :default [:enums] = @ffi_enums if defined?(@ffi_enums) cb = FFI::CallbackInfo.new(find_type(types[return_type]), arg_types.map{|e| find_type(types[e]) }, ) @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 =class << self;self;end # FFI just takes the block itself. don't need anything fancy here. .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 |