Module: WinWindow::AttachLib

Included in:
WinGDI, WinKernel, WinUser
Defined in:
lib/winwindow.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 =

: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

Instance Method Summary collapse

Class Method Details

.add_type(hash) ⇒ Object



132
133
134
135
136
137
138
139
# File 'lib/winwindow.rb', line 132

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



69
70
71
72
73
# File 'lib/winwindow.rb', line 69

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



79
80
81
82
83
84
85
86
87
# File 'lib/winwindow.rb', line 79

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.



89
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 89

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)

    # the below is for ffi < 1.0; @ffi_callbacks goes away in the future. it's ignored by 
    # newer versions of ffi. so no harm in continuing to set it here. 
    @ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
    @ffi_callbacks[callback_type_name] = cb
    # and the below is for newer versions of ffi (1.0.*). of course, @ffi_module.callback 
    # works in newer. at some point I'll drop support for older broken versions and just 
    # use ffi's #callback. 
    typedef cb, callback_type_name
  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



74
75
76
77
# File 'lib/winwindow.rb', line 74

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