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 =
:nodoc: all
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
187 188 189 190 191 192 193 194 |
# File 'lib/winwindow.rb', line 187 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
70 71 72 73 74 |
# File 'lib/winwindow.rb', line 70 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
80 81 82 83 84 85 86 87 88 |
# File 'lib/winwindow.rb', line 80 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.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/winwindow.rb', line 90 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
75 76 77 78 |
# File 'lib/winwindow.rb', line 75 def use_lib(lib) @ffi_module.ffi_lib lib @ffi_module.ffi_convention :stdcall end |