Ruby - passing a method to a DLL library as a call

2019-07-11 03:42发布

问题:

Let's say I have a C/C++ library with this function, compiled to a DLL:

#include <Windows.h>

extern "C" __declspec(dllexport) void __stdcall myFunction(void (*myCallback)(int)) {
    int result = MessageBox(
        0, (LPCWSTR)L"Press yes or no", (LPCWSTR)L"Test", MB_YESNO
    );
    myCallback(result);
}

It just opens standard Win32 message box and passes the result to a callback function.

The question is: is it possible to use this function in Ruby, via Fiddle or something similar, and pass a Ruby method to it somehow so it is called from within the C++ code?

Here is the code I use to import DLL library to Ruby:

require "fiddle"

myLibrary = Fiddle.dlopen("myLibrary.dll")
myFunction = Fiddle::Function.new(
  myLibrary["myFunction"], 
  [Fiddle::TYPE_VOIDP], 
  Fiddle::TYPE_VOID
)

def myCallback(value)
  puts "MessageBox result is #{value}"
end

And this obviously doesn't work:

myFunction.call(method(:myCallback))

It just throws a TypeError - can't convert Method to Integer.

Is there a way to pass the callback to the C function?

回答1:

So I found the solution:

myClosure = Class.new(Fiddle::Closure) {
  def call(value)
    puts "MessageBox result is #{value}"  
  end
}.new(Fiddle::TYPE_VOID, [Fiddle::TYPE_INT])

Then I can simply call the C function:

myFunction.call(myClosure)

I don't really know how this works - but it works fine.



标签: c++ c ruby dll